查看: 56|回复: 0

[Reverse] 深入浅出angr(六)

[复制链接]

22

主题

23

帖子

0

精华

VIP

Rank: 16

学币
10
荣耀
0
rank
0
违规
0

VIP

    发表于 2020-6-15 00:47:55 | 显示全部楼层 |阅读模式

    前言  就我感觉angr比较适合用来解决混淆的题目,面对混淆题去混淆感觉自己能力不够,直接动态调试,又觉得非常浪费时间,那么这时angr可以成为非常好的帮手。
    如何快速的寻找find和avoid  在解题时我们时常会遇到带有强混淆的程序,这类程序要找出所有的find和avoid是一件耗时耗力的事情,那么我们可以采取何种高效的办法进行寻找呢?
      这里以hackcon2016_angry-reverser为例。
      IDA载入

    深入浅出angr(六)

    深入浅出angr(六)
      很明显的混淆,如果自己分析一遍,然后去除混淆也是需要费点时间的,不过如果你掌握了angr,那么只需要几分钟就可以解决此题,根本不要关心其使用了何种加密方式。
      此题中,正确的路径只有一条find=0x405a6e,需要避免的路径则有很多,我们可以通过如下代码,得到所有需要avoid的地址。
    e = open('./yolomolo', 'rb').read()
    
    avoids = []
    
    index = 0
    while True:
    index = e.find(b'\xB9\x00\x00\x00\x00',index+1)
    if index == -1:
    break
    addr = 0x400000 + index
    avoids.append()
    
    print (len(avoids))
    print (avoids)
      其中\xB9\x00\x00\x00\x00是mov ecx 0的机器码,因此完整代码可以如下组织:
    import angr
    import claripy
    
    def main():
    flag    = claripy.BVS('flag', 20*8, explicit_name=True)
    buf     = 0x606000
    crazy   = 0x400646
    find    = 0x405a6e
    e = open('./yolomolo', 'rb').read()
    
    avoids = []
    
    index = 0
    while True:
    index = e.find(b'\xB9\x00\x00\x00\x00',index+1)
    if index == -1:
    break
    addr = 0x400000 + index
    avoids.append(addr)
    
    proj = angr.Project('./yolomolo')
    state = proj.factory.blank_state(addr=crazy, add_options={angr.options.LAZY_SOLVES})
    
    state.memory.store(buf, flag, endness='Iend_BE')
    state.regs.rdi = buf
    
    
    for i in range(19):
    state.solver.add(flag.get_byte(i) >= 0x30)
    state.solver.add(flag.get_byte(i) <= 0x7f)
    
    simgr = proj.factory.simulation_manager(state)
    
    simgr.explore(find=find, avoid=avoids)
    found = simgr.found[0]
    return found.solver.eval(flag, cast_to=bytes)
    
    if __name__ in '__main__':
    import logging
    logging.getLogger('angr.sim_manager').setLevel(logging.DEBUG)
    print(main())

    例题  其实angr最适合拿来解决线性的程序。
    就比如说这题ekopartyctf2016_rev250

    深入浅出angr(六)

    深入浅出angr(六)
      如果去混淆,不一定能去除成功,如果动态调试,必定会耗费相当多的时间。如果你会使用angr,那么使用angr是在容易不过的事情了。
      由于需要调用当前的动态库,我们可以这样运行LD_LIBRARY_PATH=./ ./FUck_binary

    深入浅出angr(六)

    深入浅出angr(六)
      OK,并不是命令行参数输入。
      通过IDA,获取更多的信息。

    深入浅出angr(六)

    深入浅出angr(六)
      最终的find应该在这里。

    深入浅出angr(六)

    深入浅出angr(六)
      需要避免的分支0x403ABA,403A7E等
      我们可以通过之前提到过的方法提取出所有的avoid分支。
    avoids = []
    def get_avoids():
    file_bytes = open('./FUck_binary','rb').read()
    index = 0
    while True:
    index = file_bytes.find(b'\x66\x90',index+1)
    if index == -1:
    break
    if index < 0x3a7e:
    continue
    addr = 0x400000+index
    avoids.append(addr)
      在对输入进行条件约束时我们可以这么组织,这是常用的限制可打印字符的方式。
      state.solver.And(c <= '~', c >= ' ')
      跑了一下结果还以为代码写错了,这答案也太让人摸不着头脑了。

    深入浅出angr(六)

    深入浅出angr(六)
      代码如下:
    import angr
    import claripy
    
    BUF_LEN = 100
    
    avoids = []
    def get_avoids():
    file_bytes = open('./FUck_binary','rb').read()
    index = 0
    while True:
    index = file_bytes.find(b'\x66\x90',index+1)
    if index == -1:
    break
    if index < 0x3a7e:
    continue
    addr = 0x400000+index
    avoids.append(addr)
    def main():
    
    p = angr.Project('FUck_binary')
    flag = claripy.BVS('flag', BUF_LEN*8)
    state = p.factory.entry_state(stdin=flag)
    
    for c in flag.chop(8):
    state.solver.add(state.solver.And(c <= '~', c >= ' '))
    
    ex = p.factory.simulation_manager(state)
    ex.explore(find=0x403a40,avoid=avoids)
    
    found = ex.found[0]
    print(found.posix.dumps(0))
    
    if __name__ == '__main__':
    #main()
    get_avoids()
    main()
    总结
      既然选择了angr,便只顾风雨兼程



    温馨提示:
    1.如果您喜欢这篇帖子,请给作者点赞评分,点赞会增加帖子的热度,评分会给作者加学币。(评分不会扣掉您的积分,系统每天都会重置您的评分额度)。
    2.回复帖子不仅是对作者的最好奖励,还可以获得学币奖励,请尊重作者的劳动成果,拒绝做伸手党!
    3.发广告、灌水回复等违规行为一经发现直接禁言,如果本帖内容涉嫌违规,请点击论坛底部的举报反馈按钮,也可以在【投诉建议】板块发帖举报。
    学逆向论坛-免费的逆向学习论坛
    微信公众号
    快速回复 返回顶部 返回列表