WindowsHook
WindowsHook
以MessageBox为例演示两种方法
修改入口点
获取原函数地址
需定义
FARPROC pfOldMsgBoxW; //指向函数的远指针
//获取原API入口地址
HMODULE hModule = LoadLibrary(L"User32.dll");
pfOldMsgBoxW = GetProcAddress(hModule, "MessageBoxW");
创建新函数
注意传参与返回值应与原函数一致。
int WINAPI MyMessageBoxW(HWND hWnd, LPCWSTR lpText, LPCWSTR lpCaption, UINT uType)
{
printf("FUCK YOU VIRTUALPROTECT!\n");
return 0;
}
保存原函数的前5字节
// 将原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
//获取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函数
//开启钩子的函数
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);
}
//关闭钩子的函数
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);
}
完整代码
#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表
获取原函数地址
int OldAddr;
OldAddr = (int)GetProcAddress(LoadLibrary(L"user32.dll"), "MessageBoxA");
创建新函数
int WINAPI NewMessageBox (HWND hWnd, LPCSTR lpText, LPCSTR lpCaption, UINT uType)
{
printf("FUCK YOU VIRTUALPROTECT!");
return 0;
}
遍历IAT表
遍历IAT表寻找原函数的地址,将其改写为新函数的地址
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;
}
完整代码
#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;
}