如何使用Capstone在反汇编代码同一行打印完整原始二进制操作码
如何使用Capstone在反汇编代码同一行打印完整原始二进制操作码
问题根源分析
你当前的代码只打印了指令操作码的第一个字节,核心原因是:你在DbgPrint里直接引用了insn[j].bytes[0]——这只是cs_insn结构体中存储指令字节数组的第一个元素。而x86指令的长度是可变的(从1到15字节不等),Capstone会把当前指令的完整长度存在insn[j].size成员里,你需要利用这个值遍历整个bytes数组才能打印出完整的原始操作码。
解决方案:遍历完整的指令字节数组
下面提供两种实用的修改方案,你可以根据需求选择:
方案1:直接循环打印每个字节
这种方式最直接,无需额外缓冲区,在输出地址后,循环遍历当前指令的所有字节并逐个打印:
if (count > 0) { for (size_t j = 0; j < count; j++) { // 先打印指令地址 DbgPrint("0x%p\t", (void*)(uintptr_t)insn[j].address); // 遍历当前指令的所有字节,以两位十六进制格式打印 for (size_t k = 0; k < insn[j].size; k++) { DbgPrint("%02x", insn[j].bytes[k]); } // 最后打印助记符和操作数 DbgPrint("\t%s\t\t%s\n", insn[j].mnemonic, insn[j].op_str); } cs_free(insn, count); }
方案2:先拼接成格式化字符串再打印(更整洁)
如果想要操作码部分的格式更统一(比如对齐输出),可以先把所有字节拼接成一个连续的十六进制字符串,再一次性输出:
if (count > 0) { for (size_t j = 0; j < count; j++) { char opcode_buf[32] = {0}; // x86最长指令为15字节,15*2=30字符,预留足够空间 // 拼接所有指令字节到缓冲区 for (size_t k = 0; k < insn[j].size; k++) { snprintf(opcode_buf + (k * 2), sizeof(opcode_buf) - (k * 2), "%02x", insn[j].bytes[k]); } // 一次性输出完整的反汇编行 DbgPrint("0x%p\t%s\t%s\t\t%s\n", (void*)(uintptr_t)insn[j].address, opcode_buf, insn[j].mnemonic, insn[j].op_str ); } cs_free(insn, count); }
效果验证
以你提到的指令push qword ptr [rbp + 8]为例,假设它的原始操作码是08 75 ff(长度3字节),修改后的代码会输出:
0x0000000000391334 0875ff push qword ptr [rbp + 8]
完全匹配你期望的完整操作码输出效果。
关键注意事项
- 必须依赖
insn[j].size:不要硬编码遍历的字节数,不同x86指令的长度差异极大,size成员是Capstone提供的准确指令长度标识。 - 缓冲区大小预留:方案2中的
opcode_buf要足够容纳最长x86指令的十六进制字符串(15字节需要30个字符,加上终止符,32字节完全足够)。
内容来源于stack exchange
相关产品推荐
相关产品推荐

