《逆向工程核心原理》<04-32> 通过DLL注入实现IAT钩取的技术
来源:互联网 发布:16年广东省的经济数据 编辑:程序博客网 时间:2024/06/06 02:17
原理: 通过DLL注入实现IAT钩取的技术
(技术流程: IAT-DLL注入-CreatRemoteThread.etc)
在保持运行代码不变的前提下, 将IAT保存的API起始地址变为用户函数的起始地址
Detail:先向目标进程(calc.exe)注入用户DLL(hookiat.dll), 然后在calc.exe进程的IAT区域更改4个字节大小的地址来钩取IAT
代码:
代码(hookiat.cpp):
01- DllMain()
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved){ switch( fdwReason ) { case DLL_PROCESS_ATTACH : // 保存原始API地址 g_pOrgFunc = GetProcAddress(GetModuleHandle(L"user32.dll"), "SetWindowTextW"); // # hook IAT钩取 // 用hookiat.MySetWindowText()钩取user32.SetWindowTextW() // 即将user32.SetWindowTextW()的地址更改为hookiat.MySetWindowTextW() hook_iat("user32.dll", g_pOrgFunc, (PROC)MySetWindowTextW); break; case DLL_PROCESS_DETACH : // # unhook IAT"脱钩" // 将calc.exe的IAT恢复原值 hook_iat("user32.dll", (PROC)MySetWindowTextW, g_pOrgFunc); break; } return TRUE;}
02- MySetWindowTextW()
BOOL WINAPI MySetWindowTextW(HWND hWnd, LPWSTR lpString) { wchar_t* pNum = L"零一二三四五六七八九"; wchar_t temp[2] = {0,}; int i = 0, nLen = 0, nIndex = 0; nLen = wcslen(lpString); for(i = 0; i < nLen; i++) { // 将阿拉伯数字转换为中文数字 // lpString是宽字符(2byte)字符串 if( L'0' <= lpString[i] && lpString[i] <= L'9' ) { temp[0] = lpString[i]; nIndex = _wtoi(temp); lpString[i] = pNum[nIndex]; } } // 调用user32.SetWindowTextW() API // (修改lpString缓冲区的内容) return ((PFSETWINDOWTEXTW)g_pOrgFunc)(hWnd, lpString);}
注: DllMain()中只钩取or脱钩了IAT, 即只修改了地址, 而参数不发生变化.
又因参数相同, 所以MySetWindowTextW()参数lpString是原本SetWindowTextW()的字符串指针
该指针指向一块存放输出显示的字符串的缓冲区.
03- hook_iat()
BOOL hook_iat(LPCSTR szDllName, PROC pfnOrg, PROC pfnNew){ HMODULE hMod; LPCSTR szLibName; PIMAGE_IMPORT_DESCRIPTOR pImportDesc; PIMAGE_THUNK_DATA pThunk; DWORD dwOldProtect, dwRVA; PBYTE pAddr; // 1 读取PE文件头信息, 并查找IAT的位置 // 1-1 从ImageBase开始, 经由PE签名找到IDT // hMod, pAddr = ImageBase of calc.exe // = VA to MZ signature (IMAGE_DOS_HEADER) hMod = GetModuleHandle(NULL); pAddr = (PBYTE)hMod; // pAddr = VA to PE signature (IMAGE_NT_HEADERS) pAddr += *((DWORD*)&pAddr[0x3C]); // pAddr == ImageBase + ImageBase:[0x3C] == 01000000 + F0 // dwRVA = RVA to IMAGE_IMPORT_DESCRIPTOR Table dwRVA = *((DWORD*)&pAddr[0x80]); // dwRVA == pAddr:[0x80] == [01000000 + 0xF0 + 0x80] == 170 // pImportDesc = VA to IMAGE_IMPORT_DESCRIPTOR Table pImportDesc = (PIMAGE_IMPORT_DESCRIPTOR)((DWORD)hMod+dwRVA); // pImportDesc == ImageBase + dwRVA == (*p)(01000000 + 170) == VA to IDT for( ; pImportDesc->Name; pImportDesc++ ) { // 1-2 通过遍历IDT中IID, 比较IID-> Name 与 DllName 是否一致 // szLibName = VA to IMAGE_IMPORT_DESCRIPTOR.Name szLibName = (LPCSTR)((DWORD)hMod + pImportDesc->Name); if( !_stricmp(szLibName, szDllName) ) //若一致, 则找到所需IID的地址 { // 1-3 通过IID-> FirstThunk, 得到IAT // pThunk = IMAGE_IMPORT_DESCRIPTOR.FirstThunk // = VA to IAT(Import Address Table) pThunk = (PIMAGE_THUNK_DATA)((DWORD)hMod + pImportDesc->FirstThunk); // pThunk->u1.Function = VA to API for( ; pThunk->u1.Function; pThunk++ ) { // 1-4 通过遍历IAT的函数, 比较IAT-> Function 与 pfnOrg 是否一致 if( pThunk->u1.Function == (DWORD)pfnOrg ) // 若一致, 则找到所需函数的地址 { // 2 得到IAT函数地址, 下面要修改(hooking)它的值 // 更改内存属性为E/R/W VirtualProtect((LPVOID)&pThunk->u1.Function, 4, PAGE_EXECUTE_READWRITE, &dwOldProtect); // 修改IAT值(钩取) pThunk->u1.Function = (DWORD)pfnNew; // 恢复内存属性 VirtualProtect((LPVOID)&pThunk->u1.Function, 4, dwOldProtect, &dwOldProtect); return TRUE; } } } } return FALSE;}
Debug:
Debug_calc.exe:
0. 选定目标API PEview-> IAT 查看导入的API1. OD-> 所有模块间的调用-> 搜索"SetWindowTextW" 下断2. 断下后, 查看栈 VA:[07FB40]值为07FB5C, 数据窗口跟随, 其值为"0"字符串3. f9运行, 输入任意数字, 断下后查看栈 VA:[07F7F0]值为07F80C, 其值为输入的数字字符串4. 修改字符串, 注意小端逆序5. f9运行, 框内的显示已被修改
Debug_calc.exe(hooked):
1. od-> Attach calc.exe-> 中断于新Dll-> f92. cmd-> InjectDll.exe i <PID> hookiat.dll-> od断在hookiat.dll3. 查找DllMain() od-> 查找 当前模块中的名称-> GetProcAddress 双击跟随 GetProcAddress() && GetModuleHandleW() 函数及参数与Dllmain()的一致 VA[01F01130] mov eax,dword ptr ss:[esp+0x8] 为 DllMain()函数起始地址
DllMain():
VA[01F01155] push hookiat.01F01000; 压入MySetWindowTextW()地址 VA[01F0115A] push EAX; eax == SetQWindowTextW()地址 VA[01F01160] call hook.01F01090; 调用hook_iat()函数
注: 优化掉"user32.dll"字符串参数, 被硬编码到hook_iat()函数
hook_iat():
// 1-1 从ImageBase开始, 经由PE签名找到IDTVA[01F010A1] mov edi,eax; VA[01F010A3] mov eax,dword ptr ds:[edi+0x3C]; // pAddr == ImageBase + ImageBase:[0x3C] == 01000000 + F0VA[01F010A6] mov eax,dword ptr ds:[eax+edi+0x80]; // dwRVA == pAddr:[0x80] == [01000000 + 0xF0 + 0x80] == 170VA[01F010AD] add eax,edi; // pImportDesc == ImageBase + dwRVA == (*p)(01000000 + 170) == VA to IDT// 1-2 通过遍历IDT中IID, 比较IID-> Name 与 DllName 是否一致VA[01F010CA] call hookiat.01F075CA; // 调用stricmp()函数// 1-3 通过IID-> FirstThunk, 得到IAT(实际是 IAT上第一个函数的地址)VA[01F010D6] mov esi,dword ptr ds:[ebx+0x4];VA[01F010D9] add esi,edi;// 1-4 通过遍历IAT的函数, 比较IAT-> Function 与 pfnOrg 是否一致VA[01F010E0] cmp dword ptr ds:[esi],ebp;// 2 得到IAT函数地址, 下面要修改(hooking)它的值VA[01F01117] mov dword ptr ds:[esi],edx; // edx为MySetWindowTextW() esi指向SetWindowTextW()
MySetWindowTextW():
- OD-> 所有模块间的调用-> 搜索”SetWindowTextW” 下断 f9后输入
VA[01002628] call dword ptr ds:[<&USER32.SetWindowTextW>]; // 钩取后, user32.SetWindowTextW()的地址 变为 hookiat.MySetWindowTextW()的地址
VA[01E91063] mov cx,word ptr ds:[eax*2+0x1E9927C];//将阿拉伯数字转换为韩文数字(字符串)VA[01E9107D] dword ptr ds:[01E9B6B8];// ds:[1000B6B8]为user32.SetWindowTextW()的地址
0 0
- 《逆向工程核心原理》<04-32> 通过DLL注入实现IAT钩取的技术
- 《逆向工程核心原理》<04-33> 通过DLL注入修改API代码实现API钩取的技术
- 《逆向工程核心原理》<04-30> 通过Debug修改代码实现API钩取的技术
- 逆向工程核心原理学习笔记1-通过IAT手工定位notepad.exe中的导入函数
- 《逆向工程核心原理》<03> DLL注入的3种姿势
- 逆向工程核心原理读书笔记-代码注入
- 逆向工程核心原理读书笔记-代码注入
- 《逆向工程核心原理》<04-34> 高级全局API钩取
- 《逆向工程核心原理》<03-25> 通过修改PE加载DLL
- 《逆向工程核心原理》》<06> 高级逆向分析技术
- 《逆向工程核心原理》
- 《逆向工程核心原理》
- 逆向工程核心原理
- 《逆向工程核心原理》<03-27> 代码注入
- 逆向工程核心原理读书笔记-API钩取之记事本小写转大写
- 逆向工程核心原理读书笔记-API钩取之计算器显示中文数字
- 逆向工程核心原理读书笔记-API钩取之隐藏进程(一)
- 逆向工程核心原理读书笔记-API钩取之隐藏进程(二)
- CCPC2016解题报告
- 泰斯特
- 学习springmvc的第三天(2:构造方法注入)
- 《Cracking the Coding Interview程序员面试金典》----单词最近距离
- scala 第一天
- 《逆向工程核心原理》<04-32> 通过DLL注入实现IAT钩取的技术
- Curl命令介绍
- Uva 11732 "strcmp()" Anyone? 左儿子右兄弟的trie
- final关键字的使用
- nload查看网络使用情况
- Arm架构之系统调用
- 完美解决因scrollview和recycleview引起的滑动冲突
- 散列表分析(Java实现)
- servlet到底是什么?