Angr:强大的二进制分析工具包

开篇

今天我们来介绍一款python实现的二进制分析工具 — angr,由加州大学圣巴巴拉分校的计算机安全实验室开发。

angr是一个支持多CPU架构的二进制分析python工具包,可以对二进制文件进行各种静态分析,以及具有进行动态符号执行的能力,比如:

  • 将二进制代码反汇编为中间表示(IR,Intermediate Representation);
  • 程序插桩;
  • 符号执行;
  • 控制流分析;
  • 数据依赖性分析;
  • 值集分析(VSA,Value Set Analysis);

angr项目的目标是创建一个用户友好的二进制分析套件,允许用户简单地启动iPython并通过几个命令就可以轻松执行复杂的二进制分析。

要以编程的方式分析二进制文件,通常按照以下几个步骤,大致是:
1.将二进制文件载入分析程序;
2.将二进制转换为中间表示(IR);
3.进行实际分析,比如:

  • 部分或完整程序静态分析,比如依赖分析,程序切片等等;
  • 对程序状态空间的象征性探索,比如模拟执行直到发现溢出漏洞;
  • 上述方法的组合,比如只模拟执行导致内存写入的程序片段,以便找到溢出漏洞。

angr提供了各种组件来解决上面的各个步骤,接下来我们从安装开始,并通过示例来讲解下angr的能力。

安装

angr是Python 3.8+的库,因此必须安装到Python环境中才能使用。在安装之前我们可以通过conda创建一个python 3.10的虚拟环境:

conda create --name py310 python=3.10
conda activate py310

然后通过pip安装angr:

pip install -i https://pypi.tuna.tsinghua.edu.cn/simple angr 

核心概念

要开始使用angr,我们需要对一些基本的angr概念,以及如何构造一些基本的angr对象有一个基本的了解。

Project对象

使用angr的第一个操作总是将二进制文件加载进来,如下:

>>> import angr
>>> proj = angr.Project('/bin/true')

Project对象是angr中最先创建的,也是最基础的对象,angr中其它类型的对象都依赖于该对象。有了它,我们才能在加载的二进制文件上进行分析和模拟。

Project对象中包含一些基本属性,这些属性说明了加载的二进制文件的一些基本信息:

import monkeyhex   # 以十六进制方式查看打印的数字
>>> proj.arch      # 二进制文件所属的CPU架构,为archinfo.Arch对象的实例 
<Arch AMD64 (LE)>
>>> proj.arch.name # CPU架构名称
'AMD64'
>>> proj.arch.bits # CPU架构的位数,此处为64位
0x40
>>> proj.entry     # 二进制文件的程序入口点地址
0x401670
>>> proj.filename  # 二进制文件名
'/bin/true'

Loader加载器

获取静态的二进制文件在内存虚拟地址空间中的表示是相当复杂的,angr内部有一个叫做CLE的模块来处理这个问题。CLE模块执行的结果称为加载器,可以在proj.loader 属性中找到。我们可以用它来查看与你的程序一起加载的共享库,以及对加载后的地址空间执行基本查询:

>>> proj.loader # 查看加载的二进制对象和其内存映射区域的起始和终止地址
<Loaded true, maps [0x400000:0x5004000]>>>> proj.loader.shared_objects # 查看链接的共享库,以及各共享库的内存映射起始和终止地址
{'ld-linux-x86-64.so.2': <ELF Object ld-2.24.so, maps [0x2000000:0x2227167]>,'libc.so.6': <ELF Object libc-2.24.so, maps [0x1000000:0x13c699f]>}>>> proj.loader.min_addr # 查看加载的二进制对象的内存映射区域的起始地址
0x400000
>>> proj.loader.max_addr # 查看加载的二进制对象的内存映射区域的终止地址
0x5004000>>> proj.loader.main_object  # 查看加载的主对象和它的内存映射区域的起始地址
<ELF Object true, maps [0x400000:0x60721f]>>>> proj.loader.main_object.execstack  # 查看主对象的栈区域是否是可执行的
False
>>> proj.loader.main_object.pic  # 该主对象是否是位置无关的(位置无关的代码是一种在内存中可以加载到任意位置并且仍然能够正确执行的代码)
True

Factory工厂

在angr中有很多类,它们中的大多数都需要一个project对象来实例化。angr提供了 proj.factory属性,基于该属性可以创建多个需要经常使用的对象。

