PE結構中的地址互轉,這次再來系統的復習一下關於PE結構中各種地址的轉換方式,最終通過編程來實現自動解析計算,最后將這個功能集成到我的迷你解析器中,本章中使用的工具是上次講解PE結構文章中制作的CMD迷你結構解析器,如果不知道參數的基本使用請看前一篇。
PE工具的使用與下載:https://www.cnblogs.com/LyShark/p/12960816.html
將VA地址轉換為FOA文件偏移: VA就是虛擬地址,轉換為FOA文件偏移,其手工計算過程如下所示。
首先需要得到 ImageBase(鏡像基址)
其次得到入口點地址,將兩個地址相加即可得到VA,也就是實際裝入地址。
通過上方的已知條件我們就可以計算出程序實際裝入內存后的入口地址了.
VA(實際裝入地址) = ImageBase(基址) + RVA(偏移) => 00400000 + 0000158b = 0040158b
如果不放心,可以將源程序拖入X64DBG中觀察是否一致,如下OEP為 0040158b
與我們的計算結果完全一致。
接着我們需要得到 .text節
基地址以及 .text節
RVA,如下命令即可獲取到。
虛擬地址開始位置:節區基地址 + 節區RVA => 00400000 + 00001000 = 00401000
虛擬地址結束位置:text節地址 + 節區尺寸 => 00401000 + 0x00000B44 = 00401B44
計算得出,虛擬地址text節開始位置 00401000
結束位置是 00401B44
打開X64dbg驗證沒錯 確實落在了 text節上。
判斷是否落在了.text節的依據是 開始位置 >= 401000 結束位置 <= 402000 很明顯:00401B44小於402000。
接着我們就來計算一下,當前的VA地址0040158B
其對應到文件中的偏移FOA位置是多少,計算公式如下。
RVA(相對偏移) = VA - (.text節首地址) => 0040158B - 00401000 = 58B
FOA(文件偏移) = RVA + .text節對應到文件中的偏移 => 58B + 400 = 98B
計算出結果了,我們使用WinHEX定位到98B
處看看是否符合要求,機器碼完全一致,符合要求。
接着就是使用C語言來實現這一計算過程了,有了計算流程之后使用C語言實現就變得簡單許多。
DWORD VA_To_FOA(HANDLE ImageBase,DWORD dwVA)
{
PIMAGE_NT_HEADERS pNtHead = NULL;
PIMAGE_FILE_HEADER pFileHead = NULL;
PIMAGE_SECTION_HEADER pSection = NULL;
DWORD NumberOfSectinsCount = 0;
DWORD dwImageBase = 0;
pNtHead = GetNtHeader(ImageBase);
pSection = IMAGE_FIRST_SECTION(pNtHead);
dwImageBase = pNtHead->OptionalHeader.ImageBase;
NumberOfSectinsCount = pNtHead->FileHeader.NumberOfSections;
for (int each = 0; each < NumberOfSectinsCount; each++)
{
DWORD Section_Start = dwImageBase + pSection[each].VirtualAddress; // 獲取節的開始地址
DWORD Section_Ends = dwImageBase + pSection[each].VirtualAddress + pSection[each].Misc.VirtualSize; // 獲取節的結束地址
if (dwVA >= Section_Start && dwVA <= Section_Ends)
{
DWORD RVA = dwVA - pNtHead->OptionalHeader.ImageBase; // 計算RVA
DWORD FOA = pSection[each].PointerToRawData + (RVA - pSection[each].VirtualAddress); // 計算FOA
return FOA;
}
}
return -1;
}
將FOA文件偏移轉換為VA地址: 將十六進制的文件偏移地址,反轉為VA地址。
如下,通過公式計算一下文件偏移為0xF43的位置,其對應到VA虛擬地址是多少。
VPK(實際大小) = (text節首地址 - ImageBase) - 實際偏移 => 401000-400000-400 = C00
VA(虛擬地址) = FOA(.text節) + ImageBase + VPK => F43 + 400000 + C00 = 401B43
計算后的結果F43
對應到VA地址是401B43
驗證一下,沒錯。
通過C語言實現也很簡單,只需要把這個計算過程流程化即可。
DWORD RVA_To_FOA(HANDLE ImageBase, DWORD dwRVA)
{
PIMAGE_NT_HEADERS pNtHead = NULL;
PIMAGE_FILE_HEADER pFileHead = NULL;
PIMAGE_SECTION_HEADER pSection = NULL;
DWORD NumberOfSectinsCount = 0;
DWORD dwImageBase = 0;
pNtHead = GetNtHeader(ImageBase);
pSection = IMAGE_FIRST_SECTION(pNtHead);
dwImageBase = pNtHead->OptionalHeader.ImageBase;
NumberOfSectinsCount = pNtHead->FileHeader.NumberOfSections;
for (int each = 0; each < NumberOfSectinsCount; each++)
{
DWORD Section_Start = pSection[each].VirtualAddress; // 計算RVA開始位置
DWORD Section_Ends = pSection[each].VirtualAddress + pSection[each].Misc.VirtualSize; // 計算RVA結束位置
if (dwRVA >= Section_Start && dwRVA <= Section_Ends)
{
DWORD VA = pNtHead->OptionalHeader.ImageBase + dwRVA; // 得到VA地址
DWORD FOA = pSection[each].PointerToRawData + (dwRVA - pSection[each].VirtualAddress); // 得到FOA
return FOA;
}
}
return -1;
}
將RVA相對地址轉換為FOA文件偏移: RVA就是相對地址,將相對地址轉換為FOA文件內偏移,例如將158b
轉換為FOA。
FOA = 實際偏移 + (RVA - 虛擬偏移) => 0x00000400 + (158b - 0x00001000) = 400 + 58b = 98B
計算出結果158b
虛擬地址對應到文件偏移為98B
,驗證一下看看。
使用C語言實現此過程。
DWORD RVA_To_FOA(HANDLE ImageBase, DWORD dwRVA)
{
PIMAGE_NT_HEADERS pNtHead = NULL;
PIMAGE_FILE_HEADER pFileHead = NULL;
PIMAGE_SECTION_HEADER pSection = NULL;
DWORD NumberOfSectinsCount = 0;
DWORD dwImageBase = 0;
pNtHead = GetNtHeader(ImageBase);
pSection = IMAGE_FIRST_SECTION(pNtHead);
dwImageBase = pNtHead->OptionalHeader.ImageBase;
NumberOfSectinsCount = pNtHead->FileHeader.NumberOfSections;
for (int each = 0; each < NumberOfSectinsCount; each++)
{
DWORD Section_Start = pSection[each].VirtualAddress; // 計算RVA開始位置
DWORD Section_Ends = pSection[each].VirtualAddress + pSection[each].Misc.VirtualSize; // 計算RVA結束位置
if (dwRVA >= Section_Start && dwRVA <= Section_Ends)
{
DWORD VA = pNtHead->OptionalHeader.ImageBase + dwRVA; // 得到VA地址
DWORD FOA = pSection[each].PointerToRawData + (dwRVA - pSection[each].VirtualAddress); // 得到FOA
return FOA;
}
}
return -1;
}
將FOA文件偏移轉換為VA地址: 將FOA文件偏移轉換為VA內存裝載地址,老樣子,我們計算一下 FOA 98B
轉為VA是多少?
首先計算RVA:RVA = pSection[each].VirtualAddress + (dwFOA - pSection[each].PointerToRawData);
RVA = 虛擬偏移 + (98B - 實際偏移) = 0x00001000 + (98B - 400) = 58B
DWORD VA = RVA + pNtHead->OptionalHeader.ImageBase;
VA = 00400000 + 00001000 + 58B = 40158b
結果就是40158b
沒錯,接着看看如何使用C語言實現計算過程吧。
DWORD FOA_To_VA(HANDLE ImageBase, DWORD dwFOA)
{
PIMAGE_NT_HEADERS pNtHead = NULL;
PIMAGE_FILE_HEADER pFileHead = NULL;
PIMAGE_SECTION_HEADER pSection = NULL;
DWORD NumberOfSectinsCount = 0;
DWORD dwImageBase = 0;
pNtHead = GetNtHeader(ImageBase);
pSection = IMAGE_FIRST_SECTION(pNtHead);
dwImageBase = pNtHead->OptionalHeader.ImageBase;
NumberOfSectinsCount = pNtHead->FileHeader.NumberOfSections;
for (int each = 0; each < NumberOfSectinsCount; each++)
{
DWORD PointerRawStart = pSection[each].PointerToRawData; // 文件偏移開始位置
DWORD PointerRawEnds = pSection[each].PointerToRawData + pSection[each].SizeOfRawData; // 文件偏移結束位置
if (dwFOA >= PointerRawStart && dwFOA <= PointerRawEnds)
{
DWORD RVA = pSection[each].VirtualAddress + (dwFOA - pSection[each].PointerToRawData); // 計算出RVA
DWORD VA = RVA + pNtHead->OptionalHeader.ImageBase; // 計算出VA
return VA;
}
}
return -1;
}
實現無腦轉換器(閉着眼轉換): 為了節約大家的轉換時間,以及讓大家少動一些腦細胞,我決定將轉換功能一並集成到解析器中,下面我給大家整體演示一遍使用方法。
先來演示一下VA轉換為RVA的過程,將VA地址40158B
轉換為FOA地址是多少?
輸入命令 GetPE.exe c://lyshark.exe --VaToFoa 0040158b
完成計算,對應FOA 是 0000098B
計算結果完全一致。
在反轉回去將FOA0000098B
轉為VA地址,完全一致,沒問題了,無腦亂搞。