1、基本案例——disasm函数
capstone有非常简单的API,所以使用该框架编写工具非常简单。接下来,下面的代码实现的功能是反汇编一些X86二进制文件,并打印出其对应的汇编语句。
代码展示:
from capstone import * #将capstone模块中函数全部导入
code=b"\x55\x48\x8b\x13\x00\x00" #设置需要进行反汇编的十六进制机器码
#创建Cs类对象md,我们需要给这个类传两个参数:硬件架构,硬件模式(位长)
md=Cs(CS_ARCH_X86,CS_MODE_64) #表示此时md对象对采用x86架构64位,对机器码进行汇编
for i in md.disasm(code,0x1000): #循环遍历disasm函数返回的列表
print("0x%x:\t %s\t%s" %(i.address,i.mnemonic,i.op_str))
代码解释:(此时的行数是不计注释和空行)
代码的前两行的作用分别是导入模块中需要使用的函数(或类)和设置需要进行反汇编的机器码。第三的作用是为Cs类创建一个类对象md,便于在后续代码中调用Cs类中定义的方法。
反汇编二进制文件(机器码)实际上使用的是Cs类中定义的成员函数disasm()。因为我们在代码的第三行已经初始了一个类对象md,所以当我们要使用disasm()这个函数的时候,直接使用类对象调用即可---md.disasm()。disasm需要传两个参数:
①第一个参数:需要进行反汇编的机器码;
②第二个参数:反汇编的开始地址,默认情况下,disasm会反汇编传入的所有机器码,直到没有代码或断开为止。本例中,第二个参数设置为0x1000。
disasm函数的执行完成后,会返回一个CsInsn类的指令列表。
代码的第四行使用for循环遍历disasm函数返回的列表,第五行打印该指令的一些内部信息。
执行结果:
类CsInsn公开了我们要访问的反汇编指令的所有内部信息。以下是一些常用的字段: id 汇编指令的id
address 汇编指令的地址
mnemonic 指令的助记符
op_str 汇编指令的操作码
size 汇编指令的大小,以字节为单位
bytes 指令的字节序列
验证代码如下:
2.更精简的API——disasm_lite函数
刚刚我介绍了capstone模块中的Cs类中的成员函数disasm()。这个函数处理后会返回一个CsInsn类列表。返回结果提供了反汇编指令的全部可用信息。但是当我只需要汇编代码的基本信息,如:地址、大小、助记符等基本的数据,我们可以使用disasm_lite()函数,该函数返回一个元组,元组包括:地址、大小、助记符、op_str。这个函数的执行速度相比于disasm函数会更快。
代码展示:
from capstone import *
code=b"\x55\x48\x8b\x13\x00\x00"
md=Cs(CS_ARCH_X86,CS_MODE_64)
for (address,size,mnemonic,op_str) in md.disasm_lite(code,0x1000):
print("0x"+str(address),size,mnemonic,op_str)
运行结果:
3、对可执行文件的.text节进行反汇编,且将反汇编内容保存到huibain.txt文件中:
具体代码:
from capstone import * # 导入Capstone库,用于反汇编
import pefile # 导入PE文件解析库
def FOA_Disassembly(FilePath):
global VirtualAddress,VirtualSize,ActualOffset
pe = pefile.PE(FilePath) # 解析PE文件
ImageBase = pe.OPTIONAL_HEADER.ImageBase #从pe文件对象中获取可选头部(OPTIONAL_HEADER)中的ImageBase字段,并将其赋值给变量
#pe对象中的ImageBase字段通常用来指定可执行文件中加载时的基地址,
#这个值可以影响程序在内存中的加载位置。
# 通过获取Imagebase字段的值,可以了解程序在加载时的首先基地址
#PE对象中的sections属性,用于获取PE文件中的各个节。
for item in pe.sections:
#当从外部数据源读取数据时,数据通常以字节流的形式表示。
#Python中decode函数用于将字节流解码为字符串,本次实验中解码后的字符串以UTF-8进行编码
if str(item.Name.decode('UTF-8').strip(b'\x00'.decode())) == ".text": # 查找包含代码的节
VirtualAddress = item.VirtualAddress # 节的虚拟地址
VirtualSize = item.Misc_VirtualSize # 节的虚拟大小
ActualOffset = item.PointerToRawData # 节在文件中的偏移量
StartVA = ImageBase + VirtualAddress # 起始虚拟地址
StopVA = ImageBase + VirtualAddress + VirtualSize # 结束虚拟地址
with open(FilePath, "rb") as fp:
#Python中seek函数的作用:移动文件读写指针到指定的偏移量位置
fp.seek(ActualOffset)
HexCode = fp.read(VirtualSize) # 读取.text节中的信息,使用read函数读取.text大小byte的信息
md = Cs(CS_ARCH_X86, CS_MODE_32) # 初始化Capstone引擎,指定架构和模式
with open("./huibain.txt","a",encoding="utf-8") as f:
for item in md.disasm(HexCode, 0): # 反汇编节中的代码
addr = hex(int(StartVA) + item.address) # 计算指令的虚拟地址
dic = {"Addr": str(addr), "OpCode": item.mnemonic + " " + item.op_str} # 构建指令信息字典
f.write(dic["Addr"]+" "+dic["OpCode"])
f.write("\n")
if __name__ == "__main__":
ref = FOA_Disassembly("./test.exe") # 调用函数解析指定的可执行文件
print("转换完成!请查看当前目录下,huibain.txt文件") # 打印反汇编结果
运行成功截图: