早就听闻了angr,之前看wp也有大佬使用了angr,上一次打开angrctf一头雾水,还要装环境啥的,就先搁置了。现在趁着军训开始angr的学习。
 
tnnd两天都没配置好一个虚拟环境,还是在朋友的帮助下搞了个docker,woc真难绷,或许以后有能力了可以搞一个虚拟机,包含所有的逆向需要的环境hhh。一天后来考古,那个docker用起来着实别扭,不知道出了什么问题,不能将主机的文件拷贝到容器中,还有就是用了docker start 容器id也启动不了容器,只好另寻他路,本来想放弃的,可是一想到被这环境折磨三四天了,哎。终于,在wsl的虚拟环境成功搭建!!!
记录一下启动步骤
1 2 3 4 5 # $  source  myenv/bin/activate# $  deactivate 
 
(15条消息) 在wsl上安装angr框架_wsl2下安装angr workon_ljahum的博客-CSDN博客 
Angr介绍 看一看官方文档的解释
angr is a multi-architecture binary analysis toolkit, with the capability to perform dynamic symbolic execution (like Mayhem, KLEE, etc.) and various static analyses on binaries. 
angr是一个多架构二进制分析工具包,具有执行动态符号执行(例如Mayhem,KLEE等)和各种静态分析的能力。
 
什么叫符号执行 呢?
符号执行 符号执行是一种静态分析技术,是一种计算机科学领域的程序分析技术,通过采用抽象的符号代替精确值作为程序输入变量,得出每个路径抽象的输出结果。 这一技术在硬件、底层程序测试中有一定的应用,能够有效的发现程序中的漏洞。符号执行就是给程序传递一个符号而不是具体的值,让符号伴随程序运行,当遇到分支时angr会保留所有分支以及进入分支的约束条件,最后根据约束条件对我们传递的符号约束求解。这听着有点像全自动z3。
概念有点抽象,不如直接做题。
Angr_CTF 参考链接:angr符号执行练习 00_angr_find_哔哩哔哩_bilibili 
                   angr从入门到精通 
                  angr核心概念即模块解读 
使用步骤 
创建project 
设置state 
新建符号量 : BVS (bitvector symbolic ) 或 BVV (bitvector value) 
把符号量设置到内存或者其他地方 
设置 Simulation Managers , 进行路径探索的对象 
运行,探索满足路径需要的值 
约束求解,获取执行结果 
 
00_angr_find 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 import  angrimport  sysdef  angr00 ():     path_to_binary="./home/mzyy/AngerCTF/00_angr_find/00_angr_find"    project=angr.Project(path_to_binary)    initial_state=project.factory.entry_state()   simulation=project.factory.simgr(initial_state)   print_good_address=0x8048678         simulation.explore(find=print_good_address)    if  simulation.found:     solution_state=simulation.found[0 ]       print (solution_state.posix.dumps(0 )) if  __name__ == "__main__" :    angr00() 
 
下面是用ipython写的截的图,是跟着B站的一位up主来的。
01_angr_avoid 
反编译main函数时说函数过大无法反编译(可以通过修改ida的设置文件,提高最多分析长度来解决此问题)。这一题实际上也不需要,根据函数名,我们找到avoid_me的地址加到参数中即可。
查看avoid_me的交叉引用,发现巨多。我们可以看到全是main函数在引用,这就是main函数巨大的原因吧。
1 2 3 4 5 6 7 8 9 10 11 12 13 import  angrdef  angr01 ():    path="./angrctf/01_angr_avoid"      p=angr.Project(path)     init_state=p.factory.entry_state()     sm=p.factory.simgr(init_state)     sm.explore(find=0x080485FC ,avoid=0x080485BF )     if  sm.found:         solution_state=sm.found[0 ]         print (solution_state.posix.dumps(0 )) if  __name__ == "__main__" :    angr01() 
 
