WindowsHook

以MessageBox为例演示两种方法

修改入口点

获取原函数地址

需定义

1
FARPROC pfOldMsgBoxW;  //指向函数的远指针
1
2
3
//获取原API入口地址
HMODULE hModule = LoadLibrary(L"User32.dll");
pfOldMsgBoxW = GetProcAddress(hModule, "MessageBoxW");

创建新函数

注意传参与返回值应与原函数一致。

1
2
3
4
5
int WINAPI MyMessageBoxW(HWND hWnd, LPCWSTR lpText, LPCWSTR lpCaption, UINT uType)
{
printf("FUCK YOU VIRTUALPROTECT!\n");
return 0;
}

保存原函数的前5字节

1
2
3
4
5
6
7
8
9
// 将原API的入口前5个字节代码保存到OldCode[]
_asm
{
lea edi, OldCode //获取OldCode数组的地址,放到edi
mov esi, pfOldMsgBoxW //获取原API入口地址,放到esi
cld //方向标志位,为以下两条指令做准备
movsd //复制原API入口前4个字节到OldCode数组
movsb //复制原API入口第5个字节到OldCode数组
}

保存新函数的前4字节

注意将NewCode[0]设置为0xe9

1
2
3
4
5
6
7
8
9
10
11
12
13
//获取MyMessageBoxW的相对地址,为Jmp做准备
//int nAddr= UserFunAddr – SysFunAddr - (我们定制的这条指令的大小);
//Jmp nAddr;
//(我们定制的这条指令的大小), 这里是5,5个字节嘛
_asm
{
lea eax, MyMessageBoxW //获取我们的MyMessageBoxW函数地址
mov ebx, pfOldMsgBoxW //原系统API函数地址
sub eax, ebx //int nAddr = UserFunAddr - SysFunAddr
sub eax, 5 //nAddr = nAddr - 5
mov dword ptr[NewCode + 1], eax //将算出的地址nAddr保存到NewCode后面4个字节
//注:一个函数地址占4个字节
}

创建HookOn与HookOff函数

1
2
3
4
5
6
7
8
9
10
11
12
13
//开启钩子的函数
void HookOn()
{
DWORD dwTemp = 0;
DWORD dwOldProtect;
DWORD dwPid = GetCurrentProcessId();
HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, 0, dwPid);

//修改API函数入口前5个字节为jmp xxxxxx
VirtualProtectEx(hProcess, pfOldMsgBoxW, 5, PAGE_READWRITE, &dwOldProtect);
WriteProcessMemory(hProcess, pfOldMsgBoxW, NewCode, 5, 0);
VirtualProtectEx(hProcess, pfOldMsgBoxW, 5, dwOldProtect, &dwTemp);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
//关闭钩子的函数
void HookOff()
{
DWORD dwTemp = 0;
DWORD dwOldProtect;
DWORD dwPid = GetCurrentProcessId();
HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, 0, dwPid);

//恢复API函数入口前5个字节
VirtualProtectEx(hProcess, pfOldMsgBoxW, 5, PAGE_READWRITE, &dwOldProtect);
WriteProcessMemory(hProcess, pfOldMsgBoxW, OldCode, 5, 0);
VirtualProtectEx(hProcess, pfOldMsgBoxW, 5, dwOldProtect, &dwTemp);
}

完整代码

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
55
56
57
58
59
60
61
62
63
64
65
66
67
68
#include <iostream>
#include <Windows.h>

using namespace std;

FARPROC pfOldMsgBoxW;
BYTE NewCode[5] = {0xe9}, OldCode[5];

void HookOn()
{
DWORD dwTemp = 0;
DWORD dwOldProtect;
DWORD dwPid = GetCurrentProcessId();
HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, 0, dwPid);

VirtualProtectEx(hProcess, pfOldMsgBoxW, 5, PAGE_READWRITE, &dwOldProtect);
WriteProcessMemory(hProcess, pfOldMsgBoxW, NewCode, 5, 0);
VirtualProtectEx(hProcess, pfOldMsgBoxW, 5, dwOldProtect, &dwTemp);
}

void HookOff()
{
DWORD dwTemp = 0;
DWORD dwOldProtect;
DWORD dwPid = GetCurrentProcessId();
HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, 0, dwPid);

VirtualProtectEx(hProcess, pfOldMsgBoxW, 5, PAGE_READWRITE, &dwOldProtect);
WriteProcessMemory(hProcess, pfOldMsgBoxW, OldCode, 5, 0);
VirtualProtectEx(hProcess, pfOldMsgBoxW, 5, dwOldProtect, &dwTemp);
}

int WINAPI MyMessageBoxW(HWND hWnd, LPCWSTR lpText, LPCWSTR lpCaption, UINT uType)
{
printf("FUCK YOU VIRTUALPROTECT!\n");
return 0;
}

int main()
{
HMODULE hModule = LoadLibrary(L"User32.dll");
pfOldMsgBoxW = GetProcAddress(hModule, "MessageBoxW");

_asm
{
lea edi, OldCode
mov esi, pfOldMsgBoxW
cld
movsd
movsb
}

_asm
{
lea eax, MyMessageBoxW
mov ebx, pfOldMsgBoxW
sub eax, ebx
sub eax, 5
mov dword ptr[NewCode + 1], eax
}

MessageBoxW(0, L"test", L"test", 0);
HookOn();
MessageBoxW(0, L"test", L"test", 0);
HookOff();
MessageBoxW(0, L"test", L"test", 0);
return 0;
}

修改IAT表

获取原函数地址

1
2
int OldAddr;
OldAddr = (int)GetProcAddress(LoadLibrary(L"user32.dll"), "MessageBoxA");

创建新函数

1
2
3
4
5
int WINAPI NewMessageBox (HWND hWnd, LPCSTR lpText, LPCSTR lpCaption, UINT uType)
{
printf("FUCK YOU VIRTUALPROTECT!");
return 0;
}

遍历IAT表

遍历IAT表寻找原函数的地址,将其改写为新函数的地址

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
int SetIATHook(int OldAddr, int NewAddr)
{
DWORD ImageBase = 0;
DWORD dwTemp;
PDWORD pFunAddr = 0;
PIMAGE_DOS_HEADER pDosHeader = NULL;
PIMAGE_NT_HEADERS pNtHeader = NULL;
PIMAGE_FILE_HEADER pFileHeader = NULL;
PIMAGE_OPTIONAL_HEADER pOptionalHeader = NULL;
PIMAGE_DATA_DIRECTORY pDataDirectory = NULL;
PIMAGE_IMPORT_DESCRIPTOR pImportDirectory = NULL;

ImageBase = (DWORD)GetModuleHandle(NULL);
pDosHeader = (PIMAGE_DOS_HEADER)ImageBase;
pNtHeader = (PIMAGE_NT_HEADERS)(ImageBase + pDosHeader->e_lfanew);
pFileHeader = (PIMAGE_FILE_HEADER)((DWORD)pNtHeader + 4);
pOptionalHeader = (PIMAGE_OPTIONAL_HEADER)((DWORD)pFileHeader + sizeof(_IMAGE_FILE_HEADER));
pDataDirectory = pOptionalHeader->DataDirectory;
pImportDirectory = (PIMAGE_IMPORT_DESCRIPTOR)(ImageBase + (pDataDirectory + 1)->VirtualAddress);

VirtualProtect((LPVOID)ImageBase, 0x20000, 0x40, &dwTemp);

while (pImportDirectory->FirstThunk != 0 && pImportDirectory->OriginalFirstThunk != 0)
{
pFunAddr = (PDWORD)(ImageBase + pImportDirectory->FirstThunk);
while (*pFunAddr)
{
if (OldAddr == *pFunAddr)
{
*pFunAddr = NewAddr;
return 0;
}
pFunAddr++;
}
pImportDirectory++;
}
return 0;
}

完整代码

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
55
56
57
58
59
60
#include <iostream>
#include <stdio.h>
#include <Windows.h>

using namespace std;

int SetIATHook(int OldAddr, int NewAddr)
{
DWORD ImageBase = 0;
DWORD dwTemp;
PDWORD pFunAddr = 0;
PIMAGE_DOS_HEADER pDosHeader = NULL;
PIMAGE_NT_HEADERS pNtHeader = NULL;
PIMAGE_FILE_HEADER pFileHeader = NULL;
PIMAGE_OPTIONAL_HEADER pOptionalHeader = NULL;
PIMAGE_DATA_DIRECTORY pDataDirectory = NULL;
PIMAGE_IMPORT_DESCRIPTOR pImportDirectory = NULL;

ImageBase = (DWORD)GetModuleHandle(NULL);
pDosHeader = (PIMAGE_DOS_HEADER)ImageBase;
pNtHeader = (PIMAGE_NT_HEADERS)(ImageBase + pDosHeader->e_lfanew);
pFileHeader = (PIMAGE_FILE_HEADER)((DWORD)pNtHeader + 4);
pOptionalHeader = (PIMAGE_OPTIONAL_HEADER)((DWORD)pFileHeader + sizeof(_IMAGE_FILE_HEADER));
pDataDirectory = pOptionalHeader->DataDirectory;
pImportDirectory = (PIMAGE_IMPORT_DESCRIPTOR)(ImageBase + (pDataDirectory + 1)->VirtualAddress);

VirtualProtect((LPVOID)ImageBase, 0x20000, 0x40, &dwTemp);

while (pImportDirectory->FirstThunk != 0 && pImportDirectory->OriginalFirstThunk != 0)
{
pFunAddr = (PDWORD)(ImageBase + pImportDirectory->FirstThunk);
while (*pFunAddr)
{
if (OldAddr == *pFunAddr)
{
*pFunAddr = NewAddr;
return 0;
}
pFunAddr++;
}
pImportDirectory++;
}
return 0;
}

int WINAPI NewMessageBox (HWND hWnd, LPCSTR lpText, LPCSTR lpCaption, UINT uType)
{
printf("FUCK YOU VIRTUALPROTECT!");
return 0;
}

int main(int argc, char* argv[])
{
int OldAddr;
OldAddr = (int)GetProcAddress(LoadLibrary(L"user32.dll"), "MessageBoxA");
MessageBoxA(0, "test", "Old", 0);
SetIATHook(OldAddr, (int)NewMessageBox);
MessageBoxA(0, "test", "Old", 0);
return 0;
}