首页
社区
课程
招聘
[原创][15Pb培训第三阶段课后小项目]PE解析工具
发表于: 2013-12-3 16:30 5422

[原创][15Pb培训第三阶段课后小项目]PE解析工具

2013-12-3 16:30
5422

【原创】[15Pb培训第三阶段课后小项目]PE解析工具
本工具只能简单的现实PE文件的解析,尚未添加编辑功能,处于未完成阶段.
如文中本文中有错误或者本人理解错误以及不透彻的地方,希望大神们指点一二,在此不胜感激.
下面先贴上工具主界面图片:
 

一.  PE头部
.DOS头
PE文件总体可分为DOS部首,PE文件头,节表,以及节内容四大部分.是以”MZ”(5A4Dh)开始的,用一个64字节大小的IMAGE_DOS_HEADER_STRUCT结构来表示DOS文件头.跟着DOS部首的就是PE文件头,在DOS文件头的e_lfanew字段(也就是文件偏移0x3C)保存着PE文件头的相对文件偏移.
.PE文件头
struct _IMAGE_NT_HEADERS {
    DWORD             Signature;
    IMAGE_FILE_HEADER     FileHeader;
    IMAGE_OPTIONAL_HEADER32 OptionalHeader;
} IMAGE_NT_HEADERS32, *PIMAGE_NT_HEADERS32;

  PE文件头以一个大小为0xF8h的IMAGE_NT_HEADERS结构体表示,结构第一个字段Signature是该文件头的标志,它总是0x4550h(“PE”),可以根据该字段与DOS文件头的e_magic字段来判断一个文件是否是PE文件.第二个字段是一个大小为0x14h字节大小的IMAGE_FILE_HEADER结构体.
  struct _IMAGE_FILE_HEADER {
    WORD    Machine;          // 运行平台
    WORD    NumberOfSections;    // 文件节的数目
    DWORD   TimeDateStamp;      // 文件创建时间
    DWORD   PointerToSymbolTable;  // 指向符号表(调试使用)
    DWORD   NumberOfSymbols;    // 符号表中符号个数(调试使用)
    WORD    SizeOfOptionalHeader;  // IMAGE_OPTIONAL_HEADER32结构大小
    WORD    Characteristics;
}IMAGE_FILE_HEADER, *PIMAGE_FILE_HEADER;

第三字段是一个大小为0xE0h的IMAGE_OPTIONAL_HEADER32的结构体.
typedef struct _IMAGE_OPTIONAL_HEADER {
    WORD    Magic;            // 标志
    BYTE    MajorLinkerVersion;      // 链接器主版本号  
    BYTE    MinorLinkerVersion;      // 链接器次版本号
    DWORD   SizeOfCode;          // 所有代码区段的总大小
    DWORD   SizeOfInitializedData;    // 所有初始化数据区段的总大小
    DWORD   SizeOfUninitializedData;  // 所有未初始化数据区段的总大小
    DWORD   AddressOfEntryPoint;    // 程序执行入口RVA
    DWORD   BaseOfCode;          // 代码区段起始RVA
    DWORD   BaseOfData;         // 数据区段起始RVA
    DWORD   ImageBase;          // 程序默认装载基址
    DWORD   SectionAlignment;      // 内存中区段的对齐值(一般为1000)
    DWORD   FileAlignment;        // 文件中区段的对齐值(一般为200)
    WORD    MajorOperatingSystemVersion;  // 操作系统主版本号
    WORD    MinorOperatingSystemVersion;  // 操作系统次版本号
    WORD    MajorImageVersion;      // 用户自定义主版本号
    WORD    MinorImageVersion;      // 用户自定义次版本号
    WORD    MajorSubsystemVersion;    // 所需要子系统主版本号
    WORD    MinorSubsystemVersion;    // 所需要子系统次版本号
    DWORD   Win32VersionValue;      // 保留,一般为0
    DWORD   SizeOfImage;        // 映像装入内存后的总尺寸
    DWORD   SizeOfHeaders;        // 所有头部的总大小
    DWORD   CheckSum;          // 映像校验和
    WORD    Subsystem;          // 文件子系统
    WORD    DllCharacteristics;      // 显示DLL特性的标志
    DWORD   SizeOfStackReserve;      // 初始化堆栈大小
    DWORD   SizeOfStackCommit;      // 初始化实际堆栈大小
    DWORD   SizeOfHeapReserve;      // 初始化保留堆栈大小
    DWORD   SizeOfHeapCommit;      // 初始化实际保留堆栈大小
    DWORD   LoaderFlags;        // 与调试相关,默认为0
DWORD   NumberOfRvaAndSizes;      // 数据目录表的项数
// 数据目录数组
    IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES];
} IMAGE_OPTIONAL_HEADER32, *PIMAGE_OPTIONAL_HEADER32;

