windows 下,api钩子目前比较稳定和健壮的方法。
1、读取pe 文件:ImageDirectoryEntryToData
2、找到函数表中的 函数地址
(PROC *)&pThunk->u1.Function;
3、替换函数地址
WriteProcessMemory(GetCurrentProcess(), ppfn, &pfnNew, sizeof(pfnNew), nullptr)
该方法和cpu无关,不需要汇编知识和其他知识,只需要c++相关知识和pe文件结构。
需要注意的有:动态LoadLibrary之后,也需要再一次挂钩。如果需要在其它进程挂钩api,还需要dll挂载知识。
#include "stdafx.h"
#include <windows.h>
#include <iostream>
#include <ImageHlp.h>
#include <tlhelp32.h>
#include <psapi.h>
#pragma comment(lib, "ImageHlp")
void ReplaceIATEntryInAllMods(PCSTR pszCalleeModName, PROC pfnCurrent, PROC pfnNew);
int WINAPI MyMessageBox(HWND hWnd, LPCWSTR lpText, LPCWSTR lpCaption, UINT uType);
PROC g_pOldMsgBox = nullptr;
int main()
{
MessageBox(nullptr, L"修改前", L"", MB_OK);
g_pOldMsgBox = ::GetProcAddress(GetModuleHandleA("User32.dll"), "MessageBoxW");
ReplaceIATEntryInAllMods("User32.dll", g_pOldMsgBox, (PROC)MyMessageBox);
MessageBox(nullptr, L"修改前", L"", MB_OK);
getchar();
return 0;
}
int WINAPI MyMessageBox(HWND hWnd, LPCWSTR lpText, LPCWSTR lpCaption, UINT uType)
{
typedef int(WINAPI *pMsgBoxFunType) (HWND hWnd, LPCWSTR lpText, LPCWSTR lpCaption, UINT uType);
pMsgBoxFunType pMsgBox = (pMsgBoxFunType)((void *)(g_pOldMsgBox));
return (*pMsgBox)(nullptr, L"修改后", L"", MB_OK);
}
void ReplaceIATEntryInOneMod(PCSTR pszCalleemodName,PROC pfnCurrent,PROC pfnNew,HMODULE hModCaller)
{
ULONG ulSize = 0;
PIMAGE_IMPORT_DESCRIPTOR pImportDesc = nullptr;
try
{
pImportDesc = (PIMAGE_IMPORT_DESCRIPTOR)ImageDirectoryEntryToData(hModCaller,TRUE, IMAGE_DIRECTORY_ENTRY_IMPORT,&ulSize);
}
catch (...)
{
}
if (nullptr == pImportDesc)
{
return;
}
for (; pImportDesc->Name; ++pImportDesc)
{
PSTR pszModName = (PSTR)((PBYTE)hModCaller + pImportDesc->Name);
if (0 != lstrcmpiA(pszModName, pszCalleemodName))
{
continue;
}
PIMAGE_THUNK_DATA pThunk = (PIMAGE_THUNK_DATA)((PBYTE)hModCaller + pImportDesc->FirstThunk);
for (;pThunk->u1.Function; ++ pThunk )
{
PROC *ppfn = (PROC *)&pThunk->u1.Function;
bool bFind = (*ppfn == pfnCurrent);
if (!bFind)
{
continue;
}
if (!WriteProcessMemory(GetCurrentProcess(), ppfn, &pfnNew, sizeof(pfnNew), nullptr)
&& (ERROR_NOACCESS == GetLastError()))
{
DWORD dwOldProtect = 0;
if (VirtualProtect(ppfn, sizeof(pfnNew), PAGE_WRITECOPY, &dwOldProtect))
{
WriteProcessMemory(GetCurrentProcess(), ppfn, &pfnNew, sizeof(pfnNew), nullptr);
VirtualProtect(ppfn, sizeof(pfnNew), dwOldProtect, &dwOldProtect);
}
}
return;
}
}
}
HMODULE ModuleFromAddress(PVOID pv)
{
MEMORY_BASIC_INFORMATION mbi = {};
return ((0 != VirtualQuery(pv, &mbi, sizeof(mbi))) ? (HMODULE)mbi.AllocationBase:nullptr);
}
void ReplaceIATEntryInAllMods(PCSTR pszCalleeModName, PROC pfnCurrent, PROC pfnNew)
{
HMODULE hmodThisMod = ModuleFromAddress(ReplaceIATEntryInAllMods);
hmodThisMod = GetModuleHandle(NULL);
hmodThisMod = nullptr;
auto hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, GetCurrentProcessId());
if (INVALID_HANDLE_VALUE == hSnap)
{
return;
}
MODULEENTRY32 me = { sizeof(me) };
if (!Module32First(hSnap, &me))
{
CloseHandle(hSnap);
return;
}
do
{
if (me.hModule != hmodThisMod)
{
ReplaceIATEntryInOneMod(pszCalleeModName, pfnCurrent, pfnNew, me.hModule);
}
} while (Module32Next(hSnap, &me));
CloseHandle(hSnap);
}