实例介绍
要说在Hook技术里面最基础的,那就是IAT Hook,它的原理就是通过修改PE结构中的IAT表,将其替换成我们自己定义的函数,最终实现Hook,所以在进行Hook之前,我们得很清楚的PE结构,接下来我们先讲解一下怎么索引到IAT表。
0x01 PE文件格式解析
随便拖一个程序进入Uedit进行分析
这一部分就是PE文件的DOS头,先看看DOS头的结构体,咱边看结构体边分析:
typedef struct IMAGE_DOS_HEADER { WORD e_magic; WORD e_cblp; WORD e_cp; WORD e_crlc; WORD e_cparhdr; WORD e_minalloc; WORD e_maxalloc; WORD e_ss; WORD e_sp; WORD e_csum; WORD e_ip; WORD e_cs; WORD e_lfarlc; WORD e_ovno; WORD e_res[4]; WORD e_oemid; WORD e_oeminfo; WORD e_res2[10]; DWORD e_lfanew; }IMAGE_DOS_HEADER, *PIMAGE_DOS_HEADER;
在DOS头里面最关键是两个成员就是e_magic,e_lfanew(其他的可以忽略),e_magic就是DOS头的标识,也就是MZ,为什么是MZ呢,其实就是Mark Zbikowski,他是MS-DOS主要开发者之一,为了纪念老人家,e_lfanew就是下一个头的偏移(基于文件基址),可能有同学要有疑问了,为啥现在还要有这个DOS头呢,因为微软为了向下兼容,所以才没有删除DOS头,那么加上偏移我们来看看:
PE头也有它自己的结构体,Signature和e_magic是一个道理,这里的Signature是PE。
typedef struct IMAGE_NT_HEADERS { DWORD Signature; IMAGE_FILE_HEADER FileHeader; IMAGE_OPTIONAL_HEADER32 OptionalHeader; } IMAGE_NT_HEADERS,*PIMAGE_NT_HEADERS;
选择的区域是上面结构体中的FileHeader
它也有自己的结构体,感兴趣的小伙伴可以自己去查查每个字段的具体含义,这里就不展开了:
typedef struct _IMAGE_FILE_HEADER { WORD Machine; //运行平台 WORD NumberOfSections; //节表数目 DWORD TimeDateStamp; //时间戳 DWORD PointerToSymbolTable; DWORD NumberOfSymbols; //符号数 WORD SizeOfOptionalHeader; //可选部首长度 WORD Characteristics; //文件属性 }
说完FileHeader,重点就来了,那就是OptionalHeade,除去Signature,FileHeader剩下的就是OptionalHeade:
结构体如下,我们关注其最重要的一个成员DataDirectory(数据目录),它包含了我们要替换的导入表。
typedef struct _IMAGE_OPTIONAL_HEADER { WORD Magic; BYTE MajorLinkerVersion; BYTE MinorLinkerVersion; DWORD SizeOfCode; DWORD SizeOfInitializedData; DWORD SizeOfUninitializedData; DWORD AddressOfEntryPoint; DWORD BaseOfCode; DWORD BaseOfData; DWORD ImageBase; DWORD SectionAlignment; DWORD FileAlignment; WORD MajorOperatingSystemVersion; WORD MinorOperatingSystemVersion; WORD MajorImageVersion; WORD MinorImageVersion; WORD MajorSubsystemVersion; WORD MinorSubsystemVersion; DWORD Win32VersionValue; DWORD SizeOfImage; DWORD SizeOfHeaders; DWORD CheckSum; WORD Subsystem; WORD DllCharacteristics; DWORD SizeOfStackReserve; DWORD SizeOfStackCommit; DWORD SizeOfHeapReserve; DWORD SizeOfHeapCommit; DWORD LoaderFlags; DWORD NumberOfRvaAndSizes; IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES];} IMAGE_OPTIONAL_HEADER, *PIMAGE_OPTIONAL_HEADER;
它妥妥的有十六张表,我们只关注导入表:
typedef struct _IMAGE_IMPORT_DESCRIPTOR {union {DWORD Characteristics;DWORD OriginalFirstThunk; } DUMMYUNIONNAME;DWORD TimeDateStamp; DWORD ForwarderChain; DWORD Name; //指向DLL名字的RVADWORD FirstThunk; } IMAGE_IMPORT_DESCRIPTOR;
这里面最重要的就是OriginalFirstThunk,Name,FirstThunk
其中OriginalFirstThunk,FirstThunk分别指向INT和IAT表,心心念念的IAT表终于登场了,这两个成员指向的都是同一个表,为什么这样做等下说
当我们的函数加载完成后,我们IAT指向了函数真正的地址
在IAT在加载完真正的函数地址之后,如果没有INT表来标识具体的函数名称的话,操作系统就完全不知道它加载的这个函数名称是啥,只有一个函数的实现偏移和实现,并不知道它是啥,所以才会有INT表的存在。
0x02 IAT Hook 代码编写
到此PE结构也就讲解完了,也就可以开始写IAT Hook
我们的代码应该包含以下功能:
1.定义我们自己的Hook后的函数
int WINAPI MyMessageBoxA(HWND hWnd, LPCSTR lpText, LPCSTR lpCaption, UINT uType){ return OldMessageBoxA(hWnd, "Hello NSDA", lpCaption, uType);}
我们自己的MessageBox必须和原来的MessageBox的参数一模一样,这样才能保证在调用自己的函数的时候不会报错
2.接下来就是找到IAT表
HMODULE ImageBase = GetModuleHandle(NULL); //获得模块基地址 PIMAGE_DOS_HEADER pDosHead = (PIMAGE_DOS_HEADER)(DWORD)ImageBase; DWORD dwTemp = (DWORD)pDosHead (DWORD)pDosHead->e_lfanew;PIMAGE_NT_HEADERS pNtHead = (PIMAGE_NT_HEADERS)dwTemp; PIMAGE_OPTIONAL_HEADER pOpHead = (PIMAGE_OPTIONAL_HEADER)&pNtHead->OptionalHeader;DWORD dwInputTable = pOpHead->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress; DWORD dwTemp = (DWORD)GetModuleHandle(NULL) dwInputTable;PIMAGE_IMPORT_DESCRIPTOR pImport = (PIMAGE_IMPORT_DESCRIPTOR)dwTemp;PIMAGE_IMPORT_DESCRIPTOR pCurrent = pImport;
通过GetModuleHandle获得模块基地址之后,我们就可以拿到程序的DOS头,PE头,文件头,可选头
3.接下来就是遍历IAT将其替换成我们自己函数的地址
while (*(DWORD*)pFirstThunk != NULL) { if (*(DWORD*)pFirstThunk == (DWORD)OldMessageBoxA) { DWORD oldProtected; VirtualProtect(pFirstThunk, 0x1000, PAGE_EXECUTE_READWRITE, &oldProtected); memcpy(pFirstThunk, (DWORD *)&dwTemp, 4); VirtualProtect(pFirstThunk, 0x1000, oldProtected, &oldProtected); } pFirstThunk ; }
通过遍历IAT表找到MessageBox的地址之后进行替换,有一点需要注意的,需要先修改文件的页属性才能进行替换(在XP系统上不用)
小贴士
感谢您为本站写下的评论,您的评论对其它用户来说具有重要的参考价值,所以请认真填写。
- 类似“顶”、“沙发”之类没有营养的文字,对勤劳贡献的楼主来说是令人沮丧的反馈信息。
- 相信您也不想看到一排文字/表情墙,所以请不要反馈意义不大的重复字符,也请尽量不要纯表情的回复。
- 提问之前请再仔细看一遍楼主的说明,或许是您遗漏了。
- 请勿到处挖坑绊人、招贴广告。既占空间让人厌烦,又没人会搭理,于人于己都无利。
关于好例子网
本站旨在为广大IT学习爱好者提供一个非营利性互相学习交流分享平台。本站所有资源都可以被免费获取学习研究。本站资源来自网友分享,对搜索内容的合法性不具有预见性、识别性、控制性,仅供学习研究,请务必在下载后24小时内给予删除,不得用于其他任何用途,否则后果自负。基于互联网的特殊性,平台无法对用户传输的作品、信息、内容的权属或合法性、安全性、合规性、真实性、科学性、完整权、有效性等进行实质审查;无论平台是否已进行审查,用户均应自行承担因其传输的作品、信息、内容而可能或已经产生的侵权或权属纠纷等法律责任。本站所有资源不代表本站的观点或立场,基于网友分享,根据中国法律《信息网络传播权保护条例》第二十二与二十三条之规定,若资源存在侵权或相关问题请联系本站客服人员,点此联系我们。关于更多版权及免责申明参见 版权及免责申明
网友评论
我要评论