使用 unicorn 和 capstone 库来模拟 ARM Thumb 指令的执行,并实现多个钩子(hook)来监控代码执行、系统调用和内存读写操作(二)

cpp 复制代码
import unicorn
import capstone
import binascii

def printArm32Regs(mu):
    for i in range(66,78):
        print("R%d,value:%x"%(i-66,mu.reg_read(i)))

#typedef void (*uc_cb_hookcode_t)(uc_engine *uc, uint64_t address, uint32_t size, void *user_data);
def hook_code(mu,address,size,user_data):
    code=mu.mem_read(address,size)
    CP=capstone.Cs(capstone.CS_ARCH_ARM,capstone.CS_MODE_THUMB)
    for i in CP.disasm(code,0,len(code)):
        print("[addr:%x]:%s %s\n"%(address,i.mnemonic,i.op_str))
    print("-----------------------------")
    printArm32Regs(mu)
    print("-----------------------------")
    return

#typedef void (*uc_cb_hookintr_t)(uc_engine *uc, uint32_t intno, void *user_data);
def hook_syscall(mu,intno,user_data):
    print("syscall num:0x%d is called!!"%intno)
    if intno==2:
        print("exit syscall is called!!")
    print("-----------------------------")
    printArm32Regs(mu)
    print("-----------------------------")
    return

#void (*uc_cb_hookmem_t)(uc_engine *uc, uc_mem_type type,uint64_t address, int size, int64_t value, void *user_data);
def hook_mem_write_unmapped(mu,type,address,size,value,user_data):
    if type==unicorn.UC_MEM_WRITE_UNMAPPED:
       print("UC_HOOK_MEM_WRITE_UNMAPPED addr:0x%x,size:%d,value:0x%x"%(address,size,value))
       mu.mem_map(0x0,0x1000)
    print("hook_mem type:%d addr:0x%x,size:%d,value:0x%x" % (type, address, size, value))
    return True


def hook_mem(mu,type,address,size,value,user_data):
    if type==unicorn.UC_MEM_WRITE:
       print("write addr:0x%x,size:%d,value:0x%x"%(address,size,value))
    if type==unicorn.UC_MEM_READ:
       print("read addr:0x%x,size:%d,value:0x%x"%(address,size,value))
    print("hook_mem type:%d addr:0x%x,size:%d,value:0x%x"%(type,address,size,value))
    return


def testthumb():
#  text:00008ACA 0A 46                       MOV             R2, R1  ; Rd = Op2
# .text:00008ACC 03 46                       MOV             R3, R0  ; Rd = Op2
#.text:00008B04 04 92                        STR             R2, [SP,#0x40+var_30] ; Store to Memory
    CODE=b'\x0a\x46\x03\x46\x04\x92\x4F\xF0\x0B\x07\x00\xdf'
    CP=capstone.Cs(capstone.CS_ARCH_ARM,capstone.CS_MODE_THUMB)
    for i in CP.disasm(CODE,0,len(CODE)):
        print("[addr:%x]:%s %s\n"%(i.address,i.mnemonic,i.op_str))
    mu=unicorn.Uc(unicorn.UC_ARCH_ARM,unicorn.UC_MODE_THUMB)
    ADDRESS=0x1000
    SIZE=1024
    mu.mem_map(ADDRESS,SIZE)
    mu.mem_write(ADDRESS,CODE)
    bytes=mu.mem_read(ADDRESS,10)
    print("ADDRESS:%x,content:%s"%(ADDRESS,binascii.b2a_hex(bytes)))
    mu.reg_write(unicorn.arm_const.UC_ARM_REG_R0,0x100)
    mu.reg_write(unicorn.arm_const.UC_ARM_REG_R1,0x200)
    mu.reg_write(unicorn.arm_const.UC_ARM_REG_R2,0x300)
    mu.reg_write(unicorn.arm_const.UC_ARM_REG_R3,0x400)
    hook_code1=mu.hook_add(unicorn.UC_HOOK_CODE, hook_code)
    #mu.hook_del(hook_code1)
    '''/*
  Callback function for hooking memory (READ, WRITE & FETCH)

  @type: this memory is being READ, or WRITE
  @address: address where the code is being executed
  @size: size of data being read or written
  @value: value of data being written to memory, or irrelevant if type = READ.
  @user_data: user data passed to tracing APIs
*/
typedef void (*uc_cb_hookmem_t)(uc_engine *uc, uc_mem_type type,
        uint64_t address, int size, int64_t value, void *user_data);'''
    #mu.hook_add(unicorn.UC_HOOK_MEM_WRITE,hook_mem)
    mu.hook_add(unicorn.UC_HOOK_MEM_WRITE,hook_mem)
    mu.hook_add(unicorn.UC_HOOK_INTR,hook_syscall)
    mu.hook_add(unicorn.UC_HOOK_MEM_WRITE_UNMAPPED,hook_mem_write_unmapped)
    try:
        mu.emu_start(ADDRESS+1,ADDRESS+len(CODE))
        print("emulat over")
        printArm32Regs(mu)
        bytes=mu.mem_read(0x10,4)
        print("mem:0x%x,value:%s"%(0x10,binascii.b2a_hex(bytes)))
    except unicorn.UcError as e:
        print(e)
    #def hook_add(self, htype, callback, user_data=None, begin=1, end=0, arg1=0):






    return
