骑麦兜看落日

[Binary]Unicorn学习

字数统计: 2.1k阅读时长: 9 min
2019/10/30 Share

相关函数原型


这一部分注释写的很详细了,我就直接翻译好了

所有函数原型都在include/unicorn/unicorn.h

uc_open

1
2
UNICORN_EXPORT
uc_err uc_open(uc_arch arch, uc_mode mode, uc_engine **uc);

创建一个新的unicorn实例

@arch:架构类型 (UC_ARCH_*)
@mode:硬件模式.UC_MODE_*的组合
@uc:指向uc_engine的指针, 将在返回时更新

@return 成功时返回UC_ERR_OK,失败时为其他值(有关详细错误,请参考uc_err枚举).

uc_close

1
2
UNICORN_EXPORT
uc_err uc_close(uc_engine *uc);

关闭一个unicorn实例
注意:必须在不再使用@uc时才调用此函数.该API释放了@uc的某些缓存,因此在@uc关闭后将Unicorn API和@uc一起使用可能会使您的应用程序崩溃.此后,@uc无效,并且不再可用.

@uc:指向uc_open返回的句柄的指针

@return 成功时返回UC_ERR_OK,失败时为其他值(有关详细错误,请参考uc_err枚举).

uc_reg_write

1
2
UNICORN_EXPORT
uc_err uc_reg_write(uc_engine *uc, int regid, const void *value);

向寄存器写.

@uc: uc_open()返回的句柄
@regid: 要修改的寄存器ID.
@value: 指向将设置为寄存器@regid的值的指针

@return 成功时返回UC_ERR_OK,失败时为其他值(有关详细错误,请参考uc_err枚举).

uc_reg_read

1
2
UNICORN_EXPORT
uc_err uc_reg_read(uc_engine *uc, int regid, void *value);

从寄存器读.

@uc: uc_open()返回的句柄
@regid: 要获取的寄存器ID.
@value: 指向存储寄存器值的变量的指针.

@return 成功时返回UC_ERR_OK,失败时为其他值(有关详细错误,请参考uc_err枚举).

uc_mem_write

1
2
UNICORN_EXPORT
uc_err uc_mem_write(uc_engine *uc, uint64_t address, const void *bytes, size_t size);

向内存中写入一定的字节.

@uc: uc_open()返回的句柄
@address:要写入的内存起始地址.
@bytes:指向包含要写入内存的数据的指针.
@size:要写入的内存大小.

注意: @bytes必须足够大以容纳@size字节.

@return 成功时返回UC_ERR_OK,失败时为其他值(有关详细错误,请参考uc_err枚举).

uc_mem_read

1
2
UNICORN_EXPORT
uc_err uc_mem_read(uc_engine *uc, uint64_t address, void *bytes, size_t size);

从内存中读取一定的字节.

@uc: uc_open()返回的句柄
@address:要读取的内存起始地址.
@bytes:指向包含从内存复制的数据的指针.
@size:要读取的内存大小.

注意: @bytes必须足够大以容纳@size字节.

@return 成功时返回UC_ERR_OK,失败时为其他值(有关详细错误,请参考uc_err枚举).

uc_emu_start

1
2
UNICORN_EXPORT
uc_err uc_emu_start(uc_engine *uc, uint64_t begin, uint64_t until, uint64_t timeout, size_t count);

Emulate machine code in a specific duration of time.

@uc: uc_open()返回的句柄
@begin:模拟开始的地址
@until:模拟停止的地址(即当该地址被击中时)
@timeout:模拟代码的持续时间(以微秒为单位).当该值为0时,我们将无限长地模拟代码,直到代码结束.
@count:要模拟的指令数.当该值为0时,我们将模拟所有可用代码,直到代码结束.

@return 成功时返回UC_ERR_OK,失败时为其他值(有关详细错误,请参考uc_err枚举).

uc_emu_stop

1
2
UNICORN_EXPORT
uc_err uc_emu_stop(uc_engine *uc);

停止模拟(由uc_emu_start()API开始的).
通常从通过追踪API注册的回调函数中调用此方法.

@uc: uc_open()返回的句柄

@return 成功时返回UC_ERR_OK,失败时为其他值(有关详细错误,请参考uc_err枚举).

uc_hook_add

1
2
3
UNICORN_EXPORT
uc_err uc_hook_add(uc_engine *uc, uc_hook *hh, int type, void *callback,
void *user_data, uint64_t begin, uint64_t end, ...);

注册hook事件的回调.
当hook事件被击中时,回调将被执行.

