Top Level Interfaces

原文

在开始之前

在IPython(或其他Python命令行解释器)中使用和探索angr是我们设计angr的一个主要用例。当你不确定哪些接口可用时,tab补全是你的好帮手!
有时,IPython中的tab补全会很慢。我们发现在不降低完成结果有效性的情况下,以下解决方案是有用的:

# Drop this file in IPython profile's startup directory to avoid running it every time.
import IPython
py = IPython.get_ipython()
py.Completer.use_jedi = False

核心概念

在开始使用angr之前,你需要对一些基本的angr概念和如何构建一些基本的angr对象有一个基本的概述。我们将通过检查加载二进制文件后哪些内容可以直接提供给您来了解这个问题!
你使用angr的第一个动作总是将二进制文件加载到项目中。在这些例子中,我们将使用/bin/true。

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

在angr中,项目是你的控制基础。有了它,您将能够对刚刚加载的可执行文件分派分析和模拟。几乎你在angr中使用的每一个对象都依赖于以某种形式存在的项目。

基本属性

首先,我们有一些关于项目的基本属性:它的CPU架构、文件名和入口点的地址。

>>> import monkeyhex # this will format numerical results in hexadecimal
>>> proj.arch
<Arch AMD64 (LE)>
>>> proj.entry
0x401670
>>> proj.filename
'/bin/true'
  • arch是archinfo.Arch的一个实例。Arch对象,无论程序被编译的是哪种体系结构,在这种情况下是小端amd64。它包含了大量关于其运行的CPU的文本数据,您可以在闲暇时细读这些数据。通常你关心的是arch.bits、arch.bytes(它是Arch类上的@property声明)、arch.name和arch .memory_endness。
  • entry是二进制文件的入口点!
  • filename是二进制文件的绝对文件名。引人入胜的东西!

加载程序

从一个二进制文件到它在虚拟地址空间中的表示是相当复杂的!我们有一个叫做CLE的模块来处理这个问题。CLE的结果称为加载程序,可以在.loader属性中找到。我们很快就会详细介绍如何使用它,但现在只需要知道,你可以使用它来查看angr加载在你的程序旁边的共享库,并对加载的地址空间执行基本查询。

>>> proj.loader
<Loaded true, maps [0x400000:0x5004000]>

>>> proj.loader.shared_objects # may look a little different for you!
{'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  # we've loaded several binaries into this project. Here's the main one!
<ELF Object true, maps [0x400000:0x60721f]>

>>> proj.loader.main_object.execstack  # sample query: does this binary have an executable stack?
False
>>> proj.loader.main_object.pic  # sample query: is this binary position-independent?
True

工厂

在angr中有很多类,它们中的大多数都需要实例化一个项目。我们提供project.factory,它为您想要经常使用的公共对象提供了几个方便的构造函数,而不是让您到处传递项目,。
本节还将介绍几个基本的angr概念。

Blocks

首先,我们有project.factory.block(),它用于从给定地址提取一个基本的代码块。这是一个重要的事实——angr以基本块为单位分析代码。你将返回一个Block对象,它可以告诉你关于代码块的许多有趣的事情:

>>> block = proj.factory.block(proj.entry) # lift a block of code from the program's entry point
<Block for 0x401670, 42 bytes>

>>> block.pp()                          # pretty-print a disassembly to stdout
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                  # how many instructions are there?
0xb
>>> block.instruction_addrs             # what are the addresses of the instructions?
[0x401670, 0x401672, 0x401675, 0x401676, 0x401679, 0x40167d, 0x40167e, 0x40167f, 0x401686, 0x40168d, 0x401694]

此外,你可以使用Block对象来获取代码块的其他表示:

>>> block.capstone                       # capstone disassembly
<CapstoneBlock for 0x401670>
>>> block.vex                            # VEX IRSB (that's a python internal address, not a program address)
<pyvex.block.IRSB at 0x7706330>

States

这是关于angr的另一个事实——Project对象只代表程序的“初始化映像”。当你使用angr执行时,你正在使用一个特定的对象来表示一个模拟的程序状态——一个SimState。让我们现在就抓住一个!

>>> state = proj.factory.entry_state()
<SimState @ 0x401670>

一个SimState包含一个程序的内存,寄存器,文件系统数据…任何可以通过执行更改的“实时数据”都有一个home状态。稍后我们将深入讨论如何与状态交互,但现在,我们使用state.regs和state.mem访问寄存器和内存的这种状态:

>>> state.regs.rip        # get the current instruction pointer
<BV64 0x401670>
>>> state.regs.rax
<BV64 0x1c>
>>> state.mem[proj.entry].int.resolved  # interpret the memory at the entry point as a C int
<BV32 0x8949ed31>

那些不是python的int型!那些是bitvectors。Python整数与CPU上的单词没有相同的语义,例如在溢出时进行包装,所以我们使用位向量,你可以将其视为由一系列位表示的整数,以在angr中表示CPU数据。注意,每个位向量都有一个.length属性,用来描述它以位为单位的宽度。
我们将很快学习如何使用它们,但现在,这里是如何从python的int类型转换为位向量,然后再转换回来:

>>> bv = state.solver.BVV(0x1234, 32)       # create a 32-bit-wide bitvector with value 0x1234
<BV32 0x1234>                               # BVV stands for bitvector value
>>> state.solver.eval(bv)                # convert to python int
0x1234

你可以将这些位向量存储回寄存器和内存中,或者你可以直接存储一个python整数,它将被转换为一个适当大小的位向量:

>>> state.regs.rsi = state.solver.BVV(3, 64)
>>> state.regs.rsi
<BV64 0x3>

>>> state.mem[0x1000].long = 4
>>> state.mem[0x1000].long.resolved
<BV64 0x4>

一开始,mem界面有点令人困惑,因为它使用了一些相当强大的python魔法。如何使用它的简短版本是:

  • 使用数组[index]表示法指定地址
  • 使用.<type>指定内存应该被解释为<type>(常用值:char, short, int, long, size_t, uint8_t, uint16_t…)
  • 从那里,你可以:
    • 为它存储一个值,可以是位向量,也可以是python int类型
    • 使用.resolved以获取位向量的值
    • 使用.concrete获取python int类型的值
      后面将介绍更高级的用法!
      最后,如果你尝试读取更多的寄存器,你可能会遇到一个非常奇怪的值:
>>> state.regs.rdi
<BV64 reg_48_11_64{UNINITIALIZED}>

这仍然是一个64位向量,但它不包含数值。相反,它有一个名字!这被称为符号变量,它是符号执行的基础。别慌!我们将在两章之后详细讨论这些问题。

Simulation Managers

如果一个状态允许我们在一个给定的时间点表示一个程序,那么一定有一种方法可以让它到达下一个时间点。模拟管理器是angr中的主要接口,用于执行,模拟,你想叫它什么都行,带有状态。作为一个简短的介绍,让我们展示如何在前面的几个基本块中勾选我们之前创建的状态。
首先,我们创建将要使用的模拟管理器。构造函数可以接受状态或状态列表。

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

一个模拟管理器可以包含一个状态(state)的许多贮藏(stash)。默认的贮藏,active,是我们输入的内容来初始化的。我们可以通过simgr.active[0]看看我们更多的state信息!
现在…准备好,我们要开始表演了。

>>> simgr.step()

我们刚刚进行了一个基本块的符号执行!我们可以再次查看active的stash,注意到它已被更新,而且,它没有修改我们的原始状态。SimState对象在执行时被视为不可变的—您可以安全地使用单个状态作为多轮执行的“基础”。

>>> simgr.active
[<SimState @ 0x1020300>]
>>> simgr.active[0].regs.rip                 # new and exciting!
<BV64 0x1020300>
>>> state.regs.rip                           # still the same!
<BV64 0x401670>

/bin/true并不是一个很好的例子来描述如何用符号执行来做一些有趣的事情,所以我们现在就到此为止。

分析

angr预先打包了几个内置的分析器,你可以用它们来从程序中提取一些有趣的信息。在这里,他们是:

>>> proj.analyses.            # Press TAB here in ipython to get an autocomplete-listing of everything:
 proj.analyses.BackwardSlice        proj.analyses.CongruencyCheck      proj.analyses.reload_analyses       
 proj.analyses.BinaryOptimizer      proj.analyses.DDG                  proj.analyses.StaticHooker          
 proj.analyses.BinDiff              proj.analyses.DFG                  proj.analyses.VariableRecovery      
 proj.analyses.BoyScout             proj.analyses.Disassembly          proj.analyses.VariableRecoveryFast  
 proj.analyses.CDG                  proj.analyses.GirlScout            proj.analyses.Veritesting           
 proj.analyses.CFG                  proj.analyses.Identifier           proj.analyses.VFG                   
 proj.analyses.CFGEmulated          proj.analyses.LoopFinder           proj.analyses.VSA_DDG               
 proj.analyses.CFGFast              proj.analyses.Reassembler

本书后面会介绍其中的一些内容,但一般来说,如果你想了解如何使用给定的分析,你应该查看api文档。下面是一个非常简单的例子:以下是如何构建和使用一个快速控制流图:

# Originally, when we loaded this binary it also loaded all its dependencies into the same virtual address  space
# This is undesirable for most analysis.
>>> proj = angr.Project('/bin/true', auto_load_libs=False)
>>> cfg = proj.analyses.CFGFast()
<CFGFast Analysis Result at 0x2d85130>

# cfg.graph is a networkx DiGraph full of CFGNode instances
# You should go look up the networkx APIs to learn how to use this!
>>> cfg.graph
<networkx.classes.digraph.DiGraph at 0x2da43a0>
>>> len(cfg.graph.nodes())
951

# To get the CFGNode for a given address, use cfg.get_any_node
>>> entry_node = cfg.get_any_node(proj.entry)
>>> len(list(cfg.graph.successors(entry_node)))
2

现在怎么办呢?

读完这一页,您现在应该已经熟悉了几个重要的angr概念:基本块、状态、位向量、仿真管理器和分析。不过,除了将angr用作美化的调试器之外,你真的不能做任何有趣的事情!继续读下去,你会释放出更深层次的力量……

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,616评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,020评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,078评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,040评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,154评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,265评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,298评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,072评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,491评论 1 306
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,795评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,970评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,654评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,272评论 3 318
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,985评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,223评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,815评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,852评论 2 351

推荐阅读更多精彩内容