Capstone 是一款开源的反汇编框架,目前该引擎支持的CPU架构包括x86、x64、ARM、MIPS、POWERPC、SPARC等,Capstone 的特点是快速、轻量级、易于使用,它可以良好地处理各种类型的指令,支持将指令转换成AT&T汇编语法或Intel汇编语法等多种格式。Capstone的库可以集成到许多不同的应用程序和工具中,因此被广泛应用于反汇编、逆向工程、漏洞分析和入侵检测等领域,著名的比如IDA Pro、Ghidra、Hopper Disassembler等调试器都在使用该引擎。

读者可自行下载符合条件的版本,这里笔者选择的是capstone-4.0.2-win32版本,下载并解压这个版本,当读者解压后以后即可在项目中引用该引擎,Capstone引擎的配置非常容易,仅仅需要配置引用目录及库目录即可,配置完成如下图所示;

实现反汇编的第一步则是打开一个可执行文件,通常在引擎内可调用cs_open()函数实现打开,当打开成功时则该函数会返回一个句柄(handle)用来进行后续的反汇编操作,函数的原型通常如下:

cs_err cs_open
(
cs_arch arch,
cs_mode mode,
csh *handle
)

其中,各参数的含义如下:

  • arch:指定要打开的CPU架构,例如CS_ARCH_X86表示x86架构,CS_ARCH_ARM表示ARM架构等。
  • mode:指定CPU的模式,例如CS_MODE_32表示32位模式,CS_MODE_64表示64位模式等。
  • handle:一个指针,用于返回打开成功后的句柄handle。

如上所示,函数返回值为cs_err类型,表示函数执行的状态或错误码,它是一个枚举类型,当函数执行成功时返回的数值为CS_ERR_OK,其次函数的第一个参数是指定CPU架构为x86,第二个参数是指定模式为32位模式,最后一个参数用来返回(handle)句柄。

当一个进程被打开后,则下一步可以通过调用cs_disasm()函数来实现对打开文件的反汇编,cs_disasm函数是Capstone反汇编框架中的一个函数,用于对指定的二进制数据进行反汇编,返回解码后的指令信息。函数原型通常如下:

size_t cs_disasm
(
csh handle,
const uint8_t *code,
size_t code_size,
uint64_t address,
size_t count,
cs_insn *insn
);

其中,各参数的含义如下:

  • handle:反汇编器句柄,表示使用哪一个Capstone实例来执行反汇编操作。
  • code:待反汇编的二进制数据的指针,可以是一个地址。
  • code_size:待反汇编的数据的长度,以字节为单位。
  • address:指定待反汇编数据的地址,通常为起始地址。
  • count:指定要反汇编的指令数,如果为0,则会一直反汇编至遇到code_size终止。
  • insn:指向用于保存反汇编结果的cs_insn结构体对象指针,在函数调用结束后存储反汇编结果。

函数返回值为size_t类型,代表解码的指令数量。在cs_disasm()函数中,我们通过将待反汇编的数据以及其它必要的参数传递给该函数,然后使用cs_insn结构体对象来存储反汇编结果。通过该函数,我们可以获取指令的指令助记符、指令操作数、寻址模式、使用的寄存器等信息。

当读者理解了这两个API接口后,那么反汇编实现将变得很容易实现,我们来看一下官方针对反汇编实现的一种方式,我们自行封装一个DisassembleCode()函数,该函数传入机器码字符串以及该字符串的长度则会输出该字符串的反汇编代码片段,这段代码的实现如下所示;

#include <stdio.h>
#include <inttypes.h>
#include <capstone/capstone.h> #pragma comment(lib,"capstone32.lib") // 反汇编字符串
void DisassembleCode(char *start_offset, int size)
{
csh handle;
cs_insn *insn;
size_t count; char *buffer = "\x55\x8b\xec\x81\xec\x24\x03\x00\x00\x6a\x17\x90\x90\x90"; // 打开句柄
if (cs_open(CS_ARCH_X86, CS_MODE_32, &handle) != CS_ERR_OK)
{
return;
} // 反汇编代码,地址从0x1000开始,返回总条数
count = cs_disasm(handle, (unsigned char *)start_offset, size, 0x1000, 0, &insn); if (count > 0)
{
size_t index;
for (index = 0; index < count; index++)
{
for (int x = 0; x < insn[index].size; x++)
{
printf("机器码: %d -> %02X \n", x, insn[index].bytes[x]);
} printf("地址: 0x%"PRIx64" | 长度: %d 反汇编: %s %s \n", insn[index].address, insn[index].size, insn[index].mnemonic, insn[index].op_str);
} cs_free(insn, count);
}
else
{
printf("反汇编返回长度为空 \n");
} cs_close(&handle);
} int main(int argc, char *argv[])
{
char *buffer = "\x55\x8b\xec\x81\xec\x24\x03\x00\x00\x6a\x17\x90\x90\x90";
DisassembleCode(buffer, 14); system("pause");
return 0;
}

