您现在的位置是:网站首页> 编程资料编程资料
LyScript实现Hook隐藏调试器的方法详解_python_
2023-05-25
300人已围观
简介 LyScript实现Hook隐藏调试器的方法详解_python_
LyScript 插件集成的内置API函数可灵活的实现绕过各类反调试保护机制,前段时间发布的那一篇文章并没有详细讲解各类反调试机制的绕过措施,本次将补充这方面的知识点,运用LyScript实现绕过大多数通用调试机制,实现隐藏调试器的目的。
我们以此实现Patches如下函数:
- IsDebuggerPresent
- ZwQueryInformationProcess
- CheckRemoteDebuggerPresent
- PEB.IsDebugged
- PEB.ProcessHeap.Flag
- PEB.NtGlobalFlag
- PEB.Ldr 0xFEEEFEEE filling
- GetTickCount
- ZwQuerySystemInformation
- FindWindowA
- FindWindowW
- FindWindowExA
- FindWindowExW
- EnumWindows
首先第一步我们需要自己封装实现一个反汇编转机器码的函数,其作用是当用户传入汇编列表时,自动将其转为机器码并输出为列表格式。
from LyScript32 import MyDebug # 传入汇编代码,得到对应机器码 def get_opcode_from_assemble(dbg_ptr,asm): byte_code = bytearray() addr = dbg_ptr.create_alloc(1024) if addr != 0: asm_size = dbg_ptr.assemble_code_size(asm) # print("汇编代码占用字节: {}".format(asm_size)) write = dbg_ptr.assemble_write_memory(addr,asm) if write == True: for index in range(0,asm_size): read = dbg_ptr.read_memory_byte(addr + index) # print("{:02x} ".format(read),end="") byte_code.append(read) dbg_ptr.delete_alloc(addr) return byte_code else: return bytearray(0) # 传入汇编机器码得到机器码列表 def GetOpCode(dbg, Code): ShellCode = [] for index in Code: ref = get_opcode_from_assemble(dbg,index) for opcode in ref: ShellCode.append(opcode) return ShellCode if __name__ == "__main__": dbg = MyDebug() connect = dbg.connect() ShellCode = GetOpCode(dbg, ["DB 0x64","mov eax,dword ptr ds:[18]","sub eax,eax","ret"]) print(ShellCode) dbg.close() 输出效果如下:

