// // Copy from Matt Pietrek // Given an RVA, look up the section header that encloses it and return a // pointer to its IMAGE_SECTION_HEADER // PIMAGE_SECTION_HEADER __AddImportTable_GetEnclosingSectionHeader( DWORD rva, PIMAGE_NT_HEADERS pNTHeader ) { PIMAGE_SECTION_HEADER section = IMAGE_FIRST_SECTION32(pNTHeader); unsigned i; for ( i=0; i < pNTHeader->FileHeader.NumberOfSections; i++, section++ ) { // Is the RVA within this section? if ( (rva >= section->VirtualAddress) && (rva < (section->VirtualAddress + section->Misc.VirtualSize))) return section; } return 0; }
int AddImportDll( IN HANDLE hFile, IN LPSTR lpDllName, IN DWORD dwBase, IN 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 = __AddImportTable_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;
strcpy(Add_Data.szDllName, lpDllName); strcpy(Add_Data.szFuncName, "Startup");
// // +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, "[X] Not enough space!/n/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; }
// // 修改[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT]中VirtualAddress和Size成员,设置为0 // lDistanceToMove = (long)&(pNTHeader->OptionalHeader.DataDirectory [IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT].VirtualAddress) - dwBase; dwBuffer = 0; SetFilePointer(hFile, lDistanceToMove, NULL, FILE_BEGIN); WriteFile(hFile, (PVOID)&dwBuffer, 4, &dwBytesWritten, NULL); WriteFile(hFile, (PVOID)&dwBuffer, 4, &dwBytesWritten, NULL);
// // 修改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; } // // 修改SECTION的Characteristics属性修改为E0000020 // lDistanceToMove = (long)&(pSection->Characteristics) - dwBase; dwBuffer = 0xE0000020; SetFilePointer(hFile, lDistanceToMove, NULL, FILE_BEGIN); nRet = WriteFile(hFile, (PVOID)&dwBuffer, 4, &dwBytesWritten, NULL); if(!nRet) { fprintf(stderr, "WriteFile(Characteristics) 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); printf("[V] Modify PE file Successfully!/n/n"); return 0; } | |