通过修改IAT来hook。
注意点:由于IAT不一定是连续的,因此有时候会要先定位那个模块,再找对应的IAT表。
主要测试代码如下:
1.dll(用于注入的dll):
// 1.cpp : Defines the entry point for the DLL application.
//
#include "stdafx.h"
DWORD g_dwOldAddr; // 原始函数地址
DWORD g_dwNewAddr; // Hook函数地址
DWORD g_dwIATHookFlag; // 标志有没有被hook
BOOL SetIATHook(DWORD dwOldAddr, DWORD dwNewAddr){
BOOL bFlag = FALSE;
DWORD dwImageBase = 0;
PDWORD pFuncAddr = NULL;
PIMAGE_NT_HEADERS pNtHeader = NULL;
PIMAGE_IMPORT_DESCRIPTOR pImportDescriptor = NULL;
DWORD dwOldProtect = 0;
// 得到exe模块基址
dwImageBase = (DWORD)GetModuleHandle(NULL);
pNtHeader = (PIMAGE_NT_HEADERS)(dwImageBase + ((PIMAGE_DOS_HEADER)dwImageBase)->e_lfanew);
pImportDescriptor = (PIMAGE_IMPORT_DESCRIPTOR)(dwImageBase +
pNtHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress);
// 遍历IAT表 找到这个函数的地址
while (pImportDescriptor->FirstThunk != 0 && bFlag == FALSE)
{
pFuncAddr = (PDWORD)(dwImageBase + pImportDescriptor->FirstThunk);
while (*pFuncAddr) // 遍历该模块中的函数
{
if(dwOldAddr == *pFuncAddr){
// 找到要Hook的函数,先修改内存页的属性
VirtualProtect(pFuncAddr, sizeof(DWORD), PAGE_READWRITE, &dwOldProtect);
*pFuncAddr = dwNewAddr; // !!!更改过IAT中函数的地址
VirtualProtect(pFuncAddr, sizeof(DWORD), dwOldProtect, 0);
bFlag = TRUE;
break;
}
pFuncAddr ++;
}
pImportDescriptor = (PIMAGE_IMPORT_DESCRIPTOR)((DWORD)pImportDescriptor+sizeof(IMAGE_IMPORT_DESCRIPTOR)); // 这里之前搞错了,现在更正一下
}
// 修改状态
g_dwOldAddr = dwOldAddr;
g_dwNewAddr = dwNewAddr;
g_dwIATHookFlag = 1;
return bFlag;
}
BOOL UnIATHook(){
BOOL bFlag = FALSE;
DWORD dwImageBase = 0;
PDWORD pFuncAddr = NULL;
PIMAGE_NT_HEADERS pNtHeader = NULL;
PIMAGE_IMPORT_DESCRIPTOR pImportDescriptor = NULL;
DWORD dwOldProtect = 0;
// 判断是否hook
if (!g_dwIATHookFlag)
{
OutputDebugString("UnIATHook失败:尚未进行IAT Hook!");
return bFlag;
}
// 得到exe模块基址
dwImageBase = (DWORD)GetModuleHandle(NULL);
pNtHeader = (PIMAGE_NT_HEADERS)(dwImageBase + ((PIMAGE_DOS_HEADER)dwImageBase)->e_lfanew);
pImportDescriptor = (PIMAGE_IMPORT_DESCRIPTOR)(dwImageBase +
pNtHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress);
// 遍历IAT表 找到这个函数的地址
while (pImportDescriptor->FirstThunk != 0 && bFlag == FALSE)
{
pFuncAddr = (PDWORD)(dwImageBase + pImportDescriptor->FirstThunk);
while (*pFuncAddr) // 遍历该模块中的函数
{
if(g_dwNewAddr == *pFuncAddr){
// 找到要Hook的函数,先修改内存页的属性
VirtualProtect(pFuncAddr, sizeof(DWORD), PAGE_READWRITE, &dwOldProtect);
*pFuncAddr = g_dwOldAddr; // !!!更改过IAT中函数的地址
VirtualProtect(pFuncAddr, sizeof(DWORD), dwOldProtect, 0);
bFlag = TRUE;
break;
}
pFuncAddr ++;
}
pImportDescriptor = (PIMAGE_IMPORT_DESCRIPTOR)((DWORD)pImportDescriptor+sizeof(PIMAGE_IMPORT_DESCRIPTOR));
}
// 修改状态
g_dwOldAddr = 0;
g_dwNewAddr = 0;
g_dwIATHookFlag = 1;
return bFlag;
}
int WINAPI MyMessageBox(HWND hWnd, LPCSTR lpText,LPCSTR lpCaption, UINT uType){
char lpNewText[] = "你被hook了";
// 定义MessageBox函数指针
typedef int (WINAPI *PFNMESSAGEBOX)(HWND, LPCSTR, LPCSTR, UINT);
// 执行真正的函数
int ret = ((PFNMESSAGEBOX)g_dwOldAddr)(hWnd, lpNewText, lpCaption, uType);
return ret;
}
// 线程函数
DWORD WINAPI ThreadProc(LPVOID lpParameter){
// 保存原始函数地址
DWORD pOldFuncAddr = (DWORD)GetProcAddress(LoadLibrary("user32.dll"), "MessageBoxA");
// 安装或者卸载HOOK
if (!g_dwIATHookFlag){
SetIATHook(pOldFuncAddr, (DWORD)MyMessageBox);
}else{
UnIATHook();
}
return 0;
}
BOOL APIENTRY DllMain( HANDLE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch ( ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
CreateThread(NULL,0,
(LPTHREAD_START_ROUTINE)ThreadProc,
NULL, 0,NULL);//创建新线程执行代码
break;
case DLL_PROCESS_DETACH:
break;
case DLL_THREAD_ATTACH:
break;
case DLL_THREAD_DETACH:
break;
}
return TRUE;
}
injection.cpp(运行来注入dll的程序):
#include <windows.h>
#include <tlhelp32.h>
#include <stdio.h>
DWORD GetPid(char* szName){
HANDLE hprocessSnap = NULL;
PROCESSENTRY32 pe32 = {0};
hprocessSnap = CreateToolhelp32Snapshot(
TH32CS_SNAPPROCESS,
0);//捕捉所有进程的快照
if (hprocessSnap == INVALID_HANDLE_VALUE){
//快照失败
return 0;
}
//初始化pe32结构体
pe32.dwSize = sizeof(PROCESSENTRY32);
if (Process32First(hprocessSnap, &pe32)){
do{
if (!strcmp(szName, pe32.szExeFile)){
printf("Process Found, PID: %d
", (int)pe32.th32ProcessID);
return (int)pe32.th32ProcessID;
}
//遍历查找进程名
}while (Process32Next(hprocessSnap, &pe32));
}else{
CloseHandle(hprocessSnap);
}
return 0;
}
//远程线程注入
BOOL load_dll(DWORD dwProcessID, char* szDllPathName)
//进程PID和dll完整的路径
{
BOOL bRet;
HANDLE hProcess;
HANDLE hThread;
DWORD dwLength;
DWORD dwLoadAddr;
LPVOID lpAllocAddr;
DWORD dwThreadID;
HMODULE hModule;
//获取进程句柄
hProcess = OpenProcess(PROCESS_ALL_ACCESS,FALSE,dwProcessID);
printf("%x
", hProcess);
if (hProcess == NULL)
{
OutputDebugString("fail to open process
");
return FALSE;
}
//把DLL文件路径字符串存入被注入进程的内存空间
//计算dll路径名字长度,并且加上结尾0的空间
dwLength = strlen(szDllPathName)+1;
//远程申请内存空间
lpAllocAddr = (LPVOID)VirtualAllocEx(hProcess,NULL,dwLength,MEM_COMMIT,PAGE_READWRITE);
if (lpAllocAddr == NULL){
OutputDebugString("VirtualAllocEx error
");
CloseHandle(hProcess);
return FALSE;
}
//拷贝dll路径名字到目标进程的内存
bRet = WriteProcessMemory(hProcess, lpAllocAddr,szDllPathName,dwLength,NULL);
if (bRet == NULL){
OutputDebugString("bRet error
");
CloseHandle(hProcess);
return FALSE;
}
//获取kernel32.dll的地址
hModule = GetModuleHandle("Kernel32.dll");
if (!hModule)
{
OutputDebugString("GetModuleHandle error
");
CloseHandle(hProcess);
return FALSE;
}
//获取LoadLibraryA函数地址
dwLoadAddr = (DWORD)GetProcAddress(hModule, "LoadLibraryA");
if (!dwLoadAddr )
{
OutputDebugString("GetProcAddress error
");
CloseHandle(hProcess);
CloseHandle(hModule);
return FALSE;
}
//创建远程线程,加载dll
hThread = CreateRemoteThread(hProcess, NULL, 0, (unsigned long (__stdcall *)(void *))dwLoadAddr, lpAllocAddr, 0, NULL);
printf("%x
", hThread);
if (hThread == NULL)
{
OutputDebugString("fail to open RomoteThread
");
CloseHandle(hProcess);
return FALSE;
}
CloseHandle(hProcess);
return TRUE;
}
void main(){
load_dll(GetPid("1.exe"), "C:\Users\thinkpad\Desktop\IATHook\dll\1\Debug\1.dll");
}
被注入的程序:
#include <windows.h>
int main(){
while (1){
MessageBox(0,0,0,0);
Sleep(1000);
}
return 0;
}
经过测试可以成功hookMessageBoxA这样一个函数。
但是有些细节做的不是很好,有空改进一下。