Patch_PEB
PEB结构存在许多反调试变量,首先我们需要先将这些变量填充为空。
# ---------------------------------------------- # By: LyShark # Email: me@lyshark.com # Project: https://github.com/lyshark/LyScript # ---------------------------------------------- from LyScript32 import MyDebug # 传入汇编代码,得到对应机器码 def get_opcode_from_assemble(dbg_ptr,asm): byte_code = bytearray() addr = dbg_ptr.create_alloc(1024) if addr != 0: asm_size = dbg_ptr.assemble_code_size(asm) # print("汇编代码占用字节: {}".format(asm_size)) write = dbg_ptr.assemble_write_memory(addr,asm) if write == True: for index in range(0,asm_size): read = dbg_ptr.read_memory_byte(addr + index) # print("{:02x} ".format(read),end="") byte_code.append(read) dbg_ptr.delete_alloc(addr) return byte_code else: return bytearray(0) # 传入汇编机器码得到机器码列表 def GetOpCode(dbg, Code): ShellCode = [] for index in Code: ref = get_opcode_from_assemble(dbg,index) for opcode in ref: ShellCode.append(opcode) return ShellCode def Patch_PEB(dbg): PEB = dbg.get_peb_address(dbg.get_process_id()) if PEB == 0: return 0 # 写出0 Patching PEB.IsDebugged dbg.write_memory_byte(PEB + 0x2,GetOpCode(dbg,["db 0"])[0]) print("补丁地址: {}".format(hex(PEB+0x2))) # 写出0 Patching PEB.ProcessHeap.Flag temp = dbg.read_memory_dword(PEB + 0x18) temp += 0x10 dbg.write_memory_dword(temp, GetOpCode(dbg,["db 0"])[0]) print(("补丁地址: {}".format(hex(temp)))) # 写出0 atching PEB.NtGlobalFlag dbg.write_memory_dword(PEB+0x68, 0) print(("补丁地址: {}".format(hex(PEB+0x68)))) # 循环替换 Patch PEB_LDR_DATA 0xFEEEFEEE fill bytes about 3000 of them addr = dbg.read_memory_dword(PEB + 0x0c) while addr != 0: addr += 1 try: b = dbg.read_memory_dword(addr) c = dbg.read_memory_dword(addr + 4) # 仅修补填充运行 print(b) if (b == 0xFEEEFEEE) and (c == 0xFEEEFEEE): dbg.write_memory_dword(addr,0) dbg.write_memory_dword(addr + 4, 0) print("patch") except Exception: break if __name__ == "__main__": dbg = MyDebug() connect = dbg.connect() Patch_PEB(dbg) dbg.close() Patch_IsDebuggerPresent
该函数用于检测自身是否处于调试状态,其C系列代码如下所示,绕过此种方式很简单,只需要在函数头部写出ret指令即可。
#include#include int _tmain(int argc, _TCHAR* argv[]) { BOOL ref = IsDebuggerPresent(); printf("是否被调试: %d \n", ref); getchar(); return 0; }
注意:此Api检查PEB中的值,因此如果修补PEB,则无需修补Api,这段绕过代码如下。
from LyScript32 import MyDebug # 传入汇编代码,得到对应机器码 def get_opcode_from_assemble(dbg_ptr,asm): byte_code = bytearray() addr = dbg_ptr.create_alloc(1024) if addr != 0: asm_size = dbg_ptr.assemble_code_size(asm) # print("汇编代码占用字节: {}".format(asm_size)) write = dbg_ptr.assemble_write_memory(addr,asm) if write == True: for index in range(0,asm_size): read = dbg_ptr.read_memory_byte(addr + index) # print("{:02x} ".format(read),end="") byte_code.append(read) dbg_ptr.delete_alloc(addr) return byte_code else: return bytearray(0) # 传入汇编机器码得到机器码列表 def GetOpCode(dbg, Code): ShellCode = [] for index in Code: ref = get_opcode_from_assemble(dbg,index) for opcode in ref: ShellCode.append(opcode) return ShellCode def Patch_IsDebuggerPresent(dbg): # 得到模块句柄 ispresent = dbg.get_module_from_function("kernel32.dll","IsDebuggerPresent") print(hex(ispresent)) if(ispresent <= 0): print("无法得到模块基地址,请以管理员方式运行调试器.") return 0 # 将反调试语句转为机器码 ShellCode = GetOpCode(dbg, ["DB 0x64", "mov eax,dword ptr ds:[18]", "sub eax,eax", "ret"]) print(ShellCode) flag = 0 for index in range(0,len(ShellCode)): flag = dbg.write_memory_byte(ispresent + index,ShellCode[index]) if flag: flag = 1 else: flag = 0 return flag if __name__ == "__main__": dbg = MyDebug() connect = dbg.connect() ref = Patch_IsDebuggerPresent(dbg) print("补丁状态: {}".format(ref)) dbg.close() 当程序运行后会向IsDebuggerPresent函数写出返回,从而实现绕过调试的目的。

Patch_CheckRemoteDebuggerPresent
此Api调用ZwQueryInformationProcess因此通常不需要对两者进行修补。
from LyScript32 import MyDebug # 传入汇编代码,得到对应机器码 def get_opcode_from_assemble(dbg_ptr,asm): byte_code = bytearray() addr = dbg_ptr.create_alloc(1024) if addr != 0: asm_size = dbg_ptr.assemble_code_size(asm) # print("汇编代码占用字节: {}".format(asm_size)) write = dbg_ptr.assemble_write_memory(addr,asm) if write == True: for index in range(0,asm_size): read = dbg_ptr.read_memory_byte(addr + index) # print("{:02x} ".format(read),end="") byte_code.append(read) dbg_ptr.delete_alloc(addr) return byte_code else: return bytearray(0) # 传入汇编机器码得到机器码列表 def GetOpCode(dbg, Code): ShellCode = [] for index in Code: ref = get_opcode_from_assemble(dbg,index) for opcode in ref: ShellCode.append(opcode) return ShellCode def Patch_CheckRemoteDebuggerPresent(dbg): # 得到模块句柄 ispresent = dbg.get_module_from_function("kernel32.dll","CheckRemoteDebuggerPresent") print(hex(ispresent)) # 将反调试语句转为机器码 ShellCode = GetOpCode(dbg, [ "mov edi,edi", "push ebp", "mov ebp,esp", "mov eax,[ebp+0xc]", "push 0", "pop dword ptr ds:[eax]", "xor eax,eax", "pop ebp", "ret 8" ] ) print(ShellCode) flag = 0 for index in range(0,len(ShellCode)): flag = dbg.write_memory_byte(ispresent + index,ShellCode[index]) if flag: flag = 1 else: flag = 0 return flag if __name__ == "__main__": dbg = MyDebug() connect = dbg.connect() ref = Patch_CheckRemoteDebuggerPresent(dbg) print("写出状态: {}".format(ref)) dbg.close() 写出效果如下:

