angr学习笔记(三)--路径爆炸问题的处理

符号执行最大的问题就是路径爆炸,当一个程序存在循环结构时,即使逻辑十分简单也可能会产生规模十分巨大的执行路径,本文记录三种处理路径爆炸的方法:

1.避免进入循环结果,手动添加约束条件

循环结果如下

 

该循环结构在程序中比较两个字符串是否相等,每次循环都会有if语句生成两个不同的分支,路径成指数级增长,该函数可以通过手动添加约束条件来避免执行

 solution.found[0].solver.add(string1=='BWYRUBQCMVSBRGFU')

使程序停止在该函数之前,再添加约束条件后求解,得出效果与执行完该函数一致

 

import angr
import sys
import claripy
def Go():
    p=angr.Project("./08con",auto_load_libs=False)
    istate=p.factory.blank_state(addr=0x08048627)
    
    buff_addr=0x0804A050
    
    
    passwd0=claripy.BVS('passwd0',16*8)
    
    istate.memory.store(buff_addr,passwd0)
    
    sm=p.factory.simulation_manager(istate)
    
    solution=sm.explore(find=0x08048678)    //提前停止
    
    print(len(solution.found))
    if solution.found:
    
        string1=solution.found[0].memory.load(buff_addr,16)         //读出此刻状态下的字符串值
        solution.found[0].solver.add(string1=='BWYRUBQCMVSBRGFU')   //对此刻字符串值条件约束条件
        solution0=solution.found[0].solver.eval(passwd0,cast_to=bytes)  //求解该字符串


        print("[+] Success! Solution is: {}".format(solution0))
    else:
        raise Exception("error")
        
        
if __name__=="__main__":
    Go()

 

 

2.hooks方法

就是用我们自己设计的函数去取代被hook的函数

找到会导致路径爆炸的函数,用自己编写的函数取代该函数即可,可以利用函数地址hook,也可以利用函数名进行hook

 

利用函数地址hook:

@p.hook(check_equals_called_address, length=instruction_to_skip_length)
    def skip_check(state):
        flag=state.memory.load(buff_addr,16)
        string1='XKSPZSJKJYQCQXZV'
        state.regs.eax=claripy.If(
            string1==flag,
            claripy.BVV(1,32),
            claripy.BVV(0,32)
        )

@p.hook() 第一个参数是需要被hook的函数地址,length是call该函数指令占据的字节大小

 

 如图,addr=0x80486B8,length=D-8

 

 state.regs.eax=claripy.If()
设置寄存器eax的值,使该函数与被hook的函数具有一样的效果,函数的返回值被保存在eax中,字符串相等则返回BVV(1,32),否则返回BVV(0,32)



利用函数名hook
当一个需要被hook的函数被调用了很多次时,利用地址hook便会出现问题,而通过程序的符号表利用函数名完全可以解析出地址
hook函数名的方法:
class Replace_check(angr.SimProcedure):
		def run(self,user_input,length):
			user_input_addr=user_input
			flag=self.state.memory.load(user_input_addr,length)
			string1='WQNDNKKWAWOLXBAC'
			
			self.state.regs.eax=claripy.If(
				string1==flag,
				claripy.BVV(1,32),
				claripy.BVV(0,32)
				)
	
check_funcname='check_equals_WQNDNKKWAWOLXBAC'
	
p.hook_symbol(check_funcname,Replace_check())

  

class Replace_check(angr.SimProcedure) 需要替换的函数名 Replace_check()
def run(self,user_input,length)  run函数名固定,self后面的参数与被hook的函数参数保持一致
p.hook_symbol(check_funcname,Replace_check())  第一个参数时被替换的函数名,第二个参数是构造出来的函数
完成exp
import angr
import sys
import claripy
def Go():
    p=angr.Project("./10sim",auto_load_libs=False)
    istate=p.factory.entry_state()
    
    class Replace_check(angr.SimProcedure):
        def run(self,user_input,length):
            user_input_addr=user_input
            flag=self.state.memory.load(user_input_addr,length)
            string1='WQNDNKKWAWOLXBAC'
            
            self.state.regs.eax=claripy.If(
                string1==flag,
                claripy.BVV(1,32),
                claripy.BVV(0,32)
                )
    
    check_funcname='check_equals_WQNDNKKWAWOLXBAC'
    
    p.hook_symbol(check_funcname,Replace_check())
    
    sm=p.factory.simulation_manager(istate)
    
    def succ(state):
        output1=state.posix.dumps(1)
        if b'Good Job.' in output1:
            return True
        else:
            return False
            
    def _abort(state):
        output2=state.posix.dumps(1)
        if b'Try again.' in output2:
            return True
        else:
            return False
    
    solution=sm.explore(find=succ,avoid=_abort)
    print(len(solution.found))
    if solution.found:
        solution0=solution.found[0].posix.dumps(0)
        print(solution0)
    else:
        raise Exception("error")
        
        
if __name__=="__main__":
    Go()

 



3.veritesting技术处理路径爆炸
简单粗暴,只需要在angr里我们只要在构造模拟管理器时,启用Veritesting了就行
sm=p.factory.simulation_manager(istate,veritesting=True)

忽视循环结构,直接硬怼,耗时较长

完整版
import angr
import sys
import claripy
def Go():
	p=angr.Project("./12ver",auto_load_libs=False)
	istate=p.factory.entry_state()
	
	sm=p.factory.simulation_manager(istate,veritesting=True)
	
	def succ(state):
		output1=state.posix.dumps(1)
		if b'Good Job.' in output1:
			return True
		else:
			return False
			
	def _abort(state):
		output2=state.posix.dumps(1)
		if b'Try again.' in output2:
			return True
		else:
			return False
	
	solution=sm.explore(find=succ,avoid=_abort)
	print(len(solution.found))
	if solution.found:
		solution0=solution.found[0].posix.dumps(0)
		print(solution0)
	else:
		raise Exception("error")
		
		
if __name__=="__main__":
	Go()

  

 

 

 
posted @ 2021-12-23 00:17  re0juren  阅读(1399)  评论(1编辑  收藏  举报