angr简单学习

147 阅读11分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路。


昂戈儿、昂戈儿、探戈里戈昂戈儿(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作为其的一个封装(可以看成),则必然可以从任意代码进行执行

这里我们还需要引进一个新的东西,charipyangr底层所依赖的库,实际上是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图;如下则为位于08048697stack图示:

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

故我们需要将0xffffd34c0xffffd348符号向量化,同时不破坏栈的一个整体结构即可使用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去除混淆的优势,不足与实践