IATHOOK(1): 對當前程序hook出彈窗並修改內容


IAThook的原理學習帖子有很多,我需要復現一下幾個基本概念先:

1.  PE結構下IID數組相關指針(放假太久都快忘了各個指針位置了)

這個之前我寫過簡單的分析工具,參考:https://bbs.pediy.com/thread-255851.htm   結構總覽:

 

2. 主要思路:

雖然r3層的鈎子是對進程局部hook,但是實現iat hook為什么就一定要外注入DLL呢(手動狗頭)

       程序運行有一個小彈窗,然后開始hook,利用GetModuleHandle(NULL)獲取當前進程模塊句柄,然后確定目標 dll名字和目標函數名稱:(char*)"user32.dll", (char*)"MessageBoxA"  ,LoadLibrary動態加載起來目標dll,獲得相應的基質和GetProcAddress目標函數指針(這里對PE的結構處理函數可參考我之前的帖子https://bbs.pediy.com/thread-255851.htm  對PE的基本處理函數應有盡有)。找到目標函數之后,需要進行權限修改,因為目標只有讀權限,這里借鑒了加密與解密。 找到之后獲得目標函數地址后賦給我們之前定義好的Detor,就可以對源messagebox就行修改了。

 

3.完整代碼如下:

vs2019:  如果提示const char[]轉 char*    就對函數形參加const, 項目屬性改成多字符集

#include <windows.h>
#include <stdio.h>
#include <imagehlp.h>
#pragma comment(lib,"imagehlp.lib")


//以MessageBoxA的原型定義一個函數指針類型
typedef int
(WINAPI* PMessageBoxA)(HWND hWnd, LPCTSTR lpText, LPCTSTR lpCaption, UINT uType);

//以MessageBoxA的原型定義一個函數來替代原始的MessageBoxA Detor函數
int WINAPI My_MessageBoxA(HWND hWnd, LPCTSTR lpText, LPCTSTR lpCaption,UINT uType);

//存在以下關系
//*(*pThunkPointer) == *pOriginalFuncAddr ;
BOOL InstallHook(
    HMODULE hModToHook,
    char* szModuleName,
    char* szFuncName,
    PVOID ProxyFunc,
    PULONG_PTR* pThunkPointer,
    ULONG_PTR* pOriginalFuncAddr
);

VOID ShowMsgBox(const char* szMsg);
BOOL IAT_InstallHook();
VOID IAT_UnInstallHook();
//保存原始MessageBoxA的地址
PMessageBoxA OldMessageBox = NULL;
//指向IAT中pThunk的地址
PULONG_PTR g_PointerToIATThunk = NULL;

int main(int argc, char* argv[])
{
    ShowMsgBox("1+1=2 ? 對嗎");
    IAT_InstallHook();
    ShowMsgBox("八對");
    IAT_UnInstallHook();
    ShowMsgBox("hook卸載完成");
    return 0;
}

//之所以把這個調用單獨放在一個函數中,是因為Release模式下對調用進行了優化,第二次調用時直接采用了寄存器尋址而不是導入表
//因此,單獨放在一個函數中可以避免這個情況。

VOID ShowMsgBox(const char* szMsg)
{
    MessageBoxA(NULL, szMsg, "Test", MB_OK);
}


int WINAPI My_MessageBoxA(
    HWND hWnd,          // handle of owner window
    LPCTSTR lpText,     // address of text in message box
    LPCTSTR lpCaption,  // address of title of message box
    UINT uType          // style of message box
)
{
    int ret;
    char newText[1024] = { 0 };
    char newCaption[256] = "jentle";
    printf("MessageBox丟失!\n");
    //在調用原函數之前,可以對IN(輸入類)參數進行干涉
    lstrcpy(newText, lpText);//為防止原函數提供的緩沖區不夠,這里復制到我們自己的一個緩沖區中再進行操作
    lstrcat(newText, "\t MessageBox Hacked by jentle");//篡改的消息框內容
    ret = OldMessageBox(hWnd, newText, newCaption, uType);//調用原MessageBox,並保存返回值
    return ret;//這里你還可以干涉原始函數的返回值

}

BOOL IAT_InstallHook()
{
    BOOL bResult = FALSE;
    HMODULE currectExe = GetModuleHandle(NULL);
    PULONG_PTR pt;
    ULONG_PTR OrginalAddr;
    bResult = InstallHook(currectExe, (char*)"user32.dll", (char*)"MessageBoxA", (PVOID)My_MessageBoxA, &pt, &OrginalAddr);
    if (bResult)
    {
        printf("************************Hook完畢! pThunk=0x%p  OriginalAddr = 0x%p*********************************\n", pt, OrginalAddr);
        g_PointerToIATThunk = pt;
        OldMessageBox = (PMessageBoxA)OrginalAddr;
    }
    return bResult;

}

VOID IAT_UnInstallHook()
{

    DWORD dwOLD;
    MEMORY_BASIC_INFORMATION  mbi;
    if (g_PointerToIATThunk)
    {
        //查詢並修改內存頁的屬性
        VirtualQuery((LPCVOID)g_PointerToIATThunk, &mbi, sizeof(mbi));
        VirtualProtect(mbi.BaseAddress, mbi.RegionSize, PAGE_EXECUTE_READWRITE, &dwOLD);
        //將原始的MessageBoxA地址填入IAT中
        *g_PointerToIATThunk = (ULONG)OldMessageBox;
        //恢復內存頁的屬性
        VirtualProtect(mbi.BaseAddress, mbi.RegionSize, dwOLD, 0);
    }

}
BOOL InstallHook(
    HMODULE hModToHook, //待Hook的模塊基址
     char* szModuleName, //目標DLL名字
    char* szFuncName, //目標函數名字
    PVOID DetourFunc, //Detour函數
    PULONG_PTR* pThunkPointer, //
    ULONG_PTR* pOriginalFuncAddr
)
{
    PIMAGE_IMPORT_DESCRIPTOR  pImportDescriptor;
    PIMAGE_THUNK_DATA         pThunkData;
    ULONG ulSize;
    HMODULE hModule = 0;
    ULONG_PTR TargetFunAddr;
    PULONG_PTR lpAddr;
    char* szModName;
    BOOL result = FALSE;
    BOOL bRetn = FALSE;

    hModule = LoadLibrary(szModuleName);//動態加載目標DLL
    TargetFunAddr = (ULONG_PTR)GetProcAddress(hModule, szFuncName);  //目標函數指針
    printf("目標%s函數地址 :0x%p\n", szFuncName, TargetFunAddr);
    printf("hook模塊基質(此exe):0x%p\n", hModToHook);  //需要hook的程序,這個是此程序
    pImportDescriptor = (PIMAGE_IMPORT_DESCRIPTOR)ImageDirectoryEntryToData(hModToHook, TRUE, IMAGE_DIRECTORY_ENTRY_IMPORT, &ulSize);; //IID指針
    printf("IID數組地址:0x%p\n", pImportDescriptor);
    while (pImportDescriptor->FirstThunk)
    {
        szModName = (char*)((PBYTE)hModToHook + pImportDescriptor->Name);
        printf("當前模塊(DLL)名稱:%s\n", szModName);
        if (stricmp(szModName, szModuleName) != 0)
        {
            printf("DLL名字不對下一個\n");
            pImportDescriptor++;
            continue;
        }
        //程序的導入表處理完畢后OriginalFirstThunk可能是無效的,不能再根據名稱來查找,而是遍歷FirstThunk直接根據地址判斷
        pThunkData = (PIMAGE_THUNK_DATA)((BYTE*)hModToHook + pImportDescriptor->FirstThunk);
        while (pThunkData->u1.Function)
        {
            lpAddr = (ULONG_PTR*)pThunkData;
            //找到了地址
            if ((*lpAddr) == TargetFunAddr)
            {
                printf("目標函數找到!\n");
                //通常情況下導入表所在內存頁都是只讀的,因此需要先修改內存頁的屬性為可寫
                DWORD dwOldProtect;
                MEMORY_BASIC_INFORMATION  mbi;
                VirtualQuery(lpAddr, &mbi, sizeof(mbi));
                bRetn = VirtualProtect(mbi.BaseAddress, mbi.RegionSize, PAGE_EXECUTE_READWRITE, &dwOldProtect);
                if (bRetn)
                {
                    //內存頁屬性修改成功,繼續下一步操作,先保存原始數據
                    if (pThunkPointer != NULL)
                    {
                        *pThunkPointer = lpAddr;
                    }
                    if (pOriginalFuncAddr != NULL)
                    {
                        *pOriginalFuncAddr = *lpAddr;
                    }
                    //修改地址
                    *lpAddr = (ULONG_PTR)DetourFunc;
                    result = TRUE;
                    //恢復內存頁的屬性
                    VirtualProtect(mbi.BaseAddress, mbi.RegionSize, dwOldProtect, 0);
                }
                break;
            }
            pThunkData++;
        }
        pImportDescriptor++;
    }

    FreeLibrary(hModule);
    return result;
}

4. 運行情況:

 

確定之后返回:

 

區別正常邏輯:

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM