Capstone反汇编(二)

本文阅读 5 分钟
首页 Linux,系统 正文

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

1.1 cs_option

反编译引擎的运行时选项

cs_option(csh ud, cs_opt_type type, size_t value)

1.2 cs_opt_type

type是cs_option函数的第二个参数,是反汇编引擎运行时枚举选项

// 反汇编引擎的运行时选项
typedef enum cs_opt_type { 
    CS_OPT_INVALID = 0,    // <未指定选项
    CS_OPT_SYNTAX,    // 汇编输出语法
    CS_OPT_DETAIL,    // 将指令结构分解为细节
    CS_OPT_MODE,    // 在运行时更改引擎的模式
    CS_OPT_MEM,    // 用户自定义动态内存相关函数
    CS_OPT_SKIPDATA, // 反汇编时跳过数据,然后引擎处于 SKIPDATA 模式。
    CS_OPT_SKIPDATA_SETUP, // 为 SKIPDATA 选项设置用户自定义函数
    CS_OPT_MNEMONIC, // 自定义指令助记符
    CS_OPT_UNSIGNED, // 以无符号形式打印立即操作数
} cs_opt_type;

1.3 cs_opt_value

英文很容易理解,这里就不翻译了

/// Runtime option value (associated with option type above)
typedef enum cs_opt_value { 
    CS_OPT_OFF = 0,  ///< Turn OFF an option - default for CS_OPT_DETAIL, CS_OPT_SKIPDATA, CS_OPT_UNSIGNED.
    CS_OPT_ON = 3, ///< Turn ON an option (CS_OPT_DETAIL, CS_OPT_SKIPDATA).
    CS_OPT_SYNTAX_DEFAULT = 0, ///< Default asm syntax (CS_OPT_SYNTAX).
    CS_OPT_SYNTAX_INTEL, ///< X86 Intel asm syntax - default on X86 (CS_OPT_SYNTAX).
    CS_OPT_SYNTAX_ATT,   ///< X86 ATT asm syntax (CS_OPT_SYNTAX).
    CS_OPT_SYNTAX_NOREGNAME, ///< Prints register name with only number (CS_OPT_SYNTAX)
    CS_OPT_SYNTAX_MASM, ///< X86 Intel Masm syntax (CS_OPT_SYNTAX).
    CS_OPT_SYNTAX_MOTOROLA, ///< MOS65XX use $ as hex prefix
} cs_opt_value;

1.4 例程演示

使用cs_option函数,加上反编译引擎的运行时选项,反汇编出来的语法为AT&T语法

// 以AT&T语法显示
  cs_option(handle, CS_OPT_SYNTAX, CS_OPT_SYNTAX_ATT);
#include <stdio.h>
#include <string.h>
#include <inttypes.h>

#include <capstone/capstone.h>

#define CODE "\x55\x48\x8b\x05\xb8\x13\x00\x00"


static void print_string_hex(unsigned char *str, size_t len)
{ 
    unsigned char *c;

    printf("Code: ");
    for (c = str; c < str + len; c++) { 
        printf("0x%02x ", *c & 0xff);
    }
    printf("\n");
}


int main(void)
{ 
    csh handle;
    cs_insn *insn;
    size_t count;

    if (cs_open(CS_ARCH_X86, CS_MODE_64, &handle) != CS_ERR_OK)
        return -1;

        // 以AT&T语法显示
    cs_option(handle, CS_OPT_SYNTAX, CS_OPT_SYNTAX_ATT); 

    print_string_hex(CODE, strlen(CODE));
    printf("Disasm:\n");

    count = cs_disasm(handle, CODE, sizeof(CODE)-1, 0x1000, 0, &insn);
    if (count > 0) { 
        size_t j;
        for (j = 0; j < count; j++) { 
            printf("0x%"PRIx64":\t%s\t\t%s : ", insn[j].address, insn[j].mnemonic,
                    insn[j].op_str);

            for(int i = 0 ; i < insn[j].size; i++)
            { 
                printf("0x%02x ", insn[j].bytes[i]);
            }
            printf("\n");
        }

        cs_free(insn, count);
    } else
        printf("ERROR: Failed to disassemble given code!\n");

    cs_close(&handle);

    return 0;
}

看一下结果反汇编出来的语法变成了AT&T语法 img 其中:

insn[j].bytes[i]是指令的机器码,即对应的二进制
insn[j].size是该机器指令的长度
for(int i = 0 ; i < insn[j].size; i++)
{ 
    printf("0x%02x ", insn[j].bytes[i]);
}

