本文主要讲解 HOOK API 的传统实现方式, 很多新手再玩HOOK的时候经常抄袭别人的代码,至于到底怎么实现的,可能看了半天没看明白。
所以高手请飘过~~~~~~~~~~~ 嘿嘿本人是搞破解的一直在加脱壳版里的,最近搞安全工作就来这里混了 请高手多多支持1
废话不说请看下文
注意:本文为了为了方便直接用 VirtualProtect 这个API的原型进行解释,而所有地址都只是为了方便讲解自行设定的,
你可以从 step1-9 个步骤看 jmp 的过程很容易就理解其真实原理,再不明白的话你只能改行了。
代码:
MyFunc: 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 00401000 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00401010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 type TVirtualProtect = function(lpAddress: Pointer; dwSize, flNewProtect: DWORD; lpflOldProtect: Pointer): BOOL; stdcall; var PVirtualProtect: TVirtualProtect; function HookVirtualProtect(lpAddress: Pointer; dwSize, flNewProtect: DWORD; lpflOldProtect: Pointer): BOOL; stdcall; begin Result:= PVirtualProtect(lpAddress, dwSize, flNewProtect, lpflOldProtect); -> step8 返回 00010005 (转移后的原API开始) {HOOK CODE} -> step9 这里自然就是你自己要写的代码了 end;
由原来返回的 00010005 处 -5 读取 10000000 (原 API 地址), 00010005 处 -1 读取 05 (原API指令长度)
RtlMoveMemory(10000000, 00010005, 05);
FreeMem, GlobalFree, HeapFree 释放堆(00010005-5);
当然还有过程中的 VirtualProtect 修改内存属性这里就不再叙述了
OnHOOK API 过程如下
代码:
Heap:原 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 00010000 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00010010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00010000 00 DB 00 -> step3 GetMem, GlobalAlloc, HeapAlloc 申请堆 00010001 00 DB 00 00010002 00 DB 00 00010003 00 DB 00 00010004 00 DB 00 00010005 00 DB 00 00010006 00 DB 00 00010007 00 DB 00 00010008 00 DB 00 00010009 00 DB 00 0001000A 00 DB 00 0001000B 00 DB 00 0001000C 00 DB 00 0001000D 00 DB 00 0001000E 00 DB 00 Heap:改 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 00010000 00 00 00 10 05 8B FF 55 8B EC E9 F6 FF FE 0F 00 00010010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00010000 00000010 DD 10000000 -> step4 CopyMemory, RtlMoveMemory, P^ 写入原API地址 DWORD 00010004 05 DB 05 -> step7 写入原API指令长度 00010005 8BFF MOV EDI,EDI -> step5 计算原API指令长度 并在此 00010005 位置写入 00010007 55 PUSH EBP 00010008 8BEC MOV EBP,ESP 0001000A E9 F6FFFE0F JMP 10000005 -> step6 10000005(原API继续) - 00010005(原API开始) -5(原API指令长度) -5(这个JMP用的指令长度) = 0FFEFFF6 指令地址 10000000 指令长度 2 存储长度 2 指令地址 10000002 指令长度 1 存储长度 3 指令地址 10000003 指令长度 2 存储长度 5 指令地址 10000005 堆栈地址 00010005 API:原 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10000000 8B FF 55 8B EC FF 75 14 FF 75 10 FF 75 0C FF 75 10000010 08 6A FF E8 75 FF FF FF 5D C2 10 00 90 90 90 90 10000000 > 8BFF MOV EDI,EDI -> step1 GetProcAddress(LoadLibraryA('kernel32.dll'), 'VirtualProtect') 10000002 55 PUSH EBP 10000003 8BEC MOV EBP,ESP 10000005 FF75 14 PUSH DWORD PTR SS:[EBP+14] 10000008 FF75 10 PUSH DWORD PTR SS:[EBP+10] 1000000B FF75 0C PUSH DWORD PTR SS:[EBP+C] 1000000E FF75 08 PUSH DWORD PTR SS:[EBP+8] 10000011 6A FF PUSH -1 10000013 E8 75FFFFFF CALL kernel32.VirtualProtectEx 10000018 5D POP EBP 10000019 C2 1000 RETN 10 1000001C 90 NOP 1000001D 90 NOP 1000001E 90 NOP 1000001F 90 NOP API:改 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10000000 E9 FB 0F 40 F0 FF 75 14 FF 75 10 FF 75 0C FF 75 10000010 08 6A FF E8 75 FF FF FF 5D C2 10 00 90 90 90 90 10000000 > E9 FB0F40F0 JMP 00401000 -> step2 00401000(MyFunc地址) - 10000000(API地址) - 5(指令长度) = F0400FFB 10000005 FF75 14 PUSH DWORD PTR SS:[EBP+14] 10000008 FF75 10 PUSH DWORD PTR SS:[EBP+10] 1000000B FF75 0C PUSH DWORD PTR SS:[EBP+C] 1000000E FF75 08 PUSH DWORD PTR SS:[EBP+8] 10000011 6A FF PUSH -1 10000013 E8 75FFFFFF CALL kernel32.VirtualProtectEx 10000018 5D POP EBP 10000019 C2 1000 RETN 10 1000001C 90 NOP 1000001D 90 NOP 1000001E 90 NOP 1000001F 90 NOP
话外音:
简单实现 SetWindowsHookEx 钩子注入的检查法, 没有什么技术含量只是用于简单的对自身程序或自身程序创建的进程进行简单保护, 发现后直接 退出进程
0012FC28 77D28055 /CALL 到 LoadLibraryExW 来自 user32.77D2804F
0012FC2C 0012FC88 |FileName = "D:\QS0905\qsl.dll"
0012FC30 00000000 |hFile = NULL
0012FC34 00000008 \Flags = LOAD_WITH_ALTERED_SEARCH_PATH
首先对自身进程或创建进程的 LoadLibraryExW HOOK掉, 并实时监测, 检查达到此入口函数的 ESP 是否是 USER32.DLL 模块中, 并且检查 Flags = LOAD_WITH_ALTERED_SEARCH_PATH, 也可以检查 DLL 路径是否是自身程序或者创建进程的所在目录,如果满足,说明是被外部程序挂了钩子, 如果是被远程线程注入的话就比较难判断, 不过都在R3下的还是可以监测到的, R0的话只能说 佛祖保佑你. ok 就到这里咯