Patch_GetTickCount
GetTickCount返回(retrieve)从操作系统启动所经过(elapsed)的毫秒数,常用于定时计数,绕过方式只需初始化即可。
from LyScript32 import MyDebug # 传入汇编代码,得到对应机器码 def get_opcode_from_assemble(dbg_ptr,asm): byte_code = bytearray() addr = dbg_ptr.create_alloc(1024) if addr != 0: asm_size = dbg_ptr.assemble_code_size(asm) # print("汇编代码占用字节: {}".format(asm_size)) write = dbg_ptr.assemble_write_memory(addr,asm) if write == True: for index in range(0,asm_size): read = dbg_ptr.read_memory_byte(addr + index) # print("{:02x} ".format(read),end="") byte_code.append(read) dbg_ptr.delete_alloc(addr) return byte_code else: return bytearray(0) # 传入汇编机器码得到机器码列表 def GetOpCode(dbg, Code): ShellCode = [] for index in Code: ref = get_opcode_from_assemble(dbg,index) for opcode in ref: ShellCode.append(opcode) return ShellCode def Patch_GetTickCount(dbg): # 得到模块句柄 ispresent = dbg.get_module_from_function("kernel32.dll","GetTickCount") print(hex(ispresent)) # 将反调试语句转为机器码 ShellCode = GetOpCode(dbg, [ "mov edx,0x7ffe0000", "sub eax,eax", "add eax,0xB0B1560D", "ret" ] ) print(ShellCode) flag = 0 for index in range(0,len(ShellCode)): flag = dbg.write_memory_byte(ispresent + index,ShellCode[index]) if flag: flag = 1 else: flag = 0 return flag if __name__ == "__main__": dbg = MyDebug() connect = dbg.connect() ref = Patch_GetTickCount(dbg) print("写出状态: {}".format(ref)) dbg.close() 写出效果如下:

Patch_ZwQueryInformationProcess
此函数打补丁需要跳转两次,原因是因为函数开头部分无法填充更多指令,需要我们自己来申请空间,并实现跳转。
# ---------------------------------------------- # By: LyShark # Email: me@lyshark.com # Project: https://github.com/lyshark/LyScript # ---------------------------------------------- from LyScript32 import MyDebug # 传入汇编代码,得到对应机器码 def get_opcode_from_assemble(dbg_ptr,asm): byte_code = bytearray() addr = dbg_ptr.create_alloc(1024) if addr != 0: asm_size = dbg_ptr.assemble_code_size(as
相关内容
- python进行数据合并concat/merge_python_
- Python和Excel的完美结合的常用操作案例汇总_python_
- Python 处理 Pandas DataFrame 中的行和列_python_
- python安装包出现Retrying (Retry(total=4, connect=None, read=None, redirect=None, status=None))问题解决_python_
- Python Panda中索引和选择 series 的数据_python_
- Python Pandas教程之series 上的转换操作_python_
- Numpy安装、升级与卸载的详细图文教程_python_
- 将imagenet2012数据为tensorflow的tfrecords格式并跑验证的详细过程_python_
- Python Pandas教程之使用 pandas.read_csv() 读取 csv_python_
- Python 运算符Inplace 与Standard _python_
点击排行
本栏推荐
