// ReadFile.cpp : 此檔案包含 "main" 函數。程式執行将在此處開始并結束。
//
#include "pch.h"
#include <iostream>
#include <Windows.h>
/*
* PE學習,參考《PE權威指南》
* 先了解PE的結構,才能更好的了解代碼,如果反過來,是很難有效了解PE結構的
* 先練習32位的PE結構,64位系統可以使用C:\Windows\SysWOW64這個目錄下的檔案練習
* 64位需使用PIMAGE_NT_HEADERS64
*/
/*
* RVA轉FOA
* 思路:先根據輸入的位址找出它所在的節,然後計算其在檔案中的偏移值
*/
DWORD RVAToFOA(PIMAGE_SECTION_HEADER pSectionHeader, DWORD addr)
{
PIMAGE_SECTION_HEADER pTemp = pSectionHeader;
for (; (pTemp->VirtualAddress <= addr && pTemp->VirtualAddress != 0); pTemp++)
{
if (pTemp->VirtualAddress == 0)
{
break;
}
if (pTemp->VirtualAddress == addr)
{
pTemp++;
break;
}
}
pTemp--;
DWORD foa = addr - pTemp->VirtualAddress + pTemp->PointerToRawData;
//DWORD endRVA = pTemp->VirtualAddress + pTemp->Misc.VirtualSize;
//DWORD endFOA = pTemp->PointerToRawData + pTemp->SizeOfRawData;
//printf("\nVirtualAddress %08X + %08X = %08X, ", pTemp->VirtualAddress, pTemp->Misc.VirtualSize, endRVA);
//printf("PointerToRawData %08X + %08X = %08X\n", pTemp->PointerToRawData, pTemp->SizeOfRawData, endFOA);
//printf("RVA: %08X --> FOA: %08X\n\n", addr, foa);
return foa;
}
/*
* 擷取檔案路徑
*/
void GetFile(TCHAR* szPath)
{
#if 1
if (!GetModuleFileName(NULL, szPath, MAX_PATH))
{
printf("Cannot install service (%d)\n", GetLastError());
return;
}
char* pPathEnd = (char*)szPath + strlen(szPath);
while (pPathEnd--)
{
if (*pPathEnd == '\\')
{
*pPathEnd = '\0';
break;
}
}
// user32test.dll ntoskrnltest.exe
//strcat_s(szPath, "\\ntdlltest.dll");
// special? ntoskrnltest.exe
strcat_s(szPath, MAX_PATH, "\\SysWOW64\\kernel32.dll");
#else
strcpy_s(szPath, "D:\\test.dll");
#endif
}
/*
* 讀取檔案到記憶體
*/
bool ReadFile(const char* name, char** p)
{
bool bRet = false;
FILE* fp = NULL;
errno_t error = fopen_s(&fp, name, "rb");
if (error == 0)
{
fseek(fp, 0, SEEK_END);
DWORD bytes = ftell(fp);
// do not forget to free memory later
*p = (char*)malloc(bytes);
fseek(fp, 0, SEEK_SET);
fread_s(*p, bytes, sizeof(char), bytes, fp);
fclose(fp);
bRet = true;
}
else
{
printf("ReadFile %s error %d\n", name, error);
}
return bRet;
}
void PrintFileHeader(PIMAGE_NT_HEADERS32 pNTHeaders)
{
printf("==============File Header Size: %08X ==============\n", sizeof(IMAGE_FILE_HEADER));
printf("Machine: %04X\n", pNTHeaders->FileHeader.Machine);
printf("NumberOfSections: %04X\n", pNTHeaders->FileHeader.NumberOfSections);
printf("TimeDateStamp: %08X\n", pNTHeaders->FileHeader.TimeDateStamp);
printf("PointerToSymbolTable: %08X\n", pNTHeaders->FileHeader.PointerToSymbolTable);
printf("NumberOfSymbols: %08X\n", pNTHeaders->FileHeader.NumberOfSymbols);
printf("SizeOfOptionalHeader: %04X\n", pNTHeaders->FileHeader.SizeOfOptionalHeader);
printf("Characteristics: %04X\n", pNTHeaders->FileHeader.Characteristics);
}
const char* directoryNameArray[IMAGE_NUMBEROF_DIRECTORY_ENTRIES] = {
"Export Directory",
"Import Directory",
"Resource Directory",
"Exception Directory",
"Security Directory",
"Base Relocation Directory",
"Debug Directory",
"Description Directory",
"Special Directory",
"TLS,Thread Storage Directory",
"Load Configuration Directory",
"Bound Import Directory",
"IAT,Import Address Table Directory",
"Delay Import Directory",
"COM_DESCRIPTOR,COR20 Header Directory",
"Reserved Directory"
};
void PrintOptionalHeaders(PIMAGE_NT_HEADERS32 pNTHeaders)
{
printf("==============Optional Headers Size: %08X ==============\n", sizeof(IMAGE_OPTIONAL_HEADER32));
//
// Standard fields.
//
printf("Magic: %04X\n", pNTHeaders->OptionalHeader.Magic);
printf("MajorLinkerVersion: %02X\n", pNTHeaders->OptionalHeader.MajorLinkerVersion);
printf("MinorLinkerVersion: %02X\n", pNTHeaders->OptionalHeader.MinorLinkerVersion);
printf("SizeOfCode: %08X\n", pNTHeaders->OptionalHeader.SizeOfCode);
printf("SizeOfInitializedData: %08X\n", pNTHeaders->OptionalHeader.SizeOfInitializedData);
printf("SizeOfUninitializedData: %08X\n", pNTHeaders->OptionalHeader.SizeOfUninitializedData);
printf("AddressOfEntryPoint: %08X\n", pNTHeaders->OptionalHeader.AddressOfEntryPoint);
printf("BaseOfCode: %08X\n", pNTHeaders->OptionalHeader.BaseOfCode);
printf("BaseOfData: %08X\n", pNTHeaders->OptionalHeader.BaseOfData);
//
// NT additional fields.
//
printf("ImageBase: %08X\n", pNTHeaders->OptionalHeader.ImageBase);
printf("SectionAlignment: %08X\n", pNTHeaders->OptionalHeader.SectionAlignment);
printf("FileAlignment: %08X\n", pNTHeaders->OptionalHeader.FileAlignment);
printf("MajorOperatingSystemVersion: %04X\n", pNTHeaders->OptionalHeader.MajorOperatingSystemVersion);
printf("MinorOperatingSystemVersion: %04X\n", pNTHeaders->OptionalHeader.MinorOperatingSystemVersion);
printf("MajorImageVersion: %04X\n", pNTHeaders->OptionalHeader.MajorImageVersion);
printf("MinorImageVersion: %04X\n", pNTHeaders->OptionalHeader.MinorImageVersion);
printf("MajorSubsystemVersion: %04X\n", pNTHeaders->OptionalHeader.MajorSubsystemVersion);
printf("MinorSubsystemVersion: %04X\n", pNTHeaders->OptionalHeader.MinorSubsystemVersion);
printf("Win32VersionValue: %08X\n", pNTHeaders->OptionalHeader.Win32VersionValue);
printf("SizeOfImage: %08X\n", pNTHeaders->OptionalHeader.SizeOfImage);
printf("SizeOfHeaders: %08X\n", pNTHeaders->OptionalHeader.SizeOfHeaders);
printf("CheckSum: %08X\n", pNTHeaders->OptionalHeader.CheckSum);
printf("Subsystem: %04X\n", pNTHeaders->OptionalHeader.Subsystem);
printf("DllCharacteristics: %04X\n", pNTHeaders->OptionalHeader.DllCharacteristics);
printf("SizeOfStackReserve: %08X\n", pNTHeaders->OptionalHeader.SizeOfStackReserve);
printf("SizeOfStackCommit: %08X\n", pNTHeaders->OptionalHeader.SizeOfStackCommit);
printf("SizeOfHeapReserve: %08X\n", pNTHeaders->OptionalHeader.SizeOfHeapReserve);
printf("SizeOfHeapCommit: %08X\n", pNTHeaders->OptionalHeader.SizeOfHeapCommit);
printf("LoaderFlags: %08X\n", pNTHeaders->OptionalHeader.LoaderFlags);
printf("NumberOfRvaAndSizes: %08X\n", pNTHeaders->OptionalHeader.NumberOfRvaAndSizes);
for (int i = 0; i < IMAGE_NUMBEROF_DIRECTORY_ENTRIES; i++)
{
printf("DataDirectory[%02d] VirtualAddress: %08X", i,
pNTHeaders->OptionalHeader.DataDirectory[i].VirtualAddress);
printf(", Size: %08X %s\n", pNTHeaders->OptionalHeader.DataDirectory[i].Size, directoryNameArray[i]);
}
IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES];
}
/*
* 列印節表
* 說明:檔案頭 + DOS Stub + DOS頭 + NT頭 + 節表,
* 這些内容在檔案中和加載到記憶體中是完全一樣的,做拉伸練習時要注意
*/
void PrintSectionHeader(PIMAGE_NT_HEADERS32 pNTHeaders)
{
printf("==============SECTION HEADER: Size: %08X ==============\n", sizeof(IMAGE_SECTION_HEADER));
PIMAGE_SECTION_HEADER pSectionHeader = (PIMAGE_SECTION_HEADER)((char*)pNTHeaders + sizeof(IMAGE_NT_HEADERS32));
char* Name[IMAGE_SIZEOF_SHORT_NAME + 1] = { 0 };
int sectionNum = pNTHeaders->FileHeader.NumberOfSections;
for (int i = 0; i < sectionNum; i++)
{
memcpy_s(Name, IMAGE_SIZEOF_SHORT_NAME, pSectionHeader->Name, IMAGE_SIZEOF_SHORT_NAME);
printf("%d %s\nVirtualAddress: %08X, VirtualSize: %08X ==> %08X\nPointerToRawData: %08X, SizeOfRawData: %08X "
"==> %08X\n",
i, Name, pSectionHeader->VirtualAddress, pSectionHeader->Misc.VirtualSize,
pSectionHeader->VirtualAddress + pSectionHeader->Misc.VirtualSize, pSectionHeader->PointerToRawData,
pSectionHeader->SizeOfRawData, pSectionHeader->PointerToRawData + pSectionHeader->SizeOfRawData);
pSectionHeader++;
}
}
/*
* 列印導出表資訊
* 導出表資訊常見于DLL,但EXE也可以存在導出表
*/
void PrintExportTable(char* fileBuffer, PIMAGE_NT_HEADERS32 pNTHeaders, PIMAGE_SECTION_HEADER pFirstSectionHeader)
{
printf("==============Export Table Size: %08X ==============\n", sizeof(IMAGE_EXPORT_DIRECTORY));
IMAGE_DATA_DIRECTORY exportDirectory = pNTHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT];
printf("EXPORT %08X+ %08X\n", exportDirectory.VirtualAddress, exportDirectory.Size);
// 如果存在導出表
if (exportDirectory.VirtualAddress > 0)
{
// 将導出表相對虛拟位址RVA轉為檔案偏移FOA
DWORD exportFOA = RVAToFOA(pFirstSectionHeader, exportDirectory.VirtualAddress);
printf("EXPORT RVA: %08X -- FOA: %08X\n", exportDirectory.VirtualAddress, exportFOA);
// 将記憶體中的位元組資訊轉為導出表結構體
PIMAGE_EXPORT_DIRECTORY imageExportDirectory = (PIMAGE_EXPORT_DIRECTORY)(fileBuffer + exportFOA);
printf("Characteristics: %08X\n", imageExportDirectory->Characteristics);
printf("TimeDateStamp: %08X\n", imageExportDirectory->TimeDateStamp);
printf("MajorVersion: %08X\n", imageExportDirectory->MajorVersion);
printf("MinorVersion: %08X\n", imageExportDirectory->MinorVersion);
printf("Name: %08X\n", imageExportDirectory->Name);
printf("Base: %08X\n", imageExportDirectory->Base);
printf("NumberOfFunctions: %08X\n", imageExportDirectory->NumberOfFunctions);
printf("NumberOfNames: %08X\n", imageExportDirectory->NumberOfNames);
// 函數名稱位址表RVA轉FOA
DWORD AddressOfNamesFOA = RVAToFOA(pFirstSectionHeader, imageExportDirectory->AddressOfNames);
// 函數序号位址表RVA轉FOA
DWORD AddressOfNameOrdinalsFOA = RVAToFOA(pFirstSectionHeader, imageExportDirectory->AddressOfNameOrdinals);
// 導出函數位址表RVA轉FOA
DWORD AddressOfFunctionsFOA = RVAToFOA(pFirstSectionHeader, imageExportDirectory->AddressOfFunctions);
// 函數名稱位址表在記憶體的起始位址
int* pAddressOfNames = (int*)(fileBuffer + AddressOfNamesFOA);
// 函數序号位址表在記憶體的起始位址
WORD* pAddressOfNameOrdinals = (WORD*)(fileBuffer + AddressOfNameOrdinalsFOA);
// 導出函數位址表在記憶體的起始位址
int* pAddressOfFunctions = (int*)(fileBuffer + AddressOfFunctionsFOA);
printf("AddressOfNames RVA: %08X (FOA: %08X)\n", imageExportDirectory->AddressOfNames, AddressOfNamesFOA);
printf("AddressOfNameOrdinals RVA: %08X (FOA: %08X)\n", imageExportDirectory->AddressOfNameOrdinals,
AddressOfNameOrdinalsFOA);
printf("AddressOfFunctions RVA: %08X (FOA: %08X)\n", imageExportDirectory->AddressOfFunctions,
AddressOfFunctionsFOA);
// 緩存數組,Ordinals-- > 函數名及序号資訊
char arryOfOrdinalsInfo[2048][256] = { 0 };
for (int i = 0; i < imageExportDirectory->NumberOfNames; i++)
{
//DWORD nameAddr = RVAToFOA(pFirstSectionHeader, *pAddressOfNames);
//int* pName = (int*)(fileBuffer + nameAddr);
//printf("%d FOA:%08X=%08X %s\n", i, nameAddr, *pAddressOfNames, (char*)pName);
// 函數名稱位址表位址單元存儲的内容RVA轉FOA
DWORD nameAddr = RVAToFOA(pFirstSectionHeader, *pAddressOfNames);
// 擷取FOA對應的函數名稱
char* pName = (char*)(fileBuffer + nameAddr);
// 位址單元的内容是函數序号,Base+函數序号,是按序号方式調用的值
// 這個序号表是給名稱表查詢使用的,它必須和名稱表一一對應
sprintf_s(arryOfOrdinalsInfo[*pAddressOfNameOrdinals],
"Hint Hex: %04X (%05d) Name RVA: %08X(FOA: %08X) [Ordinals]: %04d (+Base: %04d) %s", i, i,
*pAddressOfNames, nameAddr, *pAddressOfNameOrdinals,
(*pAddressOfNameOrdinals + imageExportDirectory->Base), (char*)pName);
// WORD*型偏移2個位址,讀取下一個序号
pAddressOfNameOrdinals++;
// int*型偏移4個位址,讀取下一個位址
pAddressOfNames++;
}
for (int i = 0; i < imageExportDirectory->NumberOfFunctions; i++)
{
if (*pAddressOfFunctions)
{
// 導出函數位址RVA轉FOA,可以根據FOA直接在檔案中檢視該函數的寫死
DWORD AddressOfFunctionsFOA = RVAToFOA(pFirstSectionHeader, *pAddressOfFunctions);
if (strlen(arryOfOrdinalsInfo[i]) > 0)
{
printf("%s\n", arryOfOrdinalsInfo[i]);
}
else
{
printf(" no function name info\n");
}
printf(" %04d [Function Entry Point] RVA: %08X FOA: %08X\n", i, *pAddressOfFunctions,
AddressOfFunctionsFOA);
// out put code
printf(" Code: ");
unsigned char* pAddr = (unsigned char*)(fileBuffer + AddressOfFunctionsFOA);
for (int i = 0; i < 10; i++)
{
printf("%02X ", *pAddr);
pAddr++;
}
printf("\n\n");
}
pAddressOfFunctions++;
}
}
}
/*
* 列印導入表資訊
*/
void PrintImportTable(char* fileBuffer, PIMAGE_NT_HEADERS32 pNTHeaders, PIMAGE_SECTION_HEADER pFirstSectionHeader)
{
printf("==============IMPORT Table Size: %08X ==============\n", sizeof(IMAGE_IMPORT_DESCRIPTOR));
IMAGE_DATA_DIRECTORY importDirectory = pNTHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT];
printf("IMPORT %08X + %08X\n", importDirectory.VirtualAddress, importDirectory.Size);
// 導入表位址RVA轉FOA
DWORD importFOA = RVAToFOA(pFirstSectionHeader, importDirectory.VirtualAddress);
printf("IMPORT RVA: %08X -- FOA: %08X\n", importDirectory.VirtualAddress, importFOA);
// 擷取導入表描述符結構體
PIMAGE_IMPORT_DESCRIPTOR pImportDescriptor = (PIMAGE_IMPORT_DESCRIPTOR)(fileBuffer + importFOA);
// 周遊
int indexOfDLL = 0;
while (pImportDescriptor->OriginalFirstThunk != 0 && pImportDescriptor->FirstThunk != 0)
{
// 擷取導入DLL的名稱,根據這個FOA可以直接在檔案檢視到DLL名稱
DWORD dllNameFOA = RVAToFOA(pFirstSectionHeader, pImportDescriptor->Name);
// 記憶體中的DLL名稱,用于列印
unsigned char* pAddr = (unsigned char*)(fileBuffer + dllNameFOA);
// RVA轉FOA
DWORD foaOfOriginalFirstThunk = RVAToFOA(pFirstSectionHeader, pImportDescriptor->OriginalFirstThunk);
DWORD foaOfFirstThunk = RVAToFOA(pFirstSectionHeader, pImportDescriptor->FirstThunk);
printf("\nIndexOfDLL: %02d Name RVA: %08X(FOA: %08X) NAME: %s TimeDateStamp: %08X\nOriginalFirstThunk: "
"%08X(FOA: %08X)\nFirstThunk: %08X(FOA: %08X)\n",
indexOfDLL++, pImportDescriptor->Name, dllNameFOA, pAddr, pImportDescriptor->TimeDateStamp,
pImportDescriptor->OriginalFirstThunk, foaOfOriginalFirstThunk, pImportDescriptor->FirstThunk,
foaOfFirstThunk);
// 記憶體位址
int* pOriginalFirstThunk = (int*)(fileBuffer + foaOfOriginalFirstThunk);
int* pFirstThunk = (int*)(fileBuffer + foaOfFirstThunk);
printf("================INT===============\n");
//周遊INT(Import Name Table)
while (*pOriginalFirstThunk)
{
if (*pOriginalFirstThunk & IMAGE_ORDINAL_FLAG32)
{
// 函數以序号的方式導入
printf(" %08X ==> %08X\n", *pOriginalFirstThunk, *pOriginalFirstThunk & 0x7fffffff);
}
else
{
// 函數以名稱的方式導入
PIMAGE_IMPORT_BY_NAME pImportByName
= (PIMAGE_IMPORT_BY_NAME)(fileBuffer + RVAToFOA(pFirstSectionHeader, *pOriginalFirstThunk));
//printf(" %08d %08X %08X\n", i, *pIATAddr, RVAToFOA(pFirstSectionHeader, *pIATAddr));
printf(" RVA: %08X FOA: %08X Hint Hex: %04X (%05d) Name: %s\n", *pOriginalFirstThunk,
RVAToFOA(pFirstSectionHeader, *pOriginalFirstThunk), pImportByName->Hint, pImportByName->Hint,
(char*)(pImportByName->Name));
}
pOriginalFirstThunk++;
}
printf("================IAT===============\n");
// 周遊IAT(Import Address Table)
while (pFirstThunk != 0 && *pFirstThunk)
{
if (*pFirstThunk & IMAGE_ORDINAL_FLAG32)
{
// 函數以序号的方式導入
printf(" %08X ==> %08X\n", *pFirstThunk, *pFirstThunk & 0x7fffffff);
}
else
{
if (pImportDescriptor->TimeDateStamp == 0xffffffff)
{
// 導入位址需查詢綁定導入表
printf(" %08X\n", *pFirstThunk);
}
else
{
// 函數以名稱的方式導入
PIMAGE_IMPORT_BY_NAME pImportByName
= (PIMAGE_IMPORT_BY_NAME)(fileBuffer + RVAToFOA(pFirstSectionHeader, *pFirstThunk));
//printf(" %08d %08X %08X\n", i, *pIATAddr, RVAToFOA(pFirstSectionHeader, *pIATAddr));
printf(" RVA: %08X FOA: %08X Hint Hex: %04X (%05d) Name: %s\n", *pFirstThunk,
RVAToFOA(pFirstSectionHeader, *pFirstThunk), pImportByName->Hint, pImportByName->Hint,
(char*)(pImportByName->Name));
}
}
pFirstThunk++;
}
pImportDescriptor++;
}
}
void PrintIATTable(char* fileBuffer, PIMAGE_NT_HEADERS32 pNTHeaders, PIMAGE_SECTION_HEADER pFirstSectionHeader)
{
printf("==============IAT Table==============\n");
IMAGE_DATA_DIRECTORY iatDirectory = pNTHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT];
printf("IAT %08X + %08X\n", iatDirectory.VirtualAddress, iatDirectory.Size);
// RVA轉FOA,可以對照檔案和記憶體的值加深了解
DWORD iatFOA = RVAToFOA(pFirstSectionHeader, iatDirectory.VirtualAddress);
// 擷取記憶體buffer中IAT的起始位址,注意int*,加一是偏移4個位元組
int* pIATAddr = (int*)(fileBuffer + iatFOA);
printf("\nIAT RVA: %08X FOA: %08X\n", iatDirectory.VirtualAddress, iatFOA);
// 4個位元組為一組,是以除以4就是位址個數
for (int i = 0; i < iatDirectory.Size / 4; i++)
{
if (*pIATAddr)
{
if (*pIATAddr < 0x80000000)
{
if (*pIATAddr > pNTHeaders->OptionalHeader.SizeOfImage)
{
printf(" %08X\n", *pIATAddr);
}
else
{
DWORD importByNameFOA = RVAToFOA(pFirstSectionHeader, *pIATAddr);
PIMAGE_IMPORT_BY_NAME pImportByName = (PIMAGE_IMPORT_BY_NAME)(fileBuffer + importByNameFOA);
//printf(" %08d %08X %08X\n", i, *pIATAddr, RVAToFOA(pFirstSectionHeader, *pIATAddr));
printf(" %08d RVA: %08X FOA: %08X Hint Hex: %04X (%05d) Name: %s\n", i, *pIATAddr,
importByNameFOA, pImportByName->Hint, pImportByName->Hint, (char*)(pImportByName->Name));
}
}
else
{
printf(" %08d %08X\n", i, *pIATAddr);
}
}
else
{
printf(" %08d %08X\n", i, *pIATAddr);
}
pIATAddr++;
}
}
/*
* 列印重定位表
*/
void PrintBaseRelocationTable(char* fileBuffer, PIMAGE_NT_HEADERS32 pNTHeaders,
PIMAGE_SECTION_HEADER pFirstSectionHeader)
{
printf("==============BASE RELOCATION Table Size: %08X ==============\n", sizeof(IMAGE_BASE_RELOCATION));
IMAGE_DATA_DIRECTORY baseRelocationDirectory
= pNTHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC];
// RVA轉FOA
DWORD baseRelocationFOA = RVAToFOA(pFirstSectionHeader, baseRelocationDirectory.VirtualAddress);
printf("Base Relocation RVA: %08X -- FOA: %08X\n", baseRelocationDirectory.VirtualAddress, baseRelocationFOA);
// 擷取記憶體buffer中重定位表起始位址
char* pBaseRelocationAddr = (char*)(fileBuffer + baseRelocationFOA);
// 指針轉結構體
PIMAGE_BASE_RELOCATION pImageBaseRelocation = (PIMAGE_BASE_RELOCATION)(pBaseRelocationAddr);
// 重定位表結構:前8個位元組是代碼起始頁碼的起始虛拟位址和塊大小
int headSize = sizeof(pImageBaseRelocation->VirtualAddress) + sizeof(pImageBaseRelocation->SizeOfBlock);
// 注意先判斷有沒有重定位表
if (baseRelocationDirectory.VirtualAddress != 0)
{
// 周遊
while (pBaseRelocationAddr != 0 && pImageBaseRelocation->VirtualAddress != 0)
{
// ImageBase + 代碼起始頁面位址
DWORD imageDataBase = pNTHeaders->OptionalHeader.ImageBase + pImageBaseRelocation->VirtualAddress;
// 偏移8個位元組才是第一個重定位項的值,注意每個重定位項記憶體寬度時兩個位元組
WORD* pOffSetData = (WORD*)(pBaseRelocationAddr + headSize);
printf("\nVirtualAddress: %08X SizeOfBlock: %08X\n ImageBase: %08X imageDataBase: %08X\n",
pImageBaseRelocation->VirtualAddress, pImageBaseRelocation->SizeOfBlock,
pNTHeaders->OptionalHeader.ImageBase, imageDataBase);
// 周遊重定位項,一項占兩個位元組,是以除以2
for (int i = 0; i < (pImageBaseRelocation->SizeOfBlock - headSize) / 2; i++)
{
if (pImageBaseRelocation->VirtualAddress)
{
// 3c90 -> c90
//以下3 C90的含義是:
//3表示這個值對應的位址需修正,0表示不需修正
//低12位為修正位址
//實際VA=基位址+代碼其實頁面+低十二位虛拟位址
//=0x77610000+2000+c90
// 這裡處理不夠嚴謹,應先判斷是否需修正
// ImageBase + 代碼起始頁位址 + 低十二位虛拟位址
DWORD functionVirtualAddr = imageDataBase + (*pOffSetData & 0x0fff);
printf("\n%04X(%08X) \n", *pOffSetData, functionVirtualAddr);
// (代碼起始頁位址 + 低十二位虛拟位址) 轉FOA
DWORD offSetFOA
= RVAToFOA(pFirstSectionHeader, pImageBaseRelocation->VirtualAddress + (*pOffSetData & 0x0fff));
// 擷取記憶體buffer的位址,可根據FOA直接檢視偏移值的檔案内容
DWORD* pAddr = (DWORD*)(fileBuffer + offSetFOA);
printf("offSetFOA %08X --> Value: %08X(functionVirtualAddr: %08X)) \n", offSetFOA, *pAddr,
functionVirtualAddr);
// test new base測試DLL重定位為新的位址
DWORD newBase = 0x77610000;
// 重定位後的記憶體位址
DWORD newAddr = newBase + pImageBaseRelocation->VirtualAddress + (*pOffSetData & 0x0fff);
// 重定位後記憶體位址存儲的内容,這個就是檔案中需修改的值
// *pAddr是編譯時,根據DLL的ImageBase計算出的函數位址
DWORD newVaue = newBase - pNTHeaders->OptionalHeader.ImageBase + *pAddr;
printf("new functionVirtualAddr: %08X new Value: %08X\n", newAddr, newVaue);
if ((i > 0) && (i % 16 == 1))
{
printf("\n");
}
}
// 偏移兩個位元組,取下一個重定位項
pOffSetData++;
}
printf("\n");
// 下一個重定位表
pBaseRelocationAddr += pImageBaseRelocation->SizeOfBlock;
pImageBaseRelocation = (PIMAGE_BASE_RELOCATION)(pBaseRelocationAddr);
}
}
else
{
printf(" is null\n");
}
}
int main(int argc, char** argv)
{
TCHAR szPath[MAX_PATH];
if (argc <= 1)
{
printf("Please use [ReadFile.exe] [file]\n");
// use default test
GetFile(szPath);
}
else
{
printf("%d %s\n", argc, argv[1]);
strncpy_s(szPath, argv[1], strlen(argv[1]));
}
char* fileBuffer = NULL;
bool bRet = ReadFile(szPath, &fileBuffer);
if (bRet)
{
PIMAGE_DOS_HEADER pDosHeader;
PIMAGE_NT_HEADERS32 pNTHeaders;
PIMAGE_SECTION_HEADER pSectionHeader;
PIMAGE_SECTION_HEADER pFirstSectionHeader;
pDosHeader = (PIMAGE_DOS_HEADER)fileBuffer;
pNTHeaders = (PIMAGE_NT_HEADERS32)(fileBuffer + pDosHeader->e_lfanew);
pSectionHeader = (PIMAGE_SECTION_HEADER)((char*)pNTHeaders + sizeof(IMAGE_NT_HEADERS32));
pFirstSectionHeader = pSectionHeader;
PrintFileHeader(pNTHeaders);
PrintOptionalHeaders(pNTHeaders);
PrintSectionHeader(pNTHeaders);
PrintExportTable(fileBuffer, pNTHeaders, pFirstSectionHeader);
PrintImportTable(fileBuffer, pNTHeaders, pFirstSectionHeader);
PrintIATTable(fileBuffer, pNTHeaders, pFirstSectionHeader);
PrintBaseRelocationTable(fileBuffer, pNTHeaders, pFirstSectionHeader);
if (fileBuffer)
{
delete fileBuffer;
fileBuffer = NULL;
}
}
//system("pause");
}