Block对象

block对象用于从给定地址开始,提取一个指令基本块,该对象中包含了该基本块的很多有用信息。

>>> block = proj.factory.block(proj.entry) # 从程序的入口点地址开始,进行反编译,并获取第一个指令基本块
<Block for 0x401670, 42 bytes>>>> block.pp()                          # 输出该基本块的指令
0x401670:       xor     ebp, ebp
0x401672:       mov     r9, rdx
0x401675:       pop     rsi
0x401676:       mov     rdx, rsp
0x401679:       and     rsp, 0xfffffffffffffff0
0x40167d:       push    rax
0x40167e:       push    rsp
0x40167f:       lea     r8, [rip + 0x2e2a]
0x401686:       lea     rcx, [rip + 0x2db3]
0x40168d:       lea     rdi, [rip - 0xd4]
0x401694:       call    qword ptr [rip + 0x205866]>>> block.instructions                  # 该基本块的指令数量
0xb
>>> block.instruction_addrs             # 该基本块中所有指令的地址
[0x401670, 0x401672, 0x401675, 0x401676, 0x401679, 0x40167d, 0x40167e, 0x40167f, 0x401686, 0x40168d, 0x401694]

State状态

Project对象只代表程序的“初始化状态”。当使用angr模拟执行时,你可以获得一个代表模拟程序状态的特定对象—SimState对象 。

>>> state = proj.factory.entry_state()
<SimState @ 0x401670>
SimState对象包含程序的内存、寄存器、文件系统数据,可以使用state.regs 和 state.mem 来访问此状态的寄存器和内存:
>>> state.regs.rip  # 获取rip寄存器中的值,即当前执行的指令地址
<BV64 0x401670>
>>> state.regs.rax  # 获取rax寄存器中的值
<BV64 0x1c>
>>> state.mem[proj.entry].int.resolved  # 获取内存中程序入口点地址起始的4字节的内容,以int方式解释该内容
<BV32 0x8949ed31>

Simulation Managers模拟管理器

如果一个SimState对象允许我们在给定的时间点表示一个程序,那么一定有一种方法可以让它到达下一个时间点。模拟管理器是angr中的主要接口,用于进行模拟执行。作为一个简短的介绍,让我们展示如何使用我们前面创建的状态对象,向前模拟执行推进几个基本块。

首先,我们创建将要使用的模拟管理器。构造函数可以接受一个状态对象或状态对象列表。

>>> simgr = proj.factory.simulation_manager(state)
<SimulationManager with 1 active>
>>> simgr.active
[<SimState @ 0x401670>]

一个模拟管理器可以包含多种状态,默认的是active类状态,该类状态由我们传入的状态对象初始化。接下来,我们可以进行模拟执行了:

>>> simgr.step()
我们刚刚进行了一个基本块的符号执行,现在可以再次查看active的状态对象,注意到它已经更新,而且它没有修改我们的原始状态,而是创建了一个新的状态对象。SimState对象在执行时被视为不可变的,是一个不可变对象。
>>> simgr.active
[<SimState @ 0x1020300>]
>>> simgr.active[0].regs.rip                
<BV64 0x1020300>
>>> state.regs.rip                           
<BV64 0x401670>

Analyses分析

angr预先内置了多个个分析模块,可以使用它们从程序中提取有用的信息。它们是:

>>> proj.analyses.            # 使用tab显示所有的分析模块proj.analyses.BackwardSlice        proj.analyses.CongruencyCheck      proj.analyses.reload_analysesproj.analyses.BinaryOptimizer      proj.analyses.DDG                  proj.analyses.StaticHookerproj.analyses.BinDiff              proj.analyses.DFG                  proj.analyses.VariableRecoveryproj.analyses.BoyScout             proj.analyses.Disassembly          proj.analyses.VariableRecoveryFastproj.analyses.CDG                  proj.analyses.GirlScout            proj.analyses.Veritestingproj.analyses.CFG                  proj.analyses.Identifier           proj.analyses.VFGproj.analyses.CFGEmulated          proj.analyses.LoopFinder           proj.analyses.VSA_DDGproj.analyses.CFGFast              proj.analyses.Reassembler

举一个例子,下面是如何构建和使用快速控制流图:

>>> proj = angr.Project('/bin/true', auto_load_libs=False)
>>> cfg = proj.analyses.CFGFast()
<CFGFast Analysis Result at 0x2d85130>>>> cfg.graph
<networkx.classes.digraph.DiGraph at 0x2da43a0>
>>> len(cfg.graph.nodes())
951>>> entry_node = cfg.get_any_node(proj.entry)
>>> len(list(cfg.graph.successors(entry_node)))
2

总结

二进制分析是一个庞大又复杂的领域,里面有很多吸引人的内容,包括漏洞分析、逆向工程、安全研究等。angr 的出现为研究人员和安全专业人员提供了一个有力的工具,可以更好地理解和分析二进制程序。

本文介绍了angr的一些基本概念和用法,这些内容只是触及这个强大工具的表面而已。因此本文算作抛砖引玉吧,感兴趣的同学可以进一步阅读它的官方文档来学习更高级的用法,并将angr融入到二进制分析的工作中。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/698548.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【Java】接口及其实现(实验四)

目录 一、实验目的 二、实验内容 三、实验小结 一、实验目的 了解接口的作用掌握接口的定义与实现掌握接口的回调 二、实验内容 1. 定义一个接口Human&#xff0c;其中有一无参的、返回类型为void的方法speak&#xff08;&#xff09;&#xff1b;定义类Student实现接口&a…

【ECharts】调用接口获取后端数据的四种方法

使用eacharts做大屏&#xff0c;需要使用后端数据&#xff0c;下面的方法是自己试过有效的&#xff0c;有什么不对的&#xff0c;望各位大佬指点。 目录 方法一&#xff1a;在mounted中使用定时器调用eacharts方法&#xff08;定时器可以获取到data中的数据&#xff09; 方法…

C++基础(五:运算符重载)

运算符重载 对于基本数据类型&#xff0c;可以直接运算&#xff0c;但是类不能直接参与运算&#xff0c; 没有对运算符进行重载 【1】运算符重载函数名格式 返回值 operator运算符(参数) {//函数体 } 【2】运算符重载的目的 让自己定义的类也能直接参与运算 运算符重载的要求&…

Stable Diffusion 3震撼发布模型与Sora同架构

Prompt&#xff1a;Epic anime artwork of a wizard atop a mountain at night casting a cosmic spell into the dark sky that says "Stable Diffusion 3" made out of colorful energy Stability AI发布Stable Diffusion 3文本到图像模型。该模型采用扩散变换架构…

SQL库操作

1、创建数据库 概念 创建数据库&#xff1a;根据项目需求创建一个存储数据的仓库 使用create database 数据库名字创建 数据库层面可以指定字符集:charset/character set 数据库层面可以指定校对集:collate 创建数据库会在磁盘指定存放处产生一个文件夹 创建语法 create …

【算法分析与设计】1的个数

&#x1f4dd;个人主页&#xff1a;五敷有你 &#x1f525;系列专栏&#xff1a;算法分析与设计 ⛺️稳中求进&#xff0c;晒太阳 题目 编写一个函数&#xff0c;输入是一个无符号整数&#xff08;以二进制串的形式&#xff09;&#xff0c;返回其二进制表达式中数字位…

【初始RabbitMQ】交换机的实现

交换机概念 RabbitMQ消息传递模型的核心思想就是&#xff1a;生产者生产的消息从不会直接发送到队列。实际上&#xff0c;通常生产者不知道这些消息会传递到那些队列中 相反&#xff0c;生产者只能将消息发送到交换机&#xff0c;交换机的工作内容也很简单&#xff0c;一方面…

云服务器发展史

在数字化浪潮的推动下&#xff0c;云服务器作为信息技术领域的一颗璀璨明珠&#xff0c;其发展史是一部科技进步和创新思维的缩影。从最初的概念提出到现如今的广泛应用&#xff0c;云服务器经历了翻天覆地的变化&#xff0c;不仅极大地推动了信息技术的发展&#xff0c;也彻底…

JavaScript运算符

文章目录 运算符介绍算术运算符递增和递减运算符比较运算符逻辑运算符短路运算逻辑与 逻辑或 赋值运算符运算符优先级 运算符介绍 算术运算符 %取余运算符的主要用途&#xff1a; 判断某个数是否能被某个数整除。 浮点数的精度问题&#xff1a; 所以&#xff1a;不要直接判断…

