阅读:7762回复:20
关于修改导入表实现DLL注入的问题
很早以前就知道有这个修改导入表实现DLL注入的方法和代码,当时由于不涉及这方面的研究,所以没有注意,最近才想到开始研究其中的代码,但其中的关键函数AddImportDll的参数DWORD dwBase,这个dwBase是什么地址啊,我研究了半天也没弄明白,难道是pNTHeader->OptionalHeader.ImageBase不成?但我用赋值给dwBase后,程序根本不能给任何一个程序添加一个dll,所以一直不解,请高手指教!!感激不尽!!!以下就是那个函数
int AddImportDll(HANDLE hFile,DWORD dwBase,PIMAGE_NT_HEADERS pNTHeader) { // // 通过OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress // 获得导入表的RVA, 利用此RVA找到ImportTable所在的Section,之后计算Offset,公式: // Offset = (INT)(pSection->VirtualAddress - pSection->PointerToRawData) // 之后利用Offset来定位文件中ImportTable的位置. // PIMAGE_IMPORT_DESCRIPTOR pImportDesc = 0; PIMAGE_SECTION_HEADER pSection = 0; PIMAGE_THUNK_DATA pThunk, pThunkIAT = 0; int Offset = -1; pSection = GetEnclosingSectionHeader(pNTHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress,pNTHeader); if(!pSection) { fprintf(stderr, "No Import Table..\n"); return -1; } Offset = (int) (pSection->VirtualAddress - pSection->PointerToRawData); // // 计算ImportTable在文件中的位置 // pImportDesc =(PIMAGE_IMPORT_DESCRIPTOR)(pNTHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress - Offset + dwBase); // // 取出导入的DLL的个数 // int nImportDllCount = 0; while(1) { if ((pImportDesc->TimeDateStamp==0 ) && (pImportDesc->Name==0)) break; pThunk = (PIMAGE_THUNK_DATA)(pImportDesc->Characteristics); pThunkIAT = (PIMAGE_THUNK_DATA)(pImportDesc->FirstThunk); if(pThunk == 0 && pThunkIAT == 0) return -1; nImportDllCount++; pImportDesc++; } // // 恢复pImportDesc的值,方便下面的复制当前导入表的操作. // pImportDesc -= nImportDllCount; // // 取得ImportTable所在Section的RawData在文件中的末尾地址,计算公式: // dwOrigEndOfRawDataAddr = pSection->PointerToRawData + pSection->Misc.VirtualSize // DWORD dwEndOfRawDataAddr = pSection->PointerToRawData + pSection->Misc.VirtualSize; PIMAGE_IMPORT_DESCRIPTOR pImportDescVector = (PIMAGE_IMPORT_DESCRIPTOR)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, 20 * (nImportDllCount+1)); if(pImportDescVector == NULL) { fprintf(stderr, "HeapAlloc() failed. --err: %d\n", GetLastError()); return -1; } CopyMemory(pImportDescVector+1, pImportDesc, 20*nImportDllCount); // // 构造添加数据的结构,方法笨拙了点. // struct _Add_Data { char szDllName[256]; // 导入DLL的名字 int nDllNameLen; // 实际填充的名字的长度 WORD Hint; // 导入函数的Hint char szFuncName[256]; // 导入函数的名字 int nFuncNameLen; // 导入函数名字的实际长度 int nTotal; // 填充的总长度 } Add_Data; const char szDll[256] = "QQ_main.dll"; const char szFunc[256] = "SoftWareGoIn"; strcpy(Add_Data.szDllName, szDll); strcpy(Add_Data.szFuncName, szFunc); // // +1表示'\0'字符 // Add_Data.nDllNameLen = strlen(Add_Data.szDllName) + 1; Add_Data.nFuncNameLen = strlen(Add_Data.szFuncName) + 1; Add_Data.Hint = 0; // // 计算总的填充字节数 // Add_Data.nTotal = Add_Data.nDllNameLen + sizeof(WORD) + Add_Data.nFuncNameLen; // // 检查ImportTable所在的Section中的剩余空间是否能够容纳新的ImportTable. // 未对齐前RawData所占用的空间存放在pSection->VirtualSize中,用此值加上新的ImportTable长度与 // 原长度进行比较. // // nTotalLen 为新添加内容的总长度 // Add_Data.nTotal 为添加的DLL名称,Hint与导入函数的名字的总长度. // 8 为IMAGE_IMPORT_BY_NAME结构以及保留空的长度. // 20*(nImportDllCount+1) 为新的ImportTable的长度. // int nTotalLen = Add_Data.nTotal + 8 + 20*(nImportDllCount+1); printf("TotalLen: %d byte(s)\n", nTotalLen); if(pSection->Misc.VirtualSize + nTotalLen > pSection->SizeOfRawData) { fprintf(stderr, "No enough space!\n"); return -1; } IMAGE_IMPORT_DESCRIPTOR Add_ImportDesc; // // ThunkData结构的地址 // Add_ImportDesc.Characteristics = dwEndOfRawDataAddr + Add_Data.nTotal + Offset; Add_ImportDesc.TimeDateStamp = -1; Add_ImportDesc.ForwarderChain = -1; // // DLL名字的RVA // Add_ImportDesc.Name = dwEndOfRawDataAddr + Offset; Add_ImportDesc.FirstThunk = Add_ImportDesc.Characteristics; CopyMemory(pImportDescVector, &Add_ImportDesc, 20); // // 对文件进行修改 // DWORD dwBytesWritten = 0; DWORD dwBuffer = dwEndOfRawDataAddr + Offset + Add_Data.nTotal + 8; long lDistanceToMove = (long)&(pNTHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress) - dwBase; int nRet =0; // // 修改IMAGE_DIRECTOR_ENTRY_IMPORT中VirtualAddress的地址, // 使其指向新的导入表的位置 // SetFilePointer(hFile, lDistanceToMove, NULL, FILE_BEGIN); printf("OrigEntryImport: %x\n", pNTHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress); nRet = WriteFile(hFile, (PVOID)&dwBuffer, 4, &dwBytesWritten, NULL); if(!nRet) { fprintf(stderr, "WriteFile(ENTRY_IMPORT) failed. --err: %d\n", GetLastError()); return -1; } printf("NewEntryImport: %x\n", pNTHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress); // // 修改导入表长度,这个部分具体要修改为多少我也没弄明白,不过按照测试,改与不改都可以工作 // dwBuffer = pNTHeader->OptionalHeader.DataDirectory [IMAGE_DIRECTORY_ENTRY_IMPORT].Size + 40; nRet = WriteFile(hFile, (PVOID)&dwBuffer, 4, &dwBytesWritten, NULL); if(!nRet) { fprintf(stderr, "WriteFile(Entry_import.size) failed. --err: %d\n", GetLastError()); return -1; } // // 修改ImportTable所在节的长度 // lDistanceToMove = (long)&(pSection->Misc.VirtualSize) - dwBase; SetFilePointer(hFile, lDistanceToMove, NULL, FILE_BEGIN); dwBuffer = pSection->Misc.VirtualSize + nTotalLen; nRet = WriteFile(hFile, (PVOID)&dwBuffer, 4, &dwBytesWritten, NULL); if(!nRet) { fprintf(stderr, "WriteFile(Misc.VirtualSize) failed. --err: %d\n", GetLastError()); return -1; } // // 从节的末尾添加新的DLL内容 // 偷点懒,返回值就不检查了.. // lDistanceToMove = dwEndOfRawDataAddr; SetFilePointer(hFile, lDistanceToMove, NULL, FILE_BEGIN); nRet = WriteFile(hFile, Add_Data.szDllName, Add_Data.nDllNameLen, &dwBytesWritten, NULL); nRet = WriteFile(hFile, (LPVOID)&(Add_Data.Hint), sizeof(WORD), &dwBytesWritten, NULL); nRet = WriteFile(hFile, Add_Data.szFuncName, Add_Data.nFuncNameLen, &dwBytesWritten, NULL); dwBuffer = dwEndOfRawDataAddr + Add_Data.nDllNameLen + Offset; nRet = WriteFile(hFile, (LPVOID)&dwBuffer, 4, &dwBytesWritten, NULL); dwBuffer = 0; nRet = WriteFile(hFile, (LPVOID)&dwBuffer, 4, &dwBytesWritten, NULL); nRet = WriteFile(hFile, (LPVOID)pImportDescVector, 20*(nImportDllCount+1), &dwBytesWritten, NULL); HeapFree(GetProcessHeap(), 0, pImportDescVector); return 0; } |
|
沙发#
发布于:2007-03-03 11:55
注DLL有这么复杂吗?
|
|
板凳#
发布于:2007-03-03 19:58
比较喜欢暴力注入方式,Write codes to target process。
被注入的代码自己定位 api,就像病毒,而不是通过 LoadLibrary 加载 dll。 这样子很难被发现 |
|
地板#
发布于:2007-03-05 08:32
dBase应该是程序在内存中的ImageBase吧,忘了
|
|
地下室#
发布于:2007-03-05 09:55
看样子是将被修改的文件读到内存中的基地址
|
|
驱动小牛
|
5楼#
发布于:2007-03-05 15:21
这是修改引入表啊. dwbase就是 PE 头在内存中的偏移啊.不过很难有EXE有空间允许插入DLL引入项的.
|
6楼#
发布于:2007-03-06 12:07
注dll并不复杂,这里只是讨论在exe空间导入表增加一个加载dll的例子,难道没有高手给出正确答案吗?
|
|
7楼#
发布于:2007-03-07 13:45
引用第6楼xiao183于2007-03-06 12:07发表的“”: 很简单的,以前写过,连带在winlogon里禁用文件保护,模仿黑客之门的功能,代码不知道扔哪里了,我找找,你留个email,如果有,发给你 |
|
8楼#
发布于:2007-03-07 13:50
P.S. 你上面的代码是不能正常工作的,微软规定pe导入表中dll组最后一个应该为空组.......你的代码少分配了一个空间....
|
|
9楼#
发布于:2007-03-08 12:42
在LOAD IMAGE的时候在内存中插不是更好
|
|
10楼#
发布于:2007-03-12 14:42
lpExeName 是要修改的exe文件名,lpDllName是你的dll文件名
void OpenPEFile( LPSTR lpExeName, LPSTR lpDllName ) { HANDLE hFile; HANDLE hFileMapping; LPVOID lpFileBase; PIMAGE_DOS_HEADER dosHeader; PIMAGE_NT_HEADERS pNTHeader; char szNewFileName[MAX_PATH]; sprintf(szNewFileName, "%s", lpExeName); strcat(szNewFileName, ".bak"); if(!CopyFile(lpExeName, szNewFileName, FALSE)) { fprintf(stderr, "CopyFile() failed. --err: %d\n", GetLastError()); return; } // printf("lpFileName: %s lpNewFileName: %s\n", lpFileName, lpNewFileName); hFile = CreateFile(szNewFileName, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); if ( hFile == INVALID_HANDLE_VALUE ) { fprintf(stderr, "CreateFile() failed. --err: %d\n", GetLastError()); return; } hFileMapping = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 0, NULL); if ( hFileMapping == 0 ) { CloseHandle(hFile); printf("Couldn't open file mapping with CreateFileMapping()\n"); return; } lpFileBase = MapViewOfFile(hFileMapping, FILE_MAP_READ, 0, 0, 0); if ( lpFileBase == 0 ) { CloseHandle(hFileMapping); CloseHandle(hFile); printf("Couldn't map view of file with MapViewOfFile()\n"); return; } dosHeader = (PIMAGE_DOS_HEADER)lpFileBase; pNTHeader = MakePtr(PIMAGE_NT_HEADERS, dosHeader, dosHeader->e_lfanew); if ( dosHeader->e_magic == IMAGE_DOS_SIGNATURE && pNTHeader->Signature == 0x4550 ) { AddImportDll(hFile, lpDllName, (DWORD)dosHeader, pNTHeader); } else printf("unrecognized file format\n"); UnmapViewOfFile(lpFileBase); CloseHandle(hFileMapping); CloseHandle(hFile); } |
|
11楼#
发布于:2007-03-24 21:37
引用第7楼yanxizhen于2007-03-07 13:45发表的“”: 兄弟,最近出差了,所以一直没看贴,我的邮件地址是zhi-tian@163.com,麻烦你发到我邮件里吧,谢谢了 |
|
12楼#
发布于:2007-03-27 16:56
如果方便,请E我一份,找了很久了..非常感谢!!
我的邮件地址:dfsy0418@126.com |
|
13楼#
发布于:2007-04-05 11:38
硬修改导出表,添加自己的dll中的导出函数.
比直接hook目标模块的IAT,然后转到自己的dll要暴力... 如果目标程序检测自己的导出表发现改变,防止这样注入.然后在自我修复. |
|
14楼#
发布于:2007-04-29 11:22
yanxizhen大哥,我也要一个,研究很久了,谢谢!
|
|
15楼#
发布于:2007-05-10 14:47
void CAPIHook::ReplaceIATEntryInOneMod(PCSTR pszCalleeModName,
PROC pfnCurrent, PROC pfnNew, HMODULE hmodCaller) { // Get the address of the module's import section ULONG ulSize; PIMAGE_IMPORT_DESCRIPTOR pImportDesc = (PIMAGE_IMPORT_DESCRIPTOR) //获取指向PE文件中的Import中IMAGE_DIRECTORY_DESCRIPTOR数组的指针 ImageDirectoryEntryToData(hmodCaller, TRUE, IMAGE_DIRECTORY_ENTRY_IMPORT, &ulSize); if (pImportDesc == NULL) return; // This module has no import section // Find the import descriptor containing references to callee's functions // //查找记录,看看有没有我们想要的DLL for (; pImportDesc->Name; pImportDesc++) { PSTR pszModName = (PSTR) ((PBYTE) hmodCaller + pImportDesc->Name); if (lstrcmpiA(pszModName, pszCalleeModName) == 0) break; // Found } if (pImportDesc->Name == 0) return; // This module doesn't import any functions from this callee // Get caller's import address table (IAT) for the callee's functions //寻找我们想要的函数 PIMAGE_THUNK_DATA pThunk = (PIMAGE_THUNK_DATA) ((PBYTE) hmodCaller + pImportDesc->FirstThunk); // Replace current function address with new function address ////ppfn记录了与IAT表项相应的函数的地址 for (; pThunk->u1.Function; pThunk++) { // Get the address of the function address PROC* ppfn = (PROC*) &pThunk->u1.Function; // Is this the function we're looking for? BOOL fFound = (*ppfn == pfnCurrent); if (!fFound && (*ppfn > sm_pvMaxAppAddr)) { // If this is not the function and the address is in a shared DLL, // then maybe we're running under a debugger on Windows 98. In this // case, this address points to an instruction that may have the // correct address. PBYTE pbInFunc = (PBYTE) *ppfn; if (pbInFunc[0] == cPushOpCode) { // We see the PUSH instruction, the real function address follows ppfn = (PROC*) &pbInFunc[1]; // Is this the function we're looking for? fFound = (*ppfn == pfnCurrent); } } if (fFound) { // The addresses match, change the import section address //如果地址相同,也就是找到了我们想要的函数,进行改写,将其指向我们所定义的函数 WriteProcessMemory(GetCurrentProcess(), ppfn, &pfnNew, sizeof(pfnNew), NULL); return; // We did it, get out } } // If we get to here, the function is not in the caller's import section } |
|
16楼#
发布于:2007-05-15 13:42
这种手法太象病毒了吧?
|
|
|
17楼#
发布于:2007-07-28 11:54
引用第7楼yanxizhen于2007-03-07 13:45发表的 : 老大,如果方便的话,也给我发一份? 我的email:cshzxing@126.com 谢谢了:) |
|
18楼#
发布于:2007-08-15 01:11
引用第7楼yanxizhen于2007-03-07 13:45发表的 : 偶也想要一份,不知道可不可以? E-Mail: rain357@gmail.com 谢谢 |
|
19楼#
发布于:2007-09-01 22:00
引用第7楼yanxizhen于2007-03-07 13:45发表的 : 可以给我一份吗,正在学习中,十分感谢 EMAIl: zistzh@163.com |
|
上一页
下一页