Capstone反汇编
Posted 小立爱学习
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Capstone反汇编相关的知识,希望对你有一定的参考价值。
文章目录
前言
Capstone反汇编(一)
上篇文章只是简单分析了官方给出的一个案例用到的API,接下来分析其它的API和数据结构
一 cs_option API 分析
1.1 cs_option
反编译引擎的运行时选项
cs_option(csh ud, cs_opt_type type, size_t value)
1.2 cs_opt_type
type是cs_option函数的第二个参数,是反汇编引擎运行时枚举选项
// 反汇编引擎的运行时选项
typedef enum cs_opt_type
CS_OPT_INVALID = 0, // <未指定选项
CS_OPT_SYNTAX, // 汇编输出语法
CS_OPT_DETAIL, // 将指令结构分解为细节
CS_OPT_MODE, // 在运行时更改引擎的模式
CS_OPT_MEM, // 用户自定义动态内存相关函数
CS_OPT_SKIPDATA, // 反汇编时跳过数据,然后引擎处于 SKIPDATA 模式。
CS_OPT_SKIPDATA_SETUP, // 为 SKIPDATA 选项设置用户自定义函数
CS_OPT_MNEMONIC, // 自定义指令助记符
CS_OPT_UNSIGNED, // 以无符号形式打印立即操作数
cs_opt_type;
1.3 cs_opt_value
英文很容易理解,这里就不翻译了
/// Runtime option value (associated with option type above)
typedef enum cs_opt_value
CS_OPT_OFF = 0, ///< Turn OFF an option - default for CS_OPT_DETAIL, CS_OPT_SKIPDATA, CS_OPT_UNSIGNED.
CS_OPT_ON = 3, ///< Turn ON an option (CS_OPT_DETAIL, CS_OPT_SKIPDATA).
CS_OPT_SYNTAX_DEFAULT = 0, ///< Default asm syntax (CS_OPT_SYNTAX).
CS_OPT_SYNTAX_INTEL, ///< X86 Intel asm syntax - default on X86 (CS_OPT_SYNTAX).
CS_OPT_SYNTAX_ATT, ///< X86 ATT asm syntax (CS_OPT_SYNTAX).
CS_OPT_SYNTAX_NOREGNAME, ///< Prints register name with only number (CS_OPT_SYNTAX)
CS_OPT_SYNTAX_MASM, ///< X86 Intel Masm syntax (CS_OPT_SYNTAX).
CS_OPT_SYNTAX_MOTOROLA, ///< MOS65XX use $ as hex prefix
cs_opt_value;
1.4 例程演示
使用cs_option函数,加上反编译引擎的运行时选项,反汇编出来的语法为AT&T语法
// 以AT&T语法显示
cs_option(handle, CS_OPT_SYNTAX, CS_OPT_SYNTAX_ATT);
#include <stdio.h>
#include <string.h>
#include <inttypes.h>
#include <capstone/capstone.h>
#define CODE "\\x55\\x48\\x8b\\x05\\xb8\\x13\\x00\\x00"
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");
int main(void)
csh handle;
cs_insn *insn;
size_t count;
if (cs_open(CS_ARCH_X86, CS_MODE_64, &handle) != CS_ERR_OK)
return -1;
// 以AT&T语法显示
cs_option(handle, CS_OPT_SYNTAX, CS_OPT_SYNTAX_ATT);
print_string_hex(CODE, strlen(CODE));
printf("Disasm:\\n");
count = cs_disasm(handle, CODE, sizeof(CODE)-1, 0x1000, 0, &insn);
if (count > 0)
size_t j;
for (j = 0; j < count; j++)
printf("0x%"PRIx64":\\t%s\\t\\t%s : ", insn[j].address, insn[j].mnemonic,
insn[j].op_str);
for(int i = 0 ; i < insn[j].size; i++)
printf("0x%02x ", insn[j].bytes[i]);
printf("\\n");
cs_free(insn, count);
else
printf("ERROR: Failed to disassemble given code!\\n");
cs_close(&handle);
return 0;
看一下结果反汇编出来的语法变成了AT&T语法
其中:
insn[j].bytes[i]是指令的机器码,即对应的二进制
insn[j].size是该机器指令的长度
for(int i = 0 ; i < insn[j].size; i++)
printf("0x%02x ", insn[j].bytes[i]);
二、 SKIPDATA mode
默认情况下,Capstone 在遇到 a broken instruction 时会停止反汇编,大多数时候,原因是这是输入中混合的数据,Capstone 不理解这个“weird” code。
通常,建议您确定下一个代码在哪里,然后从该位置继续反汇编。 但是,在某些情况下,您只想让 Capstone 自动跳过一些数据,直到找到合法指令,然后从那里继续。 因此,为此目的引入了 SKIPDATA 模式。
简单点来说就是当输入的二进制代码中有不合法的指令,Capstone遇到这个不合法指令便会停止反汇编,不会继续反汇编后面的数据,所以引入了SKIPDATA 模式,跳过这些不合法的指令,并用一个助记符替代,然后继续反汇编后面的数据。
2.1 数据结构
cs_opt_skipdata
//用户自定义设置 SKIPDATA 选项
typedef struct cs_opt_skipdata
// Capstone 将要跳过的数据视为特殊的“指令”
// 用户可以在这里为该指令的“助记符”指定字符串。
// 默认情况下(如果 @mnemonic 为 NULL),Capstone 使用“.byte”。
const char *mnemonic;
// Capstone hits 数据时调用的用户自定义回调函数
// 如果此回调的返回值为正数 (>0), Capstone 将准确跳过该字节数并继续
// 否则,如果回调返回 0,Capstone 停止反汇编并立即从 cs_disasm() 返回
// 注意:如果此回调指针为 NULL,Capstone 将根据体系结构跳过一些字节,如下所示:
/// Arm: 2 bytes (Thumb mode) or 4 bytes.
/// Arm64: 4 bytes.
/// Mips: 4 bytes.
/// M680x: 1 byte.
/// PowerPC: 4 bytes.
/// Sparc: 4 bytes.
/// SystemZ: 2 bytes.
/// X86: 1 bytes.
/// XCore: 2 bytes.
/// EVM: 1 bytes.
/// RISCV: 4 bytes.
/// WASM: 1 bytes.
/// MOS65XX: 1 bytes.
/// BPF: 8 bytes.
cs_skipdata_cb_t callback; // default value is NULL
// 用户自定义数据将被传递给callback函数指针
void *user_data;
cs_opt_skipdata;
(2)cs_skipdata_cb_t
/**
SKIPDATA 选项的用户定义回调函数
@code: 包含要反汇编的代码的输入缓冲区。
这与传递给 cs_disasm() 的缓冲区相同。
@code_size: 上述 code 缓冲区的大小(以字节为单位)。
@offset: 当前检查字节在上述输入缓冲区 code 中的位置。
@user_data: 用户数据通过 cs_opt_skipdata 结构中的 user_data 字段传递给 cs_option()。
@return: 返回要跳过的字节数,或 0 立即停止反汇编。
*/
typedef size_t (CAPSTONE_API *cs_skipdata_cb_t)(const uint8_t *code, size_t code_size, size_t offset, void *user_data);
(3)打开 SKIPDATA mode
要让Capstone跳过一些(未知的)数据量,直到下一个合法指令,只需使用cs_option()打开选项CS_OPT_SKIPDATA(默认关闭),如下所示:
csh handle;
cs_open(CS_ARCH_X86, CS_MODE_64, &handle);
// turn on SKIPDATA mode
cs_option(handle, CS_OPT_SKIPDATA, CS_OPT_ON);
2.2 例程演示
例程采用官方的例程:
使用SKIPDATA mode 之前:
/* Capstone Disassembler Engine */
#include <stdio.h>
#include <stdlib.h>
#include <capstone/platform.h>
#include <capstone/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 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"
struct platform platforms[] =
CS_ARCH_X86,
CS_MODE_64,
(unsigned char*)RANDOM_CODE,
sizeof(RANDOM_CODE) - 1,
,
;
csh handle;
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++)
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);
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);
// print out the next offset, after the last insn
printf("0x%" PRIx64 ":\\n", insn[j-1].address + insn[j-1].size);
// free memory allocated by cs_disasm()
cs_free(insn, count);
else
printf("****************\\n");
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;
Capstone 在遇到 a broken instruction 时会停止反汇编了。
使用SKIPDATA mode 之后:
/* Capstone Disassembler Engine */
#include <stdio.h>
#include <stdlib.h>
#include <capstone/platform.h>
#include <capstone/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 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"
struct platform platforms[] =
CS_ARCH_X86,
CS_MODE_64,
(unsigned char*)RANDOM_CODE,
sizeof(RANDOM_CODE) - 1,
,
;
csh handle;
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++)
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);
// turn on SKIPDATA mode
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);
// print out the next offset, after the last insn
printf("0x%" PRIx64 ":\\n", insn[j-1].address + insn[j-1].size);
// free memory allocated by cs_disasm()
cs_free(insn, count);
else
printf("****************\\n");
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;
Capstone 在遇到 a broken instruction 时,自动跳过一些数据,用.byte代替,直到找到合法指令,然后从那里继续反汇编。
Capstone 跳过 1 个字节的数据并继续从输入流中的下一个字节进行反汇编。 在这种情况下,实际上 Capstone 将跳过数据视为指令 ID 为零的特殊指令,助记符为“.byte”,操作数字符串为其跳过的字节序列的十六进制代码。
2.3 改变助记符例程
如上所述,Capstone 认为数据将被跳过具有默认助记符“.byte”的指令。 要更改此助记符,请使用带有 CS_OPT_SKIPDATA_SETUP 的 cs_option(),如下所示:
csh handle;
cs_open(CS_ARCH_X86, CS_MODE_32, &handle);
cs_opt_skipdata skipdata =
.mnemonic = "db",
;
// customize SKIPDATA mode
cs_option(handle, CS_OPT_SKIPDATA_SETUP, &skipdata);
// Turn on SKIPDATA mode
cs_option(handle, CS_OPT_SKIPDATA, CS_OPT_ON);
/* Capstone Disassembler Engine */
#include <stdio.h>
#include <stdlib.h>
#include <capstone/platform.h>
#include <capstone/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 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 =
// rename default "data" instruction from ".byte" to "db"
"db",
;
struct platform platforms[] =
CS_ARCH_X86,
CS_MODE_64,
(unsigned char*)RANDOM_CODE,
sizeof(RANDOM_CODE) - 1,
"X86 64 (Intel syntax) - Skip data",
,
CS_ARCH_X86,
CS_MODE_64,
(unsigned char*)RANDOM_CODE,
sizeof(RANDOM_CODE) - 1,
"X86 64 (Intel syntax) - Skip data with custom mnemonic",
CS_OPT_INVALID,
CS_OPT_OFF,
CS_OPT_SKIPDATA_SETUP,
(以上是关于Capstone反汇编的主要内容,如果未能解决你的问题,请参考以下文章
Android 逆向使用 Python 解析 ELF 文件 ( Capstone 反汇编 ELF 文件中的机器码数据 | 反汇编二进制机器码 | 打印反汇编数据 )
在 Python 中读取二进制文件 (.out) 并使用 Capstone 进行反汇编
Android 逆向使用 Python 解析 ELF 文件 ( Capstone 反汇编 ELF 文件中的机器码数据 | 完整代码示例 ) ★★★