下面代码将在EXE文件中重建一个导入表,并将指定的DLL文件作为新的引用添加到导入表中,为什么要这样做呢?呵呵,用得到这种代码的人肯定不会想拿去做什么好事吧,所以用途就不介绍了!顺便说一下,下面代码已经处理了程序的附加数据和绑定引入,不会因为EXE存在附加数据或绑定引入导致添加失败。
#define NTSIGNATURE(a) ((LPVOID)((BYTE *)a + ((PIMAGE_DOS_HEADER)a)->e_lfanew))
#define PEFHDROFFSET(a) ((LPVOID)((BYTE *)NTSIGNATURE(a) + 4))
#define OPTHDROFFSET(a) ((LPVOID)((BYTE *)NTSIGNATURE(a) + 4 + sizeof(IMAGE_FILE_HEADER)))
#pragma pack(push) // 保存对齐状态
#pragma pack(1)
typedef struct _NEW_IMPORT
{
char szDllName[20]; // 导入DLL的名字
WORD Hint; // 导入函数的Hint
char szFuncName[20]; // 导入函数的名字
IMAGE_THUNK_DATA data[2];
} NEW_IMPORT, *PNEW_IMPORT;
#pragma pack(pop)
//---------------------------------------------------------------------------
// 返回RVA所指向的节
//---------------------------------------------------------------------------
PIMAGE_SECTION_HEADER GetSectionByRVA(DWORD rva, PIMAGE_NT_HEADERS pNTHeader)
{
PIMAGE_SECTION_HEADER section = IMAGE_FIRST_SECTION(pNTHeader);
DWORD i;
for (i = 0; i < pNTHeader->FileHeader.NumberOfSections; i++)
{
if ((rva >= section[i].VirtualAddress) && (rva < (section[i].VirtualAddress + section[i].Misc.VirtualSize)))
return §ion[i];
}
return NULL;
}
//---------------------------------------------------------------------------
// 返回文件偏移所指向的节
//---------------------------------------------------------------------------
PIMAGE_SECTION_HEADER GetSectionByFileOffset(DWORD dwFileOffset, PIMAGE_NT_HEADERS pNTHeader)
{
PIMAGE_SECTION_HEADER section = IMAGE_FIRST_SECTION(pNTHeader);
DWORD i;
for (i = 0; i < pNTHeader->FileHeader.NumberOfSections; i++)
{
if ((dwFileOffset >= section[i].PointerToRawData) && (dwFileOffset < (section[i].PointerToRawData + section[i].SizeOfRawData)))
return §ion[i];
}
return NULL;
}
//---------------------------------------------------------------------------
// 将RVA转换为文件偏移
//---------------------------------------------------------------------------
DWORD RVAToFileOffset(DWORD rva, PIMAGE_NT_HEADERS pNTHeader)
{
PIMAGE_SECTION_HEADER section = GetSectionByRVA(rva, pNTHeader);
return section->PointerToRawData + (rva - section->VirtualAddress);
}
//---------------------------------------------------------------------------
// 将文件偏移转换为RVA
//---------------------------------------------------------------------------
DWORD FileOffsetToRVA(DWORD dwFileOffset, PIMAGE_NT_HEADERS pNTHeader)
{
PIMAGE_SECTION_HEADER section = GetSectionByFileOffset(dwFileOffset, pNTHeader);
return section->VirtualAddress + (dwFileOffset - section->PointerToRawData);
}
int CMiniShellDlg::AddDllImport(LPVOID lpFile, ULONG nFileSize, LPCSTR lpDllName, LPCSTR lpFuncName)
{
PIMAGE_SECTION_HEADER pLastSection, pNewSection;
DWORD AddBase, nImportCount;
PIMAGE_DOS_HEADER pdh;
PIMAGE_NT_HEADERS pnh;
PIMAGE_FILE_HEADER pfh;
PIMAGE_OPTIONAL_HEADER poh;
PIMAGE_IMPORT_DESCRIPTOR pOldImport, pNewImport;
NEW_IMPORT Add_Data = {0};
// 判断是不是有效的PE文件
if (*(PWORD)lpFile != IMAGE_DOS_SIGNATURE || *(PDWORD)NTSIGNATURE(lpFile) != IMAGE_NT_SIGNATURE)
{
MessageBox(_T("错误,不是PE文件/r/n"), _T("错误"), MB_ICONERROR);
return 0;
}
pdh = (PIMAGE_DOS_HEADER)lpFile;
pnh = (PIMAGE_NT_HEADERS)NTSIGNATURE(lpFile);
pfh = (PIMAGE_FILE_HEADER)PEFHDROFFSET(lpFile);
poh = (PIMAGE_OPTIONAL_HEADER)OPTHDROFFSET(lpFile);
if (!(poh->Magic & 0x100))
{
MessageBox(_T("错误:无效 Win32 程序/r/n"), _T("错误"), MB_ICONERROR);
return 0;
}
pLastSection = IMAGE_FIRST_SECTION(pnh) + pfh->NumberOfSections - 1;
// 一般PE中的节都采用512字节或4K字节的对齐方式
if (poh->FileAlignment != 0x200 && poh->FileAlignment != 0x1000)
{
MessageBox(_T("错误:无法处理该文件/r/n"), _T("错误"), MB_ICONERROR);
return 0;
}
PBYTE pOverlayData = (PBYTE)lpFile + pLastSection->PointerToRawData + pLastSection->SizeOfRawData;
DWORD nOverlayData = nFileSize - (pLastSection->PointerToRawData + pLastSection->SizeOfRawData);
if (pLastSection->PointerToRawData + pLastSection->SizeOfRawData < nFileSize)
{
MessageBox(_T("文件具有附加数据,生成的文件可能无法运行/r/n"), _T("警告"), MB_ICONWARNING);
}
if ((DWORD)((PBYTE)(pLastSection + 2) - (PBYTE)lpFile) > poh->SizeOfHeaders)
{
MessageBox(_T("错误:空间不足,无法添加节/r/n"), _T("错误"), MB_ICONERROR);
return 0;
}
pNewImport = (PIMAGE_IMPORT_DESCRIPTOR)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IMAGE_IMPORT_DESCRIPTOR) * 30);
pOldImport = (PIMAGE_IMPORT_DESCRIPTOR)((PBYTE)lpFile + RVAToFileOffset(poh->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress, pnh));
for (nImportCount = 0;; nImportCount++)
{
if (pOldImport[nImportCount].OriginalFirstThunk == 0 &&
pOldImport[nImportCount].TimeDateStamp == 0 &&
pOldImport[nImportCount].ForwarderChain == 0 &&
pOldImport[nImportCount].Name == 0 &&
pOldImport[nImportCount].FirstThunk == 0)
break;
pNewImport[nImportCount] = pOldImport[nImportCount]; // 拷贝原导入描述
}
AddBase = (DWORD)(pLastSection->VirtualAddress + pLastSection->Misc.VirtualSize + (poh->SectionAlignment - 1)) & ~(poh->SectionAlignment - 1);
strcpy(Add_Data.szDllName, lpDllName);
Add_Data.Hint = 0;
strcpy(Add_Data.szFuncName, lpFuncName);
Add_Data.data[0].u1.Function = 0;
Add_Data.data[0].u1.Ordinal = 0;
Add_Data.data[0].u1.ForwarderString = (PBYTE)(AddBase + FIELD_OFFSET(NEW_IMPORT, Hint));
// 添加一个导入描述
pNewImport[nImportCount].FirstThunk = AddBase + FIELD_OFFSET(NEW_IMPORT, data);
pNewImport[nImportCount].Name = AddBase + FIELD_OFFSET(NEW_IMPORT, szDllName);
pNewImport[nImportCount].ForwarderChain = -1;
pNewImport[nImportCount].OriginalFirstThunk = AddBase + FIELD_OFFSET(NEW_IMPORT, data);
pNewImport[nImportCount].TimeDateStamp = -1;
nImportCount += 2;
// 添加一个新节
pfh->NumberOfSections++;
pNewSection = pLastSection + 1;
strcpy((char *)pNewSection->Name, ".rdata");
pNewSection->Characteristics = 0x40000040;
pNewSection->PointerToLinenumbers = 0;
pNewSection->NumberOfLinenumbers = 0;
pNewSection->PointerToRelocations = 0;
pNewSection->NumberOfRelocations = 0;
pNewSection->VirtualAddress = AddBase;
pNewSection->PointerToRawData = (pLastSection->PointerToRawData + pLastSection->SizeOfRawData + (poh->FileAlignment - 1)) & ~(poh->FileAlignment - 1);
pNewSection->SizeOfRawData = sizeof(Add_Data) + nImportCount * sizeof(IMAGE_IMPORT_DESCRIPTOR);
pNewSection->Misc.VirtualSize = pNewSection->SizeOfRawData;
poh->SizeOfImage = pNewSection->VirtualAddress + pNewSection->Misc.VirtualSize;
// 修改导入描述表位置
poh->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress = AddBase + sizeof(NEW_IMPORT);
poh->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size = (nImportCount - 1) * sizeof(IMAGE_IMPORT_DESCRIPTOR);
PBYTE pNewOverlayData = (PBYTE)lpFile + pNewSection->PointerToRawData + pNewSection->SizeOfRawData;
// 将文件中的附加数据往后移动,腾出空间来添加代码
memmove(pNewOverlayData, pOverlayData, nOverlayData);
// 在新节中写入导入描述
memcpy((PBYTE)lpFile + RVAToFileOffset(AddBase, pnh), &Add_Data, sizeof(Add_Data));
memcpy((PBYTE)lpFile + RVAToFileOffset(AddBase, pnh) + sizeof(Add_Data), pNewImport, nImportCount * sizeof(IMAGE_IMPORT_DESCRIPTOR));
if (poh->DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].VirtualAddress != 0)
{
// IAT所在节改成可写
GetSectionByRVA(poh->DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].VirtualAddress, pnh)->Characteristics |= 0x80000000;
}
// 删除Windows程序的导入绑定
poh->DataDirectory[IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG].VirtualAddress = 0;
poh->DataDirectory[IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG].Size = 0;
poh->DataDirectory[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT].VirtualAddress = 0;
poh->DataDirectory[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT].Size = 0;
poh->DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].VirtualAddress = 0;
poh->DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].Size = 0;
return pNewSection->PointerToRawData + pNewSection->SizeOfRawData + nOverlayData;
}