首页
社区
课程
招聘
[原创]capstone学习: 反汇编器如何实现的
发表于: 2025-11-17 13:47 6599

[原创]capstone学习: 反汇编器如何实现的

2025-11-17 13:47
6599

编译

让 ai 写个例子运行(capstone 中的 tests 不太容易跟):

编译运行这个例子看看:

输出

完美.

让我们从这个代码中的 cs_disasm 开始看, 前面的一些初始化的代码跳过:

核心流程概括一下就是: 初始化各种变量, 缓存, 架构信息等; 循环调用 handle->disasm 方法解码; 处理好缓存, 缓存扩容以及资源释放等. 我们继续跟入 handle->disasm:

可以看到各个架构都有实现, 我们只看 arm64 也就是 arch/AArch64/AArch64Module.c 中的:

跟入 AArch64_getInstruction:

跟入 getInstruction, 来到了 arch/AArch64/AArch64Disassembler.c 中:

首先要看看 const uint8_t *Tables[] = { DecoderTable32, DecoderTableFallback32 }; 这两个表:


一个非常长的文件, 其实还是 c 代码, 看注释像是状态转移表.

接着去看 decodeInstruction_4 如何来的, 跟进去发现:

, DecodeInstruction(decodeInstruction_4, fieldFromInstruction_4, decodeToMCInst_4, uint32_t) 这行定义了 decodeInstruction_4, 找到 DecodeInstruction 是一个宏:

实际上是在定义一个函数, 函数名就是传进来的第一个参数, 在看这个函数, 一个 while 大循环, 里面一些 case, 还定义了一个 DecodeStatus S = MCDisassembler_Success; 看着就是一个状态机.

其中 decodeULEB128:

将 ULEB128 编码的二进制数据转换为 64 位无符号整数, ULEB128 编码特点: 1. 小端序存储; 2. 每个字节最高位(bit7)为"延续位"(1=后续还有字节, 0=结束); 3. 低7位存储有效数据.

函数第一个参数 DecodeTable 就是上边那个表, 表中每一个宏(类似 MCD_OPC_SoftFail)都对应一个 case, 有相应的处理. 为了完全搞清楚这个函数, 我们还要在看看 fieldnamedecoder, 回到:

这个函数就是 decodeInstruction_4 中的 fieldname.

发现与 DecodeInstruction 类似, 都是在定义一个函数, 函数名都是宏第一个参数. 这个函数的功能很简单, 就是通过位运算精准提取指令中的指定位段.

这个太长我就不贴全了, 这个函数就是 decodeInstruction_4 中的 decoder.

看着是在反汇编每条指令, 首先看下 Check:

将两个结果取 &, 看看是否失败. 其中 Out 传进来的 S, 即以往的状态, In 是本次解码的状态.

再跟入这些解码函数看一看:

再看 AArch64MCRegisterClasses:

又是一个大表, 存了一些这样的数组:

又找了一下 MCRegisterClass:

总结一下就是通过传进来的 RegNo 作为查表获取的字节数组的索引, 找到 Register, 对应了 MCInst 具体寄存器枚举, 跟入 MCOperand_CreateReg0:

那么 Operand 有了, Opcode 呢, 回到 DecodeInstruction, 找到 S = decoder(S, DecodeIdx, insn, MI, Address, Decoder, &DecodeComplete); 也就是 decoder 调用的地方:

发现它上边就有 MCInst_setOpcode(MI, Opc);, 已经在表中取出来了, 然后在根据 DecodeIdx 去填充寄存器.

现在举例说明一下这个状态机的运行过程, 蛋疼的是这个文件不能调试

只能静态脑补一下了, 拿这个举例 0x8B, 0x02, 0x40, 0xF9, // ldr x11, [x0],

可以看到 capstone 是一个线性反汇编器而非递归下降反汇编器!

git clone git@github.com:capstone-engine/capstone.git
cmake -B build -DCMAKE_BUILD_TYPE=Debug -DCMAKE_EXPORT_COMPILE_COMMANDS=ON
cmake --build build
sudo cmake --install build --prefix "/usr/local"
git clone git@github.com:capstone-engine/capstone.git
cmake -B build -DCMAKE_BUILD_TYPE=Debug -DCMAKE_EXPORT_COMPILE_COMMANDS=ON
cmake --build build
sudo cmake --install build --prefix "/usr/local"
#include "capstone/aarch64.h"
#include <iostream>
#include <cstdint>
#include <capstone/capstone.h>
 
// AARCH64 测试指令
// 包含常见指令: MOV, ADD, SUB, LDR, STR, BR, CMP, B.eq 等
const uint8_t arm64_code[] = {
  0x8B, 0x02, 0x40, 0xF9,       // ldr x11, [x0]        ; 从 x0 指向的地址加载数据到 x11
  0x20, 0x08, 0x40, 0xF9,       // ldr x0, [x1, #0x20]  ; 从 x1+0x20 地址加载数据到 x0
  0x00, 0x00, 0x00, 0x91,     // add x0, x0, #0x0     ; x0 = x0 + 0(空操作, 演示格式)
  0x01, 0x00, 0x00, 0x91,   // add x1, x0, #0x0     ; x1 = x0 + 0
  0x02, 0x20, 0x40, 0xF9,   // ldr x2, [x1]         ; 从 x1 指向地址加载数据到 x2
  0x03, 0x30, 0x00, 0xB9,   // str w3, [x2, #0x8]   ; 将 w3 低32位数据存储到 x2+0x8 地址
  0x04, 0x00, 0x00, 0x54,   // cmp x0, x4           ; 比较 x0 和 x4
  0x00, 0x00, 0x00, 0x54,   // cmp x0, x0           ; 比较 x0 和 x0(结果为相等)
  0x00, 0x00, 0x00, 0x58,   // ldr x0, [x0]         ; 从 x0 指向地址加载数据到 x0
  0x00, 0x00, 0x1F, 0xD6    // br x0                ; 跳转到 x0 指向的地址
};
 
