
微信公众平台:电子计算机与网络信息安全
ID:Computer-network
写PE查看器并并非件繁杂的事儿,只需依照PE构造一步一步地分析就可以了。下边简易地分析在其中几个字段內容,表明一下节表的信息内容,其他的內容只需稍加改动就可以。PE查看器的页面如下图1所显示。

图1 PE查看器分析文本文档程序流程
PE查看器的页面依照图1所显示的设定,但是这一可以根据本人的喜好开展合理布局设定。撰写该PE查看器的流程为开启文件并建立文件内存映像,分辨文件是不是为PE文件并得到PE文件格式有关结构体的表针,分析基本上的PE字段名,枚举类型节表,最终关掉文件。必须在类中加上好多个成员变量及组员函数,加上的內容如下图2所显示。

图2 在类中增加的成员变量及组员函数
依照之前所讲的次序,先后完成加上的每个组员函数。
BOOLCPeParseDlg::FileCreate(char*szFileName){BOOLbRet=FALSE;m_hFile=CreateFile(szFileName,GENERIC_READ|GENERIC_WRITE,FILE_SHARE_READ,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);if(m_hFile==INVALID_HANDLE_VALUE){returnbRet;}m_hMap=CreateFileMapping(m_hFile,NULL,PAGE_READWRITE|SEC_IMAGE,0,0,0);if(m_hMap==NULL){CloseHandle(m_hFile);returnbRet;}m_lpBase=MapViewOfFile(m_hMap,FILE_MAP_READ|FILE_SHARE_WRITE,0,0,0);if(m_lpBase==NULL){CloseHandle(m_hMap);CloseHandle(m_hFile);returnbRet;}bRet=TRUE;returnbRet;}
这一函数的首要功用是开启文件并建立内存文件映像。通常对文件开展持续读写能力时立即应用ReadFile()和WriteFile()2个函数。当不持续实际操作文件时,每一次在ReadFile()或是WriteFile()后就需要应用SetFilePointer()来调节文件表针的部位,那样的实际操作比较繁杂。内存文件映像的功能是把全部文件投射入过程的网站空间中,那样实际操作文件如同实际操作内存自变量或内存数据信息一样便捷。
建立内存文件映像所采用的函数有两个,分别是CreateFileMapping()和MapViewOfFile()。CreateFileMapping()函数的界定如下所示:
HANDLECreateFileMapping(HANDLEhFile,LPSECURITY_ATTRIBUTESlpAttributes,DWORDflProtect,DWORDdwMaximumSizeHigh,DWORDdwMaximumSizeLow,LPCTSTRlpName);
参数表明如下所示。
hFile:该参数是 CreateFile()函数回到的句柄。
lpAttributes:是安全性特性,该值通常是 NULL。
flProtect:建立文件投射后的特性,通常设定为可读可读 PAGE_READWRITE。假如必须像运载可实行文件那般把文件投射入内存得话,那麼必须应用 SEC_IMAGE。最终3个参数在这儿为0。假如建立的投射必须在多进程中共享资源数据信息得话,那麼最后一个参数设置为一个字符串数组,便于根据该名字寻找该块共享资源内存。
该函数的传参为一个内存投射的句柄。
MapViewOfFile()函数的界定如下所示:
LPVOIDMapViewOfFile(HANDLEhFileMappingObject,DWORDdwDesiredAccess,DWORDdwFileOffsetHigh,DWORDdwFileOffsetLow,SIZE_TdwNumberOfBytesToMap);
参数表明如下所示。
hFileMappingObject:该参数为 CreateFileMapping()回到的句柄。
dwDesiredAccess:想得到的访问限制,一般来说也是可写可读 FILE_MAP_READ、FILE_MAP_WRITE。
最终3个参数一般给0值就可以了。
依照程序编写的规定,开启要关掉,申请办理要释放出来。CreateFileMapping()的关掉必须应用CloseHandle()函数。MapViewOfFile()的关掉,要应用UnmapViewOfFile()函数,该函数的界定如下所示:
BOOLUnmapViewOfFile(LPCVOIDlpBaseAddress);
该函数的参数便是MapViewOfFile()函数的传参。
然后说PE查看器,文件早已开启,就需要分辨文件是不是为合理的PE文件了。如果是有效的PE文件,就把分析PE文件格式的有关结构体的表针也获得。编码如下所示:
BOOLCPeParseDlg::IsPeFileAndGetPEPointer(){BOOLbRet=FALSE;//判断是不是为MZ头m_pDosHdr=(PIMAGE_DOS_HEADER)m_lpBase;if(m_pDosHdr->e_magic!=IMAGE_DOS_SIGNATURE){returnbRet;}//依据IMAGE_DOS_HEADER的e_lfanew的非常值得到PE头的部位m_pNtHdr=(PIMAGE_NT_HEADERS)((DWORD)m_lpBase m_pDosHdr->e_lfanew);//分辨是不是为PE\0\0if(m_pNtHdr->Signature!=IMAGE_NT_SIGNATURE){returnbRet;}//得到节表的部位m_pSecHdr=(PIMAGE_SECTION_HEADER)((DWORD)&(m_pNtHdr->OptionalHeader) m_pNtHdr->FileHeader.SizeOfOptionalHeader);bRet=TRUE;returnbRet;}
这一段编码应当很容易了解,继续看分析PE文件格式的一部分。
VOIDCPeParseDlg::ParseBasePe(){CStringStrTmp;//通道详细地址StrTmp.Format("X",m_pNtHdr->OptionalHeader.AddressOfEntryPoint);SetDlgItemText(IDC_EDIT_EP,StrTmp);//印象基详细地址StrTmp.Format("X",m_pNtHdr->OptionalHeader.ImageBase);SetDlgItemText(IDC_EDIT_IMAGEBASE,StrTmp);//射频连接器版本信息StrTmp.Format("%d.%d",m_pNtHdr->OptionalHeader.MajorLinkerVersion,m_pNtHdr->OptionalHeader.MinorLinkerVersion);SetDlgItemText(IDC_EDIT_LINKVERSION,StrTmp);//节表总数StrTmp.Format("X",m_pNtHdr->FileHeader.NumberOfSections);SetDlgItemText(IDC_EDIT_SECTIONNUM,StrTmp);//文档两端对齐值尺寸StrTmp.Format("X",m_pNtHdr->OptionalHeader.FileAlignment);SetDlgItemText(IDC_EDIT_FILEALIGN,StrTmp);//内存对齐值大小StrTmp.Format("X",m_pNtHdr->OptionalHeader.SectionAlignment);SetDlgItemText(IDC_EDIT_SECALIGN,StrTmp);}
PE文件格式的基础信息,便是简洁地获得结构体的成员变量,沒有太多繁杂的內容。获得导进表、导出来表比获得基础信息繁杂。下面开展节表的枚举类型,实际编码如下所示:
VOIDCPeParseDlg::EnumSections(){intnSecNum=m_pNtHdr->FileHeader.NumberOfSections;inti=0;CStringStrTmp;for(i=0;i<nSecNum;i ){m_SectionLIst.InsertItem(i,(constchar*)m_pSecHdr[i].Name);StrTmp.Format("X",m_pSecHdr[i].VirtualAddress);m_SectionLIst.SetItemText(i,1,StrTmp);StrTmp.Format("X",m_pSecHdr[i].Misc.VirtualSize);m_SectionLIst.SetItemText(i,2,StrTmp);StrTmp.Format("X",m_pSecHdr[i].PointerToRawData);m_SectionLIst.SetItemText(i,3,StrTmp);StrTmp.Format("X",m_pSecHdr[i].SizeOfRawData);m_SectionLIst.SetItemText(i,4,StrTmp);StrTmp.Format("X",m_pSecHdr[i].Characteristics);m_SectionLIst.SetItemText(i,5,StrTmp);}}
最终的動作是释放出来姿势,由于非常简单,这儿也不得出编码了。将这种自定义函数根据页面上的“查询”按键联络起來,全部PE查看器就算是写完了。