Angr做题笔记
00_angr_find
程序:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
   | int __cdecl main(int argc, const char **argv, const char **envp) {   int i;    char v5[9];    unsigned int v6;      v6 = __readgsdword(0x14u);   printf("Enter the password: ");   __isoc99_scanf("%8s", v5);   for ( i = 0; i <= 7; ++i )     v5[i] = complex_function(v5[i], i);   if ( !strcmp(v5, "JACEJGCS") )     puts("Good Job.");   else     puts("Try again.");   return 0; }
   | 
 
脚本:
1 2 3 4 5 6 7 8 9
   | import angr project=angr.Project("./00_angr_find",auto_load_libs=False) state=project.factory.entry_state() sim=project.factory.simgr(state)	 sim.explore(find=0x08048675) if sim.found:     res=sim.found[0]     res=res.posix.dumps(0)     print(res)
   | 
 
sim.found[0]代表探索路径时得到的一条可解的路径。res.posix.dumps(0)表示去获取对应路径中,stdin的内容。
01_angr_avoid
加上表示被避开的路径:
1 2 3 4 5 6 7 8 9
   | import angr project=angr.Project("./01_angr_avoid",auto_load_libs=False) state=project.factory.entry_state() sim=project.factory.simgr(state) sim.explore(find=0x080485E0,avoid=0x080485A8) if sim.found:     res=sim.found[0]     res=res.posix.dumps(0)     print(res)
   | 
 
02_angr_find_condition
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
   | int __cdecl main(int argc, const char **argv, const char **envp) {   int i;    int j;    char v6[20];    char v7[20];    unsigned int v8;      v8 = __readgsdword(0x14u);   for ( i = 0; i <= 19; ++i )     v7[i] = 0;   qmemcpy(v7, "VXRRJEUR", 8);   printf("Enter the password: ");   __isoc99_scanf("%8s", v6);   for ( j = 0; j <= 7; ++j )     v6[j] = complex_function(v6[j], j + 8);   if ( !strcmp(v6, v7) )     puts("Good Job.");   else     puts("Try again.");   return 0; }
   | 
 
不同点在于:这个汇编程序中到处都是“Good Job.”,没法全部罗列出来。对find参数修改为一个函数:
1 2 3 4 5 6 7 8 9 10 11
   | import angr def succ(state):     res=state.posix.dumps(1)     if b"Good Job." in res:         return True     else:         return False project=angr.Project("./02_angr_find_condition",auto_load_libs=False) state=project.factory.entry_state() sim=project.factory.simgr(state) sim.explore(find=succ)
   | 
 
state.posix.dumps(1)返回stdout中的内容,avoid也可以这么用。
03_angr_simbolic_registers
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
   | int __cdecl main(int argc, const char **argv, const char **envp) {   int v3;    int v4;    int v5;    int v6;    unsigned int v7;    unsigned int v9;    unsigned int v10;      printf("Enter the password: ");   v4 = get_user_input();   v6 = v5;   v7 = complex_function_1(v4);   v9 = complex_function_2(v3);   v10 = complex_function_3(v6);   if ( v7 || v9 || v10 )     puts("Try again.");   else     puts("Good Job.");   return 0; }
   | 
 
其中输入函数如下:
1 2 3 4 5 6 7 8 9 10 11
   | int get_user_input() {   int v1;    int v2;    int v3;    unsigned int v4;      v4 = __readgsdword(0x14u);   __isoc99_scanf("%x %x %x", &v1, &v2, &v3);   return v1; }
   | 
 
Angr对scanf这类格式化字符串的支持并不好,但是这样写也能得到结果:
1 2 3 4 5 6 7 8 9 10 11
   | import angr project=angr.Project("./03_angr_symbolic_registers",auto_load_libs=False) state=project.factory.entry_state() sim=project.factory.simgr(state) sim.explore(find=0x80489E9) if sim.found:     res=sim.found[0]     res=res.posix.dumps(0)     print(res) else:     print("No")
   | 
 
正确的操作:看汇编,发现__isoc99_scanf函数实际操作将值储存在寄存器中:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
   | .text:0804891E                 lea     ecx, [ebp+var_10] .text:08048921                 push    ecx .text:08048922                 lea     ecx, [ebp+var_14] .text:08048925                 push    ecx .text:08048926                 lea     ecx, [ebp+var_18] .text:08048929                 push    ecx .text:0804892A                 push    offset aXXX     ; "%x %x %x" .text:0804892F                 call    ___isoc99_scanf .text:08048934                 add     esp, 10h .text:08048937                 mov     ecx, [ebp+var_18] .text:0804893A                 mov     eax, ecx .text:0804893C                 mov     ecx, [ebp+var_14] .text:0804893F                 mov     ebx, ecx .text:08048941                 mov     ecx, [ebp+var_10] .text:08048944                 mov     edx, ecx
   | 
 