默认情况下,Capstone 在遇到 a broken instruction 时会停止反汇编,大多数时候,原因是这是输入中混合的数据,Capstone 不理解这个“weird” code。 通常,建议您确定下一个代码在哪里,然后从该位置继续反汇编。 但是,在某些情况下,您只想让 Capstone 自动跳过一些数据,直到找到合法指令,然后从那里继续。 因此,为此目的引入了 SKIPDATA 模式。

简单点来说就是当输入的二进制代码中有不合法的指令,Capstone遇到这个不合法指令便会停止反汇编,不会继续反汇编后面的数据,所以引入了SKIPDATA 模式,跳过这些不合法的指令,并用一个助记符替代,然后继续反汇编后面的数据。

2.1 数据结构

cs_opt_skipdata

//用户自定义设置 SKIPDATA 选项
typedef struct cs_opt_skipdata { 
    // Capstone 将要跳过的数据视为特殊的“指令”
    // 用户可以在这里为该指令的“助记符”指定字符串。
    // 默认情况下(如果 @mnemonic 为 NULL),Capstone 使用“.byte”。
    const char *mnemonic;

    // Capstone hits 数据时调用的用户自定义回调函数
    // 如果此回调的返回值为正数 (>0), Capstone 将准确跳过该字节数并继续
    // 否则,如果回调返回 0,Capstone 停止反汇编并立即从 cs_disasm() 返回
    // 注意:如果此回调指针为 NULL,Capstone 将根据体系结构跳过一些字节,如下所示:
    /// Arm: 2 bytes (Thumb mode) or 4 bytes.
    /// Arm64: 4 bytes.
    /// Mips: 4 bytes.
    /// M680x: 1 byte.
    /// PowerPC: 4 bytes.
    /// Sparc: 4 bytes.
    /// SystemZ: 2 bytes.
    /// X86: 1 bytes.
    /// XCore: 2 bytes.
    /// EVM: 1 bytes.
    /// RISCV: 4 bytes.
    /// WASM: 1 bytes.
    /// MOS65XX: 1 bytes.
    /// BPF: 8 bytes.
    cs_skipdata_cb_t callback;     // default value is NULL

    // 用户自定义数据将被传递给callback函数指针
    void *user_data;
} cs_opt_skipdata;

(2)cs_skipdata_cb_t

/** SKIPDATA 选项的用户定义回调函数 @code: 包含要反汇编的代码的输入缓冲区。 这与传递给 cs_disasm() 的缓冲区相同。 @code_size: 上述 code 缓冲区的大小(以字节为单位)。 @offset: 当前检查字节在上述输入缓冲区 code 中的位置。 @user_data: 用户数据通过 cs_opt_skipdata 结构中的 user_data 字段传递给 cs_option()。 @return: 返回要跳过的字节数,或 0 立即停止反汇编。 */
typedef size_t (CAPSTONE_API *cs_skipdata_cb_t)(const uint8_t *code, size_t code_size, size_t offset, void *user_data);

(3)打开 SKIPDATA mode 要让Capstone跳过一些(未知的)数据量,直到下一个合法指令,只需使用cs_option()打开选项CS_OPT_SKIPDATA(默认关闭),如下所示:

csh handle;
cs_open(CS_ARCH_X86, CS_MODE_64, &handle);

// turn on SKIPDATA mode
cs_option(handle, CS_OPT_SKIPDATA, CS_OPT_ON);

2.2 例程演示

例程采用官方的例程: 使用SKIPDATA mode 之前:

/* Capstone Disassembler Engine */

#include <stdio.h>
#include <stdlib.h>

#include <capstone/platform.h>
#include <capstone/capstone.h>

struct platform { 
    cs_arch arch;
    cs_mode mode;
    unsigned char *code;
    size_t size;
    const char *comment;
    cs_opt_type opt_type;
    cs_opt_value opt_value;
    cs_opt_type opt_skipdata;
    size_t skipdata;
};

static void print_string_hex(unsigned char *str, size_t len)
{ 
    unsigned char *c;

    printf("Code: ");
    for (c = str; c < str + len; c++) { 
        printf("0x%02x ", *c & 0xff);
    }
    printf("\n");
}


