首页
社区
课程
招聘
[原创]PE解析软件
发表于: 2013-12-4 15:06 6074

[原创]PE解析软件

2013-12-4 15:06
6074
//计算值将Rva转换成Foa
DWORD RVA2Offset(DWORD dwRVA);      
//加载PE 
BOOL  LoadPe(); 
//判断是否为PE文件
BOOL  IsPE_File();                                      
//获取PE映像文件头
void  GetFileHeader();
//获取PE映像扩展头
void  GetOptionalHeader();
//获取PE区段信息
void  GetSectionHeader();
//导出表
void  GetExportDirectory();
//导入表
void  GetImportDirectory();
//解析PE映像文件头
void  GetFileHeader()
{
    m_PeHead = m_pNT->FileHeader;
    m_pImageHeaderNum = m_PeHead.NumberOfSections;
 
}
//获取PE映像扩展头
void  GetOptionalHeader()
{
    m_Optinal = m_pNT->OptionalHeader;
    m_pDataDir =(PIMAGE_DATA_DIRECTORY)m_pNT->OptionalHeader.DataDirectory;
}
DWORD CPeHear::RVA2Offset( DWORD dwRVA )
{
 
    for ( DWORD i=0; i<m_pNT->FileHeader.NumberOfSections; i++ )
    {
        if ( dwRVA>=m_pSection[i].VirtualAddress && dwRVA<m_pSection[i].VirtualAddress+m_pSection[i].Misc.VirtualSize )
        {
            DWORD dwR_Offset = dwRVA - m_pSection[i].VirtualAddress;
            DWORD dwOffset   = (DWORD)m_lpFileImage + dwR_Offset + m_pSection[i].PointerToRawData;
            return dwOffset;
        }
    }
    return 0;  
}
typedef  struct _SECTIONHEADER
{
    CString NAME;
    DWORD PointerToRawData;                 //区段在文件中的偏移 
    DWORD SizeOfRawData;                    //文件中区段对齐大小
    DWORD MiscVirtualSize;                  //偏移大小
    DWORD VirtualAddress;                   //区段的RVA地址
 
}SECTION,*PSECTION
typedef struct  _EXPORT
{
    DWORD      ID;      //导出函数的序号
    DWORD      EAT;     //导出函数的地址RVA
    DWORD      EX_RVA;  //导出函数的地址偏移
    CString    NAME;    //导出的函数名称
}EXPORTA,*PEXPORT;
void GetExportDirectory()
{
     
 
    PIMAGE_DATA_DIRECTORY pExportDir = &m_pDataDir[IMAGE_DIRECTORY_ENTRY_EXPORT];
    if (pExportDir->Size == 0)
    return;
    DWORD                 dwExportOfffset = RVA2Offset(pExportDir->VirtualAddress);
    m_pExport    = (PIMAGE_EXPORT_DIRECTORY)dwExportOfffset;
    m_ExportOffset = RVA2Offset(m_Optinal.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress) - (DWORD)m_lpFileImage;
    PDWORD pEAT = (PDWORD)RVA2Offset(m_pExport->AddressOfFunctions);
    PDWORD pENT = (PDWORD)RVA2Offset(m_pExport->AddressOfNames);
    PWORD  pEIT = (PWORD) RVA2Offset(m_pExport->AddressOfNameOrdinals);
    //m_ExportOffset = 
 
    for ( DWORD dwOrdinal=0; dwOrdinal<m_pExport->NumberOfFunctions; dwOrdinal++ )
    {
        if ( !pEAT[dwOrdinal] )
            continue;
 
        for ( DWORD dwIndex=0; dwIndex<m_pExport->NumberOfFunctions; dwIndex++ )
        {
                EXPORTA saveImport;
            if ( pEIT[dwIndex] == dwOrdinal )
            {
                PCHAR pszFunName = (PCHAR)RVA2Offset(pENT[dwIndex]);
                saveImport.NAME.Format(_T("%S"),pszFunName);
                saveImport.EX_RVA = m_pExport->AddressOfFunctions;
                saveImport.ID   = m_pExport->Base+dwOrdinal;
                saveImport.EAT  = pEAT[dwOrdinal];
                m_vExport.push_back(saveImport);
                break;
            }
            else if ( dwIndex == m_pExport->NumberOfFunctions-1 )
            {
                saveImport.NAME.Format(_T("(Null)"));
                saveImport.ID   = m_pExport->Base+dwOrdinal;
                saveImport.EX_RVA = m_pExport->AddressOfFunctions;
                saveImport.EAT  = pEAT[dwOrdinal];
                m_vExport.push_back(saveImport);
                break;
            }
        }
    }
 
}
typedef struct _IMAGE_IMPORT_DESCRIPTOR {
    union {
        DWORD   Characteristics;            
        DWORD   OriginalFirstThunk;         // 指向输入名称表(IAT)的RVA
    } DUMMYUNIONNAME;
    DWORD   TimeDateStamp;                  //时间标识
    DWORD   ForwarderChain;                 // 转发链如果不转发此值为0
    DWORD   Name;                           //指向导入映像文件的名字
    DWORD   FirstThunk;                     // 指向导入地址表(IAT)的RVA
} IMAGE_IMPORT_DESCRIPTOR;
 
 
typedef struct _IMAGE_THUNK_DATA32 {
    union {
        DWORD ForwarderString;      // 转发字符的RVA
        DWORD Function;             // 被导入函数的地址
        DWORD Ordinal;              //被导入函数的序号
        DWORD AddressOfData;        // 指向输入名称
    } u1;
} IMAGE_THUNK_DATA32;
 
 
typedef struct _IMAGE_IMPORT_BY_NAME {
    WORD    Hint;                   //需导入函数序号
    CHAR   Name[1];                 //导入函数名称
} IMAGE_IMPORT_BY_NAME, *PIMAGE_IMPORT_BY_NAME;
void CPeHear::GetImportDirectory()
{
 
    PIMAGE_DATA_DIRECTORY pDir = (PIMAGE_DATA_DIRECTORY)m_pNT->OptionalHeader.DataDirectory;
    PIMAGE_DATA_DIRECTORY pDataDir = pDir+IMAGE_DIRECTORY_ENTRY_IMPORT;
    PIMAGE_IMPORT_DESCRIPTOR pImport = (PIMAGE_IMPORT_DESCRIPTOR)RVA2Offset(pDataDir->VirtualAddress);
 
 
    while ( pImport->Name )
    {
        IMPORT saveImport;
 
        saveImport.pszDllName = (PCHAR)RVA2Offset(pImport->Name);
        PIMAGE_THUNK_DATA32 pINT = (PIMAGE_THUNK_DATA32)RVA2Offset(pImport->OriginalFirstThunk);
         
        while ( pINT->u1.Ordinal )
        {
            if ( !IMAGE_SNAP_BY_ORDINAL32(pINT->u1.Ordinal) )
            {
                PIMAGE_IMPORT_BY_NAME pByName = (PIMAGE_IMPORT_BY_NAME)RVA2Offset(pINT->u1.AddressOfData);
                saveImport.NAME.Format(_T("%s"),pByName->Name);
                saveImport.ID = pByName->Hint;   
                saveImport.IM_RVA = pImport->FirstThunk;
                saveImport.Offset = RVA2Offset(pImport->FirstThunk);
                m_vImport.push_back(saveImport);
                pINT++;
                continue;
            } 
            // 2.4.2 如果最高位为1,则直接打印Ordinal部分
            saveImport.NAME.Format(_T("Null"));
            saveImport.ID = pINT->u1.Ordinal&0x0000FFFF;
            saveImport.IM_RVA = pImport->FirstThunk;
            saveImport.Offset = RVA2Offset(pImport->FirstThunk);
            m_vImport.push_back(saveImport);
            pINT++;
        }
        m_vpImport.push_back(pImport);
         
        pImport++;
    }
}
    static PVOID                    m_lpFileImage;           //文件内存中起始加载位置
    static CString                  m_strInPath;                 //文件名
    static IMAGE_FILE_HEADER        m_PeHead;                //PE映像文件头
    static IMAGE_OPTIONAL_HEADER    m_Optinal;               //PE映像扩展头
    static PIMAGE_SECTION_HEADER    m_pSection;              //获取PE区段信息
    static PIMAGE_DOS_HEADER        m_pDos;                  //DOS头地址
    static PIMAGE_NT_HEADERS        m_pNT;                   //PE头地址
    static PIMAGE_DATA_DIRECTORY    m_pDataDir;              //PE数据目录
    static PIMAGE_EXPORT_DIRECTORY  m_pExport;               //输出表
    //static PIMAGE_IMPORT_DESCRIPTOR m_pImport;                 //输入表
 
    static CString                 m_pszDllName;            
    static DWORD                   m_pImageHeaderNum;       //区段数量
    static DWORD                   m_NumberOfRvaAndSizes;   //
    static DWORD                   m_ExportOffset;          //导出表的偏移
 
    static vector<SECTION>  m_vSection;                       //保存区段中的信息
    static vector<EXPORTA>  m_vExport;                        //保存导出表的信息
    static vector<IMPORT>   m_vImport;                        //保存导入表的信息
    static vector<PIMAGE_IMPORT_DESCRIPTOR> m_vpImport;       
  • Signature是PE文件头的标识,其值始终为0x00004550,ASCII码为“PE/0/0”,win32SDK使用#define IMAGE_NT_SIGNATURE定义了这个值,我们可以通过DOS和PE这两个标识来判断该文件是否为PE文件。
  • FileHeader是标准PE头
  • OptionalHeader是扩展PE头,重要的信息都存放在IMAGE_OPTIONAL_HEADER这个结构体中。
  • SizeOfCode 所有代码区段的总大小。
  • AddressOfEntryPoint 程序执行入口RVA。也就是我们所说的OEP。
  • ImageBase 文件在内存中的首选装入地址,默认加载基址,为PE文件的优先装载地址。比如,如果该值是400000h,PE装载器将尝试把文件装到虚拟地址空间的400000h处。字眼"优先"表示若该地址区域已被其他模块占用,那PE装载器会选用其他空闲地址。
  • SectionAlignment:映像文件在内存中的区段对齐大小。

  • [招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)

    上传的附件:
    收藏
    免费 5
    支持
    分享
    最新回复 (2)
    雪    币: 181
    活跃值: (134)
    能力值: ( LV6,RANK:80 )
    在线值:
    发帖
    回帖
    粉丝
    2
    打破0回复
    2013-12-4 16:52
    0
    雪    币: 76
    活跃值: (114)
    能力值: ( LV2,RANK:10 )
    在线值:
    发帖
    回帖
    粉丝
    3
    不错,学习。
    2013-12-4 17:06
    0
    游客
    登录 | 注册 方可回帖
    返回
    //