我们手动设置寄存器的值,然后将get_user_input函数跳过:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
   | import angr,claripy project=angr.Project("./03_angr_symbolic_registers",auto_load_libs=False) state=project.factory.blank_state(addr=0x08048980) input1=claripy.BVS("input1",32)  input2=claripy.BVS("input2",32) input3=claripy.BVS("input3",32) state.regs.eax=input1 state.regs.ebx=input2 state.regs.edx=input3 sim=project.factory.simgr(state) sim.explore(find=0x80489E9) if sim.found:     res=sim.found[0]     res1=res.solver.eval(input1)     res2=res.solver.eval(input2)     res3=res.solver.eval(input3)     print(hex(res1)+" "+hex(res2)+" "+hex(res3)) else:     print("No")
   | 
 
04_angr_symbolic_stack
1 2 3 4 5 6 7 8 9 10 11 12 13
   | int handle_user() {   int v1;    int v2[3];      __isoc99_scanf("%u %u", v2, &v1);   v2[0] = complex_function0(v2[0]);   v1 = complex_function1(v1);   if ( v2[0] == 1999643857 && v1 == -1136455217 )     return puts("Good Job.");   else     return puts("Try again."); }
   | 
 
这么一把梭也行:
1 2 3 4 5 6 7 8 9
   | import angr project=angr.Project("./04_angr_symbolic_stack",auto_load_libs=False) state=project.factory.entry_state() sim=project.factory.simgr(state) sim.explore(find=0x080486E4) if sim.found:     res=sim.found[0]     res=res.posix.dumps(0)     print(res)
   | 
 
正确的做法,看v1和v2[3]在栈中的位置:分别为[ebp-10h]和[ebp-Ch]。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
   | import angr,claripy project=angr.Project("./04_angr_symbolic_stack",auto_load_libs=False) state=project.factory.blank_state(addr=0x08048694) input1=claripy.BVS("input1",32) input2=claripy.BVS("input2",32) state.regs.ebp=state.regs.esp state.regs.esp-=0x1c state.memory.store(state.regs.ebp-0xc,input1) state.memory.store(state.regs.ebp-0x10,input2) sim=project.factory.simgr(state) sim.explore(find=0x080486E4) if sim.found:     res=sim.found[0]     res=res.solver.eval(input1)     print(res)     res=sim.found[0]     res=res.solver.eval(input2)     print(res)
   | 
 
05_angr_symbolic_memory
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
   | int __cdecl main(int argc, const char **argv, const char **envp) {   int i;      memset(&user_input, 0, 33);   printf("Enter the password: ");   __isoc99_scanf("%8s %8s %8s %8s", &user_input, &unk_A1BA1C8, &unk_A1BA1D0, &unk_A1BA1D8);   for ( i = 0; i <= 31; ++i )     *(i + 169583040) = complex_function(*(i + 169583040), i);   if ( !strncmp(&user_input, "NJPURZPCDYEAXCSJZJMPSOMBFDDLHBVN", 32) )     puts("Good Job.");   else     puts("Try again.");   return 0; }
   | 
 
一把梭:
1 2 3 4 5 6 7 8
   | import angr project=angr.Project("./05_angr_symbolic_memory",auto_load_libs=False) state=project.factory.entry_state() sim=project.factory.simgr(state) sim.explore(find=0x0804866D) if sim.found:     res=sim.found[0]     print(res.posix.dumps(0))
   | 
 
跟上一道题一样:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
   | import angr,claripy project=angr.Project("./05_angr_symbolic_memory",auto_load_libs=False) state=project.factory.blank_state(addr=0x080485FE) pwd1=claripy.BVS("pwd1",64) pwd2=claripy.BVS("pwd2",64) pwd3=claripy.BVS("pwd3",64) pwd4=claripy.BVS("pwd4",64) state.memory.store(0x0A1BA1C0,pwd1) state.memory.store(0x0A1BA1C0+8,pwd2) state.memory.store(0x0A1BA1C0+8+8,pwd3) state.memory.store(0x0A1BA1C0+8+8+8,pwd4) sim=project.factory.simgr(state) sim.explore(find=0x0804866D) if sim.found:     res=sim.found[0]     print(res.solver.eval(pwd1))     print(res.solver.eval(pwd2))     print(res.solver.eval(pwd3))     print(res.solver.eval(pwd4))
   | 
 