@uc: uc_open()返回的句柄
@hh:注册返回的hook句柄.在uc_hook_del()API中使用
@type:hook类型
@callback:命中指令后运行的回调
@user_data:用户定义数据.这将作为最后一个参数@user_data传递给回调函数.
@begin:回调生效区域的起始地址(含)
@end:回调生效区域的结束地址(含)
注意 1: 仅当相关地址在[@begin,@end]范围内时,才调用回调
注意 2: 如果@begin>@end,则在此钩子类型被触发时调用回调@…:变量参数(取决于@type)
注意: 如果@type=UC_HOOK_INSN,则为指令ID(例如:UC_X86_INS_OUT)

@return 成功时返回UC_ERR_OK,失败时为其他值(有关详细错误,请参考uc_err枚举).

uc_hook_del

1
2
UNICORN_EXPORT
uc_err uc_hook_del(uc_engine *uc, uc_hook hh);

注销(删除)hook回调。
此API删除uc_hook_add()注册的hook回调.
注意: 仅当您不再要跟踪时,才应调用它.
此后,@hh无效,不再可用.

@uc: uc_open()返回的句柄
@hh:uc_hook_add()返回的句柄

@return 成功时返回UC_ERR_OK,失败时为其他值(有关详细错误,请参考uc_err枚举).

uc_mem_map

1
2
UNICORN_EXPORT
uc_err uc_mem_map(uc_engine *uc, uint64_t address, size_t size, uint32_t perms);

映射内存以进行模拟.

该API添加了可用于模拟的内存区域.

@uc: uc_open()返回的句柄
@address:要映射到的新内存区域的起始地址.此地址必须对齐4KB.否则它将返回UC_ERR_ARG错误.
@size:要映射的新内存区域的大小,该大小必须是4KB的倍数,否则将返回UC_ERR_ARG错误.
@perms:新映射区域的权限.这必须是UC_PROT_READ | UC_PROT_WRITE | UC_PROT_EXEC的某种组合,否则将返回UC_ERR_ARG错误.

@return 成功时返回UC_ERR_OK,失败时为其他值(有关详细错误,请参考uc_err枚举).

uc_mem_unmap

1
2
UNICORN_EXPORT
uc_err uc_mem_unmap(uc_engine *uc, uint64_t address, size_t size);

取消模拟内存的区域.
该API从模拟内存空间中删除内存映射.

@uc: uc_open()返回的句柄
@address: 要取消映射的内存区域的起始地址.此地址必须对齐4KB.否则它将返回UC_ERR_ARG错误.
@size: 要修改的内存区域的大小.此地址必须对齐4KB.否则它将返回UC_ERR_ARG错误.

@return 成功时返回UC_ERR_OK,失败时为其他值(有关详细错误,请参考uc_err枚举).

uc_mem_protect

1
2
UNICORN_EXPORT
uc_err uc_mem_protect(uc_engine *uc, uint64_t address, size_t size, uint32_t perms);

Set memory permissions for emulation memory.
This API changes permissions on an existing memory region.

@uc: uc_open()返回的句柄
@address:要修改的内存区域的其实地址.此地址必须对齐4KB.否则它将返回UC_ERR_ARG错误.
@size:要修改的内存区域的大小.此地址必须对齐4KB.否则它将返回UC_ERR_ARG错误.
@perms: 映射区域的新权限.这必须是UC_PROT_READ | UC_PROT_WRITE | UC_PROT_EXEC的某种组合,否则将返回UC_ERR_ARG错误.

@return 成功时返回UC_ERR_OK,失败时为其他值(有关详细错误,请参考uc_err枚举).

相关结构体


这部分仍然在include/unicorn/unicorn.h

uc_arch

架构类型

1
2
3
4
5
6
7
8
9
10
typedef enum uc_arch {
UC_ARCH_ARM = 1, // ARM architecture (including Thumb, Thumb-2)
UC_ARCH_ARM64, // ARM-64, also called AArch64
UC_ARCH_MIPS, // Mips architecture
UC_ARCH_X86, // X86 architecture (including x86 & x86-64)
UC_ARCH_PPC, // PowerPC architecture (currently unsupported)
UC_ARCH_SPARC, // Sparc architecture
UC_ARCH_M68K, // M68K architecture
UC_ARCH_MAX,
} uc_arch;

uc_mode

