LyScript 实现应用层钩子扫描器
LyScript 插件可以与调试器和反汇编器等工具集成,实现各种功能。要实现应用层钩子扫描器,需要使用 LyScript 结合调试器和Capstone反汇编器的功能来完成。
Capstone 是一个轻量级的多平台、多架构的反汇编框架,该模块支持目前所有通用操作系统,反汇编架构几乎全部支持,本篇文章将运用LyScript插件结合Capstone反汇编引擎实现一个钩子扫描器。
实现钩子扫描
要实现应用层钩子扫描,我们需要得到程序内存文件的机器码以及磁盘中的机器码,并通过capstone这个第三方反汇编引擎,对两者进行反汇编,最后逐条对比汇编指令,实现进程钩子扫描的效果。
通过LyScript插件读取出内存中的机器码,然后交给第三方反汇编库执行,并将结果输出成字典格式。
import binascii,os,sys
import pefile
from 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() 上述代码运行后,我们可以得到内存中.text代码段内所有的反汇编指令集及其它的地址信息,如下图所示;

接着我们只需要构建一个针对文件的反汇编功能,并对文件中的.text节进行反汇编,应用层钩子扫描器的实现原理基于内存与磁盘中的机器码特征对比。通过以下概述可以理解其工作原理:
-
连接调试器:使用 LyScript 插件连接到目标进程的调试器。
-
获取内存中的机器码:利用调试器读取目标进程的内存,获取程序在内存中的机器码。
-
获取磁盘中的机器码:从程序的磁盘文件中提取机器码,可以使用 pefile 库读取 PE 文件,并通过读取文件中的特定部分获取机器码。
-
反汇编机器码:使用第三方反汇编引擎(如 capstone)对内存和磁盘中的机器码进行反汇编,将其转换为汇编指令的形式。
-
对比汇编指令:逐条对比内存中的汇编指令和磁盘中的汇编指令。比较它们是否相同,可以通过指令的字符串表示或地址进行比较。
-
记录扫描结果:根据对比结果,记录存在差异的指令或地址,这可能表示应用层钩子的存在。
通过以上步骤,应用层钩子扫描器能够检测和识别程序中的应用层钩子。它利用内存和磁盘中的机器码对比来确定钩子的存在,从而提升应用程序的安全性和可靠性。
import binascii,os,sys
import pefile
from 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.addressdic = {"address": str(addr), "opcode": item.mnemonic + " " + item.op_str}dasm_memory_dict.append(dic)return dasm_memory_dict# 反汇编文件中的机器码
def get_file_disassembly(path):opcode_list = []pe = pefile.PE(path)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(path,"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 = {"address": str(addr) , "opcode": item.mnemonic + " " + item.op_str}# print("{}".format(dic))opcode_list.append(dic)return opcode_listif __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)dasm_file_list = get_file_disassembly("d://win32project1.exe")# 循环对比内存与文件中的机器码for index in range(0,len(dasm_file_list)):if dasm_memory_list[index] != dasm_file_list[index]:print("地址: {:8} --> 内存反汇编: {:32} --> 磁盘反汇编: {:32}".format(dasm_memory_list[index].get("address"),dasm_memory_list[index].get("opcode"),dasm_file_list[index].get("opcode")))dbg.close() 此处如果一致,则说明没有钩子,如果不一致则输出,这里的输出结果不一定准确,此处只是抛砖引玉。

本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!