06_angr_symbolic_dynamic_memory
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
   | int __cdecl main(int argc, const char **argv, const char **envp) {   _BYTE *v3;    _BYTE *v4;    int v6;    int v7;    int v8;    int v9;    int v10;    int v11;    int i;      buffer0 = malloc(9, v6, v7, v8);   buffer1 = malloc(9, v9, v10, v11);   memset(buffer0, 0, 9);   memset(buffer1, 0, 9);   printf("Enter the password: ");   __isoc99_scanf("%8s %8s", buffer0, buffer1);   for ( i = 0; i <= 7; ++i )   {     v3 = (_BYTE *)(buffer0 + i);     *v3 = complex_function(*(char *)(buffer0 + i), i);     v4 = (_BYTE *)(buffer1 + i);     *v4 = complex_function(*(char *)(buffer1 + i), i + 32);   }   if ( !strncmp(buffer0, "UODXLZBI", 8) && !strncmp(buffer1, "UAORRAYF", 8) )     puts("Good Job.");   else     puts("Try again.");   free(buffer0);   free(buffer1);   return 0; }
   | 
 
一把梭:
1 2 3 4 5 6 7 8
   | import angr project=angr.Project("./06_angr_symbolic_dynamic_memory",auto_load_libs=False) state=project.factory.entry_state() sim=project.factory.simgr(state) sim.explore(find=0x08048759) if sim.found:     res=sim.found[0]     print(res.posix.dumps(0))
   | 
 
这道题储存位置为堆,不能直接给出一个地址去储存。符号执行有个好处:不是真的执行,只是模拟执行代码,对地址本身没有限制,完全可以随意设定内存的使用方法。endness用于指定储存端序,project.arch.memory_endness反应平台默认端序(小端序)。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
   | import angr,claripy project=angr.Project("./06_angr_symbolic_dynamic_memory",auto_load_libs=False) state=project.factory.blank_state(addr=0x08048699) buff0=0x0ABCC8A4 buff1=0x0ABCC8AC pwd1=claripy.BVS("pwd1",64) pwd2=claripy.BVS("pwd2",64) state.memory.store(buff0,0xffffff00,endness=project.arch.memory_endness) state.memory.store(buff1,0xffffff80,endness=project.arch.memory_endness) state.memory.store(0xffffff00,pwd1) state.memory.store(0xffffff80,pwd2) sim=project.factory.simgr(state) sim.explore(find=0x08048759) if sim.found:     res=sim.found[0]     print(res.solver.eval(pwd1))     print(res.solver.eval(pwd2))
   | 
 
07_angr_symbolic_file
从文件读取。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
   | int __cdecl main(int argc, const char **argv, const char **envp) {   int result;    int i;      memset(&buffer, 0, 64);   printf("Enter the password: ");   __isoc99_scanf("%64s", &buffer);   ignore_me(&buffer, 64);   memset(&buffer, 0, 64);   fp = fopen("OJKSQYDP.txt", "rb");   fread(&buffer, 1, 64, fp);   fclose(fp);   unlink("OJKSQYDP.txt");   for ( i = 0; i <= 7; ++i )     *(_BYTE *)(i + 134520992) = complex_function(*(char *)(i + 134520992), i);   if ( strncmp(&buffer, "AQWLCTXB", 9) )   {     puts("Try again.");     exit(1);   }   puts("Good Job.");   exit(0);   _libc_csu_init();   return result; }
   | 
 
一把梭:
1 2 3 4 5 6 7 8 9
   | import angr project=angr.Project("./07_angr_symbolic_file",auto_load_libs=False) state=project.factory.entry_state() sim=project.factory.simgr(state) sim.explore(find=0x080489B0) if sim.found:     res=sim.found[0]     print(res.posix.dumps(0))
 
   | 
 
模拟文件系统:
1 2 3 4 5 6 7 8 9 10 11 12 13
   | import angr,claripy project=angr.Project("./07_angr_symbolic_file",auto_load_libs=False) state=project.factory.blank_state(addr=0x080488EA) filename = 'OJKSQYDP.txt' pwd1=claripy.BVS("pwd1",64*8) pwdfile=angr.storage.SimFile(filename,content=pwd1,size=64) state.fs.insert(filename,pwdfile)  sim=project.factory.simgr(state) sim.explore(find=0x080489B0) if sim.found:     res=sim.found[0]     print(hex(res.solver.eval(pwd1)))
 
   | 
 
