文章目录

  • 前言
  • 一 cs_option API 分析
    • 1.1 cs_option
    • 1.2 cs_opt_type
    • 1.3 cs_opt_value
    • 1.4 例程演示
  • 二、 SKIPDATA mode
    • 2.1 数据结构
    • 2.2 例程演示
    • 2.3 改变助记符例程
  • 总结
  • 参考资料

前言

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);} elseprintf("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 insnprintf("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 modecs_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 insnprintf("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,(size_t) &skipdata,},};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++) {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);// turn on SKIPDATA modecs_option(handle, CS_OPT_SKIPDATA, CS_OPT_ON);cs_option(handle, platforms[i].opt_skipdata, platforms[i].skipdata);// turn off SKIPDATA mode//cs_option(handle, CS_OPT_SKIPDATA, CS_OPT_OFF);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 insnprintf("0x%" PRIx64 ":\n", insn[j-1].address + insn[j-1].size);// free memory allocated by 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了。

总结

本文章主要讲解了cs_option函数和Capstone的SKIPDATA mode。

参考资料

https://xz.aliyun.com/t/5772
https://xz.aliyun.com/t/5753
http://www.capstone-engine.org/skipdata.html

Capstone反汇编(二)相关推荐

  1. 【Android 逆向】使用 Python 解析 ELF 文件 ( Capstone 反汇编 ELF 文件中的机器码数据 | 完整代码示例 ) ★★★

    文章目录 一.完整代码示例 二.执行结果 三.博客资源 一.完整代码示例 使用 Python 解析 ELF 文件完整代码示例 : # coding=utf-8 # 解析 elf 文件需要导入的依赖库 ...

  2. 【Android 逆向】使用 Python 解析 ELF 文件 ( Capstone 反汇编 ELF 文件中的机器码数据 | 创建反汇编解析器实例对象 | 设置汇编解析器显示细节 )

    文章目录 一.创建 Capstone 反汇编解析器实例对象 二.设置 Cs 汇编解析器显示细节 一.创建 Capstone 反汇编解析器实例对象 使用 Capstone 反汇编框架 , 首先创建 Ca ...

  3. 【Android 逆向】使用 Python 解析 ELF 文件 ( Capstone 反汇编框架 | PyCharm 中导入 Capstone 反汇编框架 )

    文章目录 一.Capstone 反汇编框架 二.PyCharm 中导入 Capstone 反汇编框架 一.Capstone 反汇编框架 Android 的 APK 安装文件中 , 可能存在若干 so ...

  4. Capstone反汇编(一)

    文章目录 前言 一.Capstone 简介 二.使用步骤 2.1 下载源码 2.2 编译源码 2.3 Linux安装Capstone 2.4 查看cstool工具 3.5 使用cstool工具 3.6 ...

  5. Linux capstone 反汇编引擎使用方法

    最进在研究反汇编引擎,在google看到capstone反汇编工具,据说是IDA都使用了capstone的引擎,记录一下: capstone 官方网站:http://www.capstone-engi ...

  6. 【Android 逆向】使用 Python 解析 ELF 文件 ( Capstone 反汇编 ELF 文件中的机器码数据 | 反汇编二进制机器码 | 打印反汇编数据 )

    文章目录 一.反汇编二进制机器码 二.打印反汇编数据 一.反汇编二进制机器码 在创建 Capstone 实例对象 , 并设置 detail 属性为 True ; 在之前读取了 节区 二进制数据 , 这 ...

  7. go语言反汇编linux,Go语言逆向去符号信息还原

    一.实例 在国内很多朋友都觉得golang的逆向分析很难,其实不然,和其他编程语言相比,go语言的函数太多.但是如果go语言不去符号话,则觉得和.net差不多难度(还是未混淆的).本文就是要解决gol ...

  8. 基于LLVM编译器的IDA自动结构体分析插件

    引用 这篇文章旨在介绍一款对基于LLVM的retdec开源反编译器工具进行二次开发的IDA自动结构体识别插件实现原理分析 文章目录 引用 简介 源码分析 LLVM编译器简介 Retdec源码分析 Kl ...

  9. LyScript 插件官方API调用案例

    本人结合LyScript插件API函数实现的一些通用案例,用于演示插件内置方法是如何灵活组合运用的,其目的是让用户可以自行研究学习API函数的参数传递,并能够通过案例的学习快速掌握官方API函数的使用 ...

最新文章

  1. 反对迭代0:停止拖延,开始迭代
  2. Python 基础(6)(常用数据结构)
  3. QuickStart系列:docker部署之MariaDB
  4. 【LeetCode笔记】剑指 Offer 16. 数值的整数次方(Java、分治)
  5. 黑马程序员--C语言基础之--sizeof()运算符的使用以及注意
  6. 图片圆角边框自适应宽高(深夜原创)
  7. IFC2x3标准阅读
  8. leetcode第26题:删除排序数组的重复项
  9. centos 6.5 安装 phpmyadmin
  10. windows 修改MySQL默认3306端口
  11. Qt实战案例(13)——Qt的界面外观详细介绍
  12. 腾讯云服务器带宽怎么计费?
  13. 冲击、碰撞试验测试技术——冲击传感器的校准
  14. Redis的复制(Master/Slaver)
  15. 导出pdf文件时加图片水印
  16. 在windows生成SSH秘钥连接linux远程主机
  17. matlab 群延迟,实现最小相位群延迟的音节切分算法的一些问题
  18. 全国计算机等级考试三级数据库技术(十四)
  19. 《软件测试---你必须掌握的100个问题》
  20. 2010 Esri中国区域用户大会9月14日开幕

热门文章

  1. 将pdf转换成jpg格式的两种方法
  2. Maplab:一个用于视觉惯性建图和定位研究的开源框架
  3. BeeWare 峰器 中文文档 - 教程 5 - 移动端:iOS
  4. WebGIS全栈修炼之路3——内视丹田Viewer
  5. vue中v-on支持的事件总结
  6. 申请美国访问学者邀请函,具体有哪些要求?
  7. 云服务器Windows系统+IIS搭建个人测试网站(纯新手)
  8. 居然嘲笑我们没有Excel的这个功能,呵呵
  9. python中easygui有几种_Python 模块EasyGui详细介绍(转载)
  10. hdu 5115 区间dp 狼BUFF