硬件模式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
typedef enum uc_mode {
UC_MODE_LITTLE_ENDIAN = 0, // little-endian mode (default mode)
UC_MODE_BIG_ENDIAN = 1 << 30, // big-endian mode

// arm / arm64
UC_MODE_ARM = 0, // ARM mode
UC_MODE_THUMB = 1 << 4, // THUMB mode (including Thumb-2)
UC_MODE_MCLASS = 1 << 5, // ARM's Cortex-M series (currently unsupported)
UC_MODE_V8 = 1 << 6, // ARMv8 A32 encodings for ARM (currently unsupported)

// arm (32bit) cpu types
UC_MODE_ARM926 = 1 << 7, // ARM926 CPU type
UC_MODE_ARM946 = 1 << 8, // ARM946 CPU type
UC_MODE_ARM1176 = 1 << 9, // ARM1176 CPU type

// mips
UC_MODE_MICRO = 1 << 4, // MicroMips mode (currently unsupported)
UC_MODE_MIPS3 = 1 << 5, // Mips III ISA (currently unsupported)
UC_MODE_MIPS32R6 = 1 << 6, // Mips32r6 ISA (currently unsupported)
UC_MODE_MIPS32 = 1 << 2, // Mips32 ISA
UC_MODE_MIPS64 = 1 << 3, // Mips64 ISA

// x86 / x64
UC_MODE_16 = 1 << 1, // 16-bit mode
UC_MODE_32 = 1 << 2, // 32-bit mode
UC_MODE_64 = 1 << 3, // 64-bit mode

// ppc
UC_MODE_PPC32 = 1 << 2, // 32-bit mode (currently unsupported)
UC_MODE_PPC64 = 1 << 3, // 64-bit mode (currently unsupported)
UC_MODE_QPX = 1 << 4, // Quad Processing eXtensions mode (currently unsupported)

// sparc
UC_MODE_SPARC32 = 1 << 2, // 32-bit mode
UC_MODE_SPARC64 = 1 << 3, // 64-bit mode
UC_MODE_V9 = 1 << 4, // SparcV9 mode (currently unsupported)

// m68k
} uc_mode;

uc_hook_type

hook类型

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
typedef enum uc_hook_type {
// Hook all interrupt/syscall events
UC_HOOK_INTR = 1 << 0,
// Hook a particular instruction - only a very small subset of instructions supported here
UC_HOOK_INSN = 1 << 1,
// Hook a range of code
UC_HOOK_CODE = 1 << 2,
// Hook basic blocks
UC_HOOK_BLOCK = 1 << 3,
// Hook for memory read on unmapped memory
UC_HOOK_MEM_READ_UNMAPPED = 1 << 4,
// Hook for invalid memory write events
UC_HOOK_MEM_WRITE_UNMAPPED = 1 << 5,
// Hook for invalid memory fetch for execution events
UC_HOOK_MEM_FETCH_UNMAPPED = 1 << 6,
// Hook for memory read on read-protected memory
UC_HOOK_MEM_READ_PROT = 1 << 7,
// Hook for memory write on write-protected memory
UC_HOOK_MEM_WRITE_PROT = 1 << 8,
// Hook for memory fetch on non-executable memory
UC_HOOK_MEM_FETCH_PROT = 1 << 9,
// Hook memory read events.
UC_HOOK_MEM_READ = 1 << 10,
// Hook memory write events.
UC_HOOK_MEM_WRITE = 1 << 11,
// Hook memory fetch for execution events
UC_HOOK_MEM_FETCH = 1 << 12,
// Hook memory read events, but only successful access.
// The callback will be triggered after successful read.
UC_HOOK_MEM_READ_AFTER = 1 << 13,
// Hook invalid instructions exceptions.
UC_HOOK_INSN_INVALID = 1 << 14,
} uc_hook_type;

regid

对于不同架构来说,寄存器不同,不过都可以在对应架构的头文件中找到

比如include/unicorn/arm.h中定义了arm架构的regid

实例

官方的例子写的实在是太棒了我不想复制一遍了,我实在是太懒了

官方例子在samples中找到

CATALOG
  1. 1. 相关函数原型
    1. 1.1. uc_open
    2. 1.2. uc_close
    3. 1.3. uc_reg_write
    4. 1.4. uc_reg_read
    5. 1.5. uc_mem_write
    6. 1.6. uc_mem_read
    7. 1.7. uc_emu_start
    8. 1.8. uc_emu_stop
    9. 1.9. uc_hook_add
    10. 1.10. uc_hook_del
    11. 1.11. uc_mem_map
    12. 1.12. uc_mem_unmap
    13. 1.13. uc_mem_protect
  2. 2. 相关结构体
    1. 2.1. uc_arch
    2. 2.2. uc_mode
    3. 2.3. uc_hook_type
    4. 2.4. regid
  3. 3. 实例