【2021.01.15】INLINE HOOK

IAT HOOK的缺点

  1. 容易被检测。
  2. 只能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

  1. 很多时候,都会检测E9来判断是否被HOOK。
  2. 将JMP....JMP修改为CALL + RET的方式来实现即可。

猜你喜欢

转载自blog.csdn.net/qq_18120361/article/details/112687384