static void test()
{ 
#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"

    struct platform platforms[] = { 
        { 
            CS_ARCH_X86,
            CS_MODE_64,
            (unsigned char*)RANDOM_CODE,
            sizeof(RANDOM_CODE) - 1,
        },

    };

    csh handle;
    uint64_t address = 0x1000;
    cs_insn *insn;
    cs_err err;
    int i;
    size_t count;

    for (i = 0; i < sizeof(platforms)/sizeof(platforms[0]); i++) { 

        err = cs_open(platforms[i].arch, platforms[i].mode, &handle);
        if (err) { 
            printf("Failed on cs_open() with error returned: %u\n", err);
            abort();
        }

        if (platforms[i].opt_type)
            cs_option(handle, platforms[i].opt_type, platforms[i].opt_value);

        count = cs_disasm(handle, platforms[i].code, platforms[i].size, address, 0, &insn);
        if (count) { 
            size_t j;

            print_string_hex(platforms[i].code, platforms[i].size);
            printf("Disasm:\n");

            for (j = 0; j < count; j++) { 
                printf("0x%" PRIx64 ":\t%s\t\t%s\n",
                        insn[j].address, insn[j].mnemonic, insn[j].op_str);
            }

            // print out the next offset, after the last insn
            printf("0x%" PRIx64 ":\n", insn[j-1].address + insn[j-1].size);

            // free memory allocated by cs_disasm()
            cs_free(insn, count);
        } else { 
            printf("****************\n");
            print_string_hex(platforms[i].code, platforms[i].size);
            printf("ERROR: Failed to disasm given code!\n");
            abort();
        }

        printf("\n");

        cs_close(&handle);
    }
}

int main()
{ 
    test();

    return 0;
}

img Capstone 在遇到 a broken instruction 时会停止反汇编了。

使用SKIPDATA mode 之后:

/* Capstone Disassembler Engine */

#include <stdio.h>
#include <stdlib.h>

#include <capstone/platform.h>
#include <capstone/capstone.h>

struct platform { 
    cs_arch arch;
    cs_mode mode;
    unsigned char *code;
    size_t size;
    const char *comment;
    cs_opt_type opt_type;
    cs_opt_value opt_value;
    cs_opt_type opt_skipdata;
    size_t skipdata;
};

static void print_string_hex(unsigned char *str, size_t len)
{ 
    unsigned char *c;

    printf("Code: ");
    for (c = str; c < str + len; c++) { 
        printf("0x%02x ", *c & 0xff);
    }
    printf("\n");
}


static void test()
{ 
#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"

    struct platform platforms[] = { 
        { 
            CS_ARCH_X86,
            CS_MODE_64,
            (unsigned char*)RANDOM_CODE,
            sizeof(RANDOM_CODE) - 1,
        },

    };

    csh handle;
    uint64_t address = 0x1000;
    cs_insn *insn;
    cs_err err;
    int i;
    size_t count;

    for (i = 0; i < sizeof(platforms)/sizeof(platforms[0]); i++) { 

        err = cs_open(platforms[i].arch, platforms[i].mode, &handle);
        if (err) { 
            printf("Failed on cs_open() with error returned: %u\n", err);
            abort();
        }

        if (platforms[i].opt_type)
            cs_option(handle, platforms[i].opt_type, platforms[i].opt_value);

        // turn on SKIPDATA mode
        cs_option(handle, CS_OPT_SKIPDATA, CS_OPT_ON);
        cs_option(handle, platforms[i].opt_skipdata, platforms[i].skipdata);

        count = cs_disasm(handle, platforms[i].code, platforms[i].size, address, 0, &insn);
        if (count) { 
            size_t j;

            print_string_hex(platforms[i].code, platforms[i].size);
            printf("Disasm:\n");

            for (j = 0; j < count; j++) { 
                printf("0x%" PRIx64 ":\t%s\t\t%s\n",
                        insn[j].address, insn[j].mnemonic, insn[j].op_str);
            }

            // print out the next offset, after the last insn
            printf("0x%" PRIx64 ":\n", insn[j-1].address + insn[j-1].size);

            // free memory allocated by cs_disasm()
            cs_free(insn, count);
        } else { 
            printf("****************\n");
            print_string_hex(platforms[i].code, platforms[i].size);
            printf("ERROR: Failed to disasm given code!\n");
            abort();
        }

        printf("\n");

        cs_close(&handle);
    }
}

int main()
{ 
    test();

    return 0;
}

Capstone 在遇到 a broken instruction 时,自动跳过一些数据,用.byte代替,直到找到合法指令,然后从那里继续反汇编。 Capstone 跳过 1 个字节的数据并继续从输入流中的下一个字节进行反汇编。 在这种情况下,实际上 Capstone 将跳过数据视为指令 ID 为零的特殊指令,助记符为“.byte”,操作数字符串为其跳过的字节序列的十六进制代码。 img

2.3 改变助记符例程

