最近开始学习angr,太多基础不会,看不懂论文啊。那么,首先在本文先学习angr的一些基本概念,然后在后面结合angr_ctf来学习更多细节,最后再来读论文。
angr是一个多架构的用于分析二进制文件的python框架,它结合了静态和动态符号分析能力,使得它能胜任多种任务。
angr功能:
angr构成(模块)
在开始利用angr之前,我们先来对angr的一些基本概念以及如何构造一些基本的angr对象进行一个基本的了解。
使用angr的第一步总是将一个二进制文件加载到分析平台。
Project是angr中的控制基础。有了它就能对刚加载的可执行文件进行分析和仿真。几乎在angr中使用的每一个对象都依赖于Project的存在。
一个Project有一些基础属性:它的CPU架构、文件名、入口地址。
把二进制文件转换为它在虚拟地址空间中的表示是复杂的。angr有一个模块CLE来处理它。CLE的结果叫做加载器(loader),在属性.loader
中可用。我们先来简单了解loader,可以通过loader来查看二进制文件加载的共享库,以及执行对加载地址空间相关的基本查询。
在angr中有很多类,它们中的大多数都需要一个实例化的project。可以使用project.factory,而不用把project到处传递。factory有几个方便的构造函数,用于经常使用的常见对象。
首先,project.factory.block()用于通过给定的地址提取一个基本块(basic block)的代码(P.S. 关于angr的一个重要的点:angr以基本块为单位来分析代码)。使用它将得到一个Block对象,这个Block对象能告诉我们关于块代码的许多有趣的信息。
另外,还可以通过Block对象得到块代码的其他表示形式。
关于angr的另一个重要的点:Project对象只代表程序的一个“初始化镜像” ,即Project 对象仅表示程序一开始的样子。而当我们再使用angr做执行操作时,实际上操作的是一个表示模拟的程序状态(simulated program state) 的特殊对象SimState。SimState代表程序的一个实例镜像,模拟执行某个时刻的状态。
一个SimState对象包括程序内存、寄存器、文件系统数据…… 任何可以通过执行操作改变的“运行时数据(live data)”都存在于state中。这里我们先进行简单的了解,使用state.regs和state.mem来访问寄存器和内存。
这些结果(BV)不是Python的整数 ,而是bitvector(位向量)。可以把bitvector看成是一串比特序列表示的整数,angr使用bitvector来表示CPU数据。每个bitvector都有一个.length属性来描述它的位宽。下面是python整数和bitvector的转换。
我们可以把bitvector存储到寄存器和内存中;或者直接存储一个python整数,它会进行自动转换,把python整数转换为合适大小的bitvector。
对于mem接口:
最后,如果你继续读取更多的寄存器,还可能会遇到下面这样的情况。edi的值仍然是一个32位的bitvector,但是它没有一个具体的值,而是有一个名字。这被叫做符号变量 ,是符号执行的基础 。
符号执行是angr中极其重要的部分之一。
符号执行 (Symbolic Execution)是一种程序分析技术。它会遍历程序的所有可能的路径,从而得到让特定代码区域执行的输入。
符号执行的细节在后面再继续学习。
state表示程序运行中的一个点,那么必定存在一种方法来到达下一个点。Simulation Manager(仿真管理器)在angr中是对state进行操作的基本接口。
首先,我们创建一个simulation manager。构造函数可以接受一个state或者state列表。单个 Simulation Manager 可以包含多个存放state的 stash, 默认的stash 是 active stash
,是使用我们传入的 state
初始化的。
调用step()
会执行了一个基本块的符号执行! 我们可以再次查看active的stash,可以注意到它已被更新,但是初始的state没有改变。SimState对象在执行时被视为不可变的——你可以安全地使用单个State作为多轮执行的“基础”。
angr 内置了一些分析方法,用于提取程序信息。
例子:如何构造和使用一个控制流图
学完这些,后面结合angr_ctf继续学!
docker run
-
itd
-
-
name angr angr
/
angr
docker
exec
-
it angr bash
su angr
docker run
-
itd
-
-
name angr angr
/
angr
docker
exec
-
it angr bash
su angr
mkdir
/
opt
/
tools
cd
/
opt
/
tools
git clone https:
/
/
gitclone.com
/
github.com
/
slimm609
/
checksec.sh.git
cd checksec.sh
ln
-
s
/
opt
/
tools
/
checksec.sh
/
checksec
/
usr
/
local
/
bin
/
checksec
mkdir
/
opt
/
tools
cd
/
opt
/
tools
git clone https:
/
/
gitclone.com
/
github.com
/
slimm609
/
checksec.sh.git
cd checksec.sh
ln
-
s
/
opt
/
tools
/
checksec.sh
/
checksec
/
usr
/
local
/
bin
/
checksec
cd
/
opt
git clone https:
/
/
gitclone.com
/
github.com
/
jakespringer
/
angr_ctf.git
cd angr_ctf
/
dist
/
cd
/
opt
git clone https:
/
/
gitclone.com
/
github.com
/
jakespringer
/
angr_ctf.git
cd angr_ctf
/
dist
/
In [
1
]:
import
angr
In [
2
]: proj
=
angr.Project(
'./00_angr_find'
)
In [
1
]:
import
angr
In [
2
]: proj
=
angr.Project(
'./00_angr_find'
)
In [
3
]:
import
monkeyhex
In [
4
]: proj.arch
Out[
4
]: <Arch X86 (LE)>
In [
5
]: proj.entry
Out[
5
]:
0x8048450
In [
6
]: proj.filename
Out[
6
]:
'./00_angr_find'
In [
3
]:
import
monkeyhex
In [
4
]: proj.arch
Out[
4
]: <Arch X86 (LE)>
In [
5
]: proj.entry
Out[
5
]:
0x8048450
In [
6
]: proj.filename
Out[
6
]:
'./00_angr_find'
In [
7
]: proj.loader
Out[
7
]: <Loaded
00_angr_find
, maps [
0x8048000
:
0x8607fff
]>
In [
8
]: proj.loader.shared_objects
Out[
8
]:
OrderedDict([(
'00_angr_find'
,
<ELF
Object
00_angr_find
, maps [
0x8048000
:
0x804a03f
]>),
(
'libc.so.6'
,
<ELF
Object
libc
-
2.31
.so, maps [
0x8100000
:
0x82edf0b
]>),
(
'ld-linux.so.2'
,
<ELF
Object
ld
-
2.31
.so, maps [
0x8300000
:
0x832c987
]>),
(
'extern-address space'
,
<ExternObject
Object
cle
(
'cle##tls'
,
<ELFTLSObjectV2
Object
cle
In [
9
]: proj.loader.min_addr
Out[
9
]:
0x8048000
In [
10
]: proj.loader.max_addr
Out[
10
]:
0x8607fff
In [
11
]: proj.loader.main_object
Out[
11
]: <ELF
Object
00_angr_find
, maps [
0x8048000
:
0x804a03f
]>
In [
12
]: proj.loader.main_object.execstack
Out[
12
]:
False
In [
13
]: proj.loader.main_object.pic
Out[
13
]:
False
In [
7
]: proj.loader
Out[
7
]: <Loaded
00_angr_find
, maps [
0x8048000
:
0x8607fff
]>
In [
8
]: proj.loader.shared_objects
Out[
8
]:
OrderedDict([(
'00_angr_find'
,
<ELF
Object
00_angr_find
, maps [
0x8048000
:
0x804a03f
]>),
(
'libc.so.6'
,
<ELF
Object
libc
-
2.31
.so, maps [
0x8100000
:
0x82edf0b
]>),
(
'ld-linux.so.2'
,
<ELF
Object
ld
-
2.31
.so, maps [
0x8300000
:
0x832c987
]>),
(
'extern-address space'
,
<ExternObject
Object
cle
(
'cle##tls'
,
<ELFTLSObjectV2
Object
cle
In [
9
]: proj.loader.min_addr
Out[
9
]:
0x8048000
In [
10
]: proj.loader.max_addr
Out[
10
]:
0x8607fff
In [
11
]: proj.loader.main_object
Out[
11
]: <ELF
Object
00_angr_find
, maps [
0x8048000
:
0x804a03f
]>
In [
12
]: proj.loader.main_object.execstack
Out[
12
]:
False
In [
13
]: proj.loader.main_object.pic
Out[
13
]:
False
In [
14
]: block
=
proj.factory.block(proj.entry)
In [
15
]: block.pp()
0x8048450
: xor ebp, ebp
0x8048452
: pop esi
0x8048453
: mov ecx, esp
0x8048455
:
and
esp,
0xfffffff0
0x8048458
: push eax
0x8048459
: push esp
0x804845a
: push edx
0x804845b
: push
0x8048710
0x8048460
: push
0x80486b0
0x8048465
: push ecx
0x8048466
: push esi
0x8048467
: push
0x80485c7
0x804846c
: call
0x8048420
In [
16
]: block
Out[
16
]: <Block
for
0x8048450
,
33
bytes>
In [
17
]: block.instructions
Out[
17
]:
0xd
In [
18
]: block.instruction_addrs
Out[
18
]:
[
0x8048450
,
0x8048452
,
0x8048453
,
0x8048455
,
0x8048458
,
0x8048459
,
0x804845a
,
0x804845b
,
0x8048460
,
0x8048465
,
0x8048466
,
0x8048467
,
0x804846c
]
In [
14
]: block
=
proj.factory.block(proj.entry)
In [
15
]: block.pp()
0x8048450
: xor ebp, ebp
0x8048452
: pop esi
0x8048453
: mov ecx, esp
0x8048455
:
and
esp,
0xfffffff0
0x8048458
: push eax
0x8048459
: push esp
0x804845a
: push edx
0x804845b
: push
0x8048710
0x8048460
: push
0x80486b0
0x8048465
: push ecx
0x8048466
: push esi
0x8048467
: push
0x80485c7
0x804846c
: call
0x8048420
In [
16
]: block
Out[
16
]: <Block
for
0x8048450
,
33
bytes>
In [
17
]: block.instructions
Out[
17
]:
0xd
In [
18
]: block.instruction_addrs
Out[
18
]:
[
0x8048450
,
0x8048452
,
0x8048453
,
0x8048455
,
0x8048458
,
0x8048459
,
0x804845a
,
0x804845b
,
0x8048460
,
0x8048465
,
0x8048466
,
0x8048467
,
0x804846c
]
In [
19
]: block.capstone
Out[
19
]: <CapstoneBlock
for
0x8048450
>
In [
20
]: block.vex
Out[
20
]: IRSB <
0x21
bytes,
13
ins., <Arch X86 (LE)>> at
0x8048450
In [
19
]: block.capstone
Out[
19
]: <CapstoneBlock
for
0x8048450
>
In [
20
]: block.vex
Out[
20
]: IRSB <
0x21
bytes,
13
ins., <Arch X86 (LE)>> at
0x8048450
In [
21
]: state
=
proj.factory.entry_state()
In [
22
]: state
Out[
22
]: <SimState @
0x8048450
>
In [
21
]: state
=
proj.factory.entry_state()
In [
22
]: state
Out[
22
]: <SimState @
0x8048450
>
In [
24
]: state.regs.eip
Out[
24
]: <BV32
0x8048450
>
In [
25
]: state.regs.eax
Out[
25
]: <BV32
0x1c
>
In [
27
]: state.mem[proj.entry].
int
.resolved
Out[
27
]: <BV32
0x895eed31
>
In [
24
]: state.regs.eip
Out[
24
]: <BV32
0x8048450
>
In [
25
]: state.regs.eax
Out[
25
]: <BV32
0x1c
>
In [
27
]: state.mem[proj.entry].
int
.resolved
Out[
27
]: <BV32
0x895eed31
>
In [
28
]: bv
=
state.solver.BVV(
0x1234
,
32
)
In [
29
]: bv
Out[
29
]: <BV32
0x1234
>
In [
30
]: state.solver.
eval
(bv)
Out[
30
]:
0x1234
In [
31
]: bv.length
Out[
31
]:
0x20
In [
28
]: bv
=
state.solver.BVV(
0x1234
,
32
)
In [
29
]: bv
Out[
29
]: <BV32
0x1234
>
In [
30
]: state.solver.
eval
(bv)
Out[
30
]:
0x1234
In [
31
]: bv.length
Out[
31
]:
0x20
In [
35
]: state.regs.esi
=
state.solver.BVV(
3
,
32
)
In [
36
]: state.regs.esi
Out[
36
]: <BV32
0x3
>
In [
37
]: state.mem[
0x1000
].
long
=
4
In [
38
]: state.mem[
0x1000
].
long
.resolved
Out[
38
]: <BV32
0x4
>
In [
39
]: state.mem[
0x1000
].
long
.concrete
Out[
39
]:
0x4
In [
35
]: state.regs.esi
=
state.solver.BVV(
3
,
32
)
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)