avatar

目录
Unicorn-CPU模拟框架数据类型及API分析与示例(二)

Unicorn-CPU模拟框架数据类型及API分析与示例(二)

0x2 API分析

uc_version

cpp
unsigned int uc_version(unsigned int *major, unsigned int *minor);

用于返回Unicorn API主次版本信息

Code
@major: API主版本号
@minor: API次版本号
@return 16进制数,计算方式 (major << 8 | minor)

提示: 该返回值可以和宏UC_MAKE_VERSION比较

源码实现

c
unsigned int uc_version(unsigned int *major, unsigned int *minor)
{
if (major != NULL && minor != NULL) {
*major = UC_API_MAJOR; //宏
*minor = UC_API_MINOR; //宏
}

return (UC_API_MAJOR << 8) + UC_API_MINOR; //(major << 8 | minor)
}

编译后不可更改,不接受自定义版本

使用示例:

cpp
#include <iostream>
#include "unicorn/unicorn.h"
using namespace std;

int main()
{
unsigned int version;
version = uc_version(NULL,NULL);
cout << hex << version << endl;
return 0;
}

输出:

image.png

得到版本号1.0.0

uc_arch_supported

c
bool uc_arch_supported(uc_arch arch);

确定Unicorn是否支持当前架构

Code
@arch: 架构类型 (UC_ARCH_*)
@return 如果支持返回True

源码实现

c
bool uc_arch_supported(uc_arch arch)
{
switch (arch) {
#ifdef UNICORN_HAS_ARM
case UC_ARCH_ARM: return true;
#endif
#ifdef UNICORN_HAS_ARM64
case UC_ARCH_ARM64: return true;
#endif
#ifdef UNICORN_HAS_M68K
case UC_ARCH_M68K: return true;
#endif
#ifdef UNICORN_HAS_MIPS
case UC_ARCH_MIPS: return true;
#endif
#ifdef UNICORN_HAS_PPC
case UC_ARCH_PPC: return true;
#endif
#ifdef UNICORN_HAS_SPARC
case UC_ARCH_SPARC: return true;
#endif
#ifdef UNICORN_HAS_X86
case UC_ARCH_X86: return true;
#endif
/* 无效或禁用架构 */
default: return false;
}
}

使用示例:

cpp
#include <iostream>
#include "unicorn/unicorn.h"
using namespace std;

int main()
{
cout << "是否支持UC_ARCH_X86架构:" << uc_arch_supported(UC_ARCH_X86) << endl;
return 0;
}

输出:

image.png

uc_open

c
uc_err uc_open(uc_arch arch, uc_mode mode, uc_engine **uc);

创建新的Unicorn实例

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

@return 成功则返回UC_ERR_OK , 否则返回 uc_err 枚举的其他错误类型

源码实现

