下面代碼将在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;
}