如上所述,Capstone 认为数据将被跳过具有默认助记符“.byte”的指令。 要更改此助记符,请使用带有 CS_OPT_SKIPDATA_SETUP 的 cs_option(),如下所示:

csh handle;
cs_open(CS_ARCH_X86, CS_MODE_32, &handle);

cs_opt_skipdata skipdata = { 
    .mnemonic = "db",
};

// customize SKIPDATA mode
cs_option(handle, CS_OPT_SKIPDATA_SETUP, &skipdata);

// Turn on SKIPDATA mode
cs_option(handle, CS_OPT_SKIPDATA, CS_OPT_ON);
/* Capstone Disassembler Engine */

#include <stdio.h>
#include <stdlib.h>

#include <capstone/platform.h>
#include <capstone/capstone.h>

struct platform { 
    cs_arch arch;
    cs_mode mode;
    unsigned char *code;
    size_t size;
    const char *comment;
    cs_opt_type opt_type;
    cs_opt_value opt_value;
    cs_opt_type opt_skipdata;
    size_t skipdata;
};

static void print_string_hex(unsigned char *str, size_t len)
{ 
    unsigned char *c;

    printf("Code: ");
    for (c = str; c < str + len; c++) { 
        printf("0x%02x ", *c & 0xff);
    }
    printf("\n");
}


static void test()
{ 
#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"


    cs_opt_skipdata skipdata = { 
        // rename default "data" instruction from ".byte" to "db"
        "db",
    };


    struct platform platforms[] = { 
        { 
            CS_ARCH_X86,
            CS_MODE_64,
            (unsigned char*)RANDOM_CODE,
            sizeof(RANDOM_CODE) - 1,
            "X86 64 (Intel syntax) - Skip data",
        },
        { 
            CS_ARCH_X86,
            CS_MODE_64,
            (unsigned char*)RANDOM_CODE,
            sizeof(RANDOM_CODE) - 1,
            "X86 64 (Intel syntax) - Skip data with custom mnemonic",
            CS_OPT_INVALID,
            CS_OPT_OFF,
            CS_OPT_SKIPDATA_SETUP,
            (size_t) &skipdata,
        },

    };

    csh handle;
    uint64_t address = 0x1000;
    cs_insn *insn;
    cs_err err;
    int i;
    size_t count;

    for (i = 0; i < sizeof(platforms)/sizeof(platforms[0]); i++) { 
        printf("****************\n");
        printf("Platform: %s\n", platforms[i].comment);
        err = cs_open(platforms[i].arch, platforms[i].mode, &handle);
        if (err) { 
            printf("Failed on cs_open() with error returned: %u\n", err);
            abort();
        }

        if (platforms[i].opt_type)
            cs_option(handle, platforms[i].opt_type, platforms[i].opt_value);

        // turn on SKIPDATA mode
        cs_option(handle, CS_OPT_SKIPDATA, CS_OPT_ON);
        cs_option(handle, platforms[i].opt_skipdata, platforms[i].skipdata);

        // turn off SKIPDATA mode
        //cs_option(handle, CS_OPT_SKIPDATA, CS_OPT_OFF);

        count = cs_disasm(handle, platforms[i].code, platforms[i].size, address, 0, &insn);
        if (count) { 
            size_t j;

            print_string_hex(platforms[i].code, platforms[i].size);
            printf("Disasm:\n");

            for (j = 0; j < count; j++) { 
                printf("0x%" PRIx64 ":\t%s\t\t%s\n",
                        insn[j].address, insn[j].mnemonic, insn[j].op_str);
            }

            // print out the next offset, after the last insn
            printf("0x%" PRIx64 ":\n", insn[j-1].address + insn[j-1].size);

            // free memory allocated by cs_disasm()
            cs_free(insn, count);
        } else { 
            printf("****************\n");
            printf("Platform: %s\n", platforms[i].comment);
            print_string_hex(platforms[i].code, platforms[i].size);
            printf("ERROR: Failed to disasm given code!\n");
            abort();
        }

        printf("\n");

        cs_close(&handle);
    }
}

int main()
{ 
    test();

    return 0;
}

img

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

本文为互联网自动采集或经作者授权后发布,本文观点不代表立场,若侵权下架请联系我们删帖处理!文章出自:https://blog.csdn.net/weixin_45030965/article/details/125248361
-- 展开阅读全文 --
BUUCTF Web [极客大挑战 2019]Knife
« 上一篇 06-24
安全面试之XSS(跨站脚本攻击)
下一篇 » 07-24

发表评论

成为第一个评论的人

热门文章

标签TAG

最近回复