Angr实例分析——strcpy_find

本博客由闲散白帽子胖胖鹏鹏胖胖鹏潜力所写,仅仅作为个人技术交流分享,不得用做商业用途。转载请注明出处,未经许可禁止将本博客内所有内容转载、商用。

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)
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值