08_angr_constraints
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
   | int __cdecl main(int argc, const char **argv, const char **envp) {   int i;      qmemcpy(&password, "AUPDNNPROEZRJWKB", 16);   memset(&buffer, 0, 17);   printf("Enter the password: ");   __isoc99_scanf("%16s", &buffer);   for ( i = 0; i <= 15; ++i )     *(i + 134520912) = complex_function(*(i + 134520912), 15 - i);   if ( check_equals_AUPDNNPROEZRJWKB(&buffer, 16) )     puts("Good Job.");   else     puts("Try again.");   return 0; } BOOL __cdecl check_equals_AUPDNNPROEZRJWKB(int a1, unsigned int a2) {   int v3;    unsigned int i;      v3 = 0;   for ( i = 0; i < a2; ++i )   {     if ( *(i + a1) == *(i + 134520896) )       ++v3;   }   return v3 == a2; }
   | 
 
一把梭不太行。缓解“路径爆炸”方法:在check函数前结束,然后手动为求解器添加条件。
1 2 3 4 5 6 7 8 9 10 11 12
   | import angr,claripy project=angr.Project("./08_angr_constraints",auto_load_libs=False) state=project.factory.blank_state(addr=0x08048625) pwd=claripy.BVS("pwd",16*8) state.memory.store(0x0804A050,pwd) sim=project.factory.simgr(state) sim.explore(find=0x08048565)  if sim.found:     res=sim.found[0]     now_str=state.memory.load(0x0804A050,16)      res.solver.add("AUPDNNPROEZRJWKB"==now_str)     print(res.solver.eval(pwd))
   | 
 
09_angr_hooks
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
   | int __cdecl main(int argc, const char **argv, const char **envp) {   BOOL v3;    int i;    int j;      qmemcpy(&password, "XYMKBKUHNIQYNQXE", 16);   memset(&buffer, 0, 17);   printf("Enter the password: ");   __isoc99_scanf("%16s", &buffer);   for ( i = 0; i <= 15; ++i )     *(_BYTE *)(i + 134520916) = complex_function(*(char *)(i + 134520916), 18 - i);   equals = check_equals_XYMKBKUHNIQYNQXE(&buffer, 16);   for ( j = 0; j <= 15; ++j )     *(_BYTE *)(j + 134520900) = complex_function(*(char *)(j + 134520900), j + 9);   __isoc99_scanf("%16s", &buffer);   v3 = equals && !strncmp(&buffer, &password, 16);   equals = v3;   if ( v3 )     puts("Good Job.");   else     puts("Try again.");   return 0; }
   | 
 
还是“路径爆炸”,第二个方法:对函数进行钩取。
1 2 3 4 5 6 7 8 9 10 11 12 13 14
   | import angr import claripy project=angr.Project("./09_angr_hooks",auto_load_libs=False) state=project.factory.entry_state() @project.hook(0x080486B3, length=5)  def skip_check(state):     compare_str="XYMKBKUHNIQYNQXE"     now_str=state.memory.load(0x0804A054,16)     state.regs.eax=claripy.If(compare_str==now_str,claripy.BVV(1, 32),claripy.BVV(0, 32))  sim=project.factory.simgr(state) sim.explore(find=0x08048768) if sim.found:     res=sim.found[0]     print(res.posix.dumps(0))
   | 
 
10_angr_simprocedures
check_equals_ORSDDWXHZURJRBDH函数的调用次数过多,不能逐个地址钩取。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
   | int __cdecl main(int argc, const char **argv, const char **envp) {   int i;    char v5[17];    unsigned int v6;      v6 = __readgsdword(0x14u);   memcpy(&password, "ORSDDWXHZURJRBDH", 16);   memset(v5, 0, sizeof(v5));   printf("Enter the password: ");   __isoc99_scanf("%16s", v5);   for ( i = 0; i <= 15; ++i )     v5[i] = complex_function(v5[i], 18 - i);   if ( check_equals_ORSDDWXHZURJRBDH(v5, 16) )     puts("Good Job.");   else     puts("Try again.");   return 0; }
   | 
 
函数钩取方式:
1 2 3 4 5 6 7 8 9 10 11
   | import angr import claripy project=angr.Project("./10_angr_simprocedures",auto_load_libs=False) state=project.factory.entry_state() class ReplaceCmp(angr.SimProcedure):     def run(self,arg1,arg2):         cmp_str="ORSDDWXHZURJRBDH"         input_str=self.state.memory.load(arg1,arg2)         return claripy.If(cmp_str==input_str,claripy.BVV(1,32),claripy.BVV(0,32)) project.hook_symbol("check_equals_ORSDDWXHZURJRBDH", ReplaceCmp())
 
   | 
 
