Python-Capstone引擎的探索

颛孙玉石
2023-12-01

没有一份详细的流程,探索是一件很痛苦的过程,本文不探讨引擎的原理和底层源码,仅仅解释引擎的使用
这是引擎的安装

pip install capstone

这是官方的帮助文档

https://github.com/kabeor/Capstone-Engine-Documentation/blob/master/Capstone-Engine%20Documentation.md

很好,我的探索是基于x86-32汇编基础上的,随便截了一段汇编代码

0040106C    60              pushad
0040106D    BB 0050B0BC     mov     ebx, 0xBCB05000
00401072    53              push    ebx
00401073    68 AD0B0000     push    0xBAD
00401078    C3              retn
00401079    B9 9C000000     mov     ecx, 0x9C
0040107E    0BC9            or      ecx, ecx
00401080    74 4D           je      short 004010CF
00401082    833D 1B014B00 0>cmp     dword ptr [0x4B011B], 0x0
00401089    61              popad




python的初始化和官方文档给的初始化还是有部分差异,只需要关注模式和位数即可,方便至极

 enum cs_arch {
	CS_ARCH_ARM = 0,	///< ARM 架构 (包括 Thumb, Thumb-2)
	CS_ARCH_ARM64,		///< ARM-64, 也叫 AArch64
	CS_ARCH_MIPS,		///< Mips 架构
   CS_ARCH_X86,		///< X86 架构 (包括 x86 & x86-64)
	CS_ARCH_PPC,		///< PowerPC 架构
	CS_ARCH_SPARC,		///< Sparc 架构
	CS_ARCH_SYSZ,		///< SystemZ 架构
	CS_ARCH_XCORE,		///< XCore 架构
	CS_ARCH_M68K,		///< 68K 架构
	CS_ARCH_TMS320C64X,	///< TMS320C64x 架构
	CS_ARCH_M680X,		///< 680X 架构
	CS_ARCH_EVM,		///< Ethereum 架构
	CS_ARCH_MAX,
	CS_ARCH_ALL = 0xFFFF, // All 架构 - for cs_support()
} cs_arch;
enum cs_mode {
	CS_MODE_LITTLE_ENDIAN = 0,	             ///< little-endian 模式 (default 模式)
	CS_MODE_ARM = 0,	                     ///< 32-bit ARM
	CS_MODE_16 = 1 << 1,	                 ///< 16-bit 模式 (X86)
	CS_MODE_32 = 1 << 2,	                 ///< 32-bit 模式 (X86)
	CS_MODE_64 = 1 << 3,	                 ///< 64-bit 模式 (X86, PPC)
	CS_MODE_THUMB = 1 << 4,	                 ///< ARM's Thumb 模式, 包括 Thumb-2
	CS_MODE_MCLASS = 1 << 5,	             ///< ARM's Cortex-M 系列
	CS_MODE_V8 = 1 << 6,	                 ///< ARMv8 A32解码方式
	CS_MODE_MICRO = 1 << 4,                  ///< MicroMips 模式 (MIPS)
	CS_MODE_MIPS3 = 1 << 5,                  ///< Mips III ISA
	CS_MODE_MIPS32R6 = 1 << 6,               ///< Mips32r6 ISA
	CS_MODE_MIPS2 = 1 << 7,                  ///< Mips II ISA
	CS_MODE_V9 = 1 << 4,                     ///< SparcV9 模式 (Sparc)
	CS_MODE_QPX = 1 << 4,                    ///< Quad Processing eXtensions 模式 (PPC)
	CS_MODE_SPE = 1 << 5,                    ///< Signal Processing Engine 模式 (PPC)
	CS_MODE_BOOKE = 1 << 6,                  ///< Book-E 模式 (PPC)
	CS_MODE_M68K_000 = 1 << 1,               ///< M68K 68000 模式
	CS_MODE_M68K_010 = 1 << 2,               ///< M68K 68010 模式
	CS_MODE_M68K_020 = 1 << 3,               ///< M68K 68020 模式
	CS_MODE_M68K_030 = 1 << 4,               ///< M68K 68030 模式
	CS_MODE_M68K_040 = 1 << 5,               ///< M68K 68040 模式
	CS_MODE_M68K_060 = 1 << 6,               ///< M68K 68060 模式
	CS_MODE_BIG_ENDIAN = 1 << 31,	         ///< big-endian 模式
	CS_MODE_MIPS32 = CS_MODE_32,	         ///< Mips32 ISA (Mips)
	CS_MODE_MIPS64 = CS_MODE_64,	         ///< Mips64 ISA (Mips)
	CS_MODE_M680X_6301 = 1 << 1,             ///< M680X Hitachi 6301,6303 模式
	CS_MODE_M680X_6309 = 1 << 2,             ///< M680X Hitachi 6309 模式
	CS_MODE_M680X_6800 = 1 << 3,             ///< M680X Motorola 6800,6802 模式
	CS_MODE_M680X_6801 = 1 << 4,             ///< M680X Motorola 6801,6803 模式
	CS_MODE_M680X_6805 = 1 << 5,             ///< M680X Motorola/Freescale 6805 模式
	CS_MODE_M680X_6808 = 1 << 6,             ///< M680X Motorola/Freescale/NXP 68HC08 模式
	CS_MODE_M680X_6809 = 1 << 7,             ///< M680X Motorola 6809 模式
	CS_MODE_M680X_6811 = 1 << 8,             ///< M680X Motorola/Freescale/NXP 68HC11 模式
	CS_MODE_M680X_CPU12 = 1 << 9,            ///< M680X Motorola/Freescale/NXP CPU12
					                         ///< 用于 M68HC12/HCS12
	CS_MODE_M680X_HCS08 = 1 << 10,           ///< M680X Freescale/NXP HCS08 模式
	CS_MODE_BPF_CLASSIC = 0,	             ///< Classic BPF 模式 (默认)
	CS_MODE_BPF_EXTENDED = 1 << 0,	         ///< Extended BPF 模式
	CS_MODE_RISCV32  = 1 << 0,               ///< RISCV RV32G
	CS_MODE_RISCV64  = 1 << 1,               ///< RISCV RV64G
	CS_MODE_RISCVC   = 1 << 2,               ///< RISCV 压缩指令模式
	CS_MODE_MOS65XX_6502 = 1 << 1,           ///< MOS65XXX MOS 6502
	CS_MODE_MOS65XX_65C02 = 1 << 2,          ///< MOS65XXX WDC 65c02
	CS_MODE_MOS65XX_W65C02 = 1 << 3,         ///< MOS65XXX WDC W65c02
	CS_MODE_MOS65XX_65816 = 1 << 4,          ///< MOS65XXX WDC 65816, 8-bit m/x
	CS_MODE_MOS65XX_65816_LONG_M = (1 << 5), ///< MOS65XXX WDC 65816, 16-bit m, 8-bit x 
	CS_MODE_MOS65XX_65816_LONG_X = (1 << 6), ///< MOS65XXX WDC 65816, 8-bit m, 16-bit x
	CS_MODE_MOS65XX_65816_LONG_MX = CS_MODE_MOS65XX_65816_LONG_M | CS_MODE_MOS65XX_65816_LONG_X,
} cs_mode;

