菜单 学习猿地 - LMONKEY

VIP

开通学习猿地VIP

尊享10项VIP特权 持续新增

知识通关挑战

打卡带练!告别无效练习

接私单赚外块

VIP优先接,累计金额超百万

学习猿地私房课免费学

大厂实战课仅对VIP开放

你的一对一导师

每月可免费咨询大牛30次

领取更多软件工程师实用特权

入驻
254
0

IAT HOOK

原创
05/13 14:22
阅读数 16122

HOOK

1.监控

2.行为改变

改变执行流,让函数先到我这里,获得优先执行权

思路

导入表中有个IAT表,在导入表结构中的FirstThunk.在调用一些API时,只要是LoadLibrary的dll,其中的API都会在IAT表中,我们可以通过IAT表来寻找我们想要"了解"的函数,并对其进行操作,比如将这个API替换成自己的函数,但是注意参数要相同,不然栈平衡不了。

 

 

 我这里用简单的MessageBox来说明IAT HOOK问题

SetHook

 1 DWORD SetIATHook(DWORD OldAddr,DWORD NewAddr)  //oldAddr是原地址,NewAddr是我们自己的函数
 2 {
 3     DWORD dwImageBase = 0;
 4     PIMAGE_DOS_HEADER pDosHeader;
 5     PIMAGE_NT_HEADERS pNTHeader = NULL;
 6     PIMAGE_FILE_HEADER pPEHeader = NULL;
 7     PIMAGE_OPTIONAL_HEADER32 pOptionHeader = NULL;
 8     PIMAGE_SECTION_HEADER pSectionHeader = NULL;
 9     PIMAGE_IMPORT_DESCRIPTOR pImport = NULL;
10     PDWORD pIATThunk = NULL;
11     DWORD oldProtected = 0;
12     bool Flag = FALSE;
13 
14     dwImageBase = (DWORD)::GetModuleHandle(NULL);   //获取进程基址
15     pDosHeader = (PIMAGE_DOS_HEADER)dwImageBase;
16     pNTHeader = (PIMAGE_NT_HEADERS)((DWORD)pDosHeader + pDosHeader->e_lfanew);
17     pPEHeader = (PIMAGE_FILE_HEADER)((DWORD)pNTHeader + 4);
18     pOptionHeader = (PIMAGE_OPTIONAL_HEADER32)((DWORD)pPEHeader + IMAGE_SIZEOF_FILE_HEADER);
19     pImport = (PIMAGE_IMPORT_DESCRIPTOR)(pOptionHeader->DataDirectory[1].VirtualAddress + dwImageBase);  //定位导入表
20       //定位IAT表
21 
22     while (pImport->FirstThunk != 0 && Flag == FALSE)
23     {
24         pIATThunk = (PDWORD)(pImport->FirstThunk + dwImageBase);
25         printf("%s\n", dwImageBase + pImport->Name);
26         while (*pIATThunk)
27         {
28             if (*pIATThunk == OldAddr)
29             {
30                 VirtualProtect(pIATThunk, 0x1000, PAGE_EXECUTE_READWRITE, &oldProtected);
31                 *pIATThunk = NewAddr;
32                 Flag = TRUE;
33                 printf("Hook成功!\n");
34                 break;
35             }
36             printf("%x\n", pIATThunk);
37             pIATThunk++;
38         }
39         pImport++;
40     }
41     
42     return Flag;
43 }

大体就是获取基址,定位导入表,IAT表,找到目标API,用我们自己的函数地址替换原来API函数地址

有一个关键的地方,30行需要改变可写属性,因为31行那个位置是不能写入的(0xc0000005),VirtualProtect然后最后一个参数必须要有值,不能是NULL,主要这个细节卡了一下

获取OldAddr

DWORD OldFunc = (DWORD)::GetProcAddress(LoadLibrary(L"USER32.dll"), "MessageBoxW");

