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

工控系统安全之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;
}

实现结果

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

 

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

七月花nancy

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值