|
@@ -0,0 +1,156 @@
|
|
|
+// HookApi-Demo.cpp : 定义控制台应用程序的入口点。
|
|
|
+//
|
|
|
+
|
|
|
+#include "stdafx.h"
|
|
|
+#include "HookApi-Demo.h"
|
|
|
+
|
|
|
+#ifdef _DEBUG
|
|
|
+#define new DEBUG_NEW
|
|
|
+#endif
|
|
|
+
|
|
|
+
|
|
|
+// 唯一的应用程序对象
|
|
|
+
|
|
|
+CWinApp theApp;
|
|
|
+
|
|
|
+using namespace std;
|
|
|
+
|
|
|
+
|
|
|
+// 定义API挂接项结构
|
|
|
+typedef struct _HOOK_ITEM {
|
|
|
+ DWORD dwAddr ; // IAT项所在地址
|
|
|
+ DWORD dwOldValue ; // IAT项的原始函数地址
|
|
|
+ DWORD dwNewValue ; // IAT项的新函数地址
|
|
|
+} HOOK_ITEM, *PHOOK_ITEM ;
|
|
|
+
|
|
|
+// 定义IAT项,用于保存MessageBoxA的IAT项信息
|
|
|
+HOOK_ITEM HookItem = {0} ;
|
|
|
+
|
|
|
+// 定义MessageBoxA函数原型
|
|
|
+typedef int (WINAPI* PFNMessageBoxA)( HWND hWnd, LPCSTR lpText, LPCSTR lpCaption, UINT uType ) ;
|
|
|
+
|
|
|
+// 定义重定向API的实现函数
|
|
|
+BOOL WINAPI RedirectApi ( PCHAR pDllName, PCHAR pFunName, DWORD dwNewProc, PHOOK_ITEM pItem ) ;
|
|
|
+
|
|
|
+// 自定义的MessageBoxA函数
|
|
|
+// 实现对原始MessageBoxA的输入、输出参数的监控,甚至是取消调用
|
|
|
+int WINAPI NEW_MessageBoxA( HWND hWnd, LPCSTR lpText, LPCSTR lpCaption, UINT uType )
|
|
|
+{
|
|
|
+ // 此处可以观察/修改调用参数,甚至可以取消调用直接返回。
|
|
|
+ // ……
|
|
|
+
|
|
|
+ // 取得原函数地址
|
|
|
+ PFNMessageBoxA pfnMessageBoxA = (PFNMessageBoxA)HookItem.dwOldValue ;
|
|
|
+
|
|
|
+ // 输出测试信息,
|
|
|
+ // 如果这里直接调用MessageBoxA,就进入无限循环
|
|
|
+ pfnMessageBoxA ( hWnd, "这是API重定向过程的消息框", "测试", 0 ) ;
|
|
|
+
|
|
|
+ // 调用原函数
|
|
|
+ int ret = pfnMessageBoxA ( hWnd, lpText, lpCaption, uType ) ;
|
|
|
+
|
|
|
+ // 此处可以查看/修改调用原函数的返回值
|
|
|
+ // ……
|
|
|
+
|
|
|
+ return ret ;
|
|
|
+}
|
|
|
+
|
|
|
+// 实现重定向API
|
|
|
+// 参数pDllName:目标API所在的DLL名称
|
|
|
+// 参数pFunName:目标API名称
|
|
|
+// 参数dwNewProc:自定义的函数地址
|
|
|
+// 参数pItem:用于保存IAT项信息
|
|
|
+BOOL WINAPI RedirectApi ( PCHAR pDllName, PCHAR pFunName, DWORD dwNewProc, PHOOK_ITEM pItem )
|
|
|
+{
|
|
|
+ // 检查参数是否合法
|
|
|
+ if ( pDllName == NULL || pFunName == NULL || !dwNewProc || !pItem )
|
|
|
+ return FALSE ;
|
|
|
+
|
|
|
+ // 检测目标模块是否存在
|
|
|
+ char szTempDllName[256] = {0} ;
|
|
|
+ DWORD dwBaseImage = (DWORD)GetModuleHandle(NULL) ;
|
|
|
+ if ( dwBaseImage == 0 )
|
|
|
+ return FALSE ;
|
|
|
+
|
|
|
+ // 取得PE文件头信息指针
|
|
|
+ PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)dwBaseImage ;
|
|
|
+ PIMAGE_NT_HEADERS pNtHeader = (PIMAGE_NT_HEADERS)(dwBaseImage + (pDosHeader->e_lfanew)) ;
|
|
|
+ PIMAGE_OPTIONAL_HEADER32 pOptionalHeader = &(pNtHeader->OptionalHeader) ;
|
|
|
+ PIMAGE_SECTION_HEADER pSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD)pNtHeader + 0x18 + pNtHeader->FileHeader.SizeOfOptionalHeader ) ;
|
|
|
+
|
|
|
+ // 遍历导入表
|
|
|
+ PIMAGE_THUNK_DATA pThunk, pIAT ;
|
|
|
+ PIMAGE_IMPORT_DESCRIPTOR pIID = (PIMAGE_IMPORT_DESCRIPTOR)(dwBaseImage+pOptionalHeader->DataDirectory[1].VirtualAddress ) ;
|
|
|
+ while ( pIID->FirstThunk )
|
|
|
+ {
|
|
|
+ // 检测是否目标模块
|
|
|
+ if ( strcmp ( (PCHAR)(dwBaseImage+pIID->Name), pDllName ) )
|
|
|
+ {
|
|
|
+ pIID++ ;
|
|
|
+ continue ;
|
|
|
+ }
|
|
|
+
|
|
|
+ pIAT = (PIMAGE_THUNK_DATA)( dwBaseImage + pIID->FirstThunk ) ;
|
|
|
+ if ( pIID->OriginalFirstThunk )
|
|
|
+ pThunk = (PIMAGE_THUNK_DATA)( dwBaseImage + pIID->OriginalFirstThunk ) ;
|
|
|
+ else
|
|
|
+ pThunk = pIAT ;
|
|
|
+
|
|
|
+ // 遍历IAT
|
|
|
+ DWORD dwThunkValue = 0 ;
|
|
|
+ while ( ( dwThunkValue = *((DWORD*)pThunk) ) != 0 )
|
|
|
+ {
|
|
|
+ if ( ( dwThunkValue & IMAGE_ORDINAL_FLAG32 ) == 0 )
|
|
|
+ {
|
|
|
+ // 检测是否目标函数
|
|
|
+ if ( strcmp ( (PCHAR)(dwBaseImage+dwThunkValue+2), pFunName ) == 0 )
|
|
|
+ {
|
|
|
+ // 填充函数重定向信息
|
|
|
+ pItem->dwAddr = (DWORD)pIAT ;
|
|
|
+ pItem->dwOldValue = *((DWORD*)pIAT) ;
|
|
|
+ pItem->dwNewValue = dwNewProc;
|
|
|
+
|
|
|
+ // 修改IAT项
|
|
|
+ DWORD dwOldProtect = 0 ;
|
|
|
+ VirtualProtect ( pIAT, 4, PAGE_READWRITE, &dwOldProtect ) ;
|
|
|
+ *((DWORD*)pIAT) = dwNewProc ;
|
|
|
+ VirtualProtect ( pIAT, 4, PAGE_READWRITE, &dwOldProtect ) ;
|
|
|
+ return TRUE ;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ pThunk ++ ;
|
|
|
+ pIAT ++ ;
|
|
|
+ }
|
|
|
+
|
|
|
+ pIID ++ ;
|
|
|
+ }
|
|
|
+
|
|
|
+ return FALSE ;
|
|
|
+}
|
|
|
+
|
|
|
+int _tmain(int argc, TCHAR* argv[], TCHAR* envp[])
|
|
|
+{
|
|
|
+ int nRetCode = 0;
|
|
|
+
|
|
|
+ // 初始化 MFC 并在失败时显示错误
|
|
|
+ if (!AfxWinInit(::GetModuleHandle(NULL), NULL, ::GetCommandLine(), 0))
|
|
|
+ {
|
|
|
+ // TODO: 更改错误代码以符合您的需要
|
|
|
+ _tprintf(_T("错误: MFC 初始化失败\n"));
|
|
|
+ nRetCode = 1;
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ // TODO: 在此处为应用程序的行为编写代码。
|
|
|
+ // 重定向API
|
|
|
+ if ( !RedirectApi("USER32.dll", "MessageBoxA", (DWORD)NEW_MessageBoxA, &HookItem ) )
|
|
|
+ OutputDebugStringA("RedirectApi failed!") ;
|
|
|
+ else
|
|
|
+ OutputDebugStringA("RedirectApi success!") ;
|
|
|
+
|
|
|
+ MessageBoxA(NULL, "正常消息框", "测试", NULL) ;
|
|
|
+ }
|
|
|
+
|
|
|
+ return nRetCode;
|
|
|
+}
|