这里是我的代码,Code保证是字节数组即可

    CODE = bytearray.fromhex("60 BB 00 50 B0 BC 53 68 AD 0B 00 00 C3 B9 9C 00 00 00 0B C9 74 4D 83 3D 1B 01 4B 00 00 61")
    md = Cs(CS_ARCH_X86, CS_MODE_32)

好的,代码成功运行,继续探索,从简单的抓起,代码遍历函数disasm在python中定义如下,比起C来说更容易上手,不是吗?

disasm(code,offset,count)

code不用我多解释,就是要解析的数据,offset就是起始地址,你想设置多少就设置多少,count就是你要解析的指令数量(不填写的话,默认为全部,具体效果自己测试,秒懂),而返回的对象是一个迭代器,迭代器元素的重要属性如下(不重要的我给删了,想看可以去官网看)

struct cs_insn {
	/// 指令ID(基本上是一个用于指令助记符的数字ID)
	/// 应在相应架构的头文件中查找'[ARCH]_insn' enum中的指令id,如ARM.h中的'arm_insn'代表ARM, X86.h中的'x86_insn'代表X86等…
	/// 即使在CS_OPT_DETAIL = CS_OPT_OFF时也可以使用此信息
	/// 注意:在Skipdata模式下,这个id字段的“data”指令为0
	unsigned int id;

	/// 指令地址 (EIP)
	/// 即使在CS_OPT_DETAIL = CS_OPT_OFF时也可以使用此信息
	uint64_t address;

	/// 指令长度
	/// 即使在CS_OPT_DETAIL = CS_OPT_OFF时也可以使用此信息
	uint16_t size;

	/// 此指令的机器码,其字节数由上面的@size表示
	/// 即使在CS_OPT_DETAIL = CS_OPT_OFF时也可以使用此信息
	uint8_t bytes[24];

	/// 指令的Ascii文本助记符
	/// 即使在CS_OPT_DETAIL = CS_OPT_OFF时也可以使用此信息
	char mnemonic[CS_MNEMONIC_SIZE];

	/// 指令操作数的Ascii文本
	/// 即使在CS_OPT_DETAIL = CS_OPT_OFF时也可以使用此信息
	char op_str[160];
} cs_insn;

完整代码如下,至此,成功打印出汇编代码O(∩_∩)O~~

    CODE = bytearray.fromhex("60 BB 00 50 B0 BC 53 68 AD 0B 00 00 C3 B9 9C 00 00 00 0B C9 74 4D 83 3D 1B 01 4B 00 00 61")
    md = Cs(CS_ARCH_X86, CS_MODE_32)
    for i in md.disasm(CODE, 0x0040106C):
        print("%x:\t%s\t%s" % (i.address, i.mnemonic, i.op_str))

当然,我对其他功能也很好奇,就尝试了下disasm_lite这个在官方中文文档中并没有给出明确的定义。他的参数传递和disasm基本没区别,但是他返回的是一个元组对象,根据代码注释可以得知只返回(address、size, mnemonic, op_str)的元组,所以用法上还是和disasm有一定的区别,因为他返回的少,所以他执行效率更快

disasm_lite(code,offset,count)
    CODE = bytearray.fromhex("60 BB 00 50 B0 BC 53 68 AD 0B 00 00 C3 B9 9C 00 00 00 0B C9 74 4D 83 3D 1B 01 4B 00 00 61")
    md = Cs(CS_ARCH_X86, CS_MODE_32)
    for i in md.disasm_lite(CODE, 0x0040106C):
        print(i)

至此,主要功能介绍完毕,其他功能大概都无关紧要

 类似资料: