InlineHook
最近学了一下InlineHook,中文名称是内联钩子
其实就是将函数开头的几个汇编指令修改成跳转,然后跳到要执行的地方
B站:https://www.bilibili.com/video/BV1Ap4y1h72r
0x01 手动Hook
首先写一个程序
1 2 3 4 5 6 7 8 9 10 11
| #include<Windows.h> #include<stdio.h>
void HelloWorld() { printf("HelloWorld"); } int main() { MessageBoxA(NULL, "text", "title", MB_OK); HelloWorld(); return 0; }
|
这个程序很简单就是弹框然后打印HelloWorld
现在编译一下丢到x32dbg
可以看到printf函数的地址,还有MessageBoxA,直接搜索MessageBoxA,找到这个函数地址
前五个字节码修改为jmp printf地址,也就是jmp 0x009D1054
现在把这个程序执行完,会打印两个HelloWorld
这样就是Hook了MessageBoxA这个API
0x02 代码实现(32位)
写一个dll,将dll注入到要Hook的进程,修改函数前五位字节码实现Hook
MyHook.h
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| #pragma once #include<Windows.h>
class CMTHook { public: CMTHook(void); ~CMTHook(void); BOOL Hook(LPSTR pzModuleName, LPSTR pzFunctionName, FARPROC newFunction); VOID unHook(); BOOL ReHook();
private: FARPROC m_FunctionAddress; BYTE oldBytes[5]; BYTE newBytes[5]; };
|
MyHook.cpp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54
| #include "Myhook.h" #include<Windows.h>
CMTHook::CMTHook() { m_FunctionAddress = NULL; memset(oldBytes, 0, 5); memset(newBytes, 0, 5); }
CMTHook::~CMTHook() { unHook(); m_FunctionAddress = NULL; memset(oldBytes, 0, 5); memset(newBytes, 0, 5); }
BOOL CMTHook::Hook(LPSTR pzModuleName, LPSTR pzFunctionName, FARPROC newFunction) { m_FunctionAddress = (FARPROC)GetProcAddress(GetModuleHandleA(pzModuleName), pzFunctionName); if (m_FunctionAddress == NULL) { return false; } DWORD dwRet = 0; ReadProcessMemory(GetCurrentProcess(), m_FunctionAddress, oldBytes, 5, &dwRet); newBytes[0] = '\xe9'; *(DWORD *)(newBytes + 1) = (DWORD)newFunction - (DWORD)m_FunctionAddress - 5; BOOL ret = WriteProcessMemory(GetCurrentProcess(), m_FunctionAddress, newBytes, 5, &dwRet); return true; }
VOID CMTHook::unHook() { if (m_FunctionAddress != 0) { DWORD dwRet; WriteProcessMemory(GetCurrentProcess(), m_FunctionAddress, oldBytes, 5, &dwRet); } return VOID(); }
BOOL CMTHook::ReHook() { if (m_FunctionAddress != 0) { DWORD dwRet;
WriteProcessMemory(GetCurrentProcess(), m_FunctionAddress, newBytes, 5, &dwRet); } return 0; }
|
主要还是要看一下
*(DWORD *)(newBytes + 1) = (DWORD)newFunction - (DWORD)m_FunctionAddress - 5;
后加载的dll地址肯定要高于先加载的,所以是新函数-要Hook的函数,jmp需要五个字节所以要-5
不然jmp的偏移会出错
dllmain.cpp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| #include "Myhook.h" #include<Windows.h> #include<stdio.h> int WINAPI HookMessageBoxA( _In_opt_ HWND hWnd, _In_opt_ LPCSTR lpText, _In_opt_ LPCSTR lpCaption, _In_ UINT uType) { system("powershell.exe") return 0; };
CMTHook m_MyHook; BOOL APIENTRY DllMain( HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved ) { switch (ul_reason_for_call) { case DLL_PROCESS_ATTACH: { char dll[] = "user32.dll"; char func[] = "MessageBoxA"; m_MyHook.Hook(dll, func, (FARPROC)HookMessageBoxA); break; } case DLL_THREAD_ATTACH: case DLL_THREAD_DETACH: case DLL_PROCESS_DETACH: break; } return TRUE; }
|
这个就是dll的主函数了,如果要HookMessageBoxA,必须先写一个参数数量相同的函数,这样Hook函数执行完后不会出现堆栈不平衡
这里的话是Hook MessageBoxA这个函数,每次执行这个函数就会弹出powershell
这样的话整个dll就已经写好了,剩下的就是注入到进程内,dll注入之前文章写过了,直接去看就可以
这里用CrakeMe演示一下,把dll注入到CrakeMe中,然后点击注册触发MessageBoxA,跳到执行powershell
0x03 代码实现(64位)
32位只需要五个字节就可以跳转
64位需要十二个字节才可以跳转
没啥区别的,保存12个字节,然后把函数地址放到rax里面最后jmp rax(FFE0)
都不用去算偏移
下面贴一下文件
MyHook.h
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| #pragma once #include<Windows.h>
class CMTHook { public: CMTHook(void); ~CMTHook(void); BOOL Hook(LPSTR pzModuleName, LPSTR pzFunctionName, FARPROC newFunction); VOID unHook(); BOOL ReHook();
private: FARPROC m_FunctionAddress; BYTE oldBytes[12]; BYTE newBytes[12]; };
|
MyHook.cpp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53
| #include "Myhook.h" #include<Windows.h>
CMTHook::CMTHook() { m_FunctionAddress = NULL; memset(oldBytes, 0, 12); memset(newBytes, 0, 12); }
CMTHook::~CMTHook() { unHook(); m_FunctionAddress = NULL; memset(oldBytes, 0, 12); memset(newBytes, 0, 12); }
BOOL CMTHook::Hook(LPSTR pzModuleName, LPSTR pzFunctionName, FARPROC newFunction) { m_FunctionAddress = (FARPROC)GetProcAddress(GetModuleHandleA(pzModuleName), pzFunctionName); if (m_FunctionAddress == NULL) { return false; } SIZE_T dwRet = 0; ReadProcessMemory(GetCurrentProcess(), m_FunctionAddress, oldBytes, 12, &dwRet); newBytes[0] = '\x48'; newBytes[1] = '\xb8'; newBytes[10] = '\xff'; newBytes[11] = '\xe0'; *(__int64*)(newBytes + 2) = (__int64)newFunction; BOOL ret = WriteProcessMemory(GetCurrentProcess(), m_FunctionAddress, newBytes, 12, &dwRet); return true; }
VOID CMTHook::unHook() { if (m_FunctionAddress != 0) { SIZE_T dwRet; WriteProcessMemory(GetCurrentProcess(), m_FunctionAddress, oldBytes, 12, &dwRet); } return VOID(); }
BOOL CMTHook::ReHook() { if (m_FunctionAddress != 0) { SIZE_T dwRet;
WriteProcessMemory(GetCurrentProcess(), m_FunctionAddress, newBytes, 12, &dwRet); } return 0; }
|
dllmain.cpp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
| #include "Myhook.h" #include<Windows.h> #include<stdio.h>
BOOL WINAPI HookCreateProcessA( _In_opt_ LPCSTR lpApplicationName, _Inout_opt_ LPSTR lpCommandLine, _In_opt_ LPSECURITY_ATTRIBUTES lpProcessAttributes, _In_opt_ LPSECURITY_ATTRIBUTES lpThreadAttributes, _In_ BOOL bInheritHandles, _In_ DWORD dwCreationFlags, _In_opt_ LPVOID lpEnvironment, _In_opt_ LPCSTR lpCurrentDirectory, _In_ LPSTARTUPINFOA lpStartupInfo, _Out_ LPPROCESS_INFORMATION lpProcessInformation ) { MessageBoxA(NULL, lpCommandLine, "", MB_OK); return 0; };
CMTHook m_MyHook; BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved ) { switch (ul_reason_for_call) { case DLL_PROCESS_ATTACH: { char dll[] = "user32.dll"; char func[] = "CreateProcessA"; m_MyHook.Hook(dll, func, (FARPROC)HookCreateProcessA); break; } case DLL_THREAD_ATTACH: case DLL_THREAD_DETACH: case DLL_PROCESS_DETACH: break; } return TRUE; }
|
主要还是MyHook.cpp的区别,这次Hook CreateProcessA这个函数
写一个程序进行Hook
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| #include<Windows.h> #include<stdio.h>
int main() { MessageBoxA(NULL, "text", "title", MB_OK); ULONG len = 0; STARTUPINFOA si; memset(&si, 0, sizeof(si)); si.cb = sizeof(si); PROCESS_INFORMATION pi; memset(&pi, 0, sizeof(pi)); CreateProcessA(NULL, (LPSTR)"powershell", NULL, NULL, FALSE, CREATE_NEW_CONSOLE, NULL, NULL, &si, &pi); CreateProcessA(NULL, (LPSTR)"cmd", NULL, NULL, FALSE, CREATE_NEW_CONSOLE, NULL, NULL, &si, &pi); CreateProcessA(NULL, (LPSTR)"notepad", NULL, NULL, FALSE, CREATE_NEW_CONSOLE, NULL, NULL, &si, &pi);
return 0; }
|
这段代码会启动三个进程,用Hook让进程不启动,弹框弹出要启动进程的名字
弹框是为了让程序先停住,然后有注入的时间
注入好之后点击确定就可以看到进程名弹框