if __name__ == '__main__':
    testthumb()

运行结果图:



一:代码概述

使用 unicorncapstone 库来模拟 ARM Thumb 指令的执行,并实现了多个钩子(hook)来监控代码执行、系统调用和内存读写操作。主要功能是加载一段机器码,执行这些指令,并在执行过程中打印出相关信息。

1.1代码结构

1. 导入库

python 复制代码
import unicorn
import capstone
import binascii
  • unicorn: 用于 CPU 模拟的库。
  • capstone: 用于反汇编机器码的库。
  • binascii: 用于处理二进制和 ASCII 之间的转换。

2. 打印寄存器值的函数

python 复制代码
def printArm32Regs(mu):
    for i in range(66, 78):
        print("R%d,value:%x" % (i - 66, mu.reg_read(i)))
  • 该函数接受一个 unicorn 模拟器实例 mu 作为参数。
  • 它循环读取 R0 到 R12(在 ARM 中,寄存器编号从 0 开始,R0 对应 66,R1 对应 67,以此类推),并打印出每个寄存器的值。

3. 钩子函数

  • 代码钩子

    python 复制代码
    def hook_code(mu, address, size, user_data):
        code = mu.mem_read(address, size)
        CP = capstone.Cs(capstone.CS_ARCH_ARM, capstone.CS_MODE_THUMB)
        for i in CP.disasm(code, 0, len(code)):
            print("[addr:%x]:%s %s\n" % (address, i.mnemonic, i.op_str))
        print("-----------------------------")
        printArm32Regs(mu)
        print("-----------------------------")
        return
    • 该函数在每次执行指令时被调用,读取当前执行的指令并反汇编,打印出指令的地址、助记符和操作数,以及当前寄存器的值。
  • 系统调用钩子

    python 复制代码
    def hook_syscall(mu, intno, user_data):
        print("syscall num:0x%d is called!!" % intno)
        if intno == 2:
            print("exit syscall is called!!")
        print("-----------------------------")
        printArm32Regs(mu)
        print("-----------------------------")
        return
    • 该函数在系统调用发生时被调用,打印出系统调用的编号,并在特定的系统调用(如 exit)时提供额外信息。
  • 未映射内存写入钩子

    python 复制代码
    def hook_mem_write_unmapped(mu, type, address, size, value, user_data):
        if type == unicorn.UC_MEM_WRITE_UNMAPPED:
            print("UC_HOOK_MEM_WRITE_UNMAPPED addr:0x%x,size:%d,value:0x%x" % (address, size, value))
            mu.mem_map(0x0, 0x1000)  # 映射未映射的内存
        print("hook_mem type:%d addr:0x%x,size:%d,value:0x%x" % (type, address, size, value))
        return True
    • 该函数在尝试写入未映射内存时被调用,打印出相关信息并映射一段内存。
  • 内存读写钩子

    python 复制代码
    def hook_mem(mu, type, address, size, value, user_data):
        if type == unicorn.UC_MEM_WRITE:
            print("write addr:0x%x,size:%d,value:0x%x" % (address, size, value))
        if type == unicorn.UC_MEM_READ:
            print("read addr:0x%x,size:%d,value:0x%x" % (address, size, value))
        print("hook_mem type:%d addr:0x%x,size:%d,value:0x%x" % (type, address, size, value))
        return
    • 该函数在内存读写操作时被调用,打印出读写的地址、大小和数值。

