Unicorn-CPU模拟框架数据类型及API分析与示例(二) 0x2 API分析 uc_version unsigned int uc_version (unsigned int *major, unsigned int *minor) ;
用于返回Unicorn API主次版本信息
@major: API主版本号 @minor: API次版本号 @return 16进制数,计算方式 (major << 8 | minor) 提示: 该返回值可以和宏UC_MAKE_VERSION比较
源码实现
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; }
编译后不可更改,不接受自定义版本
使用示例:
#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 ; }
输出:
得到版本号1.0.0
uc_arch_supported bool uc_arch_supported (uc_arch arch) ;
确定Unicorn是否支持当前架构
@arch: 架构类型 (UC_ARCH_*) @return 如果支持返回True
源码实现
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 ; } }
使用示例:
#include <iostream> #include "unicorn/unicorn.h" using namespace std ;int main () { cout << "是否支持UC_ARCH_X86架构:" << uc_arch_supported(UC_ARCH_X86) << endl ; return 0 ; }
输出:
uc_open 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_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.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释放,否则会发生泄露
使用示例:
#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_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 ; }
输出
uc_close uc_err uc_close (uc_engine *uc) ;
关闭一个uc实例,将释放内存。关闭后无法恢复。
@uc: 指向由 uc_open() 返回的指针 @return 成功则返回UC_ERR_OK , 否则返回 uc_err 枚举的其他错误类型
源码实现
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); g_free(uc->cpu->tcg_as_listener); g_free(uc->cpu->thread); 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]); } for (i = 0 ; i < UC_HOOK_MAX; i++) { cur = uc->hook[i].head; 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); memset (uc, 0 , sizeof (*uc)); free (uc); return UC_ERR_OK; }
使用实例同uc_open()
uc_query uc_err uc_query (uc_engine *uc, uc_query_type type, size_t *result) ;
查询引擎的内部状态
@uc: uc_open() 返回的句柄 @type: uc_query_type 中枚举的类型 @result: 保存被查询的内部状态的指针 @return: 成功则返回UC_ERR_OK , 否则返回 uc_err 枚举的其他错误类型
源码实现
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; }
使用示例:
#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 ; 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 ; }
输出
架构查询结果为4,对应的正是UC_ARCH_X86
uc_errno uc_err uc_errno (uc_engine *uc) ;
当某个API函数失败时,报告最后的错误号,一旦被访问,uc_errno可能不会保留原来的值。
@uc: uc_open() 返回的句柄 @return: 成功则返回UC_ERR_OK , 否则返回 uc_err 枚举的其他错误类型
源码实现
uc_err uc_errno (uc_engine *uc) { return uc->errnum; }
使用示例:
#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 ; }
输出
无错误,输出错误号为0
uc_strerror const char *uc_strerror (uc_err code) ;
返回给定错误号的解释
@code: 错误号 @return: 指向给定错误号的解释的字符串指针
源码实现
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)" ; } }
使用示例:
#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 ; }
输出