11_angr_sim_scanf
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
   | int __cdecl main(int argc, const char **argv, const char **envp) {   int i;    char v6[20];    unsigned int v7;      v7 = __readgsdword(0x14u);   print_msg();   memset(v6, 0, sizeof(v6));   qmemcpy(v6, "DCLUESMR", 8);   for ( i = 0; i <= 7; ++i )     v6[i] = complex_function(v6[i], i);   printf("Enter the password: ");   __isoc99_scanf("%u %u", &buffer0, &buffer1);   if ( !strncmp(&buffer0, v6, 4) && !strncmp(&buffer1, &v6[4], 4) )     puts("Good Job.");   else     puts("Try again.");   return 0; }
   | 
 
一把梭就行:
1 2 3 4 5 6 7 8 9
   | import angr project=angr.Project("./11_angr_sim_scanf",auto_load_libs=False) state=project.factory.entry_state() sim=project.factory.simgr(state) sim.explore(find=0x0804FCA1) if sim.found:     res=sim.found[0]     print(res.posix.dumps(0))     
   | 
 
12_angr_veritesting
函数某部分引发“路径爆炸”,其他部分在做必要的运算。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61
   |  int __cdecl main(int argc, const char **argv, const char **envp) {   int v3;    int v5;    int v6;    int v7;    int v8;    const char **v9;    int v10;    int v11;    int v12;    int v13;    int v14;    int v15;    int i;    int v17;    int v18[9];    unsigned int v19;    int *p_argc;      p_argc = &argc;   v9 = argv;   v19 = __readgsdword(0x14u);   print_msg();   memset(     v18 + 3,     0,     33,     v5,     v6,     v7,     v8,     v9,     v10,     v11,     v12,     v13,     v15,     v17,     v18[0],     v18[1],     v18[2],     v18[3],     v18[4],     v18[5]);   printf("Enter the password: ");   __isoc99_scanf("%32s", v18 + 3);   v14 = 0;   for ( i = 0; i <= 31; ++i )   {     v3 = *(v18 + i + 3);     if ( v3 == complex_function(87, i + 186) )       ++v14;   }   if ( v14 != 32 || v19 )     puts("Try again.");   else     puts("Good Job.");   return 0; }
 
  | 
 
Veritesting算法:让符号执行在动态符号执行DSE和静态符号执行SSE之间协同工作。
1 2 3 4 5 6 7 8 9
   | import angr project=angr.Project("./12_angr_veritesting",auto_load_libs=False) state=project.factory.entry_state() sim=project.factory.simgr(state,veritesting=True)  sim.explore(find=0x08048684) if sim.found:     res=sim.found[0]     print(res.posix.dumps(0)) b'CXSNIDYTOJEZUPKFAVQLGBWRMHCXSNID'
   | 
 
13_angr_static_binary
静态编译生成的二进制文件。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
   | int __cdecl main(int argc, const char **argv, const char **envp) {   int i;    int j;    char v6[20];    char v7[ 20];    unsigned int v8;      v8 = __readgsdword(0x14u);   print_msg();   for ( i = 0; i <= 19; ++i )     v7[i] = 0;   qmemcpy(v7, "LJVNEPAU", 8);   printf("Enter the password: ");   _isoc99_scanf("%8s", v6);   for ( j = 0; j <= 7; ++j )     v6[j] = complex_function(v6[j], j);   if ( !strcmp(v6, v7) )     puts("Good Job.");   else     puts("Try again.");   return 0; }
   | 
 
Angr在库函数装载时钩取这些函数,静态编译没有这个过程,会被主动分析。所以要钩取静态编译生成的库函数。Angr内置了多个库函数,需要手动钩取。
1 2 3 4 5 6 7 8 9 10 11 12 13
   | import angr project=angr.Project("./13_angr_static_binary",auto_load_libs=False) state=project.factory.entry_state() project.hook(0x0804ED40,angr.SIM_PROCEDURES['libc']['printf']()) project.hook(0x0804ED80,angr.SIM_PROCEDURES['libc']['scanf']()) project.hook(0x0804F350,angr.SIM_PROCEDURES['libc']['puts']()) project.hook(0x08048D10,angr.SIM_PROCEDURES['glibc']['__libc_start_main']()) project.hook(0x0805B450,angr.SIM_PROCEDURES['libc']['strcmp']()) sim=project.factory.simgr(state,veritesting=True) sim.explore(find=0x080489E1) if sim.found:     res=sim.found[0]     print(res.posix.dumps(0))
   |