IAT HOOK的缺点
- 容易被检测。
- 只能HOOK IAT表中的函数。
Inline Hook
DLL
dllmain.cpp
// dllmain.cpp : 定义 DLL 应用程序的入口点。
#include "pch.h"
#include "Inline Hook.h"
DWORD WINAPI ThreadProc(LPVOID lpParameter)
{
SetMessageBoxHook();
return NULL;
}
BOOL APIENTRY DllMain( HMODULE 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);
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
Inline Hook.h
#pragma once
#include <Windows.h>
VOID SetMessageBoxHook();
Inline Hook.cpp
#include "pch.h"
#include "Inline Hook.h"
#define PATCH_LENGTH 6
DWORD dwHookAddress = NULL;
DWORD dwRetAddress = NULL;
char szNewText[] = "InlineHook!";
//设置为裸函数 否则编译器会生成一堆乱七八糟的东西
void __declspec(naked) NewMessageBox()
{
_asm
{
//保存寄存器
PUSHAD
PUSHFD
//修改数据
LEA EAX, DWORD PTR DS : [szNewText]
MOV DWORD PTR SS : [ESP + 0x24 + 8] , EAX
//恢复寄存器
POPFD
POPAD
//执行覆盖的代码
MOV EDI, EDI
PUSH EBP
MOV EBP, ESP
//返回执行
JMP dwRetAddress
}
}
BOOL HookMessageBox(BOOL bOpen)
{
BOOL bRet = FALSE;
BYTE byJmpCode[PATCH_LENGTH] = { 0xE9 };
DWORD dwOldProtect = NULL;
static BYTE byOriginalCode[PATCH_LENGTH] = { 0 };
static BOOL bHookFlag = FALSE;
//初始化byJmpCode
memset(&byJmpCode[1], 0x90, PATCH_LENGTH - 1);
//储存跳转地址
*(DWORD*)&byJmpCode[1] = (DWORD)NewMessageBox - (DWORD)dwHookAddress - 5;
//备份被覆盖的硬编码
memcpy(byOriginalCode, (LPVOID)dwHookAddress, PATCH_LENGTH);
//开始PATCH
if (bOpen)
{
if (!bHookFlag)
{
VirtualProtect((LPVOID)dwHookAddress, PATCH_LENGTH, PAGE_EXECUTE_READWRITE, &dwOldProtect);
memcpy((LPVOID)dwHookAddress, byJmpCode, PATCH_LENGTH);
VirtualProtect((LPVOID)dwHookAddress, PATCH_LENGTH, dwOldProtect, NULL);
bHookFlag = TRUE;
bRet = TRUE;
}
}
else
{
if (bHookFlag)
{
VirtualProtect((LPVOID)dwHookAddress, PATCH_LENGTH, PAGE_EXECUTE_READWRITE, &dwOldProtect);
memcpy((LPVOID)dwHookAddress, byOriginalCode, PATCH_LENGTH);
VirtualProtect((LPVOID)dwHookAddress, PATCH_LENGTH, dwOldProtect, NULL);
bHookFlag = FALSE;
bRet = FALSE;
}
}
return bRet;
}
VOID SetMessageBoxHook()
{
//获取要HOOK的函数地址
dwHookAddress = (DWORD)GetProcAddress(LoadLibraryA("user32.dll"), "MessageBoxA");
dwRetAddress = dwHookAddress + PATCH_LENGTH;
//安装或卸载HOOK
HookMessageBox(TRUE);
}
Inject
Inject.cpp
#include <iostream>
#include <Windows.h>
#include <TlHelp32.h>
DWORD GetRemoteProcessId(WCHAR* szName)
{
HANDLE hProcessSnapShot = NULL;
PROCESSENTRY32 pe32 = { 0 };
hProcessSnapShot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (hProcessSnapShot == (HANDLE)-1)
{
return 0;
}
pe32.dwSize = sizeof(PROCESSENTRY32);
if (Process32First(hProcessSnapShot, &pe32))
{
do {
if (!wcscmp(szName, pe32.szExeFile)) return (int)pe32.th32ProcessID;
} while (Process32Next(hProcessSnapShot, &pe32));
}
else
CloseHandle(hProcessSnapShot);
return 0;
}
BOOL InjectDLL(DWORD dwProcessID, char* szDllPathName)
{
BOOL bRet;
HANDLE hProcess;
HANDLE hThread;
DWORD dwLength;
DWORD dwLoadAddr;
LPVOID lpAllocAddr;
DWORD dwThreadID;
HMODULE hModule;
bRet = 0;
dwLoadAddr = 0;
hProcess = 0;
hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwProcessID);
if (hProcess == NULL)
{
std::cout << "OpenProcess FAILED!!!" << std::endl;
return FALSE;
}
dwLength = strlen(szDllPathName) + 1;
lpAllocAddr = VirtualAllocEx(hProcess, NULL, dwLength, MEM_COMMIT, PAGE_READWRITE);
if (lpAllocAddr == NULL)
{
std::cout << "VirtualAllocEx FAILED!!!" << std::endl;
CloseHandle(hProcess);
return FALSE;
}
bRet = WriteProcessMemory(hProcess, lpAllocAddr, szDllPathName, dwLength, NULL);
if (!bRet)
{
std::cout << "WriteProcessMemory FAILED!!!" << std::endl;
CloseHandle(hProcess);
return FALSE;
}
hModule = GetModuleHandle(L"kernel32.dll");
if (!hModule)
{
std::cout << "GetModuleHandle FAILED!!!" << std::endl;
CloseHandle(hProcess);
return FALSE;
}
dwLoadAddr = (DWORD)GetProcAddress(hModule, "LoadLibraryA");
if (!dwLoadAddr)
{
std::cout << "GetProcAddress FAILED!!!" << std::endl;
CloseHandle(hModule);
CloseHandle(hProcess);
return FALSE;
}
hThread = CreateRemoteThread(hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)dwLoadAddr, lpAllocAddr, 0, NULL);
if (!hThread)
{
std::cout << "CreateRemoteThread FAILED!!!" << std::endl;
CloseHandle(hModule);
CloseHandle(hProcess);
return FALSE;
}
CloseHandle(hThread);
CloseHandle(hProcess);
return TRUE;
}
int main()
{
WCHAR szName[] = L"Target.exe";
char szDllPathName[] = "D:\\MyProject\\C++\\Inline Hook\\Debug\\Inline Hook.dll";
DWORD PID = GetRemoteProcessId(szName);
std::cout << "被注入进程:" << PID << std::endl;
std::cout << "DLL路径:" << szDllPathName << std::endl;
std::cout << "按任意键注入..." << std::endl;
std::cin.get();
BOOL InjectRet = InjectDLL(PID, szDllPathName);
std::cout << "isInjectDLL:" << InjectRet << std::endl;
std::cout << "按任意键继续..." << std::endl;
std::cin.get();
return 0;
}
Target
Target.cpp
#include <iostream>
#include <Windows.h>
int main()
{
std::cout << "PID:" << GetCurrentProcessId() << std::endl;
std::cout << "按任意键弹出第一个信息框..." << std::endl;
std::cin.get();
MessageBoxA(NULL, "This is oneMsg", "Target", NULL);
std::cout << "按任意键弹出第二个信息框..." << std::endl;
std::cin.get();
MessageBoxA(NULL, "This is twoMsg", "Target", NULL);
std::cout << "按任意键继续..." << std::endl;
std::cin.get();
return 0;
}
改进版的Inline Hook
VOID MessageBoxProc(HWND hWnd, LPCSTR lpText, LPCSTR lpCaption, UINT uType)
{
//这个函数怎么写都行 随意发挥 没有限制
TCHAR szBuffer[0x100];
wsprintfW(szBuffer, L"%x %x %x %x\n", hWnd, lpText, lpCaption, uType);
OutputDebugString(szBuffer);
}
//设置为裸函数 否则编译器会生成一堆乱七八糟的东西
void __declspec(naked) NewMessageBox()
{
_asm
{
//保存寄存器
PUSHAD
PUSHFD
//调用处理函数
PUSH DWORD PTR SS : [ESP + 0x28]
PUSH DWORD PTR SS : [ESP + 0x30]
PUSH DWORD PTR SS : [ESP + 0x38]
PUSH DWORD PTR SS : [ESP + 0X40]
CALL MessageBoxProc
ADD ESP, 0x10
//恢复寄存器
POPFD
POPAD
//执行覆盖的代码
MOV EDI, EDI
PUSH EBP
MOV EBP, ESP
//返回执行
PUSH dwHookAddress
ADD DWORD PTR DS : [ESP] , PATCH_LENGTH
RETN
}
}
另一种INLINE HOOK
- 很多时候,都会检测E9来判断是否被HOOK。
- 将JMP....JMP修改为CALL + RET的方式来实现即可。