網(wǎng)絡(luò)安全編程:PE編程實(shí)例之地址轉(zhuǎn)換器
PE文件的3種地址,分別是VA(虛擬地址)、RVA(相對(duì)虛擬地址)和FileOffset(文件偏移地址)。這3種地址的轉(zhuǎn)換如果始終使用手動(dòng)來計(jì)算會(huì)非常累,因此通常的做法是借助工具來完成。這里編寫一個(gè)對(duì)這3種地址進(jìn)行轉(zhuǎn)換的工具。該工具如圖1所示。
圖1 地址轉(zhuǎn)換器
這個(gè)工具是在前兩個(gè)工具的基礎(chǔ)上完成的。因此,在進(jìn)行計(jì)算的時(shí)候,應(yīng)該先要進(jìn)行“查看”,再進(jìn)行“計(jì)算”。否則,該獲取的指針還沒有獲取到。
在界面上,左邊的3個(gè)按鈕是“單選框”,單選框的設(shè)置方法如圖2所示。
圖2 對(duì)單選框的設(shè)置
3個(gè)單選框中只能有一個(gè)是選中狀態(tài),為了記錄哪個(gè)單選框是選中狀態(tài),在類中定義一個(gè)成員變量m_nSelect。對(duì)3個(gè)單選框,分別使m_nSelect值為1、2和3。下面來看主要的代碼。
在單擊“計(jì)算”按鈕后,響應(yīng)該按鈕的代碼如下:
- void CPeParseDlg::OnBtnCalc()
- {
- // TODO: Add your control notification handler code here
- DWORD dwAddr = 0;
- // 獲取的地址
- dwAddr = GetAddr();
- // 地址所在的節(jié)
- int nInNum = GetAddrInSecNum(dwAddr);
- // 計(jì)算其他地址
- CalcAddr(nInNum, dwAddr);
- }
分別看一下GetAddr()、GetAddrInSecNum()和CalcAddr()的實(shí)現(xiàn)。
獲取在編輯框中輸入的地址內(nèi)容的代碼如下:
- DWORD CPeParseDlg::GetAddr()
- {
- char szAddr[10] = { 0 };
- DWORD dwAddr = 0;
- switch ( m_nSelect )
- {
- case 1:
- {
- GetDlgItemText(IDC_EDIT_VA, szAddr, 10);
- HexStrToInt(szAddr, &dwAddr);
- break;
- }
- case 2:
- {
- GetDlgItemText(IDC_EDIT_RVA, szAddr, 10);
- HexStrToInt(szAddr, &dwAddr);
- break;
- }
- case 3:
- {
- GetDlgItemText(IDC_EDIT_FILEOFFSET, szAddr, 10);
- HexStrToInt(szAddr, &dwAddr);
- break;
- }
- }
- return dwAddr;
- }
獲取該地址所屬的第幾個(gè)節(jié)的代碼如下:
- int CPeParseDlg::GetAddrInSecNum(DWORD dwAddr)
- {
- int nInNum = 0;
- int nSecNum = m_pNtHdr->FileHeader.NumberOfSections;
- switch ( m_nSelect )
- {
- case 1:
- {
- DWORD dwImageBase = m_pNtHdr->OptionalHeader.ImageBase;
- for ( nInNum = 0; nInNum < nSecNum; nInNum ++ )
- {
- if ( dwAddr >= dwImageBase + m_pSecHdr[nInNum].VirtualAddress
- && dwAddr <= dwImageBase + m_pSecHdr[nInNum].VirtualAddress
- + m_pSecHdr[nInNum].Misc.VirtualSize)
- {
- return nInNum;
- }
- }
- break;
- }
- case 2:
- {
- for ( nInNum = 0; nInNum < nSecNum; nInNum ++ )
- {
- if ( dwAddr >= m_pSecHdr[nInNum].VirtualAddress
- && dwAddr <= m_pSecHdr[nInNum].VirtualAddress
- + m_pSecHdr[nInNum].Misc.VirtualSize)
- {
- return nInNum;
- }
- }
- break;
- }
- case 3:
- {
- for ( nInNum = 0; nInNum < nSecNum; nInNum ++ )
- {
- if ( dwAddr >= m_pSecHdr[nInNum].PointerToRawData
- && dwAddr <= m_pSecHdr[nInNum].PointerToRawData
- + m_pSecHdr[nInNum].SizeOfRawData)
- {
- return nInNum;
- }
- }
- break;
- }
- }
- return -1;
- }
計(jì)算其他地址的代碼如下:
- VOID CPeParseDlg::CalcAddr(int nInNum, DWORD dwAddr)
- {
- DWORD dwVa = 0;
- DWORD dwRva = 0;
- DWORD dwFileOffset = 0;
- switch ( m_nSelect )
- {
- case 1:
- {
- dwVa = dwAddr;
- dwRva = dwVa - m_pNtHdr->OptionalHeader.ImageBase;
- dwFileOffset = m_pSecHdr[nInNum].PointerToRawData
- + (dwRva - m_pSecHdr[nInNum].VirtualAddress);
- break;
- }
- case 2:
- {
- dwVa = dwAddr + m_pNtHdr->OptionalHeader.ImageBase;
- dwRva = dwAddr;
- dwFileOffset = m_pSecHdr[nInNum].PointerToRawData
- + (dwRva - m_pSecHdr[nInNum].VirtualAddress);
- break;
- }
- case 3:
- {
- dwFileOffset = dwAddr;
- dwRva = m_pSecHdr[nInNum].VirtualAddress
- + (dwFileOffset - m_pSecHdr[nInNum].PointerToRawData);
- dwVa = dwRva + m_pNtHdr->OptionalHeader.ImageBase;
- break;
- }
- }
- SetDlgItemText(IDC_EDIT_SECTION, (const char *)m_pSecHdr[nInNum].Name);
- CString str;
- str.Format("%08X", dwVa);
- SetDlgItemText(IDC_EDIT_VA, str);
- str.Format("%08X", dwRva);
- SetDlgItemText(IDC_EDIT_RVA, str);
- str.Format("%08X", dwFileOffset);
- SetDlgItemText(IDC_EDIT_FILEOFFSET, str);
- }
代碼都不復(fù)雜,關(guān)鍵就是CalcAddr()中3種地址的轉(zhuǎn)換。