c
uc_err uc_open(uc_arch arch, uc_mode mode, uc_engine **result)
{
struct uc_struct *uc;

if (arch < UC_ARCH_MAX) {
uc = calloc(1, sizeof(*uc)); //申请内存
if (!uc) {
// 内存不足
return UC_ERR_NOMEM;
}

uc->errnum = UC_ERR_OK;
uc->arch = arch;
uc->mode = mode;

// 初始化
// uc->ram_list = { .blocks = QTAILQ_HEAD_INITIALIZER(ram_list.blocks) };
uc->ram_list.blocks.tqh_first = NULL;
uc->ram_list.blocks.tqh_last = &(uc->ram_list.blocks.tqh_first);

uc->memory_listeners.tqh_first = NULL;
uc->memory_listeners.tqh_last = &uc->memory_listeners.tqh_first;

uc->address_spaces.tqh_first = NULL;
uc->address_spaces.tqh_last = &uc->address_spaces.tqh_first;

switch(arch) { // 根据架构进行预处理
default:
break;
#ifdef UNICORN_HAS_M68K
case UC_ARCH_M68K:
if ((mode & ~UC_MODE_M68K_MASK) ||
!(mode & UC_MODE_BIG_ENDIAN)) {
free(uc);
return UC_ERR_MODE;
}
uc->init_arch = m68k_uc_init;
break;
#endif
#ifdef UNICORN_HAS_X86
case UC_ARCH_X86:
if ((mode & ~UC_MODE_X86_MASK) ||
(mode & UC_MODE_BIG_ENDIAN) ||
!(mode & (UC_MODE_16|UC_MODE_32|UC_MODE_64))) {
free(uc);
return UC_ERR_MODE;
}
uc->init_arch = x86_uc_init;
break;
#endif
#ifdef UNICORN_HAS_ARM
case UC_ARCH_ARM:
if ((mode & ~UC_MODE_ARM_MASK)) {
free(uc);
return UC_ERR_MODE;
}
if (mode & UC_MODE_BIG_ENDIAN) {
uc->init_arch = armeb_uc_init;
} else {
uc->init_arch = arm_uc_init;
}

if (mode & UC_MODE_THUMB)
uc->thumb = 1;
break;
#endif
#ifdef UNICORN_HAS_ARM64
case UC_ARCH_ARM64:
if (mode & ~UC_MODE_ARM_MASK) {
free(uc);
return UC_ERR_MODE;
}
if (mode & UC_MODE_BIG_ENDIAN) {
uc->init_arch = arm64eb_uc_init;
} else {
uc->init_arch = arm64_uc_init;
}
break;
#endif

#if defined(UNICORN_HAS_MIPS) || defined(UNICORN_HAS_MIPSEL) || defined(UNICORN_HAS_MIPS64) || defined(UNICORN_HAS_MIPS64EL)
case UC_ARCH_MIPS:
if ((mode & ~UC_MODE_MIPS_MASK) ||
!(mode & (UC_MODE_MIPS32|UC_MODE_MIPS64))) {
free(uc);
return UC_ERR_MODE;
}
if (mode & UC_MODE_BIG_ENDIAN) {
#ifdef UNICORN_HAS_MIPS
if (mode & UC_MODE_MIPS32)
uc->init_arch = mips_uc_init;
#endif
#ifdef UNICORN_HAS_MIPS64
if (mode & UC_MODE_MIPS64)
uc->init_arch = mips64_uc_init;
#endif
} else { // 小端序
#ifdef UNICORN_HAS_MIPSEL
if (mode & UC_MODE_MIPS32)
uc->init_arch = mipsel_uc_init;
#endif
#ifdef UNICORN_HAS_MIPS64EL
if (mode & UC_MODE_MIPS64)
uc->init_arch = mips64el_uc_init;
#endif
}
break;
#endif

#ifdef UNICORN_HAS_SPARC
case UC_ARCH_SPARC:
if ((mode & ~UC_MODE_SPARC_MASK) ||
!(mode & UC_MODE_BIG_ENDIAN) ||
!(mode & (UC_MODE_SPARC32|UC_MODE_SPARC64))) {
free(uc);
return UC_ERR_MODE;
}
if (mode & UC_MODE_SPARC64)
uc->init_arch = sparc64_uc_init;
else
uc->init_arch = sparc_uc_init;
break;
#endif
}

if (uc->init_arch == NULL) {
return UC_ERR_ARCH;
}

if (machine_initialize(uc))
return UC_ERR_RESOURCE;

*result = uc;

if (uc->reg_reset)
uc->reg_reset(uc);

return UC_ERR_OK;
} else {
return UC_ERR_ARCH;
}
}

注意: uc_open会申请堆内存,使用完必须用uc_close释放,否则会发生泄露

使用示例:

cpp
#include <iostream>
#include "unicorn/unicorn.h"
using namespace std;

int main()
{
uc_engine* uc;
uc_err err;

//// 初始化 X86-32bit 模式模拟器
err = uc_open(UC_ARCH_X86, UC_MODE_32, &uc);
if (err != UC_ERR_OK) {
printf("Failed on uc_open() with error returned: %u\n", err);
return -1;
}

if (!err)
cout << "uc引擎创建成功" << endl;

//// 关闭uc
err = uc_close(uc);
if (err != UC_ERR_OK) {
printf("Failed on uc_close() with error returned: %u\n", err);
return -1;
}

if (!err)
cout << "uc引擎关闭成功" << endl;

return 0;
}

输出

image.png

uc_close

c
uc_err uc_close(uc_engine *uc);

关闭一个uc实例,将释放内存。关闭后无法恢复。

Code
@uc: 指向由 uc_open() 返回的指针

@return 成功则返回UC_ERR_OK , 否则返回 uc_err 枚举的其他错误类型

源码实现

