前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >红队 | IAT Hook技术实现

红队 | IAT Hook技术实现

作者头像
HACK学习
发布2021-05-14 15:23:45
5170
发布2021-05-14 15:23:45
举报
文章被收录于专栏:HACK学习HACK学习

HOOK

1.监控

2.行为改变

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

思路

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

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

SetHook

代码语言:javascript
复制
 DWORD SetIATHook(DWORD OldAddr,DWORD NewAddr)  //oldAddr是原地址,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);  //定位导入表0       //定位IAT表

     while (pImport->FirstThunk != 0 && Flag == FALSE)
     {
         pIATThunk = (PDWORD)(pImport->FirstThunk + dwImageBase);
         printf("%s\n", dwImageBase + pImport->Name);
         while (*pIATThunk)
         {
             if (*pIATThunk == OldAddr)
             {
                 VirtualProtect(pIATThunk, 0x1000, PAGE_EXECUTE_READWRITE, &oldProtected);
                 *pIATThunk = NewAddr;
                 Flag = TRUE;
                 printf("Hook成功!\n");
                   break;
             }
             printf("%x\n", pIATThunk);
             pIATThunk++;
         }
         pImport++;
     }

     return Flag;
 }

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

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

获取OldAddr

代码语言:javascript
复制
DWORD OldFunc = (DWORD)::GetProcAddress(LoadLibrary(L"USER32.dll"), "MessageBoxW");

UnSetHook

代码语言:javascript
复制
 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;
 }

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

自己希望执行的函数

代码语言:javascript
复制
 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;
 }

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

测试代码

代码语言:javascript
复制
int TestIATHOOK()
{
SetIATHook(OldFunc, (DWORD)MyMessageBoxW);


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

测试结果

完整代码

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

代码语言:javascript
复制
#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();


}
本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2021-05-07,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 HACK学习呀 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档