4.7 x64dbg 应用层的钩子扫描

所谓的应用层钩子(-level hooks)是一种编程技术,它允许应用程序通过在特定事件发生时执行特定代码来自定义或扩展其行为 。这些事件可以是用户交互,系统事件,或者其他应用程序内部的事件 。应用层钩子是在应用程序中添加自定义代码的一种灵活的方式 。它们可以用于许多不同的用途,如安全审计、性能监视、访问控制和行为修改等 。应用层钩子通常在应用程序的运行时被调用,可以执行一些预定义的操作或触发一些自定义代码 。
通常情况下,第三方应用在需要扩展一个程序功能是都会采用挂钩子的方式实现,而由于内存数据被修改后磁盘数据依然是原始数据,这就给扫描这些钩子提供了便利,具体来说钩子扫描的原理是通过读取磁盘中的PE文件中的反汇编代码,并与内存中的代码作比较,当两者发生差异是则可以证明此处被挂了钩子 。
本节内容中,笔者将通过一个案例并配合引擎来实现这个功能,之所以选用该引擎是因为该引擎支持包,可以非常容易的与插件互动,此外引擎在逆向工程、漏洞分析、恶意代码分析等领域有广泛的应用,著名反汇编调试器IDA则是使用了该引擎工作的 。
的安装非常容易,只需要执行pip即可完成,使用反汇编时读者只需要传入一个PE文件路径,并通过md.(, 0)即可实现反汇编任务;
代码首先使用库读取PE文件,获取文件的,以及名为".text"的节表的、和等信息 。接下来,代码计算了".text"节表的起始地址和结束地址,然后使用文件指针读取文件中".text"节表的原始数据,并使用库进行反汇编 。反汇编结果以字典形式存储,包括反汇编地址和反汇编指令 。最后,函数返回了包含所有反汇编指令的列表 。
【4.7 x64dbg 应用层的钩子扫描】from capstone import *import pefiledef Disassembly(FilePath):opcode_list = []pe = pefile.PE(FilePath)ImageBase = pe.OPTIONAL_HEADER.ImageBasefor item in pe.sections:if str(item.Name.decode('UTF-8').strip(b'\x00'.decode())) == ".text":# print("虚拟地址: 0x%.8X 虚拟大小: 0x%.8X" %(item.VirtualAddress,item.Misc_VirtualSize))VirtualAddress = item.VirtualAddressVirtualSize = item.Misc_VirtualSizeActualOffset = item.PointerToRawDataStartVA = ImageBase + VirtualAddressStopVA = ImageBase + VirtualAddress + VirtualSizewith open(FilePath,"rb") as fp:fp.seek(ActualOffset)HexCode = fp.read(VirtualSize)md = Cs(CS_ARCH_X86, CS_MODE_32)for item in md.disasm(HexCode, 0):addr = hex(int(StartVA) + item.address)dic = {"Addr": str(addr) , "OpCode": item.mnemonic + " " + item.op_str}print("[+] 反汇编地址: {} 参数: {}".format(addr,dic))opcode_list.append(dic)return opcode_listif __name__ == "__main__":Disassembly("d://lyshark.exe")
当读者运行上方代码片段时,则可输出.exe程序内text节所有反汇编代码片段,输出效果如下图所示;
接着我们需要读入内存中的PE文件机器码并通过引擎反汇编为汇编指令集,如下ly函数则是实现内存反汇编的具体实现细节 。
此案例中通过读入内存完整数据,并使用md.依次反汇编,并最终将结果存储到字典中保存 。
import binascii,os,sysimport pefilefrom capstone import *from LyScript32 import MyDebug# 得到内存反汇编代码def get_memory_disassembly(address,offset,len):# 反汇编列表dasm_memory_dict = []# 内存列表ref_memory_list = bytearray()# 读取数据for index in range(offset,len):char = dbg.read_memory_byte(address + index)ref_memory_list.append(char)# 执行反汇编md = Cs(CS_ARCH_X86,CS_MODE_32)for item in md.disasm(ref_memory_list,0x1):addr = int(pe_base) + item.addressdasm_memory_dict.append({"address": str(addr), "opcode": item.mnemonic + " " + item.op_str})return dasm_memory_dictif __name__ == "__main__":dbg = MyDebug()dbg.connect()pe_base = dbg.get_local_base()pe_size = dbg.get_local_size()print("模块基地址: {}".format(hex(pe_base)))print("模块大小: {}".format(hex(pe_size)))# 得到内存反汇编代码dasm_memory_list = get_memory_disassembly(pe_base,0,pe_size)print(dasm_memory_list)dbg.close()