Capstone反汇编(二)

王柳  金牌会员 | 2022-6-23 20:11:26 | 显示全部楼层 | 阅读模式
打印 上一主题 下一主题

主题 650|帖子 650|积分 1950

文章目录




前言

Capstone反汇编(一)
上篇文章只是简单分析了官方给出的一个案例用到的API,接下来分析其它的API和数据结构
一 cs_option API 分析

1.1 cs_option

反编译引擎的运行时选项
  1. cs_option(csh ud, cs_opt_type type, size_t value)
复制代码
1.2 cs_opt_type

type是cs_option函数的第二个参数,是反汇编引擎运行时枚举选项
  1. // 反汇编引擎的运行时选项
  2. typedef enum cs_opt_type {
  3.         CS_OPT_INVALID = 0,        // <未指定选项
  4.         CS_OPT_SYNTAX,        // 汇编输出语法
  5.         CS_OPT_DETAIL,        // 将指令结构分解为细节
  6.         CS_OPT_MODE,        // 在运行时更改引擎的模式
  7.         CS_OPT_MEM,        // 用户自定义动态内存相关函数
  8.         CS_OPT_SKIPDATA, // 反汇编时跳过数据,然后引擎处于 SKIPDATA 模式。
  9.         CS_OPT_SKIPDATA_SETUP, // 为 SKIPDATA 选项设置用户自定义函数
  10.         CS_OPT_MNEMONIC, // 自定义指令助记符
  11.         CS_OPT_UNSIGNED, // 以无符号形式打印立即操作数
  12. } cs_opt_type;
复制代码
看一下结果反汇编出来的语法变成了AT&T语法

其中:
  1. /// Runtime option value (associated with option type above)
  2. typedef enum cs_opt_value {
  3.         CS_OPT_OFF = 0,  ///< Turn OFF an option - default for CS_OPT_DETAIL, CS_OPT_SKIPDATA, CS_OPT_UNSIGNED.
  4.         CS_OPT_ON = 3, ///< Turn ON an option (CS_OPT_DETAIL, CS_OPT_SKIPDATA).
  5.         CS_OPT_SYNTAX_DEFAULT = 0, ///< Default asm syntax (CS_OPT_SYNTAX).
  6.         CS_OPT_SYNTAX_INTEL, ///< X86 Intel asm syntax - default on X86 (CS_OPT_SYNTAX).
  7.         CS_OPT_SYNTAX_ATT,   ///< X86 ATT asm syntax (CS_OPT_SYNTAX).
  8.         CS_OPT_SYNTAX_NOREGNAME, ///< Prints register name with only number (CS_OPT_SYNTAX)
  9.         CS_OPT_SYNTAX_MASM, ///< X86 Intel Masm syntax (CS_OPT_SYNTAX).
  10.         CS_OPT_SYNTAX_MOTOROLA, ///< MOS65XX use $ as hex prefix
  11. } cs_opt_value;
复制代码
  1.   // 以AT&T语法显示
  2.   cs_option(handle, CS_OPT_SYNTAX, CS_OPT_SYNTAX_ATT);  
复制代码
二、 SKIPDATA mode

默认情况下,Capstone 在遇到 a broken instruction 时会停止反汇编,大多数时候,原因是这是输入中混合的数据,Capstone 不理解这个“weird” code。
通常,建议您确定下一个代码在哪里,然后从该位置继续反汇编。 但是,在某些情况下,您只想让 Capstone 自动跳过一些数据,直到找到合法指令,然后从那里继续。 因此,为此目的引入了 SKIPDATA 模式。
简单点来说就是当输入的二进制代码中有不合法的指令,Capstone遇到这个不合法指令便会停止反汇编,不会继续反汇编后面的数据,所以引入了SKIPDATA 模式,跳过这些不合法的指令,并用一个助记符替代,然后继续反汇编后面的数据。
2.1 数据结构