4. 主测试函数

python 复制代码
def testthumb():
    CODE = b'\x0a\x46\x03\x46\x04\x92\x4F\xF0\x0B\x07\x00\xdf'
    CP = capstone.Cs(capstone.CS_ARCH_ARM, capstone.CS_MODE_THUMB)
    for i in CP.disasm(CODE, 0, len(CODE)):
        print("[addr:%x]:%s %s\n" % (i.address, i.mnemonic, i.op_str))
    mu = unicorn.Uc(unicorn.UC_ARCH_ARM, unicorn.UC_MODE_THUMB)
    ADDRESS = 0x1000
    SIZE = 1024
    mu.mem_map(ADDRESS, SIZE)
    mu.mem_write(ADDRESS, CODE)
    bytes = mu.mem_read(ADDRESS, 10)
    print("ADDRESS:%x,content:%s" % (ADDRESS, binascii.b2a_hex(bytes)))
    mu.reg_write(unicorn.arm_const.UC_ARM_REG_R0, 0x100)
    mu.reg_write(unicorn.arm_const.UC_ARM_REG_R1, 0x200)
    mu.reg_write(unicorn.arm_const.UC_ARM_REG_R2, 0x300)
    mu.reg_write(unicorn.arm_const.UC_ARM_REG_R3, 0x400)
  • 该函数定义了要执行的机器码 CODE,并使用 capstone 反汇编它。
  • 创建一个 Unicorn 模拟器实例,映射内存并写入机器码。
  • 初始化寄存器 R0 到 R3 的值。

5. 添加钩子

python 复制代码
hook_code1 = mu.hook_add(unicorn.UC_HOOK_CODE, hook_code)
mu.hook_add(unicorn.UC_HOOK_MEM_WRITE, hook_mem)
mu.hook_add(unicorn.UC_HOOK_INTR, hook_syscall)
mu.hook_add(unicorn.UC_HOOK_MEM_WRITE_UNMAPPED, hook_mem_write_unmapped)
  • 添加多个钩子,以便在执行代码、内存读写和系统调用时调用相应的钩子函数。

6. 执行指令

python 复制代码
try:
    mu.emu_start(ADDRESS + 1, ADDRESS + len(CODE))
    print("emulat over")
    printArm32Regs(mu)
    bytes = mu.mem_read(0x10, 4)
    print("mem:0x%x,value:%s" % (0x10, binascii.b2a_hex(bytes)))
except unicorn.UcError as e:
    print(e)
  • 启动模拟器,从 ADDRESS + 1 开始执行,直到 ADDRESS + len(CODE)
  • 执行完成后,打印寄存器的值和内存地址 0x10 的内容。

1.2总括

代码实现了一个简单的 ARM Thumb 指令模拟器,能够反汇编和执行指令,并通过钩子监控执行过程中的各种事件。展示了如何使用 unicorncapstone 库进行低级别的系统模拟和调试。大家阔以学习借鉴一下。

二:钩子详解

下面是对你代码中添加的钩子的详细解释,包括每个钩子的功能、触发条件和使用场景。

1. 代码钩子 (hook_code)

python 复制代码
def hook_code(mu, address, size, user_data):
    code = mu.mem_read(address, size)
    CP = capstone.Cs(capstone.CS_ARCH_ARM, capstone.CS_MODE_THUMB)
    for i in CP.disasm(code, 0, len(code)):
        print("[addr:%x]:%s %s\n" % (address, i.mnemonic, i.op_str))
    print("-----------------------------")
    printArm32Regs(mu)
    print("-----------------------------")
    return
功能
  • 目的: 在每次执行指令时被调用,打印当前执行的指令及其相关信息。
  • 操作 :
    • 从模拟器的内存中读取当前执行的指令。
    • 使用 capstone 反汇编这些指令,并打印出指令的地址、助记符和操作数。
    • 打印当前寄存器的值,以便观察指令执行前后的状态。
触发条件
  • 每当模拟器执行一条指令时,都会触发这个钩子。
使用场景
  • 适用于调试和分析代码执行过程,帮助开发者理解指令的执行顺序和寄存器状态变化。

