【Angr源码分析】1. 程序加载

1
2
path_to_binary = "./testcases/02_angr_find_condition"
project = angr.Project(path_to_binary)

Project 类是 angr 的入口,负责加载整个可执行文件。其构造函数如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class Project:
"""
这是 angr 模块的主要类。 它旨在包含一组二进制文件及其之间的关系,并对它们进行分析。
"""
def __init__(self, thing, # 需要被分析的二进制程序的路径
default_analysis_mode=None, # 默认的分析模式,缺省值是 'symbolic'
ignore_functions=None,
use_sim_procedures=True,
exclude_sim_procedures_func=None,
exclude_sim_procedures_list=(),
arch=None, simos=None,
engine=None,
load_options: Dict[str, Any]=None,
translation_cache=True,
support_selfmodifying_code=False,
store_function=None,
load_function=None,
analyses_preset=None,
concrete_target=None, # 用于 cle.Loader,表示是否需要具体执行
**kwargs):

默认情况下,angr 会使用 SimProcedures 中的符号摘要替换库函数,即设置 Hooking,这些 python 函数摘要高效地模拟库函数对状态的影响,以下简称sim,可以设置参数 exclude_sim_procedures_list 和 exclude_sim_procedures_func 指定不想被 SimProcedure 替代的符号。

构造函数的处理分为五个步骤:

  1. 加载二进制程序
1
2
3
4
5
else:
# use angr's loader, provided by cle
l.info("Loading binary %s", thing)
self.filename = str(thing)
self.loader = cle.Loader(self.filename, concrete_target=concrete_target, **load_options)
主要是调用 cle.Loader 来加载二进制程序。成功后,二进制程序及其所需的依赖将被映射到虚拟地址空间。cle 拥有许多后端,负责加载不同类型的可执行文件。 (cle.Backend,例如 cle.elf 用于加载 linux32 程序)
1
2
3
4
5
6
>>> import angr
>>> path_to_binary = "./testcases/02_angr_find_condition"
>>> project = angr.Project(path_to_binary)
>>> project.loader.shared_objects
OrderedDict([('02_angr_find_condition', <ELF Object 02_angr_find_condition, maps [0x8048000:0x804f03f]>), ('libc.so.6', <ELF Object libc-2.31.so, maps [0x8100000:0x82eef0b]>), ('ld-linux.so.2', <ELF Object ld-2.31.so, maps [0x8300000:0x832c987]>), ('extern-address space', <ExternObject Object cle##externs, maps [0x8400000:0x8407fff]>), ('cle##tls', <ELFTLSObjectV2 Object cle##tls, maps [0x8500000:0x8514807]>)])
>>>
  1. 判断可执行文件的架构,默认会使用 cle 判断的架构
1
2
elif arch is None:
self.arch = self.loader.main_object.arch
  1. 对一些默认、公有和私有对属性进行设置

    其实就是对属性做检查,对于没有给定的属性使用默认值。例如 default_analysis_mode 如果没有设置,就会被替换为 "symbolic"

  2. 安装 Project 的相关插件

    1. Factory 插件:最重要的组件,后面会继续研究。
1
2
# factory 提供了访问重要分析元件的途径。
self.factory = AngrObjectFactory(self, default_engine=engine)
1. Analysis 插件,angr 内置了一些分析方法,用于提取程序信息。

    
1
2
# AnalysisHub 包含了所有被注册和可运行的分析模块。
self.analyses = AnalysesHub(self)
1. 其他插件
  1. 确定使用的 guest OS,有 linux, windows, cgc, javavm 几种。
1
2
elif simos is None:
self.simos = os_mapping[self.loader.main_object.os](self)
  1. 注册 simprocedures 来替代库函数(略)

    这一点也是 angr 中重要的部分,这一次先不关心。

  2. 运行 OS-specific 配置(略)

1
2
# Step 7: Run OS-specific configuration
self.simos.configure_project()