这一题就是想让我们知道,避开一些错误的路径可以提高效率,我觉得将上面的avoid删掉一样可以达到目的,不过时间可能会很夸张。哎呀被打脸了,跑了十分钟左右跑出来一个killed。
好吧电脑内存不足,进程被系统杀死了,那如果内存足够大还是能跑出来的吧。提出问题和回答问题的人都好耐心好有礼貌^_^
02_angr_find_condition 很显然这次不能通过输出good job的地址来解题了,因为这一题故意设置了很多跳转,使用了多次put good job和多次put try again。根据作者的注释,在一些情况下我们可能不知道要达到的指令的地址,或者没有特定的指令目标。在这种情况下,我们只要知道一种状态,例如在某状态下二进制文件打印出“Good Job”。angr提供了一种功能强大的方法:允许搜索满足任意条件的状态。具体来讲,我们可以使用一个函数来定义一个状态,该函数接收一个state作为参数,并返回True或false表示该状态是否满足要求。当程序找到一个符合条件的状态时,他就会停止搜索。具体看下面这函数,它检查状态的标准输出是否包含字符串 “Good Job.”。
1 2 3 4 5 def  is_successful_state (state ):    if  b"Good Job."  in  state.posix.dumps(1 ):         return  True      else :         return  False  
 
find的用法 除了地址之外,find 参数还可以是一个函数,该函数接受一个路径(path)作为参数,并返回一个布尔值。当该函数返回 True 时,路径组将停止探索。例如,以下代码使用 find 方法搜索二进制文件中所有包含 win_function 函数的路径,并打印出对应的输入数据:
1 2 3 4 5 6 7 8 9 10 11 12 13 import  angrproj = angr.Project('/path/to/binary' ) state = proj.factory.entry_state() pg = proj.factory.path_group(state) def  win_function (path ):    return  "Congratulations!"  in  path.state.posix.dumps(1 ) pg.explore(find=win_function) for  found in  pg.found:    print (found.state.posix.dumps(0 )) 
 
在这个示例中,win_function 是一个用于检查路径是否包含特定输出的函数。在探索过程中,每当发现一个路径包含 win_function 函数并生成相应的结论时,路径组将停止探索,并输出相应的输入数据。
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 import  angrimport  sysdef  main (argv ):    path=argv[1 ]     p=angr.Project(path)     init_state=p.factory.entry_state()     sm=p.factory.simgr(init_state)     def  isGood (sm ):         if  b"Good Job."  in  sm.posix.dumps(1 ):             return  True          else :             return  False      def  isBad (sm ):         if  b"Try again."  in  sm.posix.dumps(1 ):             return  True          else :             return  False      sm.explore(find=isGood,avoid=isBad)     if  sm.found:         solution_state=sm.found[0 ]         print (solution_state.posix.dumps(0 ))          if  __name__ =='__main__' :    main(sys.argv) 
 