// 错误处理辅助函数
void print_error(const char* msg, cs_err err) {
  std::cerr << "[ERROR] " << msg << ": " << cs_strerror(err) << std::endl;
}
 
int main() {
  csh handle;          // Capstone 句柄
  cs_insn* insns = nullptr;  // 存储反汇编结果的指令数组
  size_t count;        // 反汇编出的指令数量
 
  // 1. 初始化 Capstone 引擎: 架构为 AARCH64, 模式为小端序(默认)
  cs_err err = cs_open(CS_ARCH_AARCH64, CS_MODE_LITTLE_ENDIAN, &handle);
  if (err != CS_ERR_OK) {
    print_error("cs_open failed", err);
    return 1;
  }
 
  // 2. 可选配置: 启用详细指令信息(如寄存器操作数, 立即数等)
  cs_option(handle, CS_OPT_DETAIL, CS_OPT_ON);
 
  // 3. 执行反汇编
  // 参数: 句柄, 指令缓冲区, 缓冲区长度, 起始地址(用于指令地址显示), 反汇编条数(0 表示全部)
  count = cs_disasm(handle, arm64_code, sizeof(arm64_code), 0x1000, 0, &insns);
 
  if (count == 0) {
    print_error("cs_disasm failed", cs_errno(handle));
    cs_close(&handle);
    return 1;
  }
 
  // 4. 打印反汇编结果
  std::cout << "=== AARCH64 反汇编结果 ===" << std::endl;
  std::cout << "地址\t\t机器码\t\t指令" << std::endl;
  std::cout << "----------------------------------------" << std::endl;
 
  for (size_t i = 0; i < count; ++i) {
    cs_insn* ins = &insns[i];
 
    // 打印地址(十六进制)
    std::printf("0x%lx\t", ins->address);
 
    // 打印机器码(2 位一组, 空格分隔)
    for (size_t j = 0; j < ins->size; ++j) {
      std::printf("%02x ", ins->bytes[j]);
    }
 
    // 补齐机器码字段(对齐显示)
    if (ins->size < 4) {
      std::printf("\t");
    }
    if (ins->size < 8) {
      std::printf("\t");
    }
 
    // 打印指令助记符 + 操作数
    std::printf("%s\t%s\n", ins->mnemonic, ins->op_str);
 
    // (可选)打印详细信息(如操作数类型, 寄存器等)
    if (ins->detail != nullptr) {
      cs_aarch64* arm64 = &ins->detail->aarch64;
      std::printf("\t\t\t操作数数量: %u\n", arm64->op_count);
 
      // 遍历每个操作数
      for (size_t j = 0; j < arm64->op_count; ++j) {
        cs_aarch64_op* op = &arm64->operands[j];
        std::printf("\t\t\t操作数 %lu: ", j + 1);
 
        switch (op->type) {
          case AARCH64_OP_REG:  // 寄存器操作数
            std::printf("寄存器 (x%u/w%u)",
            op->reg - AARCH64_REG_X0,  // 转换为 x0/x1... 格式
            op->reg - AARCH64_REG_W0); // 转换为 w0/w1... 格式
            break;
          case AARCH64_OP_IMM:  // 立即数操作数
            std::printf("立即数 0x%lx", op->imm);
            break;
          case AARCH64_OP_MEM:  // 内存操作数(如 [x0], [x1, #0x20])
            std::printf("内存 [x%u", op->mem.base - AARCH64_REG_X0);
            if (op->mem.disp != 0) {
              std::printf(", #0x%x", op->mem.disp);
            }
            std::printf("]");
            break;
          default:
            std::printf("未知类型");
            break;
        }
        std::printf("\n");
      }
      std::printf("\n");
    }
  }
 
  // 5. 释放资源(必须调用, 避免内存泄漏)
  cs_free(insns, count);
  cs_close(&handle);
 
  return 0;
}
#include "capstone/aarch64.h"
#include <iostream>
#include <cstdint>
#include <capstone/capstone.h>
 
// AARCH64 测试指令
// 包含常见指令: MOV, ADD, SUB, LDR, STR, BR, CMP, B.eq 等
const uint8_t arm64_code[] = {
  0x8B, 0x02, 0x40, 0xF9,       // ldr x11, [x0]        ; 从 x0 指向的地址加载数据到 x11
  0x20, 0x08, 0x40, 0xF9,       // ldr x0, [x1, #0x20]  ; 从 x1+0x20 地址加载数据到 x0
  0x00, 0x00, 0x00, 0x91,     // add x0, x0, #0x0     ; x0 = x0 + 0(空操作, 演示格式)
  0x01, 0x00, 0x00, 0x91,   // add x1, x0, #0x0     ; x1 = x0 + 0
  0x02, 0x20, 0x40, 0xF9,   // ldr x2, [x1]         ; 从 x1 指向地址加载数据到 x2
  0x03, 0x30, 0x00, 0xB9,   // str w3, [x2, #0x8]   ; 将 w3 低32位数据存储到 x2+0x8 地址
  0x04, 0x00, 0x00, 0x54,   // cmp x0, x4           ; 比较 x0 和 x4
  0x00, 0x00, 0x00, 0x54,   // cmp x0, x0           ; 比较 x0 和 x0(结果为相等)
  0x00, 0x00, 0x00, 0x58,   // ldr x0, [x0]         ; 从 x0 指向地址加载数据到 x0
  0x00, 0x00, 0x1F, 0xD6    // br x0                ; 跳转到 x0 指向的地址
};
 