c
uc_err uc_close(uc_engine *uc)
{
int i;
struct list_item *cur;
struct hook *hook;

// 清理内部数据
if (uc->release)
uc->release(uc->tcg_ctx);
g_free(uc->tcg_ctx);

// 清理 CPU.
g_free(uc->cpu->tcg_as_listener);
g_free(uc->cpu->thread);

// 清理所有 objects.
OBJECT(uc->machine_state->accelerator)->ref = 1;
OBJECT(uc->machine_state)->ref = 1;
OBJECT(uc->owner)->ref = 1;
OBJECT(uc->root)->ref = 1;

object_unref(uc, OBJECT(uc->machine_state->accelerator));
object_unref(uc, OBJECT(uc->machine_state));
object_unref(uc, OBJECT(uc->cpu));
object_unref(uc, OBJECT(&uc->io_mem_notdirty));
object_unref(uc, OBJECT(&uc->io_mem_unassigned));
object_unref(uc, OBJECT(&uc->io_mem_rom));
object_unref(uc, OBJECT(uc->root));

// 释放内存
g_free(uc->system_memory);

// 释放相关线程
if (uc->qemu_thread_data)
g_free(uc->qemu_thread_data);

// 释放其他数据
free(uc->l1_map);

if (uc->bounce.buffer) {
free(uc->bounce.buffer);
}

g_hash_table_foreach(uc->type_table, free_table, uc);
g_hash_table_destroy(uc->type_table);

for (i = 0; i < DIRTY_MEMORY_NUM; i++) {
free(uc->ram_list.dirty_memory[i]);
}

// 释放hook和hook列表
for (i = 0; i < UC_HOOK_MAX; i++) {
cur = uc->hook[i].head;
// hook 可存在于多个列表,可通过计数获取释放的时间
while (cur) {
hook = (struct hook *)cur->data;
if (--hook->refs == 0) {
free(hook);
}
cur = cur->next;
}
list_clear(&uc->hook[i]);
}

free(uc->mapped_blocks);

// 最后释放uc自身
memset(uc, 0, sizeof(*uc));
free(uc);

return UC_ERR_OK;
}

使用实例同uc_open()

uc_query

c
uc_err uc_query(uc_engine *uc, uc_query_type type, size_t *result);

查询引擎的内部状态

Code
@uc: uc_open() 返回的句柄
@type: uc_query_type 中枚举的类型

@result: 保存被查询的内部状态的指针

@return: 成功则返回UC_ERR_OK , 否则返回 uc_err 枚举的其他错误类型

源码实现

c
uc_err uc_query(uc_engine *uc, uc_query_type type, size_t *result)
{
if (type == UC_QUERY_PAGE_SIZE) {
*result = uc->target_page_size;
return UC_ERR_OK;
}

if (type == UC_QUERY_ARCH) {
*result = uc->arch;
return UC_ERR_OK;
}

switch(uc->arch) {
#ifdef UNICORN_HAS_ARM
case UC_ARCH_ARM:
return uc->query(uc, type, result);
#endif
default:
return UC_ERR_ARG;
}

return UC_ERR_OK;
}

使用示例:

cpp
#include <iostream>
#include "unicorn/unicorn.h"
using namespace std;
int main()
{
uc_engine* uc;
uc_err err;

//// Initialize emulator in X86-32bit mode
err = uc_open(UC_ARCH_X86, UC_MODE_32, &uc);
if (err != UC_ERR_OK) {
printf("Failed on uc_open() with error returned: %u\n", err);
return -1;
}
if (!err)
cout << "uc实例创建成功" << endl;

size_t result[] = {0};
err = uc_query(uc, UC_QUERY_ARCH, result); // 查询架构
if (!err)
cout << "查询成功: " << *result << endl;

err = uc_close(uc);
if (err != UC_ERR_OK) {
printf("Failed on uc_close() with error returned: %u\n", err);
return -1;
}
if (!err)
cout << "uc实例关闭成功" << endl;

return 0;
}

输出

image.png

架构查询结果为4,对应的正是UC_ARCH_X86

uc_errno

c
uc_err uc_errno(uc_engine *uc);

当某个API函数失败时,报告最后的错误号,一旦被访问,uc_errno可能不会保留原来的值。

Code
@uc: uc_open() 返回的句柄

@return: 成功则返回UC_ERR_OK , 否则返回 uc_err 枚举的其他错误类型

源码实现

c
uc_err uc_errno(uc_engine *uc)
{
return uc->errnum;
}

使用示例:

cpp
#include <iostream>
#include "unicorn/unicorn.h"
using namespace std;