运行上述代码片段,则可看到如下图所示的输出效果;

上述代码虽然实现了反汇编但并无法保存结果,对于一个通用程序来说,我们当然是希望这写反汇编代码能够存储到一个特殊的容器内,当需要使用是可以随时调出来,此处我们通过定义一个MyStruct并将所需反汇编指令通过ptr.push_back(location)放入到一个全局容器内进行存储,当读者调用DisassembleCode(buffer, 14)函数是则会返回std::vector<MyStruct> ptr,并在主函数内通过循环输出这个容器,改进后的代码将会更加易于使用;

#include <iostream>
#include <vector>
#include <inttypes.h>
#include <capstone/capstone.h> #pragma comment(lib,"capstone32.lib") using namespace std; typedef struct
{
int OpCodeSize;
int OpStringSize;
unsigned long long Address;
unsigned char OpCode[16];
char OpString[256];
}MyStruct; static void print_string_hex(unsigned char *str, size_t len)
{
unsigned char *c;
for (c = str; c < str + len; c++)
{
printf("0x%02x ", *c & 0xff);
}
printf("\n");
} // 反汇编字符串
std::vector<MyStruct> DisassembleCode(char *start_offset, int size)
{
std::vector<MyStruct> ptr = {}; csh handle;
cs_insn *insn;
size_t count; // 打开句柄
if (cs_open(CS_ARCH_X86, CS_MODE_32, &handle) != CS_ERR_OK)
{
return{};
} // 反汇编代码,地址从0x1000开始,返回总条数
count = cs_disasm(handle, (unsigned char *)start_offset, size, 0x0, 0, &insn); if (count > 0)
{
size_t index; // 循环反汇编代码
for (index = 0; index < count; index++)
{
// 清空
MyStruct location;
memset(&location, 0, sizeof(MyStruct)); // 循环拷贝机器码
for (int x = 0; x < insn[index].size; x++)
{
location.OpCode[x] = insn[index].bytes[x];
} // 拷贝地址长度
location.Address = insn[index].address;
location.OpCodeSize = insn[index].size; // 拷贝反汇编指令
strcpy_s(location.OpString, insn[index].mnemonic);
strcat_s(location.OpString, " ");
strcat_s(location.OpString, insn[index].op_str); // 得到反汇编长度
location.OpStringSize = strlen(location.OpString); ptr.push_back(location);
}
cs_free(insn, count);
}
else
{
return{};
}
cs_close(&handle);
return ptr;
} int main(int argc, char *argv[])
{
char *buffer = "\x55\x8b\xec\x81\xec\x24\x03\x00\x00\x6a\x17\x90\x90\x90"; // 反汇编并返回容器
std::vector<MyStruct> ptr = DisassembleCode(buffer, 14); // 循环整个容器
for (int x = 0; x < ptr.size(); x++)
{
// 输出地址
printf("%08X | ", ptr[x].Address);
printf("%03d | ", ptr[x].OpStringSize); // 输出反汇编
for (int z = 0; z < ptr[x].OpStringSize; z++)
{
printf("%c", ptr[x].OpString[z]);
}
printf("\n"); // 输出机器码
for (int y = 0; y < ptr[x].OpCodeSize; y++)
{
printf("%02X ", ptr[x].OpCode[y]);
} printf("\n");
// print_string_hex(ptr[x].OpCode, ptr[x].OpCodeSize);
} system("pause");
return 0;
}

运行后输出效果图如下图所示;

本文作者: 王瑞

本文链接: https://www.lyshark.com/post/b277703.html

版权声明: 本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!