// 错误处理辅助函数
void print_error(const char* msg, cs_err err) {
  std::cerr << "[ERROR] " << msg << ": " << cs_strerror(err) << std::endl;
}
 
int main() {
  csh handle;          // Capstone 句柄
  cs_insn* insns = nullptr;  // 存储反汇编结果的指令数组
  size_t count;        // 反汇编出的指令数量
 
  // 1. 初始化 Capstone 引擎: 架构为 AARCH64, 模式为小端序(默认)
  cs_err err = cs_open(CS_ARCH_AARCH64, CS_MODE_LITTLE_ENDIAN, &handle);
  if (err != CS_ERR_OK) {
    print_error("cs_open failed", err);
    return 1;
  }
 
  // 2. 可选配置: 启用详细指令信息(如寄存器操作数, 立即数等)
  cs_option(handle, CS_OPT_DETAIL, CS_OPT_ON);
 
  // 3. 执行反汇编
  // 参数: 句柄, 指令缓冲区, 缓冲区长度, 起始地址(用于指令地址显示), 反汇编条数(0 表示全部)
  count = cs_disasm(handle, arm64_code, sizeof(arm64_code), 0x1000, 0, &insns);
 
  if (count == 0) {
    print_error("cs_disasm failed", cs_errno(handle));
    cs_close(&handle);
    return 1;
  }
 
  // 4. 打印反汇编结果
  std::cout << "=== AARCH64 反汇编结果 ===" << std::endl;
  std::cout << "地址\t\t机器码\t\t指令" << std::endl;
  std::cout << "----------------------------------------" << std::endl;
 
  for (size_t i = 0; i < count; ++i) {
    cs_insn* ins = &insns[i];
 
    // 打印地址(十六进制)
    std::printf("0x%lx\t", ins->address);
 
    // 打印机器码(2 位一组, 空格分隔)
    for (size_t j = 0; j < ins->size; ++j) {
      std::printf("%02x ", ins->bytes[j]);
    }
 
    // 补齐机器码字段(对齐显示)
    if (ins->size < 4) {
      std::printf("\t");
    }
    if (ins->size < 8) {
      std::printf("\t");
    }
 
    // 打印指令助记符 + 操作数
    std::printf("%s\t%s\n", ins->mnemonic, ins->op_str);
 
    // (可选)打印详细信息(如操作数类型, 寄存器等)
    if (ins->detail != nullptr) {
      cs_aarch64* arm64 = &ins->detail->aarch64;
      std::printf("\t\t\t操作数数量: %u\n", arm64->op_count);
 
      // 遍历每个操作数
      for (size_t j = 0; j < arm64->op_count; ++j) {
        cs_aarch64_op* op = &arm64->operands[j];
        std::printf("\t\t\t操作数 %lu: ", j + 1);
 
        switch (op->type) {
          case AARCH64_OP_REG:  // 寄存器操作数
            std::printf("寄存器 (x%u/w%u)",
            op->reg - AARCH64_REG_X0,  // 转换为 x0/x1... 格式
            op->reg - AARCH64_REG_W0); // 转换为 w0/w1... 格式
            break;
          case AARCH64_OP_IMM:  // 立即数操作数
            std::printf("立即数 0x%lx", op->imm);
            break;
          case AARCH64_OP_MEM:  // 内存操作数(如 [x0], [x1, #0x20])
            std::printf("内存 [x%u", op->mem.base - AARCH64_REG_X0);
            if (op->mem.disp != 0) {
              std::printf(", #0x%x", op->mem.disp);
            }
            std::printf("]");
            break;
          default:
            std::printf("未知类型");
            break;
        }
        std::printf("\n");
      }
      std::printf("\n");
    }
  }
 
  // 5. 释放资源(必须调用, 避免内存泄漏)
  cs_free(insns, count);
  cs_close(&handle);
 
  return 0;
}
touch 111.cpp
g++ 111.cpp -o 111 -lcapstone
./111
touch 111.cpp
g++ 111.cpp -o 111 -lcapstone
./111
=== AARCH64 反汇编结果 ===
地址            机器码          指令
----------------------------------------
0x1000  8b 02 40 f9     ldr     x11, [x20]
                        操作数数量: 2
                        操作数 1: 寄存器 (x11/w42)
                        操作数 2: 内存 [x20]
 