Unicode转换 [ASIS 2019]Unicorn shop1

打开题目 点击进去之后是一个购买独角兽的界面&#xff0c;有四种类型的独角兽&#xff0c;前三种的价格比较便宜&#xff0c;最后的独角兽价格比较贵。 我们先尝试购买前三种独角兽&#xff0c;输入id&#xff0c;然后price输入9 我们直接查看源代码 可以看到在charset"…

操作符的属性:优先级、结合性(缺表达式求值)

C语言的操作符有2个重要的属性&#xff1a;优先级、结合性&#xff0c;这两个属性决定了表达式求值的计算顺序。 我们先简单了解一下操作符的优先级和结合性&#xff0c;附上表格&#xff0c;简单记一下顺序&#xff0c;搭配几道题来加深印象。 1.优先级 优先级指的是&#x…

linux常用的网络命令实战分享

文章目录 ifup/down命令ifconfig命令观察网络接口信息修改接口参数增加虚拟网络接口 route命令查看路由表增加路由表规则删除路由表规则 IP 命令ip linkip addr设定路由 ip route arp 命令 在实际研发运维工作中常常会涉及到网关相关的操作和知识&#xff0c;这里对linux下常用…

要赢,且不止一次,2024创维汽车势不可挡!

随着除夕钟声的敲响&#xff0c;创维汽车迎来了全新的一年。过往取得的成绩已成为了历史&#xff0c;全新的未来还有待奋斗者们去开创。为辞旧迎新&#xff0c;创维汽车于2月22日及2月23日召开了“新春启航&#xff0c;共谋发展”营销会议&#xff0c;为2024做下全新布局。 创维…

js设计模式:组合模式

作用: 可以用来将数据组合成树形的数据,可以像操作单独的对象一样去操作整个树形结构 树是相对复杂的数据,使用组合模式去封装树形的组件,是很重要的,可以对外暴露很多树的操作方法 示例: //一个树型的对象数据class Organ {constructor(label, value, parentName) {this.la…

离散化算法

离散化算法的思想是将一组连续的数据映射到一组离散的取值&#xff0c;通常是整数。它的主要目的是将连续的数据转换为离散的数据&#xff0c;以便进行统计、计数、排序等操作。 C代码实现: #include<iostream> #include<vector> #include<algorithm> usi…

数据库事物复习

事务 比如说将张三的银行账户拿出一千给李四&#xff0c;首先需要查询张三的账户余额&#xff0c;扣除1000&#xff0c;然后如果给李四加上1000的过程中出现异常会回滚事务&#xff0c;临时修改的数据会回复回去。 -- 1. 查询张三账户余额 select * from account where name …

如何用GPT进行成像光谱遥感数据处理?

第一&#xff1a;遥感科学 从摄影侦察到卫星图像 遥感的基本原理 遥感的典型应用 第二&#xff1a;ChatGPT ChatGPT可以做什么&#xff1f; ChatGPT演示使用 ChatGPT的未来 第三&#xff1a;prompt 提示词 Prompt技巧&#xff08;大几岁&#xff09; 最好的原则和策…

已解决org.springframework.web.HttpSessionRequiredException异常的正确解决方法,亲测有效!!!

已解决org.springframework.web.HttpSessionRequiredException异常的正确解决方法&#xff0c;亲测有效&#xff01;&#xff01;&#xff01; 文章目录 问题分析 报错原因 解决思路 解决方法 步骤一&#xff1a;检查Session状态 步骤二&#xff1a;确保属性名正确 步骤…

洛谷P8772 [蓝桥杯 2022 省 A] 求和(前缀和差分)

#include <stdio.h> #include<stdlib.h> int main() {int n;scanf("%d", &n);// 读取数组 aint* a (int*)malloc(n * sizeof(int));for (int i 0; i < n; i) {scanf("%d", &a[i]);}// 计算前缀和数组 prefix_sumlong long *prefi…

Windows下面使用C# 获取记事本里面的文本内容并返回数据

C#中平常我们用到最多的读取文件的方法是通过System.IO里面提供的类来操作文件,这里就不再赘述,今天我们用另外一种特殊的方式来取指定文件能用记事本打开的的文件内容。原理大概是用windows底层提供的函数去读取记事本里面的内容。大概流程如下:程序启动记事本进程并打开指…