本博客由闲散白帽子胖胖鹏鹏胖胖鹏潜力所写,仅仅作为个人技术交流分享,不得用做商业用途。转载请注明出处,未经许可禁止将本博客内所有内容转载、商用。
0x00 题目介绍
前面做了两个简单的例子,今天我们还是简单地例子(饭要一口一口的吃,步子要一步一步地走,步子太大,容易出bug。不爽你打我啊)。这次的例子是strcpy_find,代码链接:https://github.com/angr/angr-doc/tree/master/examples/strcpy_find。
拿到可执行文件先放入ida里面看下。逻辑很简单。
对字符串“Unu`mmx!onu!uid!q`rrvnse///”中的每个字符异或上1,得到新的字符串就是我们的这个密码。经过解密之后密码为“Totally not the password...”。密码验证成功之后,会进入func。
0x01 分析出密码
由于最后成功的代码中,存在着strcpy函数,我们就从这个函数触发,获得判断每个调用strcpy的state,看是不是我们拷贝了我们输入的message的那个调用,如果满足条件,则进行passwd的求解。
import angr
import claripy
def main():
#加载二进制文件,为了节省时间和内存,不加载依赖库
proj = angr.Project('strcpy_test',load_options={'auto_load_libs':False})
#通过逆向获得我们所需要的两个函数地址,strcpy地址是我们所要搜寻的,func3的地址是我们要避免进入的
addrStrcpy = 0x4004a0L
addrFunc3 = 0x40061dL
#设置参数,第一个参数为函数名,第二个参数为密码,第三个参数为消息字符串
argv = []
argv.append(proj.filename)
#第二个参数是我们需要求解的,所以使用符号变量代替,设置长度为40字节
passwd_arg_size = 40
passwd_arg = claripy.BVS('passwd_arg',8*passwd_arg_size)
argv.append(passwd_arg)
#第三个参数是我们的消息
argv.append("The3rdargument")
#初始化入口状态,并传入我们构造好的参数
state = proj.factory.entry_state(args=argv)
#为state创建一个管理器
sm = proj.factory.simulation_manager(state)
#定义我们所需要的状态;
#我们需要找到只复制message的strcpy函数
#p.state.ip为当前指令指针,当使用这个变量时,将触发断点
#我们检查strcpy中的复制的字符串是否是我们的message,是则为我们想要的状态
def successState(state):
#如果调用的函数为strcpy
if (state.ip.args[0] == addrStrcpy):
#通过逆向可以知道,RSI处存放着我们的src字符串,我们使用memory.load将其读出来获得bitvector形式的字符串
BV_strCpySrc = state.memory.load(state.regs.rsi, len(argv[2]))
#我们需要使用eval函数将bitvector变量转化成字符串
strCpySrc = state.solver.eval( BV_strCpySrc, cast_to=str)
#判断是否和我们的输入相等
if argv[2] in strCpySrc:
return True
else:
return False
else:
return False
#搜索我们想要的状态
sm.explore(find=successState, avoid=(addrFunc3,))
found = sm.found
if ( len(found) > 0):
found = sm.found[0]
#求解得到该状态时,argv[1]的可能值
result = found.solver.eval(argv[1], cast_to=str)
try:
result = result[:result.index('\0')]
except ValueError:
pass
else:
result = "couldn't find any satisfaied state"
return result
if __name__ == "__main__":
print 'The password is "%s"' % main()
上面的代码中,函数的地址可以使用CFG进行求出。下面的代码是求根据函数符号求出函数地址的方法。
#cfg.kb.functions中管理着二进制文件中函数及相关信息的对应关系
def getFuncAddress( funcName, plt=None ):
found = [
addr for addr,func in cfg.kb.functions.iteritems()
if funcName == func.name and (plt is None or func.is_plt == plt)
]
if len( found ) > 0:
print "Found "+funcName+"'s address at "+hex(found[0])+"!"
return found[0]
else:
raise Exception("No address found for function : "+funcName)
#生成CFG,使用fail_fast=True可以将生成时间最小化
cfg = project.analyses.CFG(fail_fast=True)
#获得strcpy的地址
addrStrcpy = getFuncAddress('strcpy', plt=True)