IAT hook(PE导入表hook)

IAT即Import Address Table 是PE文件的输入地址表,一个程序在运行时会加载很多模块,调用很多API函数,但这些函数不一定要程序本身实现。比如调用MessageboxA来显示一个对话框,我们并没有编写MessageboxA的实现过程,它其实是在User32.dll这个库中实现的,而程序运行时通过导入它的地址来调用。

程序映像被加载到内存时,下面这张PE结构图很重要。

IAT hook(PE导入表hook)_第1张图片

为了说明简洁,这里修改的是程序自身的IAT,如果hook其它进程的IAT,使用到远程线程,后面亦附实例代码。下面是IAT hook的实现代码:

#include <stdio.h>
#include <windows.h>
#include <Dbghelp.h>
 
#pragma comment(lib, “Dbghelp.lib”)
#pragma comment(lib, “User32.lib”)
 
typedef int(__stdcall *OLD_MessageBox)(HWND hWnd, LPCTSTR lpText, LPCTSTR lpCaption, UINT uType);
 
OLD_MessageBox g_procOldMessageBox = NULL;
 
int __stdcall HOOK_MessageBox(HWND hWnd, LPCTSTR lpText, LPCTSTR lpCaption, UINT uType)
{
    //printf(“%s\t%d\r\n”, __FUNCTION__, __LINE__);
    return g_procOldMessageBox(hWnd, LPCTSTR(“Yeah, I get it.”), LPCTSTR(“hooked”), uType);
}
 
int replace_IAT(const char *pDllName, const char *pApiName, bool bReplace)
{
    HANDLE hProcess = ::GetModuleHandle(NULL);
    DWORD dwSize = 0;
    /* 1.get IAT pointer of all dlls of a PE file. */
 
    PIMAGE_IMPORT_DESCRIPTOR pImageImport =
            (PIMAGE_IMPORT_DESCRIPTOR)ImageDirectoryEntryToData(hProcess, TRUE, IMAGE_DIRECTORY_ENTRY_IMPORT, &dwSize);
 
    if (NULL == pImageImport) {
        return -1;
    }
 
    PIMAGE_IMPORT_BY_NAME pImageImportByName = NULL;
    PIMAGE_THUNK_DATA  pImageThunkOriginal = NULL;
    PIMAGE_THUNK_DATA  pImageThunkReal = NULL;
 
    while (pImageImport) {
        /* 2.get IAT pointer of a specified dll, such as User32.dll. */
        if (0 == _strcmpi((char*)((PBYTE)hProcess + pImageImport->Name), pDllName)) {
            break;
        }
        ++pImageImport;
    }
 
    if (NULL == pImageImport) {
        return -1;
    }
 
    /* 3.get OriginalFirstThunk and FirstThunk pointer = array name. */
    pImageThunkOriginal = (PIMAGE_THUNK_DATA)((PBYTE)hProcess + pImageImport->OriginalFirstThunk);
    pImageThunkReal = (PIMAGE_THUNK_DATA)((PBYTE)hProcess + pImageImport->FirstThunk);
 
    /* 4.walk around the two array. */
    while (pImageThunkOriginal->u1.Function) {
        /* search by function name. */
        if ((pImageThunkOriginal->u1.Ordinal & IMAGE_ORDINAL_FLAG) != IMAGE_ORDINAL_FLAG) {
            /* get function name. */
            pImageImportByName = (PIMAGE_IMPORT_BY_NAME)((PBYTE)hProcess + pImageThunkOriginal->u1.AddressOfData);
 
            if (0 == _strcmpi(pApiName, (char*)pImageImportByName->Name)) {
                /* change the memory R/D privilege. */
                MEMORY_BASIC_INFORMATION mbi_thunk;
                VirtualQuery(pImageThunkReal, &mbi_thunk, sizeof(MEMORY_BASIC_INFORMATION));
                VirtualProtect(mbi_thunk.BaseAddress, mbi_thunk.RegionSize, PAGE_READWRITE, &mbi_thunk.Protect);
                if (true == bReplace) {
                    g_procOldMessageBox = (OLD_MessageBox)pImageThunkReal->u1.Function;
                    pImageThunkReal->u1.Function = (DWORD)HOOK_MessageBox;
                } else {
                    pImageThunkReal->u1.Function = (DWORD)g_procOldMessageBox;
                }
 
                DWORD dwOldProtect;
                VirtualProtect(mbi_thunk.BaseAddress, mbi_thunk.RegionSize, mbi_thunk.Protect, &dwOldProtect);
                break;
            }
        }
 
        ++pImageThunkOriginal;
        ++pImageThunkReal;
    }
 
    return 0;
}
 
int main()
{
    replace_IAT(“User32.dll”, “MessageBoxA”, true);
    MessageBoxA(NULL, “MessageBoxA has been hooked.”, “hooked”, MB_OK);
    replace_IAT(“User32.dll”, “MessageBoxA”, false);
    MessageBoxA(NULL, “MessageBoxA has been unhooked.”, “unhooked”, MB_OK);
 
    return 0;
}

运行效果图:

IAT hook(PE导入表hook)_第2张图片

附远程线程注入示例代码:

#include <Windows.h>
#include "tlhelp32.h"
#include "stdio.h"
#include "tchar.h"
 
#define PROCESS_NAME    L"iexplore.exe"
#define THREAD_SIZE     4096
 
//传递参数的结构
typedef struct _REMOTE_PARAMETER
{
    TCHAR m_msgContent[MAX_PATH];
    TCHAR m_msgTitle[MAX_PATH];
    DWORD m_dwMessageBoxAddr;
} RemotePara, *PRemotePara;
 
