本文已参与「新人创作礼」活动,一起开启掘金创作之路。
昂戈儿、昂戈儿、探戈里戈昂戈儿(angr);
github.com/jakespringe…(angr.github上的练习,可以更好的帮助我们去学习昂戈儿的使用
1. 00_angr_find
如下为题目的伪代码,这里如果按照逆向的思维我们需要逆向complex_function函数的算法。但是angr却不一样,它利用了unicorn-engine这个库(Python、C)进行跨平台模拟执行,在不断的模拟执行之中,它分析出了进入不同的块之间所需要的条件;
int __cdecl main(int argc, const char **argv, const char **envp)
{
int i; // [esp+1Ch] [ebp-1Ch]
char s1[9]; // [esp+23h] [ebp-15h] BYREF
unsigned int v6; // [esp+2Ch] [ebp-Ch]
v6 = __readgsdword(0x14u);
printf("Enter the password: ");
__isoc99_scanf("%8s", s1);
for ( i = 0; i <= 7; ++i )
s1[i] = complex_function(s1[i], i);
if ( !strcmp(s1, "JACEJGCS") )
puts("Good Job.");
else
puts("Try again.");
return 0;
}
如下我们采用了IPython去寻找到达到输出Good Job.的条件是什么?angr不关心算法的实现及逆向,而是关心达到某一块需要的条件
Python 3.8.10 (default, Jun 22 2022, 20:18:18)
Type 'copyright', 'credits' or 'license' for more information
IPython 8.5.0 -- An enhanced Interactive Python. Type '?' for help.
In [1]: import angr # 导入angr库
In [2]: p = angr.Project("./00_angr_find") # 创建项目
In [3]: init_state = p.factory.entry_state() # 返回一个状态对象,该对象表示程序的入口点处的程序
In [4]: sm = p.factory.simulation_manager(init_state) # 构造新的模拟管理器
In [5]: sm.explore(find=0x0804867D) # 向前勾选“藏匿”(最多“n”次或直到找到“num_find”状态),查找条件“查找”,避免条件“避免”。将找到的状态存储到“find_stash”中,将避免的状态存储到“avoid_stash”中
WARNING | 2022-10-02 17:13:15,378 | angr.storage.memory_mixins.default_filler_mixin | The program is accessing register with an unspecified value. This could indicate unwanted behavior.
WARNING | 2022-10-02 17:13:15,379 | angr.storage.memory_mixins.default_filler_mixin | angr will cope with this by generating an unconstrained symbolic variable and continuing. You can resolve this by:
WARNING | 2022-10-02 17:13:15,379 | angr.storage.memory_mixins.default_filler_mixin | 1) setting a value to the initial state
WARNING | 2022-10-02 17:13:15,379 | angr.storage.memory_mixins.default_filler_mixin | 2) adding the state option ZERO_FILL_UNCONSTRAINED_{MEMORY,REGISTERS}, to make unknown regions hold null
WARNING | 2022-10-02 17:13:15,379 | angr.storage.memory_mixins.default_filler_mixin | 3) adding the state option SYMBOL_FILL_UNCONSTRAINED_{MEMORY,REGISTERS}, to suppress these messages.
WARNING | 2022-10-02 17:13:15,379 | angr.storage.memory_mixins.default_filler_mixin | Filling register edi with 4 unconstrained bytes referenced from 0x80486b1 (__libc_csu_init+0x1 in 00_angr_find (0x80486b1))
WARNING | 2022-10-02 17:13:15,380 | angr.storage.memory_mixins.default_filler_mixin | Filling register ebx with 4 unconstrained bytes referenced from 0x80486b3 (__libc_csu_init+0x3 in 00_angr_find (0x80486b3))
WARNING | 2022-10-02 17:13:16,201 | angr.storage.memory_mixins.default_filler_mixin | Filling memory at 0x7ffeff60 with 4 unconstrained bytes referenced from 0x8186b90 (strcmp+0x0 in libc.so.6 (0x86b90))
Out[5]: <SimulationManager with 1 active, 16 deadended, 1 found>
In [6]: sm.found[0]
Out[6]: <SimState @ 0x804867d>
In [7]: sm.found[0].posix.dumps() # 返回文件描述符的具体内容。向后兼容性:如果您要求文件描述符1或2,它将以平面字符串的形式从stdin、stdout或stderr返回数据。
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
Cell In [7], line 1
----> 1 sm.found[0].posix.dumps()
TypeError: dumps() missing 1 required positional argument: 'fd'
In [8]: sm.found[0].posix.dumps(0) # 返回文件描述符stdin的内容
Out[8]: b'JXWVXRKX'
2. 01_angr_avoid
该题目无法使用ida反编译成伪代码,但不妨碍我们查看汇编代码,我们仅仅需要定位到成功代码以及失败代码,然后利用00_angr_find的代码即可获取到我们所需要输入的内容;
Python 3.8.10 (default, Jun 22 2022, 20:18:18)
Type 'copyright', 'credits' or 'license' for more information
IPython 8.5.0 -- An enhanced Interactive Python. Type '?' for help.
In [1]: import angr
In [2]: p = angr.Project("./01_angr_avoid")
In [3]: init_state = p.factory.entry_state()
In [4]: sm = p.factory.simulation_manager(init_state)
In [5]: sm.explore(find=0x080485E0, avoid=0x080485A8)
WARNING | 2022-10-02 18:02:23,200 | angr.storage.memory_mixins.default_filler_mixin | The program is accessing register with an unspecified value. This could indicate unwanted behavior.
WARNING | 2022-10-02 18:02:23,200 | angr.storage.memory_mixins.default_filler_mixin | angr will cope with this by generating an unconstrained symbolic variable and continuing. You can resolve this by:
WARNING | 2022-10-02 18:02:23,200 | angr.storage.memory_mixins.default_filler_mixin | 1) setting a value to the initial state
WARNING | 2022-10-02 18:02:23,200 | angr.storage.memory_mixins.default_filler_mixin | 2) adding the state option ZERO_FILL_UNCONSTRAINED_{MEMORY,REGISTERS}, to make unknown regions hold null
WARNING | 2022-10-02 18:02:23,200 | angr.storage.memory_mixins.default_filler_mixin | 3) adding the state option SYMBOL_FILL_UNCONSTRAINED_{MEMORY,REGISTERS}, to suppress these messages.
WARNING | 2022-10-02 18:02:23,200 | angr.storage.memory_mixins.default_filler_mixin | Filling register edi with 4 unconstrained bytes referenced from 0x80d4591 (__libc_csu_init+0x1 in 01_angr_avoid (0x80d4591))
WARNING | 2022-10-02 18:02:23,201 | angr.storage.memory_mixins.default_filler_mixin | Filling register ebx with 4 unconstrained bytes referenced from 0x80d4593 (__libc_csu_init+0x3 in 01_angr_avoid (0x80d4593))
WARNING | 2022-10-02 18:02:25,971 | angr.storage.memory_mixins.default_filler_mixin | Filling memory at 0x7ffeff3d with 11 unconstrained bytes referenced from 0x8187180 (strncmp+0x0 in libc.so.6 (0x87180))
WARNING | 2022-10-02 18:02:25,972 | angr.storage.memory_mixins.default_filler_mixin | Filling memory at 0x7ffeff60 with 4 unconstrained bytes referenced from 0x8187180 (strncmp+0x0 in libc.so.6 (0x87180))
Out[5]: <SimulationManager with 1 active, 16 deadended, 1 found, 8 avoid>
In [6]: sm.found[0].posix.dumps(0) # POSIX 文件描述符实现的基类
Out[6]: b'HUJOZMYS'
3. 02_angr_find_condition
该功能其实与00和01功能一致,目前我们都是针对于angr.factory.simulation_manager.explore的使用,其存在着两个参数,find以及avoid,而参数可以是Python的判断函数,也可以是一个地址;
Python 3.8.10 (default, Jun 22 2022, 20:18:18)
Type 'copyright', 'credits' or 'license' for more information
IPython 8.5.0 -- An enhanced Interactive Python. Type '?' for help.
In [1]: import angr
In [2]: p = angr.Project("./02_angr_find_condition")
In [3]: init_state = p.factory.entry_state()
In [4]: sm = p.factory.simulation_manager(init_state)
In [5]: def is_good(state):
...: return b"Good Job." in state.posix.dumps(1)
...:
In [6]: def is_bad(state):
...: return b"Try again." in state.posix.dumps(1)
...:
In [7]: sm.explore(find=is_good, avoid=is_bad)
WARNING | 2022-10-02 18:19:32,347 | angr.storage.memory_mixins.default_filler_mixin | The program is accessing register with an unspecified value. This could indicate unwanted behavior.
WARNING | 2022-10-02 18:19:32,348 | angr.storage.memory_mixins.default_filler_mixin | angr will cope with this by generating an unconstrained symbolic variable and continuing. You can resolve this by:
WARNING | 2022-10-02 18:19:32,348 | angr.storage.memory_mixins.default_filler_mixin | 1) setting a value to the initial state
WARNING | 2022-10-02 18:19:32,348 | angr.storage.memory_mixins.default_filler_mixin | 2) adding the state option ZERO_FILL_UNCONSTRAINED_{MEMORY,REGISTERS}, to make unknown regions hold null
WARNING | 2022-10-02 18:19:32,348 | angr.storage.memory_mixins.default_filler_mixin | 3) adding the state option SYMBOL_FILL_UNCONSTRAINED_{MEMORY,REGISTERS}, to suppress these messages.
WARNING | 2022-10-02 18:19:32,348 | angr.storage.memory_mixins.default_filler_mixin | Filling register edi with 4 unconstrained bytes referenced from 0x804d291 (__libc_csu_init+0x1 in 02_angr_find_condition (0x804d291))
WARNING | 2022-10-02 18:19:32,350 | angr.storage.memory_mixins.default_filler_mixin | Filling register ebx with 4 unconstrained bytes referenced from 0x804d293 (__libc_csu_init+0x3 in 02_angr_find_condition (0x804d293))
WARNING | 2022-10-02 18:19:33,187 | angr.storage.memory_mixins.default_filler_mixin | Filling memory at 0x7ffeff2d with 11 unconstrained bytes referenced from 0x8186b90 (strcmp+0x0 in libc.so.6 (0x86b90))
WARNING | 2022-10-02 18:19:33,188 | angr.storage.memory_mixins.default_filler_mixin | Filling memory at 0x7ffeff50 with 4 unconstrained bytes referenced from 0x8186b90 (strcmp+0x0 in libc.so.6 (0x86b90))
Out[7]: <SimulationManager with 1 found, 17 avoid>
In [8]: sm.found[0].posix.dumps(0)
Out[8]: b'HETOBRCU'
4. 03_angr_symbolic_registers
此时参数由一个参数变为了多参(三个),那么我们又该如何使用angr呢?这里我们需要提前说明的是angr不能很好的去处理多个参数,这就导致我们面对多参的时候很难受,但是我们明白的是angr的底层模拟是利用了unicorn-engine,而unicorn-engine可以从任意代码加载执行,那么angr作为其的一个封装(可以看成),则必然可以从任意代码进行执行
这里我们还需要引进一个新的东西,charipy是angr底层所依赖的库,实际上是z3的封装的简单前端;
Python 3.8.10 (default, Jun 22 2022, 20:18:18)
Type 'copyright', 'credits' or 'license' for more information
IPython 8.5.0 -- An enhanced Interactive Python. Type '?' for help.
In [1]: import angr,claripy
In [2]: p = angr.Project("./03_angr_symbolic_registers")
In [3]: start_addr = 0x08048980
In [4]: init_state = p.factory.blank_state(addr=start_addr)
In [5]: argv1 = claripy.BVS("argv1", 32) # claripy.ast.bv.BVS 创建位向量符号(即变量)
In [6]: argv2 = claripy.BVS("argv2", 32) #
In [7]: argv3 = claripy.BVS("argv3", 32)
In [8]: init_state.regs.eax = argv1
In [9]: init_state.regs.ebx = argv2
In [10]: init_state.regs.edx = argv3
In [11]: sm = p.factory.simulation_manager(init_state)
In [12]: def is_good(state):
...: return b"Good Job." in state.posix.dumps(1)
...:
In [13]: def is_bad(state):
...: return b"Try again." in state.posix.dumps(1)
...:
In [14]: sm.explore(find=is_good, avoid=is_bad)
Out[14]: <SimulationManager with 1 found, 3 avoid>
In [15]: sm.found[0].posix.dumps(0) # 没有执行scanf,故stdin为空
Out[15]: b''
In [16]: sm.found[0].solver.eval(argv1) # solver 求解器引擎
Out[16]: 3120549966
In [17]: sm.found[0].solver.eval(argv2) # eval此函数最多返回表达式expr的n个可能的解决方案
Out[17]: 3438690280
In [18]: sm.found[0].solver.eval(argv3)
Out[18]: 2413091161
5. 04_angr_symbolic_stack
在03_angr_symbolic_registers题目当中,我们选择了符号化向量寄存器,而本题当中,因为为i386,参数传递位于stack栈上,故我们本题需要符号化栈上数值;
.text:08048679 ; =============== S U B R O U T I N E =======================================
.text:08048679
.text:08048679 ; Attributes: bp-based frame
.text:08048679
.text:08048679 ; int handle_user()
.text:08048679 public handle_user
.text:08048679 handle_user proc near ; CODE XREF: main+21↓p
.text:08048679
.text:08048679 var_10 = dword ptr -10h
.text:08048679 var_C = dword ptr -0Ch
.text:08048679
.text:08048679 ; __unwind {
.text:08048679 push ebp
.text:0804867A mov ebp, esp
.text:0804867C sub esp, 18h
.text:0804867F sub esp, 4
.text:08048682 lea eax, [ebp+var_10] // 第二个参数
.text:08048685 push eax
.text:08048686 lea eax, [ebp+var_C] // 第一个参数
.text:08048689 push eax
.text:0804868A push offset aUU ; "%u %u"
.text:0804868F call ___isoc99_scanf // stdin输入点
.text:08048694 add esp, 10h // 清理scanf的栈情况
.text:08048697 mov eax, [ebp+var_C] // blank_state 我们需要执行的入口点
.text:0804869A sub esp, 0Ch
.text:0804869D push eax
.text:0804869E call complex_function0
.text:080486A3 add esp, 10h
.text:080486A6 mov [ebp+var_C], eax
.text:080486A9 mov eax, [ebp+var_10]
.text:080486AC sub esp, 0Ch
.text:080486AF push eax
.text:080486B0 call complex_function1
.text:080486B5 add esp, 10h
.text:080486B8 mov [ebp+var_10], eax
.text:080486BB mov eax, [ebp+var_C]
.text:080486BE cmp eax, 773024D1h
.text:080486C3 jnz short loc_80486CF
.text:080486C5 mov eax, [ebp+var_10]
.text:080486C8 cmp eax, 0BC4311CFh
.text:080486CD jz short loc_80486E1
如上所示,我们需要提取出来栈的一个情况;这里实际上是可以利用gdb得到一个十分清晰的stack图;如下则为位于08048697的stack图示:
00:0000│ esp 0xffffd340 —▸ 0xf7fba088 (environ) —▸ 0xffffd41c —▸ 0xffffd590 ◂— 'SHELL=/bin/bash'
01:0004│ 0xffffd344 —▸ 0xf7ffd990 ◂— 0x0
02:0008│ edx 0xffffd348 ◂— 0x162e // 第二个参数
03:000c│ 0xffffd34c ◂— 0x4d2 // 第一个参数
04:0010│ 0xffffd350 —▸ 0x80487ce ◂— 0x65746e45 /* 'Enter the password: ' */
05:0014│ 0xffffd354 —▸ 0xffffd414 —▸ 0xffffd543 ◂— 0x746e6d2f ('/mnt')
06:0018│ ebp 0xffffd358 —▸ 0xffffd368 ◂— 0x0
07:001c│ 0xffffd35c —▸ 0x804871a (main+38) ◂— 0xb8
08:0020│ 0xffffd360 —▸ 0xf7fe22b0 (_dl_fini) ◂— endbr32
09:0024│ 0xffffd364 —▸ 0xffffd380 ◂— 0x1
0a:0028│ 0xffffd368 ◂— 0x0
故我们需要将0xffffd34c和0xffffd348符号向量化,同时不破坏栈的一个整体结构即可使用angr;
import angr,claripy
def main():
p = angr.Project("04_angr_symbolic_stack") # 创建一个项目
start_addr = 0x08048694
init_state = p.factory.blank_state(addr=start_addr) # 获取blank_state(特定块的状态)
# 如下是针对于该块的状态进行一定的修改以及初始化成如上图stack的样式;
init_state.stack_push(init_state.regs.ebp) # push ebp
init_state.regs.ebp = init_state.regs.esp # mov ebp,esp
init_state.regs.esp -= 8 # sub esp,8
argv1 = init_state.solver.BVS("argv1", 32)
argv2 = init_state.solver.BVS("argv2", 32)
init_state.stack_push(argv1) # push argv1 // 符号向量1
init_state.stack_push(argv2) # push argv2 // 符号向量2
init_state.regs.edx = init_state.regs.esp # mov edx,esp
init_state.regs.esp -= 8 # sub esp,8
# 此时init_state状态的stack区将于我们gdb所查看的大体情况一致
sm = p.factory.simgr(init_state) # 创建一个工作台(simgr与simulation_manager函数一致)
def is_good(state):
return b"Good Job." in state.posix.dumps(1)
def is_bad(state):
return b"Try again." in state.posix.dumps(1)
sm.explore(find=is_good, avoid=is_bad) # 开始探索条件
if sm.found:
in1 = sm.found[0].solver.eval(argv1) # 求解
in2 = sm.found[0].solver.eval(argv2) # 求解
print("solution: {} {}".format(in1, in2))
if __name__ == "__main__":
main()
6. 05_angr_symbolic_memory
在上述的练习当中,我们由regs(寄存器)到stack(栈),本题我们将来到了神秘的memory(内存),我们来一探究竟;
import angr,claripy
def main():
p = angr.Project("./05_angr_symbolic_memory")
start_addr = 0x08048601
init_state = p.factory.blank_state(addr=start_addr)
argv1 = init_state.solver.BVS("argv1", 64)
argv2 = init_state.solver.BVS("argv2", 64)
argv3 = init_state.solver.BVS("argv3", 64)
argv4 = init_state.solver.BVS("argv4", 64)
init_state.memory.store(0x0A1BA1C0, argv1) # store 创建新实例并设置标记属性
init_state.memory.store(0x0A1BA1C8, argv2)
init_state.memory.store(0x0A1BA1D0, argv3)
init_state.memory.store(0x0A1BA1D8, argv4)
sm = p.factory.simgr(init_state)
def is_good(state):
return b"Good Job." in state.posix.dumps(1)
def is_bad(state):
return b"Try again." in state.posix.dumps(1)
sm.explore(find=is_good, avoid=is_bad)
if sm.found:
in1 = sm.found[0].solver.eval(argv1, cast_to=bytes).decode("utf-8")
in2 = sm.found[0].solver.eval(argv2, cast_to=bytes).decode("utf-8")
in3 = sm.found[0].solver.eval(argv3, cast_to=bytes).decode("utf-8")
in4 = sm.found[0].solver.eval(argv4, cast_to=bytes).decode("utf-8")
print("solution: {} {} {} {}".format(in1, in2, in3, in4))
if __name__ == "__main__":
main()
7. 06_angr_symbolic_dynamic_memory
本题将再次带我们深入angr的内存上的符号化,那么还有那个内存块我们没有涉及到呢?没错,就是堆(heap);
int __cdecl main(int argc, const char **argv, const char **envp)
{
char *v3; // ebx
char *v4; // ebx
int v6; // [esp-10h] [ebp-1Ch]
int i; // [esp+0h] [ebp-Ch]
buffer0 = (char *)malloc(9u); // 位于angr的模拟执行前,故我们无法在之前malloc
buffer1 = (char *)malloc(9u); // 但是我们可以设置一块模拟之中所用不到的内存充当malloc所申请的内存
memset(buffer0, 0, 9u);
memset(buffer1, 0, 9u);
printf("Enter the password: ");
__isoc99_scanf("%8s %8s", buffer0, buffer1, v6); // 由于angr的特性,故我们必须从多参输入点之后进行模拟执行过程
for ( i = 0; i <= 7; ++i )
{
v3 = &buffer0[i];
*v3 = complex_function(buffer0[i], i);
v4 = &buffer1[i];
*v4 = complex_function(buffer1[i], i + 32);
}
if ( !strncmp(buffer0, "UODXLZBI", 8u) && !strncmp(buffer1, "UAORRAYF", 8u) )
puts("Good Job.");
else
puts("Try again.");
free(buffer0);
free(buffer1);
return 0;
}
import angr,claripy
def main():
p = angr.Project("./06_angr_symbolic_dynamic_memory")
start_addr = 0x08048699
init_state = p.factory.blank_state(addr=start_addr)
esp = init_state.regs.esp
argv1 = init_state.solver.BVS("argv1",64)
argv2 = init_state.solver.BVS("argv2",64)
buffer0 = esp + 0x100 # 这里采用了栈上我们模拟执行所用不到的地址充当我们malloc申请的内存
buffer1 = esp + 0x200 #
buffer0_addr = 0x0ABCC8A4
buffer1_addr = 0x0ABCC8AC
init_state.memory.store(buffer0_addr, buffer0, endness=p.arch.memory_endness)
init_state.memory.store(buffer1_addr, buffer1, endness=p.arch.memory_endness)
init_state.memory.store(buffer0, argv1)
init_state.memory.store(buffer1, argv2)
sm = p.factory.simgr(init_state)
def is_good(state):
return b"Good Job." in state.posix.dumps(1)
def is_bad(state):
return b"Try again." in state.posix.dumps(1)
sm.explore(find=is_good, avoid=is_bad)
if sm.found:
in1 = sm.found[0].solver.eval(argv1, cast_to=bytes).decode("utf-8")
in2 = sm.found[0].solver.eval(argv2, cast_to=bytes).decode("utf-8")
print("solution: {} {}".format(in1, in2))
if __name__ == "__main__":
main()
8. 07_angr_symbolic_file
本题将来到了针对于文件描述符的操作了,我们将可以虚拟出一个文件并挂载到模拟之中;
import angr,claripy
def main():
p = angr.Project("./07_angr_symbolic_file")
start_addr = 0x080488EA
init_state = p.factory.blank_state(addr = start_addr)
filename = "OJKSQYDP.txt"
# 普通SimFile用于在磁盘上建模文件。它是SimSymbolicMemory的子类,因此加载和存储到它/从它存储都非常简单。
argv = init_state.solver.BVS("argv", 0x40 * 8) # 符号向量化
sim_file = angr.storage.SimFile(filename, content=argv, size=0x40)
init_state.fs.insert(filename, sim_file) # 虚拟文件系统挂载在/proc上(目前,在Linux上)
sm = p.factory.simgr(init_state)
def is_good(state):
return b"Good Job." in state.posix.dumps(1)
def is_bad(state):
return b"Try again." in state.posix.dumps(1)
sm.explore(find=is_good, avoid=is_bad)
if sm.found:
in1 = sm.found[0].solver.eval(argv, cast_to=bytes).decode("utf-8")
print("solution: {}".format(in1))
if __name__ == "__main__":
main()
9. 08_angr_constraints
本题当中我们将引入路径爆炸这个angr的问题,这道题目我们发现是单个参数,故我们可以使用00_angr_find的脚本进行测试,这个时候我们便会发现脚本运行到某处将无法运行,这便是路径爆炸所带来的问题;
_BOOL4 __cdecl check_equals_AUPDNNPROEZRJWKB(int a1, unsigned int a2)
{
int v3; // [esp+8h] [ebp-8h]
unsigned int i; // [esp+Ch] [ebp-4h]
v3 = 0;
for ( i = 0; i < a2; ++i )
{
if ( *(_BYTE *)(i + a1) == *(_BYTE *)(i + 134520896) )
++v3;
}
return v3 == a2;
}
如上所示,仅仅是一个如此循环比较字符的函数,便发生了路径爆炸的一个问题;
import angr,claripy
def main():
p = angr.Project("./08_angr_constraints")
start_addr = 0x08048625
init_state = p.factory.blank_state(addr=start_addr)
buffer_ = init_state.solver.BVS("buffer_", 128)
init_state.memory.store(0x0804A050, buffer_)
sm = p.factory.simgr(init_state)
sm.explore(find=0x08048565)
if sm.found:
state = sm.found[0]
buf = "AUPDNNPROEZRJWKB"
check_buf = state.memory.load(0x0804A050, 0x10) # 加载内存之中的内容
check_true = buf == check_buf
state.add_constraints(check_true) # 向状态添加一些约束。您可以传入任意数量的符号布尔值作为可变位置参数
sbuf = state.solver.eval(buffer_, cast_to=bytes).decode("utf-8")
print("stdin: {}".format(sbuf))
if __name__ == "__main__":
main()
10. 09_angr_hooks
本题我们将学习angr之中的hook的写法,hook就相当于是替换了程序之中一个真正的函数而已,这样可以防止路径爆炸等问题;
import angr,claripy
def main():
p = angr.Project("./09_angr_hooks")
init_state = p.factory.entry_state()
@p.hook(0x080486B3, length=5)
def check_equals(state):
input_buffer = state.memory.load(0x0804A054, 0x10)
desired = "XYMKBKUHNIQYNQXE"
state.regs.eax = claripy.If(
desired == input_buffer,
claripy.BVV(1, 32),
claripy.BVV(0, 32)
)
def is_good(state):
return b"Good Job." in state.posix.dumps(1)
def is_bad(state):
return b"Try again." in state.posix.dumps(1)
sm = p.factory.simgr(init_state)
sm.explore(find=is_good, avoid=is_bad)
if sm.found:
state = sm.found[0]
print("stdin: {}".format(state.posix.dumps(0)))
if __name__ == "__main__":
main()
blog.csdn.net/qq_40229814…(这篇文章简单的介绍了一下angr的原理;angr的原理其实是值得我们去深究的,很多里面的思维都是值得我们去学习的;
www.anquanke.com/post/id/251…(浅谈angr的缓解状态爆炸策略
www.52pojie.cn/thread-1484…(利用angr去除混淆的优势,不足与实践