2. 系统调用钩子 (hook_syscall)

python 复制代码
def hook_syscall(mu, intno, user_data):
    print("syscall num:0x%d is called!!" % intno)
    if intno == 2:
        print("exit syscall is called!!")
    print("-----------------------------")
    printArm32Regs(mu)
    print("-----------------------------")
    return
功能
  • 目的: 在系统调用发生时被调用,打印系统调用的编号和相关信息。
  • 操作 :
    • 打印被调用的系统调用编号。
    • 如果系统调用编号为 2(通常表示 exit),则打印特定信息。
    • 打印当前寄存器的值。
触发条件
  • 当模拟器执行系统调用指令时触发。
使用场景
  • 适用于监控和调试系统调用的执行,帮助开发者理解程序与操作系统之间的交互。

3. 未映射内存写入钩子 (hook_mem_write_unmapped)

python 复制代码
def hook_mem_write_unmapped(mu, type, address, size, value, user_data):
    if type == unicorn.UC_MEM_WRITE_UNMAPPED:
        print("UC_HOOK_MEM_WRITE_UNMAPPED addr:0x%x,size:%d,value:0x%x" % (address, size, value))
        mu.mem_map(0x0, 0x1000)  # 映射未映射的内存
    print("hook_mem type:%d addr:0x%x,size:%d,value:0x%x" % (type, address, size, value))
    return True
功能
  • 目的: 处理对未映射内存的写入操作,打印相关信息并映射内存。
  • 操作 :
    • 检查写入操作是否为未映射内存。
    • 如果是,打印地址、大小和写入的值,并映射一段内存(例如,0x0 地址的 0x1000 字节)。
    • 打印所有内存操作的类型、地址、大小和数值。
触发条件
  • 当模拟器尝试写入未映射的内存地址时触发。
使用场景
  • 适用于处理和调试内存访问错误,确保程序在访问内存时不会崩溃。

4. 内存读写钩子 (hook_mem)

python 复制代码
def hook_mem(mu, type, address, size, value, user_data):
    if type == unicorn.UC_MEM_WRITE:
        print("write addr:0x%x,size:%d,value:0x%x" % (address, size, value))
    if type == unicorn.UC_MEM_READ:
        print("read addr:0x%x,size:%d,value:0x%x" % (address, size, value))
    print("hook_mem type:%d addr:0x%x,size:%d,value:0x%x" % (type, address, size, value))
    return
功能
  • 目的: 监控内存的读写操作,打印相关信息。
  • 操作 :
    • 根据操作类型(读或写)打印相应的信息,包括地址、大小和数值。
    • 打印所有内存操作的类型、地址、大小和数值。
触发条件
  • 当模拟器执行内存读或写操作时触发。
使用场景
  • 适用于调试内存访问,帮助开发者理解程序如何与内存交互。

5.总结

这些钩子提供了对模拟器执行过程的深入监控,允许开发者在指令执行、系统调用和内存操作时获取详细信息。这对于调试、分析和理解程序的行为非常有帮助。通过这些钩子,开发者可以实时观察寄存器和内存的状态变化,从而更好地理解程序的执行流程。

相关推荐
别让别人觉得你做不到1 小时前
Python(1) 做一个随机数的游戏
python
小彭律师2 小时前
人脸识别门禁系统技术文档
python
熊大如如2 小时前
Java 反射
java·开发语言
猿来入此小猿2 小时前
基于SSM实现的健身房系统功能实现十六
java·毕业设计·ssm·毕业源码·免费学习·猿来入此·健身平台
goTsHgo3 小时前
Spring Boot 自动装配原理详解
java·spring boot
卑微的Coder3 小时前
JMeter同步定时器 模拟多用户并发访问场景
java·jmeter·压力测试
pjx9873 小时前
微服务的“导航系统”:使用Spring Cloud Eureka实现服务注册与发现
java·spring cloud·微服务·eureka
张小九994 小时前
PyTorch的dataloader制作自定义数据集
人工智能·pytorch·python
zstar-_4 小时前
FreeTex v0.2.0:功能升级/支持Mac
人工智能·python·macos·llm
苏生要努力4 小时前
第九届御网杯网络安全大赛初赛WP
linux·python·网络安全