UnSetHook

 1 DWORD UnSetIATHook(DWORD OldAddr, DWORD NewAddr)
 2 {
 3     DWORD dwImageBase = 0;
 4     PIMAGE_DOS_HEADER pDosHeader;
 5     PIMAGE_NT_HEADERS pNTHeader = NULL;
 6     PIMAGE_FILE_HEADER pPEHeader = NULL;
 7     PIMAGE_OPTIONAL_HEADER32 pOptionHeader = NULL;
 8     PIMAGE_SECTION_HEADER pSectionHeader = NULL;
 9     PIMAGE_IMPORT_DESCRIPTOR pImport = NULL;
10     PDWORD pIATThunk = NULL;
11     bool Flag = FALSE;
12 
13     dwImageBase = (DWORD)::GetModuleHandle(NULL);   //获取进程基址
14     pDosHeader = (PIMAGE_DOS_HEADER)dwImageBase;
15     pNTHeader = (PIMAGE_NT_HEADERS)((DWORD)pDosHeader + pDosHeader->e_lfanew);
16     pPEHeader = (PIMAGE_FILE_HEADER)((DWORD)pNTHeader + 4);
17     pOptionHeader = (PIMAGE_OPTIONAL_HEADER32)((DWORD)pPEHeader + IMAGE_SIZEOF_FILE_HEADER);
18     pImport = (PIMAGE_IMPORT_DESCRIPTOR)(pOptionHeader->DataDirectory[1].VirtualAddress + dwImageBase);  //定位导入表
19 
20     while (pImport->FirstThunk != 0 && Flag == FALSE)
21     {
22         pIATThunk = (PDWORD)(pImport->FirstThunk + dwImageBase);
23         while (*pIATThunk)
24         {
25             if (*pIATThunk == NewAddr)
26             {
27                 *pIATThunk = OldAddr;
28                 Flag = TRUE;
29                 break;
30             }
31             pIATThunk++;
32         }
33         pImport++;
34     }
35 
36     return Flag;
37 }

达到目的后要恢复原来的函数

自己希望执行的函数

 1 int WINAPI MyMessageBoxW(HWND hWnd, LPCWSTR lpText, LPCWSTR lpCaption, UINT uType)
 2 {
 3     printf("%x  %s    %ws   %x\n", hWnd, lpText, lpCaption, uType);
 4 
 5     typedef int (WINAPI* pMessageBox)(HWND, LPCWSTR, LPCWSTR, UINT);
 6 
 7     //int ret = MessageBox(hWnd, lpText, lpCaption, uType);
 8     int ret = ((pMessageBox)OldFunc)(hWnd, lpText, lpCaption, uType);
 9 
10     printf("返回值%x", ret);
11 
12     return ret;
13 }

参数一传进来,我们就可以接收,其实还可以改变参数等等,这里必须要定义函数指针,因为原来的MessageBox那个地址已经被我们改了,如果又使用API MessageBox的话(像我注释的那行),会进入死循环,我们想得到参数又不想干扰原来的功能,所以定义一个函数指针来调用原来那个"OldAddr"即MessageBox的地址

测试代码

int TestIATHOOK()
{
    SetIATHook(OldFunc, (DWORD)MyMessageBoxW);

    MessageBox(NULL, L"HELLO", L"HACKER", MB_OK);
    UnSetIATHook(OldFunc, (DWORD)MyMessageBoxW);
    return 1;
}

测试结果

 

 完整代码

// IATHOOK.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//

#include <iostream>
#include <windows.h>

DWORD OldFunc = (DWORD)::GetProcAddress(LoadLibrary(L"USER32.dll"), "MessageBoxW");