cs_opt_skipdata
  1. #include <stdio.h>
  2. #include <string.h>
  3. #include <inttypes.h>
  4. #include <capstone/capstone.h>
  5. #define CODE "\x55\x48\x8b\x05\xb8\x13\x00\x00"
  6. static void print_string_hex(unsigned char *str, size_t len)
  7. {
  8.         unsigned char *c;
  9.         printf("Code: ");
  10.         for (c = str; c < str + len; c++) {
  11.                 printf("0x%02x ", *c & 0xff);
  12.         }
  13.         printf("\n");
  14. }
  15. int main(void)
  16. {
  17.         csh handle;
  18.         cs_insn *insn;
  19.         size_t count;
  20.         if (cs_open(CS_ARCH_X86, CS_MODE_64, &handle) != CS_ERR_OK)
  21.                 return -1;
  22.             // 以AT&T语法显示
  23.     cs_option(handle, CS_OPT_SYNTAX, CS_OPT_SYNTAX_ATT);
  24.         print_string_hex(CODE, strlen(CODE));
  25.         printf("Disasm:\n");
  26.         count = cs_disasm(handle, CODE, sizeof(CODE)-1, 0x1000, 0, &insn);
  27.         if (count > 0) {
  28.                 size_t j;
  29.                 for (j = 0; j < count; j++) {
  30.                         printf("0x%"PRIx64":\t%s\t\t%s  : ", insn[j].address, insn[j].mnemonic,
  31.                                         insn[j].op_str);
  32.                         for(int i = 0 ; i < insn[j].size; i++)
  33.                         {
  34.                                 printf("0x%02x ", insn[j].bytes[i]);
  35.                         }
  36.                         printf("\n");
  37.                 }
  38.                 cs_free(insn, count);
  39.         } else
  40.                 printf("ERROR: Failed to disassemble given code!\n");
  41.         cs_close(&handle);
  42.     return 0;
  43. }
复制代码
(2)cs_skipdata_cb_t
  1. insn[j].bytes[i]是指令的机器码,即对应的二进制
  2. insn[j].size是该机器指令的长度
复制代码
(3)打开 SKIPDATA mode
要让Capstone跳过一些(未知的)数据量,直到下一个合法指令,只需使用cs_option()打开选项CS_OPT_SKIPDATA(默认关闭),如下所示:
  1. for(int i = 0 ; i < insn[j].size; i++)
  2. {
  3.         printf("0x%02x ", insn[j].bytes[i]);
  4. }
复制代码
2.2 例程演示

例程采用官方的例程:
使用SKIPDATA mode 之前:
  1. //用户自定义设置 SKIPDATA 选项
  2. typedef struct cs_opt_skipdata {
  3.         // Capstone 将要跳过的数据视为特殊的“指令”
  4.         // 用户可以在这里为该指令的“助记符”指定字符串。
  5.         // 默认情况下(如果 @mnemonic 为 NULL),Capstone 使用“.byte”。
  6.         const char *mnemonic;
  7.         // Capstone hits 数据时调用的用户自定义回调函数
  8.         // 如果此回调的返回值为正数 (>0), Capstone 将准确跳过该字节数并继续
  9.         // 否则,如果回调返回 0,Capstone 停止反汇编并立即从 cs_disasm() 返回
  10.         // 注意:如果此回调指针为 NULL,Capstone 将根据体系结构跳过一些字节,如下所示:
  11.         /// Arm:     2 bytes (Thumb mode) or 4 bytes.
  12.         /// Arm64:   4 bytes.
  13.         /// Mips:    4 bytes.
  14.         /// M680x:   1 byte.
  15.         /// PowerPC: 4 bytes.
  16.         /// Sparc:   4 bytes.
  17.         /// SystemZ: 2 bytes.
  18.         /// X86:     1 bytes.
  19.         /// XCore:   2 bytes.
  20.         /// EVM:     1 bytes.
  21.         /// RISCV:   4 bytes.
  22.         /// WASM:    1 bytes.
  23.         /// MOS65XX: 1 bytes.
  24.         /// BPF:     8 bytes.
  25.         cs_skipdata_cb_t callback;         // default value is NULL
  26.         // 用户自定义数据将被传递给callback函数指针
  27.         void *user_data;
  28. } cs_opt_skipdata;
复制代码

Capstone 在遇到 a broken instruction 时会停止反汇编了。
使用SKIPDATA mode 之后:
  1. /**
  2.         SKIPDATA 选项的用户定义回调函数
  3. @code: 包含要反汇编的代码的输入缓冲区。
  4.         这与传递给 cs_disasm() 的缓冲区相同。
  5. @code_size: 上述 code 缓冲区的大小(以字节为单位)。
  6. @offset: 当前检查字节在上述输入缓冲区 code 中的位置。
  7. @user_data: 用户数据通过 cs_opt_skipdata 结构中的 user_data 字段传递给 cs_option()。
  8. @return: 返回要跳过的字节数,或 0 立即停止反汇编。
  9. */
  10. typedef size_t (CAPSTONE_API *cs_skipdata_cb_t)(const uint8_t *code, size_t code_size, size_t offset, void *user_data);
