许可优化
许可优化
产品
产品
解决方案
解决方案
服务支持
服务支持
关于
关于
软件库
当前位置:服务支持 >  软件文章 >  angr内存模拟源码阅读与分析

angr内存模拟源码阅读与分析

阅读数 1
点赞 0
article_banner

angr内存模拟部分源码阅读

文章目录

  • angr内存模拟部分源码阅读
  • angr简介 代码结构 angr使用 angr源码阅读 入口部分&一些主要类 Project类 AngrObjectFactory类 SimOs类 SimulationManager类 插件系统 Mixin设计模式 插件系统介绍 PluginHub类 PluginPreset类 SimStatePlugin类 模拟内存插件 PagedMemoryMixin类 ListPagesMixin类 AddressConcretizationMixin类 符号内存地址具现化策略 SimState程序状态类 参考

      本篇阅读了一下angr的源码, 侧重分析了一下程序状态state的插件部分,还有内存插件的实现,符号化内存地址寻址时的操作等。


省流量直接看逻辑图:https://app.diagrams.net/#Hchenaotian%2Fangr-work%2Fmain%2Fangr.drawio

angr简介

angr就是angr,这是它的logo:

请添加图片描述

代码结构

逻辑结构

在这里插入图片描述

代码目录中一些比较关键的部分:

   ├── concretization_strategies:内存符号化策略

   ├── exploration_techniques:用于传给SimulationManager.use_technique,各种不同的探索方法

   ├── misc:一些初始 类  

   ├── procedures:函数摘要

   ├── simos:初始化类状态的,linux java啥的,state_entry就在这

   ├── state_plugins:状态的插件,内存、寄存器等的基础类

   ├── storage:内存插件(memory_mixin)、文件、网络类等

├── sim_state.py :程序状态类,主要类,负责注册各种功能插件

   ├── factory.py:定义程序初始状态/入口的类

   ├── project.py:主要类,angr加载程序

   └── sim_manager.py:模拟执行管理类,step、run等方法

angr使用

不是本文的重点知识,但感觉还必须有这一节,可以参考:

angr源码阅读

开始读源码,前面的部分快速看一眼干了啥就行,主要分析一下angr如何模拟内存的读写,还有遇到符号化内存地址寻址的时候的处理方法。详细的类之间的关系以及实现的功能请看逻辑图

入口部分&一些主要类

一般用angr初始化一个二进制程序分为一下几步骤:

import angr
p = angr.Project("test.out")
state = p.factory.entry_state()
simgr = p.factory.simgr(state)#simgr是simulation_manager的别名
simgr.explore(find=xxxx)

前面的这些简单过一遍,不详细分析了,主要后面分析内存相关。

Project类

angr的入口,负责启动解析一个二进制文件,根据二进制文件的类型(如ELF、PE)去解析其中的一些 信息 ,如程序段信息、程序入口点、程序导入导出函数表、程序架构、所属平台(Linux、Windows)信息等,其实就是将程序的基本信息获取一下,然后再初始化一些接下来会用到的其他类的对象,如factory等。

AngrObjectFactory类

AngrObjectFactory类就是上面代码中的p.factory,在Project类中被初始化,主要功能其实就是获取一个程序状态作为初始化状态,这里提供了不同的选择:

  • entry_state:提供程序入口处的状态
  • blank_state:空白状态,其状态由用户确认(执行地址、内存寄存器中的额值等)
  • full_init_state:完整的初始化状态,从程序最开始处
  • call_state:函数调用状态,类似blank_state,其他状态都要自己给定,但区别是可以设置参数快一些。

其实获取上面这些状态也不是factory 自己来实现的,他也是调用的SimOs类:

class AngrObjectFactory:
	··· ···
    def entry_state(self, **kwargs) -> SimState:
        return self.project.simos.state_entry(**kwargs)
    ··· ···
SimOs类

SimOs是模拟操作系统的基本类,会根据操作系统的类型不同拍生成对应操作系统的类,比如SimLinux,上述的很多获得初始化状态的方法,都来自于SimOs中的state_blank方法:

class SimOS:
    def state_blank(self, addr=None, initial_prefix=None, brk=None, stack_end=None, stack_size=1024*1024*8, stdin=None,
                    thread_idx=None, permissions_backer=None, **kwargs):
        #基本初始化状态函数
        # TODO: move ALL of this into the SimState constructor
        ··· ···

        if kwargs.get('permissions_map', None) is None: #初始化段权限
            ··· ···

        state = SimState(self.project, stack_end=stack_end, stack_size=stack_size, stack_perms=stack_perms, **kwargs)#在这里初始化SimState类

        if stdin is not None and not isinstance(stdin, SimFileBase):#stdin 指定了文件的话
            ··· ···

        last_addr = self.project.loader.main_object.max_addr
        actual_brk = (last_addr - last_addr % 0x1000 + 0x1000) if brk is None else brk
        state.register_plugin('posix', SimSystemPosix(stdin=stdin, brk=actual_brk)) 
        #posix 是 state中的插件,用于表示一些文件交互比如stdin等

        #后面初始化了寄存器、栈之类的一堆东西

总之就模拟操作系统执行程序之前,初始化了一堆东西。

SimulationManager类

该类主要可以通过一个输入程序状态来进行继续的单步执行(step)或run等操作,也是通过该类拉设置探索方式(ExplorationTechnique)。比较重要的类,但不在这里详细分析了。

插件系统

本篇重点分析的这一部分。

Mixin 设计模式  

首先了解一下angr里无处不在的Mixin设计模式:

Mixin是angr 的一个设计模式,从一个基类根据不同的小功能模块派生出一堆扩展类根据某个大功能需要的若干小功能,将这些小功能的扩展类一起用 python 多继承的方法派生出一个最终的实现大功能的类。在调用该大功能中某个实现方法的时候,会依次使用super 调用下一个小功能中的该方法。就相当于多个小功能接力棒的形式依次完成自己的工作。有些功能之间的关系是平行的(前后顺序无所谓),有些功能之间的关系是依赖的(前后顺序不能颠倒)。

在这里插入图片描述

如图所示,class2、class3、class4都是继承的class1,而class5 由class2、class3、class4共同多继承。而他们都实现了method1方法。并且在每个method1中都调用super().method1(),这样调用class5.method1()方法的时候就会按顺序调用52341的method1方法。根据这种思路,可以将一个复杂的逻辑拆成好几个小部分分别实现。在组合的时候也可以根据场景需要组合出适应不同场景功能的最终类。

插件系统介绍

插件主要涉及三个类:

  • PluginHub:插件管理器,管理一个插件池和一个激活插件列表
  • PluginPreset:插件池类,存放可选激活的插件类(是类不是对象)
  • SimStatePlugin:基本插件类,通过派生该类实现不同功能的插件

angr根据不同的大功能方向(如寄存器插件、内存插件)来划分插件,而不同种类的插件却拥有不止一种,如内存插件有默认的内存插件、快速内存插件、java的内存插件等等。而单个插件的实现使用了上面介绍的Mixin设计方法,将一个当个方向的大功能拆分成很多小功能,最后再多继承的方式组合成该大功能,这样几个相似功能的插件就可以实现部分小功能的复用。

PluginHub类

PluginHub类用作插件管理器,它通常会被派生成实际的插件管理器,比如程序状态类SimState就是派生自PluginHub,也就是说程序状态实际就是一个管理不同小状态插件的插件管理器。

class PluginHub:
    def __init__(self):
        super(PluginHub, self).__init__()
        self._active_plugins = {
   
   } # type: Dict[str, SimStatePlugin]  正在使用的插件
        self._active_preset = None # type: Optional[PluginPreset]  正在使用的插件池
        self._provided_by_preset = [] # type: List[int] 
        
    _presets = None # 类属性,插件池,可以有多个插件池,主要使用默认插件池,里面都是PluginPreset类型对象
    @classmethod
    def register_default(cls, name, plugin_cls, preset='default'):
        #类方法,用来给默认插件池注册一个插件类。
        if cls._presets is None or preset not in cls._presets:
            l.error("Preset %s does not exist yet...", preset)
            return
        cls._presets[preset].add_default_plugin(name, plugin_cls)

    @classmethod 
    def register_preset(cls, name, preset):
        #类方法,给指定插件池注册一个插件类
        if cls._presets is None:
            cls._presets = {
   
   }
        cls._presets[name] = preset
        
    @property
    def plugin_preset(self):
        #可以直接获得插件池
        return self._active_preset
    
    ··· ···
    @property
    def has_plugin_preset(self) -> bool:#查看是否存在指定名称的插件池
        """
        Check whether or not there is a plugin preset in use on this hub right now
        """
        return self._active_preset is not None
    
    def use_plugin_preset(self, preset):
        #将一个插件池设置为启用状态
        if isinstance(preset, str):#如果通过字符串指定,查看是否有该名称的插件池,获取具体插件池对象
            try:
                preset = self._presets[preset]
            except (AttributeError, KeyError):
                raise AngrNoPluginError("There is no preset named %s" % preset)

        elif not isinstance(preset, PluginPreset):
            raise ValueError("Argument must be an instance of PluginPreset: %s" % preset)

        if self._active_preset:
            l.warning("Overriding active preset %s with %s", self._active_preset, preset)
            self.discard_plugin_preset()

        preset.activate(self) #调用插件池的激活函数
        self._active_preset = preset #表示启用该插件池
        
    def get_plugin(self, name: str) -> 'SimStatePlugin':
        #从当前激活的插件中获取指定名称的插件
        if name in self._active_plugins: #如果查询到直接返回
            return self._active_plugins[name]

        elif self.has_plugin_preset: #没找到的话要从插件池中寻找该插件类,并且初始化成一个对象再返回
            plugin_cls = self._active_preset.request_plugin(name) #获取插件类
            plugin = self._init_plugin(plugin_cls) #初始化该插件

            # Remember that this plugin was provided by preset.
            self._provided_by_preset.append(id(plugin))

            self.register_plugin(name, plugin)
            return plugin

        else:
            raise AngrNoPluginError("No such plugin: %s" % name)
        
    def register_plugin(self, name: str, plugin):
        #将一个初始化好的插件添加到激活列表,也就是注册一个插件
        if self.has_plugin(name): #如果已经存在该插件,先释放然后重新注册
            self.release_plugin(name)
        self._active_plugins[name] = plugin
        setattr(self, name
免责声明:本文系网络转载或改编,未找到原创作者,版权归原作者所有。如涉及版权,请联系删


相关文章
技术文档
QR Code
微信扫一扫,欢迎咨询~
customer

online

联系我们
武汉格发信息技术有限公司
湖北省武汉市经开区科技园西路6号103孵化器
电话:155-2731-8020 座机:027-59821821
邮件:tanzw@gofarlic.com
Copyright © 2023 Gofarsoft Co.,Ltd. 保留所有权利
遇到许可问题?该如何解决!?
评估许可证实际采购量? 
不清楚软件许可证使用数据? 
收到软件厂商律师函!?  
想要少购买点许可证,节省费用? 
收到软件厂商侵权通告!?  
有正版license,但许可证不够用,需要新购? 
联系方式 board-phone 155-2731-8020
close1
预留信息,一起解决您的问题
* 姓名:
* 手机:

* 公司名称:

姓名不为空

姓名不为空

姓名不为空
手机不正确

手机不正确

手机不正确
公司不为空

公司不为空

公司不为空