unicorn
相关链接
unicorn官网
官方教程
Programming with C & Python languages
api文档
使用方法
在python下的基本使用方法如下(以arm为例)
from unicorn import *
from unicorn.arm_const import *
code =b'\x01\x10\xa0\xe3\x02 \xa0\xe3\x010B\xe0'
# mov r1, #1
# mov r2, #2
# sub r3, r2, r1
UC = Uc(UC_ARCH_ARM, UC_MODE_LITTLE_ENDIAN)
ADDRESS = 0x1000000
UC.mem_map(ADDRESS, 2 * 1024 * 1024)
UC.mem_write(ADDRESS, code)
UC.emu_start(ADDRESS, ADDRESS + len(code))
r1 = UC.reg_read(UC_ARM_REG_R1)
r2 = UC.reg_read(UC_ARM_REG_R2)
r3 = UC.reg_read(UC_ARM_REG_R3)
print(r1,r2,r3)
# 执行输出为
# 1 2 1
由于该脚本中使用了一些寄存器常量,所以除了导入unicorn,该脚本还导入了unicorn.arm_const
UC = Uc(UC_ARCH_ARM, UC_MODE_LITTLE_ENDIAN) 作用为初始化一个Unicorn类,其参数为硬件架构和模式
UC.mem_map(ADDRESS, 2 * 1024 * 1024) 意为在给定地址处开辟了一块2Mb(210241024 b)大小的内存
UC.mem_write(ADDRESS, code) 的作用是在给定的地址处将机器码写入,方便用于模拟执行。可以使用keystone用汇编指令生成机器码或使用capstone解析机器码
UC.emu_start(ADDRESS, ADDRESS + len(code)) 的作用是执行从ADDRESS 到ADDRESS + len(code) 范围内的指令。该函数原型为emu_start(begin, until, timeout=0, count=0) ,其参数含义分别如下
begin:模拟执行开始的地址
until:模拟执行结束的地址
timeout:模拟执行的时间,如果为0则不限制时间
count:模拟执行的命令数,如果为0则不限制命令
r1 = UC.reg_read(UC_ARM_REG_R1) 的含义为读取了r1寄存器的值,并将其存储,其参数为寄存器常量,位于unicorn.arm_const,每一个寄存器都拥有一个寄存器常量,用于方便索引相应的寄存器
除此之外,还可以使用hook_add函数给执行的代码添加一定的hook事件
该函数原型为hook_add(htype, callback, user_data=None, begin=1, end=0, arg1=0 )
htype:hook类型,所有类型见下文
callback:回调函数,hook到后执行的函数
user_data:用户数据,hook到时可以将此数据传递给回调函数
begin:回调生效区域的起始地址(包括)
end :回调生效区域的结束地址(包括),若begin>end,则会hook所有内容
arg1:参数,取决于htype
其回调函数模板为
def hook_block(uc, address, size, user_data):
# unicorn类
# 当前hook地址
# 当前hook大小
# hook_add中给定的user_data
pass
调用示例如下
from capstone import *
from unicorn import *
from unicorn.arm_const import *
# callback for tracing basic blocks
def hook_block(uc, address, size, user_data):
print(>>> Tracing basic block at 0x%x, block size = 0x%x %(address, size))
# callback for tracing instructions
def hook_code(uc, address, size, user_data):
print(>>> Tracing instruction at 0x%x, instruction size = 0x%x %(address, size))
code =b'\x01\x10\xa0\xe3\x02 \xa0\xe3\x010B\xe0'
CS = Cs(CS_ARCH_ARM, CS_MODE_LITTLE_ENDIAN)
UC = Uc(UC_ARCH_ARM, UC_MODE_LITTLE_ENDIAN)
ADDRESS = 0x1000000
a=CS.disasm_lite(code,0x400000)
# for (address, size, mnemonic, op_str) in Cs.disasm_lite(CS,code,0):
for (address, size, mnemonic, op_str) in a:
print(hex(address), mnemonic, op_str)
UC.mem_map(ADDRESS, 2 * 1024 * 1024)
UC.mem_write(ADDRESS, code)
# tracing all basic blocks with customized callback
UC.hook_add(UC_HOOK_BLOCK, hook_block)
# tracing one instruction at ADDRESS with customized callback
UC.hook_add(UC_HOOK_CODE, hook_code, begin=ADDRESS, end=ADDRESS)
UC.emu_start(ADDRESS, ADDRESS + len(code))
r1 = UC.reg_read(UC_ARM_REG_R1)
r2 = UC.reg_read(UC_ARM_REG_R2)
r3 = UC.reg_read(UC_ARM_REG_R3)
print(r1,r2,r3)
# 执行输出为
# 0x400000 mov r1, #1
# 0x400004 mov r2, #2
# 0x400008 sub r3, r2, r1
# >>> Tracing basic block at 0x1000000, block size = 0xc
# >>> Tracing instruction at 0x1000000, instruction size = 0x4
# 1 2 1
相关数据结构
- 支持的所有架构
typedef enum uc_arch {
UC_ARCH_ARM = 1, // ARM 架构 (包括 Thumb, Thumb-2)
UC_ARCH_ARM64, // ARM-64, 也称 AArch64
UC_ARCH_MIPS, // Mips 架构
UC_ARCH_X86, // X86 架构 (包括 x86 & x86-64)
UC_ARCH_PPC, // PowerPC 架构 (暂不支持)
UC_ARCH_SPARC, // Sparc 架构
UC_ARCH_M68K, // M68K 架构
UC_ARCH_MAX,
} uc_arch;
- 支持的所有模式
typedef enum uc_mode {
UC_MODE_LITTLE_ENDIAN = 0, // 小端序模式 (默认)
UC_MODE_BIG_ENDIAN = 1 << 30, // 大端序模式
// arm / arm64
UC_MODE_ARM = 0, // ARM 模式
UC_MODE_THUMB = 1 << 4, // THUMB 模式 (包括 Thumb-2)
UC_MODE_MCLASS = 1 << 5, // ARM's Cortex-M 系列 (暂不支持)
UC_MODE_V8 = 1 << 6, // ARMv8 A32 encodings for ARM (暂不支持)
// arm (32bit) cpu 类型
UC_MODE_ARM926 = 1 << 7, // ARM926 CPU 类型
UC_MODE_ARM946 = 1 << 8, // ARM946 CPU 类型
UC_MODE_ARM1176 = 1 << 9, // ARM1176 CPU 类型
// mips
UC_MODE_MICRO = 1 << 4, // MicroMips 模式 (暂不支持)
UC_MODE_MIPS3 = 1 << 5, // Mips III ISA (暂不支持)
UC_MODE_MIPS32R6 = 1 << 6, // Mips32r6 ISA (暂不支持)
UC_MODE_MIPS32 = 1 << 2, // Mips32 ISA
UC_MODE_MIPS64 = 1 << 3, // Mips64 ISA
// x86 / x64
UC_MODE_16 = 1 << 1, // 16-bit 模式
UC_MODE_32 = 1 << 2, // 32-bit 模式
UC_MODE_64 = 1 << 3, // 64-bit 模式
// ppc
UC_MODE_PPC32 = 1 << 2, // 32-bit 模式 (暂不支持)
UC_MODE_PPC64 = 1 << 3, // 64-bit 模式 (暂不支持)
UC_MODE_QPX = 1 << 4, // Quad Processing eXtensions 模式 (暂不支持)
// sparc
UC_MODE_SPARC32 = 1 << 2, // 32-bit 模式
UC_MODE_SPARC64 = 1 << 3, // 64-bit 模式
UC_MODE_V9 = 1 << 4, // SparcV9 模式 (暂不支持)
// m68k
} uc_mode;
- 所有内存访问类型
typedef enum uc_mem_type {
UC_MEM_READ = 16, // 内存从..读取
UC_MEM_WRITE, // 内存写入到..
UC_MEM_FETCH, // 内存被获取
UC_MEM_READ_UNMAPPED, // 未映射内存从..读取
UC_MEM_WRITE_UNMAPPED, // 未映射内存写入到..
UC_MEM_FETCH_UNMAPPED, // 未映射内存被获取
UC_MEM_WRITE_PROT, // 内存写保护,但是已映射
UC_MEM_READ_PROT, // 内存读保护,但是已映射
UC_MEM_FETCH_PROT, // 内存不可执行,但是已映射
UC_MEM_READ_AFTER, // 内存从 (成功访问的地址) 读入
} uc_mem_type;
- 所有的错误类型
typedef enum uc_err {
UC_ERR_OK = 0, // 无错误
UC_ERR_NOMEM, // 内存不足: uc_open(), uc_emulate()
UC_ERR_ARCH, // 不支持的架构: uc_open()
UC_ERR_HANDLE, // 不可用句柄
UC_ERR_MODE, // 不可用/不支持架构: uc_open()
UC_ERR_VERSION, // 不支持版本 (中间件)
UC_ERR_READ_UNMAPPED, // 由于在未映射的内存上读取而退出模拟: uc_emu_start()
UC_ERR_WRITE_UNMAPPED, // 由于在未映射的内存上写入而退出模拟: uc_emu_start()
UC_ERR_FETCH_UNMAPPED, // 由于在未映射的内存中获取数据而退出模拟: uc_emu_start()
UC_ERR_HOOK, // 无效的hook类型: uc_hook_add()
UC_ERR_INSN_INVALID, // 由于指令无效而退出模拟: uc_emu_start()
UC_ERR_MAP, // 无效的内存映射: uc_mem_map()
UC_ERR_WRITE_PROT, // 由于UC_MEM_WRITE_PROT冲突而停止模拟: uc_emu_start()
UC_ERR_READ_PROT, // 由于UC_MEM_READ_PROT冲突而停止模拟: uc_emu_start()
UC_ERR_FETCH_PROT, // 由于UC_MEM_FETCH_PROT冲突而停止模拟: uc_emu_start()
UC_ERR_ARG, // 提供给uc_xxx函数的无效参数
UC_ERR_READ_UNALIGNED, // 未对齐读取
UC_ERR_WRITE_UNALIGNED, // 未对齐写入
UC_ERR_FETCH_UNALIGNED, // 未对齐的提取
UC_ERR_HOOK_EXIST, // 此事件的钩子已经存在
UC_ERR_RESOURCE, // 资源不足: uc_emu_start()
UC_ERR_EXCEPTION, // 未处理的CPU异常
UC_ERR_TIMEOUT // 模拟超时
} uc_err;
- 所有的hook类型
typedef enum uc_hook_type {
// Hook 所有中断/syscall 事件
UC_HOOK_INTR = 1 << 0,
// Hook 一条特定的指令 - 只支持非常小的指令子集
UC_HOOK_INSN = 1 << 1,
// Hook 一段代码
UC_HOOK_CODE = 1 << 2,
// Hook 基本块
UC_HOOK_BLOCK = 1 << 3,
// 用于在未映射的内存上读取内存的Hook
UC_HOOK_MEM_READ_UNMAPPED = 1 << 4,
// Hook 无效的内存写事件
UC_HOOK_MEM_WRITE_UNMAPPED = 1 << 5,
// Hook 执行事件的无效内存
UC_HOOK_MEM_FETCH_UNMAPPED = 1 << 6,
// Hook 读保护的内存
UC_HOOK_MEM_READ_PROT = 1 << 7,
// Hook 写保护的内存
UC_HOOK_MEM_WRITE_PROT = 1 << 8,
// Hook 不可执行内存上的内存
UC_HOOK_MEM_FETCH_PROT = 1 << 9,
// Hook 内存读取事件
UC_HOOK_MEM_READ = 1 << 10,
// Hook 内存写入事件
UC_HOOK_MEM_WRITE = 1 << 11,
// Hook 内存获取执行事件
UC_HOOK_MEM_FETCH = 1 << 12,
// Hook 内存读取事件,只允许能成功访问的地址
// 成功读取后将触发回调
UC_HOOK_MEM_READ_AFTER = 1 << 13,
// Hook 无效指令异常
UC_HOOK_INSN_INVALID = 1 << 14,
} uc_hook_type;
- 宏定义Hook类型(由基本hook类型组成)
// Hook 所有未映射内存访问的事件
#define UC_HOOK_MEM_UNMAPPED (UC_HOOK_MEM_READ_UNMAPPED + UC_HOOK_MEM_WRITE_UNMAPPED + UC_HOOK_MEM_FETCH_UNMAPPED)
// Hook 所有对受保护内存的非法访问事件
#define UC_HOOK_MEM_PROT (UC_HOOK_MEM_READ_PROT + UC_HOOK_MEM_WRITE_PROT + UC_HOOK_MEM_FETCH_PROT)
// Hook 所有非法读取存储器的事件
#define UC_HOOK_MEM_READ_INVALID (UC_HOOK_MEM_READ_PROT + UC_HOOK_MEM_READ_UNMAPPED)
// Hook 所有非法写入存储器的事件
#define UC_HOOK_MEM_WRITE_INVALID (UC_HOOK_MEM_WRITE_PROT + UC_HOOK_MEM_WRITE_UNMAPPED)
// Hook 所有非法获取内存的事件
#define UC_HOOK_MEM_FETCH_INVALID (UC_HOOK_MEM_FETCH_PROT + UC_HOOK_MEM_FETCH_UNMAPPED)
// Hook 所有非法的内存访问事件
#define UC_HOOK_MEM_INVALID (UC_HOOK_MEM_UNMAPPED + UC_HOOK_MEM_PROT)
// Hook 所有有效内存访问的事件
// 注意: UC_HOOK_MEM_READ 在 UC_HOOK_MEM_READ_PROT 和 UC_HOOK_MEM_READ_UNMAPPED 之前触发 ,
// 因此这个Hook可能会触发一些无效的读取。
#define UC_HOOK_MEM_VALID (UC_HOOK_MEM_READ + UC_HOOK_MEM_WRITE + UC_HOOK_MEM_FETCH)
- 映射区域的权限
typedef enum uc_prot {
UC_PROT_NONE = 0, //无
UC_PROT_READ = 1, //读取
UC_PROT_WRITE = 2, //写入
UC_PROT_EXEC = 4, //可执行
UC_PROT_ALL = 7, //所有权限
} uc_prot;