DWORD SetIATHook(DWORD OldAddr,DWORD NewAddr)
{
    DWORD dwImageBase = 0;
    PIMAGE_DOS_HEADER pDosHeader;
    PIMAGE_NT_HEADERS pNTHeader = NULL;
    PIMAGE_FILE_HEADER pPEHeader = NULL;
    PIMAGE_OPTIONAL_HEADER32 pOptionHeader = NULL;
    PIMAGE_SECTION_HEADER pSectionHeader = NULL;
    PIMAGE_IMPORT_DESCRIPTOR pImport = NULL;
    PDWORD pIATThunk = NULL;
    DWORD oldProtected = 0;
    bool Flag = FALSE;

    dwImageBase = (DWORD)::GetModuleHandle(NULL);   //获取进程基址
    pDosHeader = (PIMAGE_DOS_HEADER)dwImageBase;
    pNTHeader = (PIMAGE_NT_HEADERS)((DWORD)pDosHeader + pDosHeader->e_lfanew);
    pPEHeader = (PIMAGE_FILE_HEADER)((DWORD)pNTHeader + 4);
    pOptionHeader = (PIMAGE_OPTIONAL_HEADER32)((DWORD)pPEHeader + IMAGE_SIZEOF_FILE_HEADER);
    pImport = (PIMAGE_IMPORT_DESCRIPTOR)(pOptionHeader->DataDirectory[1].VirtualAddress + dwImageBase);  //定位导入表
      //定位IAT表

    while (pImport->FirstThunk != 0 && Flag == FALSE)
    {
        pIATThunk = (PDWORD)(pImport->FirstThunk + dwImageBase);
        while (*pIATThunk)
        {
            if (*pIATThunk == OldAddr)
            {
                VirtualProtect(pIATThunk, 0x1000, PAGE_EXECUTE_READWRITE, &oldProtected);
                *pIATThunk = NewAddr;
                Flag = TRUE;
                printf("Hook成功!\n");
                break;
            }
            pIATThunk++;
        }
        pImport++;
    }
    
    return Flag;
}
DWORD UnSetIATHook(DWORD OldAddr, DWORD NewAddr)
{
    DWORD dwImageBase = 0;
    PIMAGE_DOS_HEADER pDosHeader;
    PIMAGE_NT_HEADERS pNTHeader = NULL;
    PIMAGE_FILE_HEADER pPEHeader = NULL;
    PIMAGE_OPTIONAL_HEADER32 pOptionHeader = NULL;
    PIMAGE_SECTION_HEADER pSectionHeader = NULL;
    PIMAGE_IMPORT_DESCRIPTOR pImport = NULL;
    PDWORD pIATThunk = NULL;
    bool Flag = FALSE;

    dwImageBase = (DWORD)::GetModuleHandle(NULL);   //获取进程基址
    pDosHeader = (PIMAGE_DOS_HEADER)dwImageBase;
    pNTHeader = (PIMAGE_NT_HEADERS)((DWORD)pDosHeader + pDosHeader->e_lfanew);
    pPEHeader = (PIMAGE_FILE_HEADER)((DWORD)pNTHeader + 4);
    pOptionHeader = (PIMAGE_OPTIONAL_HEADER32)((DWORD)pPEHeader + IMAGE_SIZEOF_FILE_HEADER);
    pImport = (PIMAGE_IMPORT_DESCRIPTOR)(pOptionHeader->DataDirectory[1].VirtualAddress + dwImageBase);  //定位导入表

    while (pImport->FirstThunk != 0 && Flag == FALSE)
    {
        pIATThunk = (PDWORD)(pImport->FirstThunk + dwImageBase);
        while (*pIATThunk)
        {
            if (*pIATThunk == NewAddr)
            {
                *pIATThunk = OldAddr;
                Flag = TRUE;
                break;
            }
            pIATThunk++;
        }
        pImport++;
    }

    return Flag;
}

int WINAPI MyMessageBoxW(HWND hWnd, LPCWSTR lpText, LPCWSTR lpCaption, UINT uType)
{
    printf("%x  %s    %ws   %x\n", hWnd, lpText, lpCaption, uType);

    typedef int (WINAPI* pMessageBox)(HWND, LPCWSTR, LPCWSTR, UINT);

    //int ret = MessageBox(hWnd, lpText, lpCaption, uType);
    int ret = ((pMessageBox)OldFunc)(hWnd, lpText, lpCaption, uType);

    printf("返回值%x", ret);

    return ret;
}

int TestIATHOOK()
{
    SetIATHook(OldFunc, (DWORD)MyMessageBoxW);

    MessageBox(NULL, L"HELLO", L"HACKER", MB_OK);
    UnSetIATHook(OldFunc, (DWORD)MyMessageBoxW);
    return 1;
}
int main()
{
    TestIATHOOK();

}    

 

发表评论

0/200
254 点赞
0 评论
收藏
为你推荐 换一批