10.4 认识Capstone反汇编引擎

认识,capstone,反汇编,引擎 · 浏览次数 : 13

小编点评

```c++ #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(\"\\");}// 反汇编字符串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(\"\\"); // 输出机器码 for (int y = 0; y < ptr[x].OpCodeSize; y++) { printf(\"%02X \", ptr[x].OpCode[y]); } printf(\"\\"); // print_string_hex(ptr[x].OpCode, ptr[x].OpCodeSize); } // system("pause"); return 0;}```

正文

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反汇编引擎相似的内容:

10.4 认识Capstone反汇编引擎

Capstone 是一款开源的反汇编框架,目前该引擎支持的CPU架构包括x86、x64、ARM、MIPS、POWERPC、SPARC等,Capstone 的特点是快速、轻量级、易于使用,它可以良好地处理各种类型的指令,支持将指令转换成AT&T汇编语法或Intel汇编语法等多种格式。Capstone的...

冯登国院士:数据安全新方向——数据使用安全

链接: 冯登国院士:数据安全新方向——数据使用安全 近日,在2023中关村论坛——数据安全治理与发展分论坛上,冯登国院士做了主题为:《数据安全新方向:数据使用安全》的分享,以下是分享全文。 各位专家,各位嘉宾,大家好: 很高兴有这个机会与大家进行交流一下对数据安全的一些认识,发言题目是《数据安全新方

千呼万唤始出来 JDK 21 LTS, 久等了

平地起惊雷!!! 目录英雄的迟暮大人时代变了JDK 21 LTS 前 JAVA并发编程模型JDK 21 LTS 中的 JAVA 并发编程模型虚拟线程 VS 线程池The Last 你可以称呼它为:JDK 8 之后的神,它也是很多人认为的 JDK 8 之后,最值得升级的版本。 以前大家都说: 他发任他

Mac上使用Royal TSX快速连接到OCI主机

**问题:** 每次使用Royal TSX连接到OCI主机都要交互式输入opc这个用户名,次数多了也蛮烦。 那如何既指定用户名,又想要通过ssh私钥登陆机器呢? 这个需求确实很初级,但也着实困扰过我,因为开始我真的以为不支持,认为这两种连接方式只能选其一。结果没想到人家是可以组合使用实现这样的需求。

.NET周报【10月最后一期 2022-11-01】

精选要闻 .NET 7 NativeAOT比.NET单文件发布文件小80% https://twitter.com/JamesNK/status/1584919726861737984?s=20&t=cOsB41s2cydu_Ibts4xnEw AOT GRPC服务器应用程序比.NET运行时自包含的

4.10 x64dbg 反汇编功能的封装

LyScript 插件提供的反汇编系列函数虽然能够实现基本的反汇编功能,但在实际使用中,可能会遇到一些更为复杂的需求,此时就需要根据自身需要进行二次开发,以实现更加高级的功能。本章将继续深入探索反汇编功能,并将介绍如何实现反汇编代码的检索、获取上下一条代码等功能。这些功能对于分析和调试代码都非常有用,因此是书中重要的内容之一。在本章的学习过程中,读者不仅可以掌握反汇编的基础知识和技巧,还能够了解如

文心一言 VS 讯飞星火 VS chatgpt (106)-- 算法导论10.1 4题

四、用go语言,重写 ENQUEUE 和 DEQUEUE 的代码,使之能处理队列的下溢和上溢。 文心一言: 在 Go 语言中,我们可以使用切片来实现队列。下面是如何实现 ENQUEUE 和 DEQUEUE 操作,同时处理队列的下溢和上溢的情况: package main import "fmt" t

Linux定时任务概述

Linux定时任务概述 基于centos7.6.1810 参考鸟哥私房菜 /etc/crontab [root@VM-4-10-centos ~]# cat /etc/crontab SHELL=/bin/bash PATH=/sbin:/bin:/usr/sbin:/usr/bin MAILTO=

[转帖]seafile 7.1.12专业版升级到seafile 8.0.11专业版教程

https://www.ittel.cn/archives/11643.html 目录 seafile 8.0.11专业版新功能 版本变更 部署环境升级 Ubuntu 18.04/20.4 Debian 10 CentOS 7.X CentOS 8.X 升级到 8.0.11 Ubuntu 18.04

解Bug之路-应用999线升高

前言 监控指标诚然是发现问题于微末之时的极佳手段,但指标往往有其表达的极限。在很多情况下,单独看一个黄金指标并不能表征系统的健康程度,反而有可能被其迷惑,进而忽略相关问题。(本文所提及的Linux Kernel源码版本为4.18.10) Bug现场 某天中午,某应用的999线突然升高。由于是个QPS