angr源码分析——angr.Project类

使用angr时,第一行语句就是:b = angr.Project('path/bin_file_name')
该代码调用的为Project类的构造函数_init_()。Project类是angr模块的主类,它对一个二进制文件进行初始的分析以及参数配置,并将数据存储起来进行后续进一步分析。
构造函数参数:
angr.project.Project(thing, default_analysis_mode=None, ignore_functions=None, use_sim_procedures=True, exclude_sim_procedures_func=None, exclude_sim_procedures_list=(), arch=None, simos=None, load_options=None, translation_cache=True, support_selfmodifying_code=False, **kwargs)
  
所需参数解释.
    :param thing:                       要分析的主要可执行对象的路径,或CLE Loader对象.
  下面的参数是可选的.

    :param default_analysis_mode:       默认使用的分析模式. 默认为 'symbolic'.

    :param ignore_functions:            函数名称列表,当从共享库导入后,这些函数不会被进入分析(调用将返回一个非约束值)

    :param use_sim_procedures:          是否用所述简化程序来替代已解决的依赖关系,其中简化程序可用                              

    :param exclude_sim_procedures_func: 一个函数,当传递一个函数名时,返回是否用简化程序包装它(这个参数是个函数???)。

    :param exclude_sim_procedures_list: 不用简化包装的函数列表.

    :param arch:                        目标架构(否则自动检测).

    :param simos:                       用于这个项目的simos类(模拟操作系统???).

    :param bool translation_cache:      布尔变量。如果为True,则缓存已转化的基本块,而不是重新转化它们.

    :param support_selfmodifying_code:  布尔变量。设定是否支持自修改代码。启用后,无论当前的内存保护如何,仿真都会尝试从当前状态而不是原始内存中读取代码.

    :param store_function:              一个函数,定义如何存储Project,默认为pickling方式(Python中的pickle,序列化对象并保存到磁盘中).

    :param load_function:               一个函数,定义如何加载Project,默认是unpicklink方式.


    任何附加的传递关键参数都将传递给'cle.Loader'。

    :ivar analyses:     The available analyses.(analyses类)
    :type analyses:     angr.analysis.Analyses
    :ivar entry:        The program entrypoint.(程序入口点)
    :ivar factory:      Provides access to important analysis elements such as path groups and symbolic execution results.(提供对重要分析元素(如路径组和符号执行结果)的访问)
    :type factory:      AngrObjectFactory
    :ivar filename:     The filename of the executable.
    :ivar loader:       The program loader. (加载器 cle.Loader类)
    :type loader:       cle.Loader
    :ivar surveyors:    The available surveyors.(surveyors类)
    :type surveyors:    angr.surveyors.surveyor.Surveyors
    :ivar storage:      Dictionary of things that should be loaded/stored with the Project. 加载和存储在Project中的字典。

    :type storage:      defaultdict(list)

Project构造函数执行流程:

第一步:将二进制文件加载进去,获得一个cle.Loader实例。首先判断加载的thing是不是cle.loader类实例,如果是则this.loader成员变量则为这个实例,如果不是,则加载一个新的cle.Loader。调用的是cle.Loader初始化函数。这个函数在分析cle模块时详细介绍。

第二步:判断二进制文件的CPU架构,可以自己指定,也可以由cle进行分析,从loader类获取。

第三步:设置默认和公共、私有属性,也就是把该配置的参数配置进去。其中有个函数是get_default_engine,获取默认引擎,这部分代码细节没有深入,只是看到有很多引擎变量,关于hook,failure,syscall,unicorn等。

(有个细节就是,启用了自修改代码,就无法使用已转化基本块缓存功能)

第四步:确定操作系统SimOS。如果未指定,则从cle.loader类中获取。

第五步:对库函数进行适当的注册。

第六步:执行操作系统特殊配置。

Project类中其他函数介绍:

备注:kwargs是keyword args 也就是关键参数的意思。

hook(addr, hook=None, length=0, kwargs=None, replace=False)
功能:用自定义的函数hook住一段代码。它用于内部提供库函数的符号,并用于插桩执行或修改控制流。当没有指定hook时,它将返回一个允许容易hook的函数装饰器。
用例:
#,proj.entry为程序入口点,在程序入口点加入自定义hook函数
@proj.hook(proj.entry)
def my_hook(state):
    print "Welcome to execution!"


hook_symbol(symbol_name, obj, kwargs=None, replace=None)
功能:用于解决二进制文件中的依赖关系。首先查找给定符号的地址,然后hook该地址。如果符号在加载库中不可用,则该地址可以由CLE外面(??)的对象提供。
此外,如果你不是提供符号名称,而是提供地址,某些秘密功能将会启动,您可能仅hook该地址,除非您使用powerpc64 ABIv1或某些未知的可怕ABI,它的函数指针指向某个地址而不是实际的函数,在这种情况下,它会做正确的事情。


load_shellcode(shellcode, arch, start_offset=0, load_address=0)
功能:基于原始字节码加载一个新Project。
参数:
shellcode – 加载的数据
arch – 架构
start_offset – 分析的起始偏移量(默认0)

load_address – 数据加载的内存地址 (默认0)

在构造一个Project类时,最先调用了cle.loader类,将二进制文件加载进去,在代码后面很多参数也是从cle中获得,所以,下篇文章将分析cle.loader类,看一看加载时都做了些什么,它是如何识别二进制文件的架构,系统等信息?

你可能感兴趣的:(物联网,漏洞挖掘)