使用angr和Radare解决CMU的二进制炸弹

本文介绍如何使用angr和Radare2分析CMU的二进制炸弹问题中的phase2部分,主要目标是找出正确的6位数字组合以避免触发炸弹。文章详细解释了使用Radare2进行二进制分析的方法,并展示了如何借助angr的符号执行功能找到解决方案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

前言

最近在学习angr的使用,主要是如何利用angr来进行符号执行分析。发现了国外一篇比较实用的文章介绍如何使用angr和Radare(二进制分析框架)来分析CMU的二进制炸弹问题。故在此翻译一下这篇文章的工作。

angr

angr是一个使用python语言编写的二进制分析框架,它主要是进行静态和动态的符号分析,现已成为CTF比赛的一大利器。angr最主要的一个工具就是符号执行,具体的符号执行可以参考MIT的一个课程(需要梯子才可以观看)。

Radare2

radare2是从零开始重写radare,以便提供一组库和工具来处理二进制文件。

在这篇文章里是先用的Radare2对二进制炸弹进行分析,弄清二进制文件的逻辑关系,然后再用angr的符号执行工具解出答案。关于radare2工具的介绍可以参考Radare2 Book

所面临的问题

要用angr和radare2所解决的问题是CMU的二进制炸弹,我们在此只分析phase2部分,如果对其他部分有兴趣的话可以参考我的另一篇博客对二进制炸弹做了全面的分析。phase2主要是要求输入6个正确的数字。

Crack

Radare2分析

  1. 使用Radare2加载程序,并输入aaa开始分析二进制程序

  2. 首先利用Radare2中的工具afl来查找符合条件的函数。使用afl并且grep(使用符号~来代表)筛选关键字, 可以看到筛选结果中有phase2。

  3. 使用seek工具来定位到我们感兴趣的函数处,此处为sym.phase_2函数。并用pdf([p]rint [d]issembly of [f]unction)命令来展示该函数的内容。

  4. 如何要展示函数中的控制流程图可以在Radare2中使用VV(两个大写的V)指令。

  5. 为了进行符号执行,我们必须弄清楚程序的输入是什么,通过radare工具反汇编出来的代码可以看出,函数read_six_numbers很有可能就是处理输入的函数。

  6. 在radare2中使用ga指令进入read_six_numbers函数, 具体的函数代码如下所示:

可以看出该函数中以六个数字作为scanf函数的输入,所以我们就将此作为输入。

  1. 接下来我们需要分析符号执行所需要开始的代码处,符号执行不能走的路径以及要到达的目标代码处。

    从上图可以看出0x400f10和0x400f20处的代码都调用explode_bomb函数。


具体的explode_bomb函数如上图所示,我们可以看出该函数会调用exit函数,所以我们要避免走到explode_bomb函数中去。即避免走到0x400f10和0x400f20。
要到达的目标函数我们可以设置到从phase2函数中返回。我们将调用完read_six_numbers函数后一条指令即0x400f0a作为程序分析的开始处。

angr分析

具体的angr分析代码如下所示:

## Binary found here: http://csapp.cs.cmu.edu/3e/bomb.tar

import angr, logging
from subprocess import Popen, PIPE
from itertools import product
import struct

def main():
    proj = angr.Project('bomb', load_options={'auto_load_libs':False})

    logging.basicConfig()
    logging.getLogger('angr.surveyors.explorer').setLevel(logging.DEBUG)

    def nop(state):
        return

    bomb_explode = 0x40143a

    # Start analysis at the phase_2 function after the sscanf
    state = proj.factory.blank_state(addr=0x400f0a)

    # Sscanf is looking for '%d %d %d %d %d %d' which ends up dropping 6 ints onto the stack
    # We will create 6 symbolic values onto the stack to mimic this
    for i in xrange(6):
        state.stack_push(state.se.BVS('int{}'.format(i), 4*8))

    # Attempt to find a path to the end of the phase_2 function while avoiding the bomb_explode
    path = proj.factory.path(state=state)
    ex = proj.surveyors.Explorer(start=path, find=(0x400f3c,),
                                 avoid=(bomb_explode, 0x400f10, 0x400f20,),
                                 enable_veritesting=True)
    ex.run()
    if ex.found:
        found = ex.found[0].state

        answer = []

        for x in xrange(3):
            curr_int = found.se.any_int(found.stack_pop())

            # We are popping off 8 bytes at a time
            # 0x0000000200000001

            # This is just one way to extract the individual numbers from this popped value
            answer.append(str(curr_int & 0xffffffff))
            answer.append(str(curr_int>>32 & 0xffffffff))

        return ' '.join(answer)

def test():
    assert main() == '1 2 4 8 16 32'

if __name__ == '__main__':
    print(main())
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值