复制代码
Capstone 在遇到 a broken instruction 时,自动跳过一些数据,用.byte代替,直到找到合法指令,然后从那里继续反汇编。
Capstone 跳过 1 个字节的数据并继续从输入流中的下一个字节进行反汇编。 在这种情况下,实际上 Capstone 将跳过数据视为指令 ID 为零的特殊指令,助记符为“.byte”,操作数字符串为其跳过的字节序列的十六进制代码。

2.3 改变助记符例程

如上所述,Capstone 认为数据将被跳过具有默认助记符“.byte”的指令。 要更改此助记符,请使用带有 CS_OPT_SKIPDATA_SETUP 的 cs_option(),如下所示:
  1. csh handle;
  2. cs_open(CS_ARCH_X86, CS_MODE_64, &handle);
  3. // turn on SKIPDATA mode
  4. cs_option(handle, CS_OPT_SKIPDATA, CS_OPT_ON);
复制代码
  1. /* Capstone Disassembler Engine */
  2. #include <stdio.h>
  3. #include <stdlib.h>
  4. #include <capstone/platform.h>
  5. #include <capstone/capstone.h>
  6. struct platform {
  7.         cs_arch arch;
  8.         cs_mode mode;
  9.         unsigned char *code;
  10.         size_t size;
  11.         const char *comment;
  12.         cs_opt_type opt_type;
  13.         cs_opt_value opt_value;
  14.         cs_opt_type opt_skipdata;
  15.         size_t skipdata;
  16. };
  17. static void print_string_hex(unsigned char *str, size_t len)
  18. {
  19.         unsigned char *c;
  20.         printf("Code: ");
  21.         for (c = str; c < str + len; c++) {
  22.                 printf("0x%02x ", *c & 0xff);
  23.         }
  24.         printf("\n");
  25. }
  26. static void test()
  27. {
  28. #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"
  29.         struct platform platforms[] = {
  30.                 {
  31.                         CS_ARCH_X86,
  32.                         CS_MODE_64,
  33.                         (unsigned char*)RANDOM_CODE,
  34.                         sizeof(RANDOM_CODE) - 1,
  35.                 },
  36.         };
  37.         csh handle;
  38.         uint64_t address = 0x1000;
  39.         cs_insn *insn;
  40.         cs_err err;
  41.         int i;
  42.         size_t count;
  43.         for (i = 0; i < sizeof(platforms)/sizeof(platforms[0]); i++) {
  44.                 err = cs_open(platforms[i].arch, platforms[i].mode, &handle);
  45.                 if (err) {
  46.                         printf("Failed on cs_open() with error returned: %u\n", err);
  47.                         abort();
  48.                 }
  49.                 if (platforms[i].opt_type)
  50.                         cs_option(handle, platforms[i].opt_type, platforms[i].opt_value);
  51.                 count = cs_disasm(handle, platforms[i].code, platforms[i].size, address, 0, &insn);
  52.                 if (count) {
  53.                         size_t j;
  54.                         print_string_hex(platforms[i].code, platforms[i].size);
  55.                         printf("Disasm:\n");
  56.                         for (j = 0; j < count; j++) {
  57.                                 printf("0x%" PRIx64 ":\t%s\t\t%s\n",
  58.                                                 insn[j].address, insn[j].mnemonic, insn[j].op_str);
  59.                         }
  60.                         // print out the next offset, after the last insn
  61.                         printf("0x%" PRIx64 ":\n", insn[j-1].address + insn[j-1].size);
  62.                         // free memory allocated by cs_disasm()
  63.                         cs_free(insn, count);
  64.                 } else {
  65.                         printf("****************\n");
  66.                         print_string_hex(platforms[i].code, platforms[i].size);
  67.                         printf("ERROR: Failed to disasm given code!\n");
  68.                         abort();
  69.                 }
  70.                 printf("\n");
  71.                 cs_close(&handle);
  72.         }
  73. }
  74. int main()
  75. {
  76.         test();
  77.         return 0;
  78. }
复制代码

从结果可以看到助记符由.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

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

王柳

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表