//获取API参数及地址
void GetMessageBoxParameter(PRemotePara pRemotePara)
{
    HMODULE hUser32 = LoadLibrary(L"User32.dll");
    pRemotePara->m_dwMessageBoxAddr = (DWORD)GetProcAddress(hUser32, "MessageBoxW");
    wcscat_s(pRemotePara->m_msgContent, L"Hello salary!\0");
    wcscat_s(pRemotePara->m_msgTitle, L"Hello\0");
    FreeLibrary(hUser32);
}
 
//远程线程处理例程
DWORD WINAPI RemoteThreadProc(PRemotePara pRemotePara)
{
    typedef int (WINAPI * MESSAGEBOXW)(HWND, LPCWSTR, LPCWSTR, UINT);
    MESSAGEBOXW MessageBoxPtr;
    MessageBoxPtr = (MESSAGEBOXW)pRemotePara->m_dwMessageBoxAddr;
    MessageBoxPtr(NULL, pRemotePara->m_msgContent, pRemotePara->m_msgTitle, MB_OK);
 
    return 0;
}
 
int main()
{
    //提升进程权限
    LUID luidTmp;
    HANDLE hToken;
    TOKEN_PRIVILEGES tkp;
 
    if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken)) {
        _tprintf(L"OpenProcessToken Failed ! \n");
        return -1;
    }
 
    if (!LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &luidTmp)) {
        _tprintf(L"LookupPrivilegeValue Failed ! \n");
        CloseHandle(hToken);
        return -1;
    }
 
    tkp.PrivilegeCount = 1;
    tkp.Privileges[0].Luid = luidTmp;
    tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
 
    if (!AdjustTokenPrivileges(hToken, FALSE, &tkp, sizeof(tkp), NULL, NULL)) {
        _tprintf(L"AdjustTokenPrivileges Failed ! \n");
        CloseHandle(hToken);
        return -1;
    }
 
    //获取进程Id
    DWORD  dwProcessId;
    PROCESSENTRY32 pe32;
    pe32.dwSize = sizeof(PROCESSENTRY32);
    HANDLE hProcessShot;
 
    hProcessShot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
    if (hProcessShot == INVALID_HANDLE_VALUE) {
        return -1;
    }
 
    if (!Process32First(hProcessShot, &pe32))
        return -1;
 
    for (int i = 0; Process32Next(hProcessShot, &pe32); i++) {
        if (wcscmp(pe32.szExeFile, PROCESS_NAME) == 0) {
            dwProcessId = pe32.th32ProcessID;
            break;
        }
    }
 
    CloseHandle(hProcessShot);
    _tprintf(L"CurrentProcessId:[%d]\n", dwProcessId);
 
    //打开进程
    HANDLE hProcess;
    hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwProcessId);
    if (hProcess == NULL) {
        _tprintf(L"OpenProcess failed!\n", dwProcessId);
    }
 
    //分配远程进程空间-函数使用
    LPVOID pRemoteThread = VirtualAllocEx(hProcess, NULL,THREAD_SIZE, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
    if (NULL == pRemoteThread) {
        _tprintf(L"VirtualAllocEx Failed!\n");
        CloseHandle(hProcess);
        return -1;
    }
 
    //远程地址空间写入代码
    if (FALSE == WriteProcessMemory(hProcess, pRemoteThread, &RemoteThreadProc, THREAD_SIZE, 0)) {
        _tprintf(L"WriteProcessMemory Failed!\n");
        VirtualFreeEx(hProcess, pRemoteThread, 0, MEM_RELEASE);
        CloseHandle(hProcess);
        return -1;
    }
 
    //分配远程进程空间-函数的参数使用
    PRemotePara pRemotePara = (PRemotePara)VirtualAllocEx(hProcess, NULL, sizeof(RemotePara), MEM_COMMIT, PAGE_READWRITE);
    if (NULL == pRemotePara) {
        _tprintf(L"VirtualAllocEx Failed!\n");
        VirtualFreeEx(hProcess, pRemoteThread, 0, MEM_RELEASE);
        CloseHandle(hProcess);
        return -1;
    }
    RemotePara remotePara;
    ZeroMemory(&remotePara, sizeof(RemotePara));
    GetMessageBoxParameter(&remotePara);
 
    //写入参数
    if (FALSE == WriteProcessMemory(hProcess, pRemotePara, &remotePara, sizeof(RemotePara), 0)) {
        _tprintf(L"WriteProcessMemory Failed!\n");
        VirtualFreeEx(hProcess, pRemoteThread, 0, MEM_RELEASE);
        VirtualFreeEx(hProcess, pRemotePara, 0, MEM_RELEASE);
        CloseHandle(hProcess);
        return -1;
    }
 
    HANDLE hThread = NULL;
    DWORD dwThreadId = 0;
 
    //创建远程线程
    hThread = CreateRemoteThread(hProcess, NULL, 0, (DWORD(WINAPI *)(LPVOID))pRemoteThread, pRemotePara, 0, &dwThreadId);
    if (NULL == hThread) {
        _tprintf(L"CreateRemoteThread Failed!%d\n", GetLastError());
    } else {
        _tprintf(L"Code Inject Success!\n");
    }
    WaitForSingleObject(hThread, INFINITE);
    CloseHandle(hThread);
    VirtualFreeEx(hProcess, pRemoteThread, 0, MEM_RELEASE);
    VirtualFreeEx(hProcess, pRemotePara, 0, MEM_RELEASE);
    CloseHandle(hProcess);
 
    return 0;
}

当然,这样子做36x这些安全工具是会报警的,并且目前来看IAT hook这种RING 3的技术也没什么太大价值,只能算多一种思路。

IAT hook(PE导入表hook)_第3张图片

你可能感兴趣的:(IAT hook(PE导入表hook))