03_angr_symbolic_registers 根据当时作者的说明,Angr目前不支持使用scanf一次读取多个变量(例如:# scanf(“%u %u))。您需要告诉仿真引擎在调用scanf后开始程序,并手动将符号注入寄存器。据说现在可以了,但学一下总没有坏处,能从中体会到angr的灵活。
首先呢确定进入的地址,就在scanf之后,0x080488C7
进去之后呢因为我们跳过了scanf所以把它的参数放到该有的位置,也就是寄存器eax,ebx,edx中
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 import  angr import  sysimport  claripydef  main (argv ): path=argv[1 ]  p=angr.Project(path)  start_address=0x080488C7   init_state=p.factory.blank_state(addr=start_address)       pass0=claripy.BVS('pass0' ,32 )  pass1=claripy.BVS('pass1' ,32 )  pass2=claripy.BVS('pass2' ,32 )  init_state.regs.eax=pass0  init_state.regs.ebx=pass1  init_state.regs.edx=pass2  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:   soulution_state=sm.found[0 ]   password0=soulution_state.solver.eval (pass0)   password1=soulution_state.solver.eval (pass1)   password2=soulution_state.solver.eval (pass2)   print ("{:x} {:x} {:x}" .format (password0,password1,password2))  else :   print ("no found" ) if  __name__=='__main__' : main(sys.argv) 
 
04_angr_symbolic_stack 做这一题之前需要回顾一下栈帧,在看《逆向工程核心原理》的时候了解过。
栈帧 函数调用 
通过push指令传参 
将call指令的下一条指令的地址压入栈中作为返回地址 
push ebp 保存ebp的原始值 ebp稍后会被用作栈帧指针 
mov ebp,esp 直到函数返回前ebp中的值都是esp的初始值 我们可以通过ebp安全的访问栈中的函数参数与局部变量 
.sub esp,x这里的x依局部变量而变,如果局部变量为两个long类型(4字节)则此处的x应该为8 
借助mov指令和ebp创建局部变量 
删除栈帧 mov esp,ebp(恢复栈指针),pop ebp(恢复ebp) 
retn 
返回原来位置后,add esp,x测出的x根据步骤0穿入的参数而定,这一步的目的是将参数从栈中清理 
 
上一个题目的scanf是单独使用的,就是将我们的输入放入栈中然后再传到寄存器,所以我们只要跳到scanf执行完之后将输入放入寄存器即可。而这一题,是直接将我们的输入当作临时变量使用,即通过栈指针访问,那么我们跳过scanf之后,函数预留的那两个临时变量的位置是空的,所以我们要对栈进行操作,将函数正确的放入栈中。看上面的图,调用scanf的时候利用寄存器从右往左传参,var_10和var_c分别是第二个参数和第一个参数,所以我们将创建的符号变量依次放入ebp+var_C和ebp+var_10处即可。
从ida我们可以看出,这个函数第二行sub   esp, 18h,实际上堆栈空间是0x18,但是在实际的做题中我们只是用到了那两个参数,我们就恢复了0x8.
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 import  angrimport  sysimport  claripydef  main (argv ):    path=argv[1 ]     project=angr.Project(path)     start_address=0x080486AE      init_state=project.factory.blank_state(addr=start_address)          pass0=claripy.BVS('pass0' ,32 )     pass1=claripy.BVS('pass1' ,32 )          init_state.regs.ebp=init_state.regs.esp     padding_size=0x8      init_state.regs.esp-=padding_size     init_state.stack_push(pass0)        init_state.stack_push(pass1)     sm=project.factory.simulation_manager(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:         solution_state=sm.found[0 ]         password0=solution_state.solver.eval (pass0)         password1=solution_state.solver.eval (pass1)         print ("{} {} " .format (password0,password1))     else :         print ("no found" ) if  __name__=='__main__' :    main(sys.argv) 
 
疑惑 eval 
solver.eval(expression) 将会解出一个可行解 
solver.eval_one(expression)将会给出一个表达式的可行解,若有多个可行解,则抛出异常。 
solver.eval_upto(expression, n)将会给出最多n个可行解,如果不足n个就给出所有的可行解。 
solver.eval_exact(expression, n)将会给出n个可行解,如果解的个数不等于n个,将会抛出异常。 
solver.min(expression)将会给出最小可行解 
solver.max(expression)将会给出最大可行解 
 
05_angr_symbolic_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 34 35 36 37 38 39 40 41 42 43 44 45 46 47 import  angrimport  sysimport  claripydef  main (argv ):  path=argv[1 ]   project=angr.Project(path)   start_address=0x08048618    init_state=project.factory.blank_state(addr=start_address)   passwd0=claripy.BVS('passwd0' ,8 *8 )   passwd1=claripy.BVS('passwd1' ,8 *8 )   passwd2=claripy.BVS('passwd2' ,8 *8 )   passwd3=claripy.BVS('passwd3' ,8 *8 )   passwd0_address=0x0AB232C0    passwd1_address=0x0AB232C8    passwd2_address=0x0AB232D0    passwd3_address=0x0AB232D8    init_state.memory.store(passwd0_address,passwd0)   init_state.memory.store(passwd1_address,passwd1)   init_state.memory.store(passwd2_address,passwd2)   init_state.memory.store(passwd3_address,passwd3)      sm=project.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:         solution_state=sm.found[0 ]         password0=solution_state.solver.eval (passwd0,cast_to=bytes ).decode()         password1=solution_state.solver.eval (passwd1,cast_to=bytes ).decode()         password2=solution_state.solver.eval (passwd2,cast_to=bytes ).decode()         password3=solution_state.solver.eval (passwd3,cast_to=bytes ).decode()         print ("{} {} {} {} " .format (password0,password1,password2,password3))   else :         print ("no found" )      if  __name__=='__main__' :  main(sys.argv) 
 
06_angr_symbolic_dynamic_memory 新知识点:符号化动态内存。
作者的解释文档这样写着:我们可以不告诉二进制程序将数据写入使用malloc()分配的内存地址,而是直接伪造一个未使用的内存块的地址,并覆盖指向数据的指针。
思路是这样的:malloc函数返回值是一个地址,储存到了buffer里,我们伪造一个地址放到buffer即可,然后在我们伪造的地址处填入符号。
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 import  angr import  sysimport  claripydef  main (argv ):    path=argv[1 ]     start_address=0x080486AF      project=angr.Project(path)     init_state=project.factory.blank_state(addr=start_address)     passwd_size=8 *8      passwd0=claripy.BVS('passwd0' ,passwd_size)     passwd1=claripy.BVS('passwd1' ,passwd_size)     fake_heap_address0=0x0804A144      fake_heap_address1=0x0804A154      real_address0=0x0A2DEF74      real_address1=0x0A2DEF7C           init_state.memory.store(real_address0,fake_heap_address0,endness=project.arch.memory_endness)     init_state.memory.store(real_address1,fake_heap_address1,endness=project.arch.memory_endness)     init_state.memory.store(fake_heap_address0,passwd0)     init_state.memory.store(fake_heap_address1,passwd1)     sm=project.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:         solution_state=sm.found[0 ]         password0=solution_state.solver.eval (passwd0,cast_to=bytes ).decode()         password1=solution_state.solver.eval (passwd1,cast_to=bytes ).decode()         print ("{} {} " .format (password0,password1))     else :         print ("no found" ) if  __name__=='__main__' :    main(sys.argv) 
 
1 2 3 init_state.memory.store(real_address0,fake_heap_address0,endness=project.arch.memory_endness) (原地址,我们指定的假地址,端序),原地址指的是存放malloc返回值的变量的地址,此处endness是和本项目相同 
 
endness可选项
1 2 3 LE  – 小端序BE – 大端序 ME – 中间序 
 
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 27 28 29 30 31 32 33 34 35 36 37 import  angrimport  sysimport  claripydef  main (argv ):    path=argv[1 ]     project=angr.Project(path)     start_address=0x080488BC      init_state=project.factory.blank_state(addr=start_address)     filename='FOQVSBZB.txt'      filesize=0x40      passwd0=claripy.BVS('passwd0' ,filesize*8 )     passwdfile=angr.storage.SimFile(filename,content=passwd0,size=filesize)     init_state.fs.insert(filename,passwdfile)          sm=project.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:         solution_state=sm.found[0 ]         password0=solution_state.solver.eval (passwd0,cast_to=bytes ).decode()         print (password0)     else :         print ("no found" ) if  __name__=='__main__' :    main(sys.argv)     
 
新操作,创建虚拟文件并将其放入仿真文件系统
1 2 3 4 5 6 7 8 9 10 filename='FOQVSBZB.txt'  filesize_byte=0x40  passwd0=claripy.BVS('passwd0' ,filesize*8 ) passwdfile=angr.storage.SimFile(filename,content=passwd0,size=filesize) init_state.fs.insert(filename,passwdfile) 
 
08_angr_constraints 开始之前先了解一下路径爆炸。因为这次的新知识点就是:通过添加约束解决路径爆炸问题。
路径爆炸 路径爆炸(Path explosion)指的是在有限状态机或接收器的设计过程中,状态数或路径数呈指数增长的现象。当程序经历的所有可能路径数量超过计算机的处理能力时,就会出现路径爆炸的问题。
路径爆炸是软件测试和验证中一个重要的问题。在对程序进行测试或验证时,需要覆盖程序的所有可能路径,以确保程序的正确性和安全性。但是,当程序中存在复杂的控制流结构时,这个任务就变得非常艰巨。
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 import  angrimport  sysimport  claripydef  main (argv ):    path=argv[1 ]     project=angr.Project(path)     start_address=0x0804863C      buffer_address=0x0804A040      ckeckfun_address=0x0804857C      init_state=project.factory.blank_state(addr=start_address)     passwd_len=16      passwd0=claripy.BVS('passwd0' ,passwd_len*8 )     init_state.memory.store(buffer_address,passwd0)     simulation=project.factory.simulation_manager(init_state)     simulation.explore(find=ckeckfun_address)     if  simulation.found:         solution_state=simulation.found[0 ]         parameter_address=buffer_address         parameter_size_bytes=16                            parameter_bitvector=solution_state.memory.load(parameter_address,parameter_size_bytes)         compare_valve='OSIWHBXIFOQVSBZB'          solution_state.solver.add(parameter_bitvector==compare_valve)         solution0=solution_state.solver.eval (passwd0,cast_to=bytes ).decode()         print (solution0)     else :         print ('no found' ) if  __name__=='__main__' :    main(sys.argv) 
 
如果按照程序之前的逻辑,按字节进行比对,16byte长度的数据就会产生2^16个分支,分支呈指数级增长,因此我们不按照他的逻辑进行比对,我们的输入经过一些操作之后还是被存储在buffer里,我们直接拿处理过后的buffer与comparedata进行比较,这样这样就变成了简单的爆破,不会造成路径爆炸。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 ckeckfun_address=0x0804857C  simulation.explore(find=ckeckfun_address) if  simulation.found:        solution_state=simulation.found[0 ]         parameter_address=buffer_address         parameter_size_bytes=16                            parameter_bitvector=solution_state.memory.load(parameter_address,parameter_size_bytes)         compare_valve='OSIWHBXIFOQVSBZB'                   solution_state.solver.add(parameter_bitvector==compare_valve)         solution0=solution_state.solver.eval (passwd0,cast_to=bytes ).decode() 
 
09_angr_hooks 新知识点:hook。
wiki:
钩子编程(hooking),也称作“挂钩”,是计算机程序设计术语,指通过拦截软件模块间的函数调用、消息传递、事件传递来修改或扩展操作系统、应用程序或其他软件组件的行为的各种技术 。 处理被拦截的函数调用、事件、消息的代码,被称为钩子(hook)。
 
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 import  angrimport  sysimport  claripydef  main (argv ):    path=argv[1 ]     project=angr.Project(path)     init_state=project.factory.entry_state()     checkfun_address=0x080486CA           jump_len=5      @project.hook(checkfun_address,length=jump_len )     def  fake_checkfun (state ):         buffer_address=0x0804A044          buffer_len=16          usr_input_string=state.memory.load(buffer_address,buffer_len)         compare_data='OSIWHBXIFOQVSBZB' .encode()                  state.regs.eax=claripy.If(usr_input_string==compare_data,claripy.BVV(1 , 32 ),claripy.BVV(0 , 32 ) )              sm=project.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:         solution_state=sm.found[0 ]         solution = solution_state.posix.dumps(0 )         print (solution)     else :         raise  Exception('Could not find the solution' ) if  __name__=='__main__' :    main(sys.argv) 
 
利用地址hook,最后部分模仿函数返回值,返回值储存在寄存器eax中。
在ida查看命令字节码长度。
1 2 3 4 5 6 7 8 9 10 11     jump_len=5      @project.hook(checkfun_address,length=jump_len )     def  fake_checkfun (state ):         buffer_address=0x0804A044          buffer_len=16          usr_input_string=state.memory.load(buffer_address,buffer_len)         compare_data='OSIWHBXIFOQVSBZB' .encode()                  state.regs.eax=claripy.If(usr_input_string==compare_data,claripy.BVV(1 , 32 ),claripy.BVV(0 , 32 ) ) 
 
10_angr_simprocedures 仍然是利用hook解决路径爆炸的问题,上一题是利用地址比较麻烦,现在学习利用函数名来hook,有点像最开始的时候用函数替换good job的地址。
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 import  angrimport  sysimport  claripydef  main (argv ):    path=argv[1 ]     project=angr.Project(path)     init_state=project.factory.entry_state()          class  Replacefun (angr.SimProcedure):           def  run (self,to_check,length ):                 buffer_address=to_check                 buffer_length=length                 user_input_string=self.state.memory.load(buffer_address,buffer_length)                 comparedata='OSIWHBXIFOQVSBZB' .encode()                 return  claripy.If(                       user_input_string==comparedata,                       claripy.BVV(1 ,32 ),                       claripy.BVV(0 ,32 )                 )     check_equals_symbol='check_equals_OSIWHBXIFOQVSBZB'      project.hook_symbol(check_equals_symbol,Replacefun())     sm=project.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:         solution_state=sm.found[0 ]         solution = solution_state.posix.dumps(0 )         print (solution)     else :         raise  Exception('Could not find the solution' )            if  __name__=='__main__' :        main(sys.argv) 
 
把新知识点放下面
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16    class  Replacefun (angr.SimProcedure):                  def  run (self,to_check,length ):                buffer_address=to_check                buffer_length=length                user_input_string=self.state.memory.load(buffer_address,buffer_length)                comparedata='OSIWHBXIFOQVSBZB' .encode()                return  claripy.If(                      user_input_string==comparedata,                      claripy.BVV(1 ,32 ),                      claripy.BVV(0 ,32 )                )    check_equals_symbol='check_equals_OSIWHBXIFOQVSBZB'     project.hook_symbol(check_equals_symbol,Replacefun()) 
 
11_angr_sim_scanf 和上面的一样,用来巩固。这样处理之后scanf可以接收多个参数。
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 import  angrimport  sysimport  claripydef  main (argv ):    path=argv[1 ]     project=angr.Project(path)     init_state=project.factory.entry_state()     class  myscanf (angr.SimProcedure):         def  run (self,format_string,para0,para1 ):             input0=claripy.BVS('input0' ,4 *8 )             input1=claripy.BVS('input1' ,4 *8 )             self.state.memory.store(para0,input0,endness=project.arch.memory_endness)             self.state.memory.store(para1,input1,endness=project.arch.memory_endness)                          self.state.globals ['solution0' ]=input0             self.state.globals ['solution1' ]=input1     scanf_symbol='__isoc99_scanf'      project.hook_symbol(scanf_symbol,myscanf())     sm=project.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:         solution_state=sm.found[0 ]         stored_solutions0 = solution_state.globals ['solution0' ]         stored_solutions1 = solution_state.globals ['solution1' ]         solution = f'{solution_state.solver.eval (stored_solutions0)}  {solution_state.solver.eval (stored_solutions1)} '          print (solution)     else :         raise  Exception('Could not find the solution' ) if  __name__=='__main__' :    main(sys.argv) 
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 class  myscanf (angr.SimProcedure):           def  run (self,format_string,para0,para1 ):                        input0=claripy.BVS('input0' ,4 *8 )            input1=claripy.BVS('input1' ,4 *8 )                        self.state.memory.store(para0,input0,endness=project.arch.memory_endness)            self.state.memory.store(para1,input1,endness=project.arch.memory_endness)                        self.state.globals ['solution0' ]=input0            self.state.globals ['solution1' ]=input1    scanf_symbol='__isoc99_scanf'     project.hook_symbol(scanf_symbol,myscanf()) 
 
12_angr_veritesting 之前使用hook或者添加约束来解决路径爆炸问题,现在直接在创建虚拟管理器的时候加上一个参数,simulation=project.factory.simgr(init_state,veritesting=True)
简单来说就是Veritesting结合了静态符合执行与动态符号执行,减少了路径爆炸的影响,在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 import  angrimport  sysimport  claripydef  main (argv ):    path=argv[1 ]     project=angr.Project(path)     init_state=project.factory.entry_state()     simulation=project.factory.simgr(init_state,veritesting=True )     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 )          simulation.explore(find=is_good,avoid=is_bad)     if  simulation.found:         solution_state=simulation.found[0 ]         solution=solution_state.posix(0 )         print (solution)     else :         print ('no found' ) if  __name__=='__main__' :    main(sys.argv) 
 
13_angr_static_binary 
作者文档里的内容:
这个挑战与第一个挑战完全相同,只是它被编译为静态二进制文件。通常,Angr会自动使用SimProcedures替换标准库函数,以实现更快的运行速度。
为了解决这个挑战,需要手动hook任何使用的标准库c函数。
 
什么叫静态什么叫动态?
拖进ida里很容易看出来,题目13function那一栏里比12多得多,这是因为静态链接 库将所有依赖项都包含在目标二进制文件中,反观动态链接 ,同台链接是指程序在训醒时才需要加载所依赖的库,当我们使用动态链接库来编译程序时,编译器并不会将所有库函数的代码都合并为一个单独的可执行文件。相反,它只是在可执行文件中留下一些标记,以便在运行时从系统或其他位置加载动态链接库。
在静态链接库中,没有动态链接库来提供符号,我们需要手动hook任何使用的标准库c函数,并确保从main函数的开头开始执行。
在动态链接库中,动态链接器会提供符号,我们不需要手动hook标准库c函数。
这一题我们就要将main函数里所用到的标准库函数hook住,用angr的方法来取代,这能大大提高效率。
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 import  angrimport  sysdef  main (argv ):    path=argv[1 ]     project=angr.Project(path)     init_state=project.factory.entry_state()          printf_address=0x0804FAB0      scanf_address=0x0804FB10      strcmp_address=0x08048228      puts_address=0x080503F0      __libc_start_main_address=0x08048D60      project.hook(printf_address,angr.SIM_PROCEDURES['libc' ]['printf' ]())     project.hook(scanf_address,angr.SIM_PROCEDURES['libc' ]['scanf' ]())     project.hook(strcmp_address,angr.SIM_PROCEDURES['libc' ]['strcmp' ]())     project.hook(puts_address,angr.SIM_PROCEDURES['libc' ]['puts' ]())          project.hook(__libc_start_main_address,angr.SIM_PROCEDURES['glibc' ]['__libc_start_main' ]())     def  isgood (state ):         return  b'Good Job.'  in  state.posix.dumps(1 )     def  isbad (state ):         return  b'Try again.'  in  state.posix.dumps(1 )     simulation=project.factory.simgr(init_state)     simulation.explore(find=isgood,avoid=isbad)     if  simulation.found:         solution_state=simulation.found[0 ]         solution=solution_state.posix.dumps(0 )         print (solution)     else :         print ('no found' )      if  __name__=='__main__' :    main(sys.argv) 
 
14_angr_shared_library