2020-10-22

it2025-12-20  10

工控系统安全之HOOK技术(上课教程)

分别采用IAT  Hook和inline Hook技术对系统函数Hook 1. 利用IAT Hook来挂钩user32.dll中的GetTopWindow函数,实现调用GetTopWindow会弹出提示框 2. 利用Inline Hook技术实现对user32.dll中的MessageBoxA的Hook,实现弹框前,先Beep一声

提示: 考虑到inline Hook实现对新手较难,可以先使用mhook库或Detours库来实现

#include "windows.h"

typedef struct _IATHOOK_DATA  {     DWORD    dwValueAddr;    //IAT项中保存函数地址的地址     DWORD    dwOriginValue;    //原始数据     DWORD    dwNewValue;        //新的数据 }IATHOOK_DATA, *PIATHOOK_DATA;

DWORD IATHook(CHAR szDllName[], CHAR szFuncName[], PIATHOOK_DATA pIATHookData); DWORD IATUnHook(PIATHOOK_DATA pIATHookData);

HWND WINAPI MyGetTopWindow(HWND hWnd);

IATHOOK_DATA    IATHookData;

int WINAPI WinMain( __in HINSTANCE hInstance, __in_opt HINSTANCE hPrevInstance, __in_opt LPSTR lpCmdLine, __in int nShowCmd ) {     IATHookData.dwNewValue = (DWORD)MyGetTopWindow;     IATHook("user32.dll", "GetTopWindow", &IATHookData);     GetTopWindow(NULL);     return    0; }

typedef HWND (WINAPI *GETTOPWINDOW)(HWND hWnd); HWND WINAPI MyGetTopWindow(HWND hWnd) {     GETTOPWINDOW    OriginGetTopWindow = (GETTOPWINDOW)IATHookData.dwOriginValue;     Beep(3000, 100);     MessageBoxA(NULL, "GetTopWindow哦", "3170604037", MB_OK);          return    OriginGetTopWindow(hWnd); }

/************************************************************************/ /*  功能:利用修改导入函数表中地址来hook函数 参数:szDllName-导入函数的dll名,szFuncName-函数名,pIATHookData-hook使用的数据 原理:通过判断IMAGE_THUNK_DATA中函数名来得到对应IAT中地址,修改导入函数表中函数地址 */ /************************************************************************/ DWORD IATHook(CHAR szDllName[], CHAR szFuncName[], PIATHOOK_DATA pIATHookData) {     DWORD                        dwBaseAddr;     PIMAGE_DOS_HEADER            pDosHeader;     PIMAGE_NT_HEADERS            pNtHeader;     PIMAGE_OPTIONAL_HEADER        pOptHeaer;     PIMAGE_THUNK_DATA            pThunk, pIAT;     PIMAGE_IMPORT_DESCRIPTOR    pImportDes;     DWORD                        dwIndex;     DWORD                        dwOriginProtect;

    if (NULL == szDllName || NULL == szFuncName || NULL == pIATHookData)     {         return    ERROR_INVALID_PARAMETER;     }

    //获取当前文件的基址     dwBaseAddr = (DWORD)GetModuleHandle(NULL);     if (NULL == dwBaseAddr)     {         return    GetLastError();     }          //从头计算得到引入表的地址     pDosHeader = (PIMAGE_DOS_HEADER)dwBaseAddr;     pNtHeader = (PIMAGE_NT_HEADERS)(dwBaseAddr + pDosHeader->e_lfanew);     pOptHeaer = &(pNtHeader->OptionalHeader);

    pImportDes = (PIMAGE_IMPORT_DESCRIPTOR)(dwBaseAddr + pOptHeaer->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress);

    while (pImportDes->FirstThunk)     {         //判断是否是对应模块         if (_stricmp((CHAR*)(dwBaseAddr+pImportDes->Name), szDllName))         {             pImportDes ++;             continue;         }

        //当PE文件被装载到内存时,PE装载器将查找IMAGE_THUNK_DATA 和 IMAGE_IMPORT_BY_NAME 这些结构数组,         //以此决定引入函数的地址。然后用引入函数真实地址来替代由FirstThunk指向的 IMAGE_THUNK_DATA 数组里的元素值         //若 OriginalFirstThunk 为0,就改用FirstThunk值。有些连接器生成PE文件时会置OriginalFirstThunk值为0,这应该算是个bug。         pIAT = (PIMAGE_THUNK_DATA)(dwBaseAddr + pImportDes->FirstThunk);         if (pImportDes->OriginalFirstThunk)         {             pThunk = (PIMAGE_THUNK_DATA)(dwBaseAddr + pImportDes->OriginalFirstThunk);         }         else         {             pThunk = pIAT;         }

        dwIndex = 0;                  do          {             //有些情况下一些函数仅由序数引出,对应该函数的 IMAGE_THUNK_DATA 值             //的低位字指示函数序数,而最高二进位 (MSB)设为1。             //32位时IMAGE_ORDINAL_FLAG = 0x80000000h。             dwIndex = *(DWORD*)pThunk;             if (dwIndex != 0)             {                 if ((dwIndex & IMAGE_ORDINAL_FLAG) == 0)                 {                     //得到函数名,继续向后跳2字节                     if (strcmp((PCHAR)(dwBaseAddr + dwIndex + 2), szFuncName) == 0)                     {                         //找到了,先保存原始数据                         pIATHookData->dwValueAddr = (DWORD)pIAT;                         pIATHookData->dwOriginValue = *(DWORD*)pIAT;                                                  //修改IAT                         VirtualProtect(pIAT, 4, PAGE_EXECUTE_READWRITE, &dwOriginProtect);                         *(DWORD*)pIAT = pIATHookData->dwNewValue;                         VirtualProtect(pIAT, 4, dwOriginProtect, &dwOriginProtect);                         return    0;                     }                 }             }             //换下一个             pThunk ++;             pIAT ++;         } while (1);         //取下一模块         pImportDes ++;     }     return    0; }

/************************************************************************/ /*  功能:修股 参数: 原理: */ /************************************************************************/ DWORD IATUnHook(PIATHOOK_DATA pIATHookData) {     DWORD    dwOriginProtect;

    VirtualProtect((PVOID)pIATHookData->dwValueAddr, 4, PAGE_EXECUTE_READWRITE, &dwOriginProtect);     *(DWORD*)pIATHookData->dwValueAddr = pIATHookData->dwOriginValue;     VirtualProtect((PVOID)pIATHookData->dwValueAddr, 4, dwOriginProtect, &dwOriginProtect);     return    0; }

实现结果

会听到电脑哔一声然后弹出窗口

 

最新回复(0)