IMAGE_DATA_DIRECTORY结构体定义如下:
struct _IMAGE_DATA_DIRECTORY {
    DWORD   VirtualAddress;    // 指向的RVA
    DWORD   Size;        // 数据的大小
} IMAGE_DATA_DIRECTORY, *PIMAGE_DATA_DIRECTORY;

实现逻辑:由于本工具用的是MFC实现的,实现起来非常简单.
1.  给每个文本框定义一个cstring类型的变量.
2.  直接把需要显示的成员格式化到对应的变量.
3.  最后用UpdateData(FALSE)更新到界面就OK.
下面放上实现的主要代码:

VOID CMFC_PEditor_Dlg::ShowPE_Info(PVOID lpImage)
{
  if (nullptr == lpImage)
  {
    MessageBox(_T("文件地址为空"),_T("错误"));
    PostMessage(WM_CLOSE,NULL,NULL);
    return;
  }
  PIMAGE_DOS_HEADER   pDos  = (PIMAGE_DOS_HEADER)lpImage;
  PIMAGE_NT_HEADERS32 pNT32 = (PIMAGE_NT_HEADERS32)((LONG)lpImage+pDos->e_lfanew);
  PIMAGE_FILE_HEADER  pFileHead = &pNT32->FileHeader;
  // 把文件信息显示到窗口对应的控件上
  m_strMachine.Format(_T("%04X"),pFileHead->Machine);
  m_strNumberOfSections.Format(_T("%04X"),pFileHead->NumberOfSections);
  m_strTimeDateStamp.Format(_T("%p"),pFileHead->TimeDateStamp);
  m_strPointerToSymbolTable.Format(_T("%p"),pFileHead->PointerToSymbolTable);
  m_strNumberOfSymbols.Format(_T("%p"),pFileHead->NumberOfSymbols);
  m_strSizeOfOptionalHeader.Format(_T("%04X"),pFileHead->SizeOfOptionalHeader);
  m_strCharacteristics.Format(_T("%p"),pFileHead->Characteristics);
  // 显示扩展头部信息
  PIMAGE_OPTIONAL_HEADER32  pOptionalHead = &pNT32->OptionalHeader;
  m_strBaseOfCode.Format(_T("%p"),pOptionalHead->BaseOfCode);
  m_strBaseOfData.Format(_T("%p"),pOptionalHead->BaseOfData);
  m_strSizeOfImage.Format(_T("%p"),pOptionalHead->SizeOfImage);
  m_strSizeOfHeader.Format(_T("%p"),pOptionalHead->SizeOfHeaders);
  m_strSectionAlignment.Format(_T("%p"),pOptionalHead->SectionAlignment);
  m_strFileAlignment.Format(_T("%p"),pOptionalHead->FileAlignment);
  m_strSubSystem.Format(_T("%p"),pOptionalHead->Subsystem);
  // 文件信息
  m_strAddrOfEntryPoint.Format(_T("%p"),pOptionalHead->AddressOfEntryPoint);
  m_strImageBase.Format(_T("%p"),pOptionalHead->ImageBase);

  UpdateData(FALSE);
}
m_lisSection.SetExtendedStyle(LVS_EX_FULLROWSELECT );
      TCHAR strTitle[6][10] = {_T("节名"),_T("虚拟大小"),_T("虚拟偏移"),
    _T("原始大小"),_T("原始偏移"),_T("特征值")};
      for (int i = 0; i < 6; i++)
  {
    m_lisSection.InsertColumn(i,strTitle[i],0,80);
  }