10.4 认识Capstone反汇编引擎的更多相关文章

  1. 反汇编引擎Capstone

    反汇编引擎Capstone   Capstone是Kali Linux自带的一款轻量级反汇编引擎.它可以支持多种硬件构架,如ARM.ARM64.MIPS.X86.该框架使用C语言实现,但支持C++.P ...

  2. 反汇编引擎diStorm3

    反汇编引擎diStorm3   diStorm3是Kali Linux自带的一款轻量级.容易使用的反汇编引擎.它可以反汇编生成16位.32位和64位指令.它支持的指令集包括FPU.MMX.SSE.SS ...

  3. 开发者不容错过的10款免费JavaScript游戏引擎

    摘要:使用HTML5.JavaScript可以帮助开发者开发出各种与众不同的游戏及游戏特效,比如3D动画.Canvas等.本文介绍10款被广泛使用的基于HTML5的JavaScript游戏引擎. 在G ...

  4. 【原创】Linux环境下的图形系统和AMD R600显卡编程(10)——R600显卡的3D引擎编程

    3D图形处理流水线需要流经多个硬件单元才能得到最后的渲染结果,流水线上的所有的硬件单元必须被正确编程,才能得到正确的结果. 总体上看,从图形处理流水线的源头开始,需要准备好vertex和index,在 ...

  5. C/C++ Capstone 引擎源码编译

    Capstone 是一个轻量级的多平台.多架构的反汇编框架.Capstone 旨在成为安全社区中二进制分析和反汇编的终极反汇编引擎.Capstone的编译非常简单只需要一步即可轻松得到对应的Lib库文 ...

  6. 反汇编基本原理与x86指令构造

    反汇编基本原理与x86指令构造 概要:旨在讲述程序的二进制代码转换到汇编.即反汇编的基本原理.以及 x86 架构的 CPU 的指令构造,有这个基础后就能够自己编写汇编程序了,也能够将二进制代码数据转换 ...

  7. MySQL内核:InnoDB存储引擎 卷1

    MySQL内核:InnoDB存储引擎卷1(MySQL领域Oracle ACE专家力作,众多MySQL Oracle ACE力捧,深入MySQL数据库内核源码分析,InnoDB内核开发与优化必备宝典) ...

  8. 10 个顶级 JavaScript 动画框架推荐

    使用JavaScript可以做出一些引人注目的动画效果,但通常不太容易实现.本文为你整理了10个非常优秀的JavaScript动画框架,使用它们你可以轻松实现动画效果.1. RaphaëlRaphaë ...

  9. MySQL支持多种存储引擎

    MySQL的强大之处在于它的插件式存储引擎,我们可以基于表的特点使用不同的存储引擎,从而达到最好的性能. MySQL有多种存储引擎:MyISAM.InnoDB.MERGE.MEMORY(HEAP).B ...

  10. BrnShop开源网上商城第五讲:自定义视图引擎

    今天这篇博文主要讲解自定义视图引擎,大家都知道在asp.net mvc框架中默认自带一个Razor视图引擎,除此之外我们也可以自定义自己的视图引擎,只需要实现IViewEngine接口,接口定义如下: ...

随机推荐

  1. 一次Mybaits查询的源码分析

    很好奇Mybaits是怎么将xml和mapper对应起来的,用一段比较简单的demo去debug追踪一下源码看看 先用xml配置的方式,看懂了再去看注解的方式是怎么实现的 获取Mapper Mybai ...

  2. 软件测试从小白进阶高手-Python自动化+Jmeter性能+App项目+接口测试

    软件测试从小白进阶高手-Python自动化+Jmeter性能+App项目+接口测试 软件测试技能,包括Python自动化.Jmeter性能测试.App项目测试.接口测试.接下来,我将从每个技能点给出一 ...

  3. XMLSpy操作手册

    最新发布的XMLSpy会让XML代码的处理更容易,还会有助于这个产品成为最主要的XML编辑器.xmlspy是符合行业标准的XML开发环境,专门用于设计,编辑和调试企业级的应用程序,包括XML, XML ...

  4. asp登录认证,记录最后一次登录时间,写入数据库代码

    最近开发了一个船员招聘网的程序,但是由于部分功能需要配合ASP代码才能使用,所以就发现以前写的这个asp登录认证代码,今天就将他公布一下. <!--#include file="con ...

  5. 云享·案例丨打造数智物流底座,华为云DTSE助力物联云仓解锁物流新“速度”

    摘要:华为云凭借领先的技术和快速响应的开发者支持服务,助力物联亿达实现云上资源高可用.提升系统安全性与稳定性,为物联亿达提供了扎实的数字化基础. 本文分享自华为云社区<云享·案例丨打造数智物流底 ...

  6. 如何使用libavfilter库给pcm音频采样数据添加音频滤镜?

    一.初始化音频滤镜 初始化音频滤镜的方法基本上和初始化视频滤镜的方法相同,不懂的可以看上篇博客,这里直接给出代码: //audio_filter_core.cpp #define INPUT_SAMP ...

  7. fidder中勾选check for certificate revocations导致手机无法连上fidder服务器

    在测试过程中因为要获取一个小程序登录API,就用手机设置代理后抓取,在抓取过程中发现提示用户名密码错误(未使用代理正常登录) 遂逐步查找,在与别人核对tools-option发现自己https页签中勾 ...

  8. 【Azure Event Hub】自定义告警(Alert Rule)用来提示Event Hub的消息incoming(生产)与outgoing(消费)的异常情况

    问题描述 在使用Azure Service Bus的时候,我们可以根据Queue中目前存在的消息数来判断当前消息是否有积压的情况. 但是,在Event Hub中,因为所有消息都会被存留到预先设定的保留 ...

  9. vue3+ts使用v-for出现unknown问题

    最近在写项目时遇到了一个问题,当我从父组件向子组件传数据并且需要将子组件对传入的数据进行v-for循环渲染时,在此出遇到了一个ts报错 报错为循环出的data类型为unknown 具体代码如下 : 子 ...

  10. Redis核心技术与实践 02 | 数据结构:快速的Redis有哪些慢操作?

    原文地址:https://time.geekbang.org/column/article/268262 博客地址:http://njpkhuan.cn/archives/redis-he-xin-j ...