PE文件的3种地址,分别是VA(虚拟地址)、RVA(相对虚拟地址)和FileOffset(文件偏移地址)。这3种地址的转换如果始终使用手动来计算会非常累,因此通常的做法是借助工具来完成。这里编写一个对这3种地址进行转换的工具。该工具如图1所示。
图1 地址转换器
这个工具是在前两个工具的基础上完成的。因此,在进行计算的时候,应该先要进行“查看”,再进行“计算”。否则,该获取的指针还没有获取到。
在界面上,左边的3个按钮是“单选框”,单选框的设置方法如图2所示。
图2 对单选框的设置
3个单选框中只能有一个是选中状态,为了记录哪个单选框是选中状态,在类中定义一个成员变量m_nSelect。对3个单选框,分别使m_nSelect值为1、2和3。下面来看主要的代码。
在单击“计算”按钮后,响应该按钮的代码如下:
voidCPeParseDlg::OnBtnCalc() { //TODO:Addyourcontrolnotificationhandlercodehere DWORDdwAddr=0; //获取的地址 dwAddr=GetAddr(); //地址所在的节 intnInNum=GetAddrInSecNum(dwAddr); //计算其他地址 CalcAddr(nInNum,dwAddr); }
分别看一下GetAddr()、GetAddrInSecNum()和CalcAddr()的实现。
获取在编辑框中输入的地址内容的代码如下:
DWORDCPeParseDlg::GetAddr() { charszAddr[10]={0}; DWORDdwAddr=0; switch(m_nSelect) { case1: { GetDlgItemText(IDC_EDIT_VA,szAddr,10); HexStrToInt(szAddr,&dwAddr); break; } case2: { GetDlgItemText(IDC_EDIT_RVA,szAddr,10); HexStrToInt(szAddr,&dwAddr); break; } case3: { GetDlgItemText(IDC_EDIT_FILEOFFSET,szAddr,10); HexStrToInt(szAddr,&dwAddr); break; } } returndwAddr; }
获取该地址所属的第几个节的代码如下:
intCPeParseDlg::GetAddrInSecNum(DWORDdwAddr) { intnInNum=0; intnSecNum=m_pNtHdr->FileHeader.NumberOfSections; switch(m_nSelect) { case1: { DWORDdwImageBase=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) { returnnInNum; } } break; } case2: { for(nInNum=0;nInNum<nSecNum;nInNum++) { if(dwAddr>=m_pSecHdr[nInNum].VirtualAddress &&dwAddr<=m_pSecHdr[nInNum].VirtualAddress +m_pSecHdr[nInNum].Misc.VirtualSize) { returnnInNum; } } break; } case3: { for(nInNum=0;nInNum<nSecNum;nInNum++) { if(dwAddr>=m_pSecHdr[nInNum].PointerToRawData &&dwAddr<=m_pSecHdr[nInNum].PointerToRawData +m_pSecHdr[nInNum].SizeOfRawData) { returnnInNum; } } break; } } return-1; }
计算其他地址的代码如下:
VOIDCPeParseDlg::CalcAddr(intnInNum,DWORDdwAddr) { DWORDdwVa=0; DWORDdwRva=0; DWORDdwFileOffset=0; switch(m_nSelect) { case1: { dwVa=dwAddr; dwRva=dwVa-m_pNtHdr->OptionalHeader.ImageBase; dwFileOffset=m_pSecHdr[nInNum].PointerToRawData +(dwRva-m_pSecHdr[nInNum].VirtualAddress); break; } case2: { dwVa=dwAddr+m_pNtHdr->OptionalHeader.ImageBase; dwRva=dwAddr; dwFileOffset=m_pSecHdr[nInNum].PointerToRawData +(dwRva-m_pSecHdr[nInNum].VirtualAddress); break; } case3: { dwFileOffset=dwAddr; dwRva=m_pSecHdr[nInNum].VirtualAddress +(dwFileOffset-m_pSecHdr[nInNum].PointerToRawData); dwVa=dwRva+m_pNtHdr->OptionalHeader.ImageBase; break; } } SetDlgItemText(IDC_EDIT_SECTION,(constchar*)m_pSecHdr[nInNum].Name); CStringstr; 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); }
代码都不复杂,关键就是CalcAddr()中3种地址的转换。
转载请注明:IT运维空间 » 安全防护 » 网络安全编程:PE编程实例之地址转换器
发表评论