上篇分析了Capstone开放的数据类型,下面就来正式看看API吧
官方开放的API只有二十个左右,但为了能写的更易懂,我将结合实例,分多篇写。
API中作者将capstone缩写为cs,下面我也用这种方式描述
void* (CAPSTONE_API *cs_malloc_t)(size_t size);
cs的动态内存分配,用于
struct cs_opt_mem { cs_malloc_t malloc; cs_calloc_t calloc; cs_realloc_t realloc; cs_free_t free; cs_vsnprintf_t vsnprintf; } cs_opt_mem;
cs_malloc_t定义于capstone.lib和capstone.dll的cs.c中,
在用户模式下,cs_mem_malloc默认使用系统malloc
Windows driver模式下,
cs_malloc_t cs_mem_malloc = cs_winkernel_malloc;
cs_winkernel_malloc定义于\capstone-4.0.1\windows\winkernel_mm.c,
实现代码
void * CAPSTONE_API cs_winkernel_malloc(size_t size) { // 长度不能分配为0 NT_ASSERT(size); // FP; NonPagedPool用于支持 Windows 7 #pragma prefast(suppress : 30030) // 分配可执行的POOL_TYPE内存 size_t number_of_bytes = 0; CS_WINKERNEL_MEMBLOCK *block = NULL; // 特定的值能造成溢出 // 如果value中的和超出或低于类型容量,函数将返回NULL。 if (!NT_SUCCESS(RtlSizeTAdd(size, sizeof(CS_WINKERNEL_MEMBLOCK), &number_of_bytes))) { return NULL; } block = (CS_WINKERNEL_MEMBLOCK *)ExAllocatePoolWithTag( NonPagedPool, number_of_bytes, CS_WINKERNEL_POOL_TAG); if (!block) { return NULL; } block->size = size; return block->data; }
OSX kernel模式下,
cs_malloc_t cs_mem_malloc = kern_os_malloc;
,这里暂且不探讨。
void* (CAPSTONE_API *cs_calloc_t)(size_t nmemb, size_t size);
cs申请内存并初始化
用于struct cs_opt_mem
,定义于cs.c
用户模式: cs_calloc_t cs_mem_calloc = calloc;
,使用系统calloc
Windows driver模式: cs_calloc_t cs_mem_calloc = cs_winkernel_calloc;
实现代码
void * CAPSTONE_API cs_winkernel_calloc(size_t n, size_t size) { size_t total = n * size; void *new_ptr = cs_winkernel_malloc(total); if (!new_ptr) { return NULL; } return RtlFillMemory(new_ptr, total, 0); }
OSX kernel模式: cs_calloc_t cs_mem_calloc = cs_kern_os_calloc;
直接调用kern_os_malloc了
void* (CAPSTONE_API *cs_realloc_t)(void *ptr, size_t size);
cs重新分配内存
用于struct cs_opt_mem
,定义于cs.c
用户模式: cs_realloc_t cs_mem_realloc = realloc;
,调用系统realloc
Windows driver模式: cs_realloc_t cs_mem_realloc = cs_winkernel_realloc;
实现代码,可以看出是利用cs_winkernel_malloc重新申请
void * CAPSTONE_API cs_winkernel_realloc(void *ptr, size_t size) { void *new_ptr = NULL; size_t current_size = 0; size_t smaller_size = 0; if (!ptr) { return cs_winkernel_malloc(size); } new_ptr = cs_winkernel_malloc(size); if (!new_ptr) { return NULL; } current_size = CONTAINING_RECORD(ptr, CS_WINKERNEL_MEMBLOCK, data)->size; smaller_size = (current_size < size) ? current_size : size; RtlCopyMemory(new_ptr, ptr, smaller_size); cs_winkernel_free(ptr); return new_ptr; }
OSX kernel模式: cs_realloc_t cs_mem_realloc = kern_os_realloc;
typedef void (CAPSTONE_API *cs_free_t)(void *ptr);
cs释放内存
用于struct cs_opt_mem
,定义于cs.c
用户模式: cs_free_t cs_mem_free = free;
,调用系统free
Windows driver模式: cs_free_t cs_mem_free = cs_winkernel_free;
实现代码
void CAPSTONE_API cs_winkernel_free(void *ptr) { if (ptr) { ExFreePoolWithTag(CONTAINING_RECORD(ptr, CS_WINKERNEL_MEMBLOCK, data), CS_WINKERNEL_POOL_TAG); } }
OSX kernel模式: cs_free_t cs_mem_free = kern_os_free;
int (CAPSTONE_API *cs_vsnprintf_t)(char *str, size_t size, const char *format, va_list ap);
按size大小输出到字符串str中
用户模式:
值得注意的是,如果系统为wince,将使用_vsnprintf函数
vsnprintf ()和_vsnprintf()对于驱动程序都是可用的,但是它们有一些不同。
在需要返回值和设置空终止符时应使用vsnprintf()
vsnprintf定义在stdio.h
Windows driver模式: cs_vsnprintf_t cs_vsnprintf = cs_winkernel_vsnprintf;
代码实现
int CAPSTONE_API cs_winkernel_vsnprintf(char *buffer, size_t count, const char *format, va_list argptr) { int result = _vsnprintf(buffer, count, format, argptr); // _vsnprintf()在字符串被截断时返回-1,在整个字符串被存储但“buffer”末尾没有“\0”时返回“count”。在这两种情况下,都需要手动添加空终止符。 if (result == -1 || (size_t)result == count) { buffer[count - 1] = '\0'; } if (result == -1) { // 在返回-1时,函数必须获取并返回一些本来要写入的字符。因此,通过重试使用temp buffer进行相同的转换,这个缓冲区就可能足够大来完成格式化,并且获得很多本应写入的字符。 char* tmp = cs_winkernel_malloc(0x1000); if (!tmp) { return result; } result = _vsnprintf(tmp, 0x1000, format, argptr); NT_ASSERT(result != -1); cs_winkernel_free(tmp); } return result; }
OSX kernel模式: cs_vsnprintf_t cs_vsnprintf = vsnprintf;
,使用默认vsnprintf
size_t (CAPSTONE_API cs_skipdata_cb_t)(const uint8_t code, size_t code_size, size_t offset, void *user_data);
SKIPDATA选项的用户自定义回调函数。
code:包含要分解的代码的输入缓冲区。和传递给cs_disasm()的缓冲区相同。
code_size:上面的code缓冲区的大小(以字节为单位)。
offset:上面提到的输入缓冲区code中当前检查字节的位置。
user_data:用户数据通过cs_opt_skipdata结构中的@user_data字段传递给cs_option()。
return:返回要跳过的字节数,或者0表示立即停止反汇编。
cs_skipdata_cb_t在struct cs_opt_skipdata
中调用,下面来看一个例子
分析写在注释中
#include <stdio.h> #include <stdlib.h> #include "platform.h" #include "capstone.h" struct platform { cs_arch arch; cs_mode mode; unsigned char* code; size_t size; const char* comment; cs_opt_type opt_type; cs_opt_value opt_value; cs_opt_type opt_skipdata; size_t skipdata; }; static void print_string_hex(unsigned char* str, size_t len) //输出机器码 { unsigned char* c; printf("Code: "); for (c = str; c < str + len; c++) { printf("0x%02x ", *c & 0xff); } printf("\n"); } static void test() { #define X86_CODE32 "\x8d\x4c\x32\x08\x01\xd8\x81\xc6\x34\x12\x00\x00\x00\x91\x92" //测试用机器码 #define RANDOM_CODE "\xed\x00\x00\x00\x00\x1a\x5a\x0f\x1f\xff\xc2\x09\x80\x00\x00\x00\x07\xf7\xeb\x2a\xff\xff\x7f\x57\xe3\x01\xff\xff\x7f\x57\xeb\x00\xf0\x00\x00\x24\xb2\x4f\x00\x78" cs_opt_skipdata skipdata = { // 把默认 "data" 描述符从 ".byte" 重命名为 "db" "db", }; struct platform platforms[2] = { //以默认描述符和自定义描述符两种方式建立一个数组 { CS_ARCH_X86, CS_MODE_32, (unsigned char*)X86_CODE32, sizeof(X86_CODE32) - 1, "X86 32 (Intel syntax) - Skip data", }, { CS_ARCH_X86, CS_MODE_32, (unsigned char*)X86_CODE32, sizeof(X86_CODE32) - 1, "X86 32 (Intel syntax) - Skip data with custom mnemonic", CS_OPT_INVALID, CS_OPT_OFF, CS_OPT_SKIPDATA_SETUP, (size_t)& skipdata, }, }; csh handle; //建立capstone句柄 uint64_t address = 0x1000; //设置起始地址 cs_insn* insn; //具体信息结构体 cs_err err; //错误枚举 int i; size_t count; //成功反汇编行数 for (i = 0; i < sizeof(platforms) / sizeof(platforms[0]); i++) { printf("****************\n"); printf("Platform: %s\n", platforms[i].comment); err = cs_open(platforms[i].arch, platforms[i].mode, &handle); //错误检查 if (err) { printf("Failed on cs_open() with error returned: %u\n", err); abort(); } if (platforms[i].opt_type) cs_option(handle, platforms[i].opt_type, platforms[i].opt_value); // 打开SKIPDATA 模式 cs_option(handle, CS_OPT_SKIPDATA, CS_OPT_ON); cs_option(handle, platforms[i].opt_skipdata, platforms[i].skipdata); count = cs_disasm(handle, platforms[i].code, platforms[i].size, address, 0, &insn); if (count) { size_t j; print_string_hex(platforms[i].code, platforms[i].size); printf("Disasm:\n"); for (j = 0; j < count; j++) { //输出汇编 printf("0x%" PRIx64 ":\t%s\t\t%s\n", insn[j].address, insn[j].mnemonic, insn[j].op_str); } // 最后一行代码后打印偏移 printf("0x%" PRIx64 ":\n", insn[j - 1].address + insn[j - 1].size); // 释放cs_disasm()申请的内存 cs_free(insn, count); } else { printf("****************\n"); printf("Platform: %s\n", platforms[i].comment); print_string_hex(platforms[i].code, platforms[i].size); printf("ERROR: Failed to disasm given code!\n"); abort(); } printf("\n"); cs_close(&handle); } } int main() { test(); return 0; }
运行结果如下,可以看出,默认的 .byte数据类型被改为db描述符
unsigned int CAPSTONE_API cs_version(int *major, int *minor);
用来输出capstone版本号
参数
major: API主版本
minor: API次版本
return: 返回主次版本的16进制,如4.0版本返回 0x0400
通过分析源码发现
该版本定义于cs.c中,编译后不可更改,不接受自定义版本
示例1:
#include <stdio.h> #include <stdlib.h> #include "platform.h" #include "capstone.h" static int test() { return cs_version(NULL, NULL); } int main() { int version = test(); printf("%X", version); return 0; }
输出
示例2,强行修改版本:
#include <stdio.h> #include <stdlib.h> #include "platform.h" #include "capstone.h" static int test() { int ma[] = { 5 }; int mi[] = { 6 }; return cs_version(ma, mi); } int main() { int version = test(); printf("%X", version); return 0; }
输出:
可以看到并不能改变
bool CAPSTONE_API cs_support(int query);
用来检查capstone库是否支持参数输入的架构或处于某编译选项
通过查看源码得知,共有四种查询参数
bool CAPSTONE_API cs_support(int query) { if (query == CS_ARCH_ALL) return all_arch == ((1 << CS_ARCH_ARM) | (1 << CS_ARCH_ARM64) | (1 << CS_ARCH_MIPS) | (1 << CS_ARCH_X86) | (1 << CS_ARCH_PPC) | (1 << CS_ARCH_SPARC) | (1 << CS_ARCH_SYSZ) | (1 << CS_ARCH_XCORE) | (1 << CS_ARCH_M68K) | (1 << CS_ARCH_TMS320C64X) | (1 << CS_ARCH_M680X) | (1 << CS_ARCH_EVM)); if ((unsigned int)query < CS_ARCH_MAX) return all_arch & (1 << query); if (query == CS_SUPPORT_DIET) { #ifdef CAPSTONE_DIET return true; #else return false; #endif } if (query == CS_SUPPORT_X86_REDUCE) { #if defined(CAPSTONE_HAS_X86) && defined(CAPSTONE_X86_REDUCE) return true; #else return false; #endif } // unsupported query return false; }
示例1(CS_ARCH_ALL,检查是否支持所有架构):
示例2(CSARCH*,检查是否支持指定架构)
示例3(检查是否处于DIET编译模式):
示例4(检查是否处于X86_REDUCE编译模式):
)
下篇将介绍更多有用的API,望支持