int main()
{
uc_engine* uc;
uc_err err;

err = uc_open(UC_ARCH_X86, UC_MODE_32, &uc);
if (err != UC_ERR_OK) {
printf("Failed on uc_open() with error returned: %u\n", err);
return -1;
}
if (!err)
cout << "uc实例创建成功" << endl;

err = uc_errno(uc);
cout << "错误号: " << err << endl;

err = uc_close(uc);
if (err != UC_ERR_OK) {
printf("Failed on uc_close() with error returned: %u\n", err);
return -1;
}
if (!err)
cout << "uc实例关闭成功" << endl;

return 0;
}

输出

image.png

无错误,输出错误号为0

uc_strerror

c
const char *uc_strerror(uc_err code);

返回给定错误号的解释

Code
@code: 错误号

@return: 指向给定错误号的解释的字符串指针

源码实现

cpp
const char *uc_strerror(uc_err code)
{
switch(code) {
default:
return "Unknown error code";
case UC_ERR_OK:
return "OK (UC_ERR_OK)";
case UC_ERR_NOMEM:
return "No memory available or memory not present (UC_ERR_NOMEM)";
case UC_ERR_ARCH:
return "Invalid/unsupported architecture (UC_ERR_ARCH)";
case UC_ERR_HANDLE:
return "Invalid handle (UC_ERR_HANDLE)";
case UC_ERR_MODE:
return "Invalid mode (UC_ERR_MODE)";
case UC_ERR_VERSION:
return "Different API version between core & binding (UC_ERR_VERSION)";
case UC_ERR_READ_UNMAPPED:
return "Invalid memory read (UC_ERR_READ_UNMAPPED)";
case UC_ERR_WRITE_UNMAPPED:
return "Invalid memory write (UC_ERR_WRITE_UNMAPPED)";
case UC_ERR_FETCH_UNMAPPED:
return "Invalid memory fetch (UC_ERR_FETCH_UNMAPPED)";
case UC_ERR_HOOK:
return "Invalid hook type (UC_ERR_HOOK)";
case UC_ERR_INSN_INVALID:
return "Invalid instruction (UC_ERR_INSN_INVALID)";
case UC_ERR_MAP:
return "Invalid memory mapping (UC_ERR_MAP)";
case UC_ERR_WRITE_PROT:
return "Write to write-protected memory (UC_ERR_WRITE_PROT)";
case UC_ERR_READ_PROT:
return "Read from non-readable memory (UC_ERR_READ_PROT)";
case UC_ERR_FETCH_PROT:
return "Fetch from non-executable memory (UC_ERR_FETCH_PROT)";
case UC_ERR_ARG:
return "Invalid argument (UC_ERR_ARG)";
case UC_ERR_READ_UNALIGNED:
return "Read from unaligned memory (UC_ERR_READ_UNALIGNED)";
case UC_ERR_WRITE_UNALIGNED:
return "Write to unaligned memory (UC_ERR_WRITE_UNALIGNED)";
case UC_ERR_FETCH_UNALIGNED:
return "Fetch from unaligned memory (UC_ERR_FETCH_UNALIGNED)";
case UC_ERR_RESOURCE:
return "Insufficient resource (UC_ERR_RESOURCE)";
case UC_ERR_EXCEPTION:
return "Unhandled CPU exception (UC_ERR_EXCEPTION)";
case UC_ERR_TIMEOUT:
return "Emulation timed out (UC_ERR_TIMEOUT)";
}
}

使用示例:

cpp
#include <iostream>
#include "unicorn/unicorn.h"
using namespace std;

int main()
{
uc_engine* uc;
uc_err err;

err = uc_open(UC_ARCH_X86, UC_MODE_32, &uc);
if (err != UC_ERR_OK) {
printf("Failed on uc_open() with error returned: %u\n", err);
return -1;
}
if (!err)
cout << "uc实例创建成功" << endl;

err = uc_errno(uc);
cout << "错误号: " << err << " 错误描述: " << uc_strerror(err) <<endl;

err = uc_close(uc);
if (err != UC_ERR_OK) {
printf("Failed on uc_close() with error returned: %u\n", err);
return -1;
}
if (!err)
cout << "uc实例关闭成功" << endl;

return 0;
}

输出

image.png

文章作者: kabeor
文章链接: https://kabeor.github.io/Unicorn-CPU%E6%A8%A1%E6%8B%9F%E6%A1%86%E6%9E%B6%E6%95%B0%E6%8D%AE%E7%B1%BB%E5%9E%8B%E5%8F%8AAPI%E5%88%86%E6%9E%90%E4%B8%8E%E7%A4%BA%E4%BE%8B(%E4%BA%8C)/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 K's House

评论