天天看點

如何在EXE上綁定一個DLL

下面代碼将在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 &section[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 &section[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;

}

繼續閱讀