欢迎访问宙启技术站
智能推送

angr中SIM_PROCEDURES的高级用法介绍

发布时间:2024-01-12 22:48:36

在angr中,SIM_PROCEDURES是一种特殊的插件,用于处理和执行函数调用。它提供了一个强大的接口,可以用于模拟执行程序中的函数调用,并为我们提供了更多控制程序行为的能力。下面将详细介绍SIM_PROCEDURES的一些高级用法,并提供使用示例。

一、SIM_PROCEDURES的基本用法

在介绍SIM_PROCEDURES的高级用法之前,先来了解一下它的基本用法。

SIM_PROCEDURES允许我们指定一个函数的模拟执行过程,包括参数的传递、函数的执行和返回值的处理等。使用SIM_PROCEDURES时,我们需要定义一个继承自angr类procedure.Procedure的子类,并重写其中的run方法。run方法会在执行函数调用时被调用,并接收一个angr中的SimState对象作为参数。

下面是一个简单的示例,演示了如何使用SIM_PROCEDURES来模拟一个简单的函数调用过程。

import angr
from angr.procedures import SIM_PROCEDURES

class CustomProcedure(angr.procedures.procedure.Procedure):

    def run(self, state):
        # 获取参数
        arg1 = state.solver.eval(state.regs.rdi)
        arg2 = state.solver.eval(state.regs.rsi)
        
        # 执行函数操作
        result = arg1 + arg2
        
        # 将结果设置为返回值
        state.regs.rax = result

p = angr.Project('binary')
state = p.factory.blank_state()

# 使用SIM_PROCEDURES将我们的自定义过程添加到angr的SimProcedures中
p.hook_symbol('add', SIM_PROCEDURES['stubs']['ReturnUnconstrained']())
p.hook_symbol('sub', CustomProcedure())

# 运行程序
simulation = p.factory.simulation_manager(state)
simulation.explore(find=0xdeadbeef)
print(simulation.found[0].registers.rax)

在上面的例子中,我们定义了一个CustomProcedure类,继承自angr的procedure.Procedure类,并重写了其中的run方法。在run方法中,我们首先通过state.solver.eval函数获取了函数调用的参数arg1和arg2,然后执行了一个简单的加法操作,并将结果设置为返回值。

然后,我们使用SIM_PROCEDURES的stubs类型中的ReturnUnconstrained过程来模拟了函数add的执行过程。将add和sub函数的名称与我们定义的过程关联起来,可以通过hook_symbol函数将自定义过程添加到angr的SimProcedures中。

最后,我们创建了一个空的SimState对象,并使用factory模块的simulation_manager函数创建了一个SimulationManager对象。通过调用simulation_manager对象的explore方法,我们可以开始模拟程序的执行过程。在找到目标地址(0xdeadbeef)后,我们打印出了RAX寄存器的值。

这个例子只是一个简单的示例,演示了如何使用SIM_PROCEDURES来模拟函数调用过程。下面,我们将进一步介绍SIM_PROCEDURES的高级用法。

二、SIM_PROCEDURES的高级用法

1. 更多类型的SIM_PROCEDURES

除了上面例子中使用的stubs类型,SIM_PROCEDURES还提供了其他类型,例如Syscalls、Trampolines和SPLs等。这些类型提供了更多的灵活性,可以模拟更多类型的函数调用。我们可以根据需求选择合适的类型,并使用相应的过程来模拟函数调用。

2. 使用SIM_PROCEDURES处理调用表

在实际程序中,经常会使用调用表(即函数指针数组),根据输入的索引值选择对应的函数进行调用。这时,我们可以使用SIM_PROCEDURES来处理调用表的模拟执行过程。

例如,下面的示例展示了如何使用SIM_PROCEDURES处理调用表的情况:

import angr
from angr.procedures import SIM_PROCEDURES

# 定义调用表
call_table = [0xdeadbeef, 0xcafebabe, 0xfeedface]

class CustomProcedure(angr.procedures.procedure.Procedure):

    def run(self, state):
        # 获取参数
        index = state.solver.eval(state.regs.rdi)
        
        # 执行调用表中对应的函数
        func_address = call_table[index]
        func = angr.SIM_PROCEDURES['stubs']['ReturnUnconstrained']()
        state.ip = func_address
        state.ret_to = state.regs.rip
        state.callstate.set_pushed_return_address(state.history.jumpkind)

p = angr.Project('binary')
state = p.factory.blank_state()

# 使用SIM_PROCEDURES将我们的自定义过程添加到angr的SimProcedures中
p.hook_symbol('call', CustomProcedure())

# 运行程序
simulation = p.factory.simulation_manager(state)
simulation.explore(find=0xdeadbeef)
print(simulation.found[0].registers.rax)

在上面的示例中,我们首先定义了一个call_table列表,其中包含了三个函数的地址。然后,我们定义了一个CustomProcedure类,继承自angr的procedure.Procedure类,并重写了其中的run方法。在run方法中,我们首先通过state.solver.eval函数获取了函数调用的参数index,然后根据index选择相应的函数进行执行。在这里,我们使用了stubs类型中的ReturnUnconstrained过程来模拟函数的执行过程。最后,我们将函数的地址设置为SimState对象的ip寄存器,以实现函数的模拟调用。

使用SIM_PROCEDURES处理调用表时,我们需要通过修改SimState对象的相关属性来实现函数的调用,并将函数的返回地址设置为ret_to属性。这样,当函数执行完毕后,程序会返回到正确的地址。

3. 结合其他插件的使用

SIM_PROCEDURES可以与其他插件一起使用,并发挥更大的作用。例如,我们可以结合使用SimMemory和SimProcedure类来模拟有状态的函数调用过程。

下面的示例演示了如何使用SimProcedure和SimMemory模拟一个有状态的函数调用过程:

import angr
from angr import sim_options
from angr.storage.memory_mixins.paged_memory.pages.multi_memory import NoPageFaultException
from angr.procedures import SIM_PROCEDURES
from angr.storage.memory_mixins.paged_memory.pages.multi_memory import NoPageFaultException

class StatefulProcedure(angr.procedures.SimProcedure):
    def run(self, *args, **kwargs):
        # 获取参数
        arg1 = args[0]
        arg2 = args[1]
        
        # 从SimMemory中读取存储在全局变量state中的数据
        state = self.state.memory.load(self.state.regs.rbp - 0x8, 4)

        # 根据state的值执行不同的操作
        if state.concrete:
            if state.any() == 1:
                result = arg1 + arg2
            else:
                result = arg1 - arg2
        else:
            # 当state的值未知时,我们可以进行符号执行
            result = self.state.solver.If(state == 1, arg1 + arg2, arg1 - arg2)

        # 返回结果
        self.state.regs.rax = result
        
p = angr.Project('binary')

# 将SimProcedure和SIM_PROCEDURES结合使用
p.hook_symbol('add', SIM_PROCEDURES['stubs']['ReturnUnconstrained']())
p.hook_symbol('sub', StatefulProcedure())

state = p.factory.blank_state(add_options={sim_options.STRICT_PAGE_ACCESS})

# 将全局变量state写入SimMemory中
state.memory.store(state.regs.rbp - 0x8, state.solver.BVS('state', 4*8))

simulation = p.factory.simulation_manager(state)
simulation.explore(find=0xdeadbeef)
print(simulation.found[0].registers.rax)

在上面的示例中,我们定义了一个StatefulProcedure类,继承自angr的SimProcedure类,并重写了其中的run方法。在run方法中,