0x1004  20 08 40 f9     ldr     x0, [x1, #0x10]
                        操作数数量: 2
                        操作数 1: 寄存器 (x0/w31)
                        操作数 2: 内存 [x1, #0x10]
 
0x1008  00 00 00 91     add     x0, x0, #0
                        操作数数量: 3
                        操作数 1: 寄存器 (x0/w31)
                        操作数 2: 寄存器 (x0/w31)
                        操作数 3: 立即数 0x0
 
0x100c  01 00 00 91     add     x1, x0, #0
                        操作数数量: 3
                        操作数 1: 寄存器 (x1/w32)
                        操作数 2: 寄存器 (x0/w31)
                        操作数 3: 立即数 0x0
 
0x1010  02 20 40 f9     ldr     x2, [x0, #0x40]
                        操作数数量: 2
                        操作数 1: 寄存器 (x2/w33)
                        操作数 2: 内存 [x0, #0x40]
 
0x1014  03 30 00 b9     str     w3, [x0, #0x30]
                        操作数数量: 2
                        操作数 1: 寄存器 (x4294967268/w3)
                        操作数 2: 内存 [x0, #0x30]
 
0x1018  04 00 00 54     b.mi    0x1018
                        操作数数量: 1
                        操作数 1: 立即数 0x1018
 
0x101c  00 00 00 54     b.eq    0x101c
                        操作数数量: 1
                        操作数 1: 立即数 0x101c
 
0x1020  00 00 00 58     ldr     x0, 0x1020
                        操作数数量: 2
                        操作数 1: 寄存器 (x0/w31)
                        操作数 2: 内存 [x4294967058, #0x1020]
 
0x1024  00 00 1f d6     br      x0
                        操作数数量: 1
                        操作数 1: 寄存器 (x0/w31)
=== AARCH64 反汇编结果 ===
地址            机器码          指令
----------------------------------------
0x1000  8b 02 40 f9     ldr     x11, [x20]
                        操作数数量: 2
                        操作数 1: 寄存器 (x11/w42)
                        操作数 2: 内存 [x20]
 
0x1004  20 08 40 f9     ldr     x0, [x1, #0x10]
                        操作数数量: 2
                        操作数 1: 寄存器 (x0/w31)
                        操作数 2: 内存 [x1, #0x10]
 
0x1008  00 00 00 91     add     x0, x0, #0
                        操作数数量: 3
                        操作数 1: 寄存器 (x0/w31)
                        操作数 2: 寄存器 (x0/w31)
                        操作数 3: 立即数 0x0
 
0x100c  01 00 00 91     add     x1, x0, #0
                        操作数数量: 3
                        操作数 1: 寄存器 (x1/w32)
                        操作数 2: 寄存器 (x0/w31)
                        操作数 3: 立即数 0x0
 
0x1010  02 20 40 f9     ldr     x2, [x0, #0x40]
                        操作数数量: 2
                        操作数 1: 寄存器 (x2/w33)
                        操作数 2: 内存 [x0, #0x40]
 
0x1014  03 30 00 b9     str     w3, [x0, #0x30]
                        操作数数量: 2
                        操作数 1: 寄存器 (x4294967268/w3)
                        操作数 2: 内存 [x0, #0x30]
 
0x1018  04 00 00 54     b.mi    0x1018
                        操作数数量: 1
                        操作数 1: 立即数 0x1018
 
0x101c  00 00 00 54     b.eq    0x101c
                        操作数数量: 1
                        操作数 1: 立即数 0x101c
 
0x1020  00 00 00 58     ldr     x0, 0x1020
                        操作数数量: 2
                        操作数 1: 寄存器 (x0/w31)
                        操作数 2: 内存 [x4294967058, #0x1020]
 
0x1024  00 00 1f d6     br      x0
                        操作数数量: 1
                        操作数 1: 寄存器 (x0/w31)
CAPSTONE_EXPORT
size_t CAPSTONE_API cs_disasm(csh ud, const uint8_t *buffer, size_t size,
                  uint64_t offset, size_t count, cs_insn **insn)
{
    // 引擎句柄结构体(存储架构, 模式, 配置等核心信息)
    struct cs_struct *handle;
    // 机器指令结构体(Capstone 内部用于存储解码后的指令信息)
    MCInst mci;
    // 当前指令的长度(字节数, 如 ARM64 通常为 4)
    uint16_t insn_size;
    // c: 已成功反汇编的指令计数: i: 循环临时变量
    size_t c = 0, i;
    // f: 指令缓存(insn_cache)的下一个空闲位置索引
    unsigned int f = 0;
    // 指令缓存: 临时存储已解码的指令, 避免频繁内存分配
    cs_insn *insn_cache;
    // total: 最终输出的指令数组内存块: total_size: 该内存块总大小
    void *total = NULL;
    size_t total_size = 0;
    // r: 解码结果标记(true=解码成功, false=解码失败/数据跳过)
    bool r;
    // tmp: 内存重分配临时指针
    void *tmp;
    // skipdata_bytes: 需要跳过的无效数据长度(当遇到非指令二进制时)
    size_t skipdata_bytes;
    // 保存原始缓冲区信息(用于 SKIPDATA 功能: 跳过无效数据)
    uint64_t offset_org;
    size_t size_org;
    const uint8_t *buffer_org;
    // 指令缓存大小(默认 INSN_CACHE_SIZE, 通常为 64)
    unsigned int cache_size = INSN_CACHE_SIZE;
    // 下一条指令的偏移量(当前指令长度, 用于移动缓冲区指针)
    size_t next_offset;
 
    // 将句柄转换为内部结构体
    handle = (struct cs_struct *)(uintptr_t)ud;
    if (!handle) {
        return 0;
    }
 
    handle->errnum = CS_ERR_OK;
 
#ifdef CAPSTONE_USE_SYS_DYN_MEM
    if (count > 0 && count <= INSN_CACHE_SIZE)
        cache_size = (unsigned int)count;
#endif
 
    buffer_org = buffer;
    offset_org = offset;
    size_org = size;
 
    // 计算初始缓存总大小: 单个 cs_insn 结构体大小 × 缓存条数
    total_size = sizeof(cs_insn) * cache_size;
    // 分配缓存内存(cs_mem_calloc 是 Capstone 封装的 calloc, 自动初始化 0)
    total = cs_mem_calloc(sizeof(cs_insn), cache_size);
    if (total == NULL) {
        handle->errnum = CS_ERR_MEM;
        return 0;
    }
 
    insn_cache = total;
 
    while (size > 0) {
        MCInst_Init(&mci, handle->arch);
        mci.csh = handle;
 
        // 给内部指令结构体设置当前指令地址(相对跳转指令需要该地址计算目标)
        mci.address = offset;
 
        // 如果启用了详细信息模式(CS_OPT_DETAIL=ON), 为当前指令分配 detail 结构体内存
        if (handle->detail_opt) {
            insn_cache->detail = cs_mem_calloc(1, sizeof(cs_detail));
        } else {
            // 未启用详细模式, detail 指针设为 NULL
            insn_cache->detail = NULL;
        }
 
        // 保存非详细模式下的基础信息: 指令地址
        mci.flat_insn = insn_cache;
        mci.flat_insn->address = offset;
 
        // 精简模式(CAPSTONE_DIET): 清零助记符和操作数字符串(减少内存占用)
#ifdef CAPSTONE_DIET
        mci.flat_insn->mnemonic[0] = '\0';
        mci.flat_insn->op_str[0] = '\0';
#endif
 
        // 核心解码调用: 调用对应架构的解码函数
        // 参数说明:
        //   ud: 引擎句柄: buffer: 当前缓冲区指针: size: 剩余缓冲区长度
        //   &mci: 输出解码后的内部指令信息: &insn_size: 输出当前指令长度
        //   offset: 当前指令地址: handle->getinsn_info: 架构专属解码信息
        r = handle->disasm(ud, buffer, size, &mci, &insn_size, offset,
                   handle->getinsn_info);
 
        // 解码成功(r=true: 当前二进制是有效指令)
        if (r) {
            // 字符串流: 用于拼接助记符和操作数(如 "add x0, x1, #0x10")
            SStream ss;
            SStream_Init(&ss);
 
            // 记录当前指令的长度(如 ARM64 指令为 4 字节)
            mci.flat_insn->size = insn_size;
 
            // 将内部 opcode 映射为公开的指令 ID(如 ARM64_INS_ADD)
            handle->insn_id(handle, insn_cache, mci.Opcode);
 
            // 配置立即数显示格式(无符号/有符号)
            SStream_opt_unum(&ss, handle->imm_unsigned);
            // 调用架构专属的指令打印函数: 将 MCInst 转为可读字符串(助记符+操作数)
            handle->printer(&mci, &ss, handle->printer_info);
            // 填充 cs_insn 结构体: 复制字符串流到 mnemonic/op_str, 拷贝指令二进制字节
            fill_insn(handle, insn_cache, &ss, &mci,
                  handle->post_printer, buffer);
 
            // 特殊处理 X86 架构的伪指令: 调整指令 ID(如某些前缀指令的ID偏移)
            if (handle->arch == CS_ARCH_X86 &&
                insn_cache->id != X86_INS_VCMP)
                insn_cache->id += mci.popcode_adjust;
 
            // 下一条指令的偏移量 = 当前指令长度
            next_offset = insn_size;
        } else {
            // 解码失败(r=false: 当前二进制不是有效指令)
 
            // 如果启用了详细模式, 释放当前指令的 detail 内存(避免泄漏)
            if (handle->detail_opt) {
                cs_mem_free(insn_cache->detail);
            }
 
            // 检查是否启用 SKIPDATA 功能: 未启用 或 剩余数据不足跳过长度 → 退出循环
            if (!handle->skipdata || handle->skipdata_size > size)
                break;
 
            // 计算需要跳过的无效数据长度:
            // 1. 如果用户注册了自定义跳过回调函数, 调用回调获取长度
            if (handle->skipdata_setup.callback) {
                skipdata_bytes = handle->skipdata_setup.callback(
                    buffer_org, size_org,  // 原始缓冲区信息
                    (size_t)(offset - offset_org),  // 当前相对于原始缓冲区的偏移
                    handle->skipdata_setup.user_data);  // 用户自定义数据
 
                // 剩余数据不足跳过长度 → 退出
                if (skipdata_bytes > size)
                    break;
                // 回调返回 0 → 用户要求不跳过, 退出
                if (!skipdata_bytes)
                    break;
            } else {
                // 2. 未注册回调: 使用默认跳过长度(handle->skipdata_size)
                skipdata_bytes = handle->skipdata_size;
            }
 
            // 填充无效数据的指令结构体(标记为非有效指令)
            insn_cache->id = 0;  // 0 表示无效指令 ID
            insn_cache->address = offset;  // 记录无效数据的起始地址
            insn_cache->size = (uint16_t)skipdata_bytes;  // 跳过的字节数
            // 拷贝无效数据的二进制到指令结构体
            memcpy(insn_cache->bytes, buffer, skipdata_bytes);
 
            // 精简模式: 清零字符串
#ifdef CAPSTONE_DIET
            insn_cache->mnemonic[0] = '\0';
            insn_cache->op_str[0] = '\0';
#else
            // 非精简模式: 设置跳过数据的助记符(如 ".byte")和操作数(如 "0x12 0x34")
            strncpy(insn_cache->mnemonic,
                handle->skipdata_setup.mnemonic,
                sizeof(insn_cache->mnemonic) - 1);
            skipdata_opstr(insn_cache->op_str, buffer, skipdata_bytes);
#endif
            // 无效数据无详细信息, detail 设为 NULL
            insn_cache->detail = NULL;
 
            // 下一条指令的偏移量 = 跳过的无效数据长度
            next_offset = skipdata_bytes;
        }
 
        // 缓存中已填充一条指令, 移动缓存索引到下一个空闲位置
        f++;
 
        // 已解码指令数+1: 如果达到用户指定的最大条数, 退出循环
        c++;
        if (count > 0 && c == count)
            break;
 
        // 检查缓存是否已满: 需要扩容(按黄金比例 1.6 倍扩容)
        if (f == cache_size) {
            // 计算新缓存大小(原大小 × 8/5 = 1.6 倍, 平衡扩容效率和内存占用)
            cache_size = cache_size * 8 / 5;
            // 计算新的总内存大小
            total_size += (sizeof(cs_insn) * cache_size);
            // 内存重分配: 扩展总内存块
            tmp = cs_mem_realloc(total, total_size);
            // 重分配失败: 释放已分配资源, 返回错误
            if (tmp == NULL) {
                // 释放所有指令的 detail 内存(避免泄漏)
                if (handle->detail_opt) {
                    insn_cache = (cs_insn *)total;
                    for (i = 0; i < c; i++, insn_cache++)
                        cs_mem_free(insn_cache->detail);
                }
                // 释放总内存块
                cs_mem_free(total);
                *insn = NULL;
                handle->errnum = CS_ERR_MEM;
                return 0;
            }
 
            // 更新总内存块指针和缓存指针
            total = tmp;
            // 缓存指针指向已解码指令的下一个空闲位置(跳过已填充的 c 条指令)
            insn_cache = (cs_insn *)((char *)total + sizeof(cs_insn) * c);
            // 重置缓存索引(新缓存从 0 开始填充)
            f = 0;
        } else {
            // 缓存未填满: 移动缓存指针到下一个空闲位置
            insn_cache++;
        }
 
        // 移动缓冲区指针: 跳过当前已处理的字节(指令/无效数据)
        buffer += next_offset;
        size -= next_offset;
        // 更新下一条指令的地址(模拟内存地址递增)
        offset += next_offset;
    }
 
    // 如果未解码到任何指令: 释放总内存, 返回 0
    if (!c) {
        cs_mem_free(total);
        total = NULL;
    } else if (f != cache_size) {
        // 缓存未用完: 缩小内存块到实际需要的大小(减少内存浪费)
        tmp = cs_mem_realloc(total,
                     total_size - (cache_size - f) * sizeof(*insn_cache));
        // 重分配失败: 释放资源, 返回错误
        if (tmp == NULL) {
            if (handle->detail_opt) {
                insn_cache = (cs_insn *)total;
                for (i = 0; i < c; i++, insn_cache++)
                    cs_mem_free(insn_cache->detail);
            }
            cs_mem_free(total);
            *insn = NULL;
            handle->errnum = CS_ERR_MEM;
            return 0;
        }
        // 更新总内存块指针(指向缩小后的内存)
        total = tmp;
    }
 
    // 将最终的指令数组返回给调用者
    *insn = total;
 
    // 返回成功解码的指令数量
    return c;
}
CAPSTONE_EXPORT
size_t CAPSTONE_API cs_disasm(csh ud, const uint8_t *buffer, size_t size,
                  uint64_t offset, size_t count, cs_insn **insn)
{
    // 引擎句柄结构体(存储架构, 模式, 配置等核心信息)
    struct cs_struct *handle;
    // 机器指令结构体(Capstone 内部用于存储解码后的指令信息)
    MCInst mci;
    // 当前指令的长度(字节数, 如 ARM64 通常为 4)
    uint16_t insn_size;
    // c: 已成功反汇编的指令计数: i: 循环临时变量
    size_t c = 0, i;
    // f: 指令缓存(insn_cache)的下一个空闲位置索引
    unsigned int f = 0;
    // 指令缓存: 临时存储已解码的指令, 避免频繁内存分配
    cs_insn *insn_cache;
    // total: 最终输出的指令数组内存块: total_size: 该内存块总大小
    void *total = NULL;
    size_t total_size = 0;
    // r: 解码结果标记(true=解码成功, false=解码失败/数据跳过)
    bool r;
    // tmp: 内存重分配临时指针
    void *tmp;
    // skipdata_bytes: 需要跳过的无效数据长度(当遇到非指令二进制时)
    size_t skipdata_bytes;
    // 保存原始缓冲区信息(用于 SKIPDATA 功能: 跳过无效数据)
    uint64_t offset_org;
    size_t size_org;
    const uint8_t *buffer_org;
    // 指令缓存大小(默认 INSN_CACHE_SIZE, 通常为 64)
    unsigned int cache_size = INSN_CACHE_SIZE;
    // 下一条指令的偏移量(当前指令长度, 用于移动缓冲区指针)
    size_t next_offset;
 
    // 将句柄转换为内部结构体
    handle = (struct cs_struct *)(uintptr_t)ud;
    if (!handle) {
        return 0;
    }
 
    handle->errnum = CS_ERR_OK;
 
#ifdef CAPSTONE_USE_SYS_DYN_MEM
    if (count > 0 && count <= INSN_CACHE_SIZE)
        cache_size = (unsigned int)count;
#endif
 
    buffer_org = buffer;
    offset_org = offset;
    size_org = size;
 
    // 计算初始缓存总大小: 单个 cs_insn 结构体大小 × 缓存条数
    total_size = sizeof(cs_insn) * cache_size;
    // 分配缓存内存(cs_mem_calloc 是 Capstone 封装的 calloc, 自动初始化 0)
    total = cs_mem_calloc(sizeof(cs_insn), cache_size);
    if (total == NULL) {
        handle->errnum = CS_ERR_MEM;
        return 0;
    }
 
    insn_cache = total;
 
    while (size > 0) {
        MCInst_Init(&mci, handle->arch);
        mci.csh = handle;
 
        // 给内部指令结构体设置当前指令地址(相对跳转指令需要该地址计算目标)
        mci.address = offset;
 
        // 如果启用了详细信息模式(CS_OPT_DETAIL=ON), 为当前指令分配 detail 结构体内存
        if (handle->detail_opt) {
            insn_cache->detail = cs_mem_calloc(1, sizeof(cs_detail));
        } else {
            // 未启用详细模式, detail 指针设为 NULL
            insn_cache->detail = NULL;
        }
 
        // 保存非详细模式下的基础信息: 指令地址
        mci.flat_insn = insn_cache;
        mci.flat_insn->address = offset;
 
        // 精简模式(CAPSTONE_DIET): 清零助记符和操作数字符串(减少内存占用)
#ifdef CAPSTONE_DIET
        mci.flat_insn->mnemonic[0] = '\0';
        mci.flat_insn->op_str[0] = '\0';
#endif
 
        // 核心解码调用: 调用对应架构的解码函数
        // 参数说明:
        //   ud: 引擎句柄: buffer: 当前缓冲区指针: size: 剩余缓冲区长度
        //   &mci: 输出解码后的内部指令信息: &insn_size: 输出当前指令长度
        //   offset: 当前指令地址: handle->getinsn_info: 架构专属解码信息
        r = handle->disasm(ud, buffer, size, &mci, &insn_size, offset,
                   handle->getinsn_info);
 
        // 解码成功(r=true: 当前二进制是有效指令)
        if (r) {
            // 字符串流: 用于拼接助记符和操作数(如 "add x0, x1, #0x10")
            SStream ss;
            SStream_Init(&ss);
 
            // 记录当前指令的长度(如 ARM64 指令为 4 字节)
            mci.flat_insn->size = insn_size;
 
            // 将内部 opcode 映射为公开的指令 ID(如 ARM64_INS_ADD)
            handle->insn_id(handle, insn_cache, mci.Opcode);
 
            // 配置立即数显示格式(无符号/有符号)
            SStream_opt_unum(&ss, handle->imm_unsigned);
            // 调用架构专属的指令打印函数: 将 MCInst 转为可读字符串(助记符+操作数)
            handle->printer(&mci, &ss, handle->printer_info);
            // 填充 cs_insn 结构体: 复制字符串流到 mnemonic/op_str, 拷贝指令二进制字节
            fill_insn(handle, insn_cache, &ss, &mci,
                  handle->post_printer, buffer);
 
            // 特殊处理 X86 架构的伪指令: 调整指令 ID(如某些前缀指令的ID偏移)
            if (handle->arch == CS_ARCH_X86 &&
                insn_cache->id != X86_INS_VCMP)
                insn_cache->id += mci.popcode_adjust;
 
            // 下一条指令的偏移量 = 当前指令长度
            next_offset = insn_size;
        } else {
            // 解码失败(r=false: 当前二进制不是有效指令)
 
            // 如果启用了详细模式, 释放当前指令的 detail 内存(避免泄漏)
            if (handle->detail_opt) {
                cs_mem_free(insn_cache->detail);
            }
 
            // 检查是否启用 SKIPDATA 功能: 未启用 或 剩余数据不足跳过长度 → 退出循环
            if (!handle->skipdata || handle->skipdata_size > size)
                break;
 
            // 计算需要跳过的无效数据长度:
            // 1. 如果用户注册了自定义跳过回调函数, 调用回调获取长度
            if (handle->skipdata_setup.callback) {
                skipdata_bytes = handle->skipdata_setup.callback(
                    buffer_org, size_org,  // 原始缓冲区信息
                    (size_t)(offset - offset_org),  // 当前相对于原始缓冲区的偏移
                    handle->skipdata_setup.user_data);  // 用户自定义数据
 
                // 剩余数据不足跳过长度 → 退出
                if (skipdata_bytes > size)
                    break;
                // 回调返回 0 → 用户要求不跳过, 退出
                if (!skipdata_bytes)
                    break;
            } else {
                // 2. 未注册回调: 使用默认跳过长度(handle->skipdata_size)
                skipdata_bytes = handle->skipdata_size;
            }
 
            // 填充无效数据的指令结构体(标记为非有效指令)
            insn_cache->id = 0;  // 0 表示无效指令 ID
            insn_cache->address = offset;  // 记录无效数据的起始地址
            insn_cache->size = (uint16_t)skipdata_bytes;  // 跳过的字节数
            // 拷贝无效数据的二进制到指令结构体
            memcpy(insn_cache->bytes, buffer, skipdata_bytes);
 
            // 精简模式: 清零字符串
#ifdef CAPSTONE_DIET
            insn_cache->mnemonic[0] = '\0';
            insn_cache->op_str[0] = '\0';
#else
            // 非精简模式: 设置跳过数据的助记符(如 ".byte")和操作数(如 "0x12 0x34")
            strncpy(insn_cache->mnemonic,
                handle->skipdata_setup.mnemonic,
                sizeof(insn_cache->mnemonic) - 1);
            skipdata_opstr(insn_cache->op_str, buffer, skipdata_bytes);
#endif
            // 无效数据无详细信息, detail 设为 NULL
            insn_cache->detail = NULL;
 
            // 下一条指令的偏移量 = 跳过的无效数据长度
            next_offset = skipdata_bytes;
        }
 
        // 缓存中已填充一条指令, 移动缓存索引到下一个空闲位置
        f++;
 
        // 已解码指令数+1: 如果达到用户指定的最大条数, 退出循环
        c++;
        if (count > 0 && c == count)
            break;
 
        // 检查缓存是否已满: 需要扩容(按黄金比例 1.6 倍扩容)
        if (f == cache_size) {
            // 计算新缓存大小(原大小 × 8/5 = 1.6 倍, 平衡扩容效率和内存占用)
            cache_size = cache_size * 8 / 5;
            // 计算新的总内存大小
            total_size += (sizeof(cs_insn) * cache_size);
            // 内存重分配: 扩展总内存块
            tmp = cs_mem_realloc(total, total_size);
            // 重分配失败: 释放已分配资源, 返回错误
            if (tmp == NULL) {
                // 释放所有指令的 detail 内存(避免泄漏)
                if (handle->detail_opt) {
                    insn_cache = (cs_insn *)total;
                    for (i = 0; i < c; i++, insn_cache++)
                        cs_mem_free(insn_cache->detail);
                }
                // 释放总内存块
                cs_mem_free(total);
                *insn = NULL;
                handle->errnum = CS_ERR_MEM;
                return 0;
            }
 
            // 更新总内存块指针和缓存指针
            total = tmp;
            // 缓存指针指向已解码指令的下一个空闲位置(跳过已填充的 c 条指令)
            insn_cache = (cs_insn *)((char *)total + sizeof(cs_insn) * c);
            // 重置缓存索引(新缓存从 0 开始填充)
            f = 0;
        } else {
            // 缓存未填满: 移动缓存指针到下一个空闲位置
            insn_cache++;
        }
 
        // 移动缓冲区指针: 跳过当前已处理的字节(指令/无效数据)
        buffer += next_offset;
        size -= next_offset;
        // 更新下一条指令的地址(模拟内存地址递增)
        offset += next_offset;
    }
 
    // 如果未解码到任何指令: 释放总内存, 返回 0
    if (!c) {
        cs_mem_free(total);
        total = NULL;
    } else if (f != cache_size) {
        // 缓存未用完: 缩小内存块到实际需要的大小(减少内存浪费)
        tmp = cs_mem_realloc(total,
                     total_size - (cache_size - f) * sizeof(*insn_cache));
        // 重分配失败: 释放资源, 返回错误
        if (tmp == NULL) {
            if (handle->detail_opt) {
                insn_cache = (cs_insn *)total;
                for (i = 0; i < c; i++, insn_cache++)
                    cs_mem_free(insn_cache->detail);
            }
            cs_mem_free(total);
            *insn = NULL;
            handle->errnum = CS_ERR_MEM;
            return 0;
        }
        // 更新总内存块指针(指向缩小后的内存)
        total = tmp;
    }
 
    // 将最终的指令数组返回给调用者
    *insn = total;
 
    // 返回成功解码的指令数量
    return c;
}
cs_err AArch64_global_init(cs_struct *ud)
{
    MCRegisterInfo *mri;
    mri = cs_mem_malloc(sizeof(*mri));
 
    AArch64_init_mri(mri);
    ud->printer = AArch64_printer;
    ud->printer_info = mri;
    ud->getinsn_info = mri;
    ud->disasm = AArch64_getInstruction;
    ud->reg_name = AArch64_reg_name;
    ud->insn_id = AArch64_get_insn_id;
    ud->insn_name = AArch64_insn_name;
    ud->group_name = AArch64_group_name;
    ud->post_printer = NULL;
#ifndef CAPSTONE_DIET
    ud->reg_access = AArch64_reg_access;
#endif
 
    return CS_ERR_OK;
}
cs_err AArch64_global_init(cs_struct *ud)
{
    MCRegisterInfo *mri;
    mri = cs_mem_malloc(sizeof(*mri));
 
    AArch64_init_mri(mri);
    ud->printer = AArch64_printer;
    ud->printer_info = mri;
    ud->getinsn_info = mri;
    ud->disasm = AArch64_getInstruction;
    ud->reg_name = AArch64_reg_name;
    ud->insn_id = AArch64_get_insn_id;
    ud->insn_name = AArch64_insn_name;
    ud->group_name = AArch64_group_name;
    ud->post_printer = NULL;
#ifndef CAPSTONE_DIET
    ud->reg_access = AArch64_reg_access;
#endif
 
    return CS_ERR_OK;
}
bool AArch64_getInstruction(csh handle, const uint8_t *code, size_t code_len,
                MCInst *MI, uint16_t *size, uint64_t address,
                void *info)
{
    AArch64_init_cs_detail(MI);
    DecodeStatus Result = AArch64_LLVM_getInstruction(
        handle, code, code_len, MI, size, address, info);
    AArch64_set_instr_map_data(MI);
    if (Result == MCDisassembler_SoftFail) {
        MCInst_setSoftFail(MI);
    }
    return Result != MCDisassembler_Fail;
}
 
DecodeStatus AArch64_LLVM_getInstruction(csh handle, const uint8_t *Bytes,
                     size_t ByteLen, MCInst *MI,
                     uint16_t *Size, uint64_t Address,
                     void *Info)
{
    DecodeStatus Result = MCDisassembler_Fail;
    Result =
        getInstruction(handle, Bytes, ByteLen, MI, Size, Address, Info);
    MCInst_handleWriteback(MI, AArch64Descs.Insts,
                   ARR_SIZE(AArch64Descs.Insts));
    return Result;
}
bool AArch64_getInstruction(csh handle, const uint8_t *code, size_t code_len,
                MCInst *MI, uint16_t *size, uint64_t address,
                void *info)
{
    AArch64_init_cs_detail(MI);
    DecodeStatus Result = AArch64_LLVM_getInstruction(
        handle, code, code_len, MI, size, address, info);
    AArch64_set_instr_map_data(MI);
    if (Result == MCDisassembler_SoftFail) {
        MCInst_setSoftFail(MI);
    }
    return Result != MCDisassembler_Fail;
}
 
DecodeStatus AArch64_LLVM_getInstruction(csh handle, const uint8_t *Bytes,

[培训]Windows内核深度攻防:从Hook技术到Rootkit实战!

最后于 2025-11-18 09:27 被nothing233编辑 ,原因: 补充
收藏
免费 33
支持
分享
最新回复 (10)
雪    币: 2386
活跃值: (2981)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
666
2025-11-17 13:53
0
雪    币: 204
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
3
6666
2025-11-17 13:58
0
雪    币: 9
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
4
牛逼
2025-11-17 14:02
0
雪    币: 7
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
5
感谢分享
2025-11-17 19:33
0
雪    币: 429
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
7
学习学习
2025-11-18 13:57
0
雪    币: 0
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
8
666
2025-11-20 16:04
0
雪    币: 0
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
9
666
2025-11-21 10:37
0
雪    币: 33
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
10
太强啦
2025-12-5 20:16
0
雪    币: 5087
活跃值: (2690)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
11
666
2025-12-21 12:32
0
游客
登录 | 注册 方可回帖
返回