2.
VOID CSection::ShowSection(CONST PVOID lpImage)
{

  if (nullptr == lpImage)
  {
    return;
  }
  PIMAGE_DOS_HEADER   pDos  = (PIMAGE_DOS_HEADER)lpImage;
  PIMAGE_NT_HEADERS32 pNT32 = (PIMAGE_NT_HEADERS32)((LONG)lpImage+pDos->e_lfanew);
  PIMAGE_SECTION_HEADER pSection = IMAGE_FIRST_SECTION(pNT32);// 取得第一个节表所在位置

  DWORD dwIndex = 0;   // 子项的索引值(可视为引导)
  LVITEM lvItem = {0};
  lvItem.mask = LVIF_TEXT|LVIF_IMAGE|LVIF_PARAM|LVIF_STATE;
  for (int i = 0; i < pNT32->FileHeader.NumberOfSections; i++)
  {
    WCHAR wTemp[30];
    lvItem.iItem = dwIndex;
    MultiByteToWideChar(CP_ACP,MB_PRECOMPOSED,(char*)pSection->Name,8,wTemp,30);
    int n = GetLastError();
    lvItem.pszText = wTemp;
    m_lisSection.InsertItem(&lvItem);

    CString strbuff;
    strbuff.Format(_T("%p"),pSection->Misc);
    m_lisSection.SetItemText(dwIndex,1,strbuff);
    strbuff.Format(_T("%p"),pSection->VirtualAddress);
    m_lisSection.SetItemText(dwIndex,2,strbuff);
    strbuff.Format(_T("%p"),pSection->SizeOfRawData);
    m_lisSection.SetItemText(dwIndex,3,strbuff);
    strbuff.Format(_T("%p"),pSection->PointerToRawData);
    m_lisSection.SetItemText(dwIndex,4,strbuff);
    strbuff.Format(_T("%p"),pSection->Characteristics);
    m_lisSection.SetItemText(dwIndex,5,strbuff);
    dwIndex++;
    pSection++;
  }
VOID CDirectory::ShowDirectory()
{
  if (nullptr == m_lpFileImage)
  {
    MessageBox(_T("文件地址为空"),_T("错误"));
    PostMessage(WM_CLOSE,NULL,NULL);
    return ;
  }
  PIMAGE_DOS_HEADER   pDos  = (PIMAGE_DOS_HEADER)m_lpFileImage;
  PIMAGE_NT_HEADERS32 pNT32 = (PIMAGE_NT_HEADERS32)((LONG)m_lpFileImage+pDos->e_lfanew);
  // pDir指向目录表
  PIMAGE_DATA_DIRECTORY pDir = pNT32->OptionalHeader.DataDirectory;
  // 输出目录
  m_strExport_RVA.Format(_T("%p"),pDir->VirtualAddress);
  m_strExport_Size.Format(_T("%p"),pDir->Size);
  pDir++;
  // 输入目录
  m_strImport_RVA.Format(_T("%p"),pDir->VirtualAddress);
  m_strImport_Size.Format(_T("%p"),pDir->Size);
  pDir++;
  // 资源目录
  m_strResources_RVA.Format(_T("%p"),pDir->VirtualAddress);
  m_strReception_Size.Format(_T("%p"),pDir->Size);
  pDir++;
  // 异常目录
  m_strException_RVA.Format(_T("%p"),pDir->VirtualAddress);
  m_strException_Size.Format(_T("%p"),pDir->Size);
  pDir++;
  // 安全目录
  m_strSecurity_RVA.Format(_T("%p"),pDir->VirtualAddress);
  m_strSecurity_Size.Format(_T("%p"),pDir->Size);
  pDir++;
  // 重定位目录
  m_strBase_RVA.Format(_T("%p"),pDir->VirtualAddress);
  m_strBase_Size.Format(_T("%p"),pDir->Size);
  pDir++;
  // 调试目录
  m_strDebug_RVA.Format(_T("%p"),pDir->VirtualAddress);
  m_strDebug_Size.Format(_T("%p"),pDir->Size);
  pDir++;
  // 版权目录
  m_strCopyright_RVA.Format(_T("%p"),pDir->VirtualAddress);
  m_strCopyright_Size.Format(_T("%p"),pDir->Size);
  pDir++;
  // 全局指针目录
  m_strGlobal_RVA.Format(_T("%p"),pDir->VirtualAddress);
  m_strGlobal_Size.Format(_T("%p"),pDir->Size);
  pDir++;
  // TLS目录
  m_strTLS_RVA.Format(_T("%p"),pDir->VirtualAddress);
  m_strTLS_Size.Format(_T("%p"),pDir->Size);
  pDir++;
  // 载入配置目录
  m_strLoadConfiguration_RVA.Format(_T("%p"),pDir->VirtualAddress);
  m_strLoadConfiguration_Size.Format(_T("%p"),pDir->Size);
  pDir++;
  // 绑定输入目录
  m_strBoundImport_RVA.Format(_T("%p"),pDir->VirtualAddress);
  m_strBoundImport_Size.Format(_T("%p"),pDir->Size);
  pDir++;
  // IAT目录
  m_strIAD_RVA.Format(_T("%p"),pDir->VirtualAddress);
  m_strIAT_Size.Format(_T("%p"),pDir->Size);
  pDir++;
  // 延迟导入目录
  m_strDelayImport_RVA.Format(_T("%p"),pDir->VirtualAddress);
  m_strDelayImport_Size.Format(_T("%p"),pDir->Size);
  pDir++;
  // COM目录
  m_strCOM_RVA.Format(_T("%p"),pDir->VirtualAddress);
  m_strCOM_Size.Format(_T("%p"),pDir->Size);
  pDir++;
  // 保留
  m_strTemp_RVA.Format(_T("%p"),pDir->VirtualAddress);
  m_strTemp_Size.Format(_T("%p"),pDir->Size);
  
  UpdateData(FALSE);
}
VOID CExport::ShowExport(CONST LPVOID lpImage)
{
  PIMAGE_DOS_HEADER     pDos     = (PIMAGE_DOS_HEADER)lpImage;
  PIMAGE_NT_HEADERS32   pNT32    = (PIMAGE_NT_HEADERS32)((LONG)lpImage+pDos->e_lfanew);
    // pExportdir指向数据目录表中的输出表目录
  PIMAGE_DATA_DIRECTORY pExportDir = pNT32->OptionalHeader.DataDirectory;
  if (0 == pExportDir->VirtualAddress)
  {
    MessageBox(_T("此文件不存在输出表"),_T("提示"));
    PostMessage(WM_CLOSE,NULL,NULL);
    return;
  }
  // 获得输出表的Offset;
  DWORD dwExportOfffset = m_pRVAToOffset->RVAToOffset(lpImage,pExportDir->VirtualAddress);
  // pExport指向输出表
  PIMAGE_EXPORT_DIRECTORY pExport = (PIMAGE_EXPORT_DIRECTORY)((DWORD)lpImage+dwExportOfffset);
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  
  // 输出表信息更新到窗口
  m_strOffset.Format(_T("%p"),dwExportOfffset);          // 输出表偏移
  m_strCharacteristics.Format(_T("%p"),pExport->Characteristics);  // 特征值
  m_strBase.Format(_T("%p"),pExport->Base);            // 索引基数
  m_strName.Format(_T("%p"),pExport->Name);            // 模块名RVA
  m_strNumberOfFun.Format(_T("%p"),pExport->NumberOfFunctions);  // 导出表成员总数
  m_strNumberOfName.Format(_T("%p"),pExport->NumberOfNames);    // 以函数名导出的个数
  m_strAddrFun.Format(_T("%p"),pExport->AddressOfFunctions);    // 导出函数地址表
  m_strAddrFunName.Format(_T("%p"),pExport->AddressOfNames);    // 函数名称地址表
  m_strAddrNum.Format(_T("%p"),pExport->AddressOfNameOrdinals);  // 导出序列号数组
  // 把模块名RVA转换成Offset再加上文件所在地址,得到模块名的Offset
  PCHAR pstrName = (PCHAR)lpImage + m_pRVAToOffset->RVAToOffset(lpImage,pExport->Name);
  m_strSzName = pstrName;                      // 模块名称字符串
  UpdateData(FALSE);              
////////////////////////////////////////////////////////////////////////////////////////////////////////////////

  PDWORD pEAT = (PDWORD)((DWORD)  // 导出表RVA转换成Offset再加上文件地址等于导出地址表
    lpImage + m_pRVAToOffset->RVAToOffset(lpImage,pExport->AddressOfFunctions));
  PDWORD pENT = (PDWORD)((DWORD)  // 函数名称RVA转换成Offset再加上文件地址等于函数名称地址表
    lpImage + m_pRVAToOffset->RVAToOffset(lpImage,pExport->AddressOfNames));
  PWORD  pEIT = (PWORD)((DWORD)  // 函数序号RVA转换成Offset再加上文件地址等于函数序号地址表
    lpImage  + m_pRVAToOffset->RVAToOffset(lpImage,pExport->AddressOfNameOrdinals));
  
  LVITEM lvItem = {0};
  lvItem.mask = LVIF_TEXT|LVIF_IMAGE|LVIF_PARAM|LVIF_STATE;
  CString strbuff;
  DWORD dwOffset = 0;
  int j = 0;
  // 遍历整个导出表中的导出函数地址
  for (DWORD i=0; i<pExport->NumberOfFunctions; i++)
  {
    // 如果该地址为nullptr,则遍历下一个地址
    if (!pEAT[i])
    {
      continue;
    }
    // 遍历以名称导出的函数
    for (DWORD dwIndex = 0; dwIndex<pExport->NumberOfFunctions; dwIndex++)
    {
      // 比较序号是否有函数序号与其对应
      if (pEIT[dwIndex] == i)
      {
        // 如果序号数组中的序号与函数名的序号相符
        lvItem.iItem = j;
        TCHAR szName[8] = {0};
        wsprintf(szName,_T("%04X"),i + pExport->Base);
        lvItem.pszText = szName;
        m_lisExport.InsertItem(&lvItem);      // 插入序号

        strbuff.Format(_T("%p"),pEAT[j]);
        m_lisExport.SetItemText(j,1,strbuff);  // 插入RVA
        // 把函数RVA转换成Offset
        dwOffset = m_pRVAToOffset->RVAToOffset(lpImage,pEAT[j]);
        strbuff.Format(_T("%p"),dwOffset);
        m_lisExport.SetItemText(j,2,strbuff);  // 插入偏移

        pstrName = (PCHAR)lpImage + m_pRVAToOffset->RVAToOffset(lpImage,pENT[dwIndex]);
        USES_CONVERSION;
        strbuff = A2W(pstrName);
        m_lisExport.SetItemText(j,3,strbuff);  // 插入函数名
        j++;
        break;
      }
      // 如果遍历完整个序号数组,都没找到与函数相符的序号
      else if ( dwIndex == pExport->NumberOfFunctions-1 )
      {
        // 该序号没有对应的函数名,
        lvItem.iItem = j;
        TCHAR szName[8] = {0};
        wsprintf(szName,_T("%04X"),i + pExport->Base);
        lvItem.pszText = szName;
        m_lisExport.InsertItem(&lvItem);      // 插入序号

        strbuff.Format(_T("%p"),pEAT[j]);
        m_lisExport.SetItemText(j,1,strbuff);  // 插入RVA
        // 把函数RVA转换成Offset
        dwOffset = m_pRVAToOffset->RVAToOffset(lpImage,pEAT[j]);
        strbuff.Format(_T("%p"),dwOffset);
        m_lisExport.SetItemText(j,2,strbuff);  // 插入偏移

        strbuff.Format(_T("%s"),_T("-"));    // 用"-"表示无对应的函数名
        m_lisExport.SetItemText(j,3,strbuff);  // 插入函数名
        j++;
      }
    }
  }
}

[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

上传的附件:
收藏
免费 5
支持
分享
最新回复 (0)
游客
登录 | 注册 方可回帖
返回
//