吾爱破解 - LCG - LSG |安卓破解|病毒分析|www.52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 6724|回复: 17
收起左侧

[原创] 自己总结的简单PE结构解析,有需要的可以看看

[复制链接]
Auller 发表于 2016-10-6 21:12
DOS标志
PIMAGE_DOS_HEADER PDos=PIMAGE_DPS_HEADERBufBuf为文件大小);
根据pDos->e_magic判断是否为pe结构(010 Editor中显示为4d5a
判断NT
PIMAGE_NT_HEADER32 pNtH=(PIMAGE_NT_HEADERS)(Buf + pDosH->e_lfanew);
根据pNtH->Signature判断是否为pe结构(010 Editor中显示为4550
判断可选头
PIMAGE_OPTIONAL_HEADER32 pOptH=&(pNtH->OptionalHeader);
pOptH->AddressOfEntryPoint   PE入口点
pOptH->ImageBase             镜像基址
pOptH->SizeOfImage           镜像大小
pOptH->BaseOfCode            代码基址
pOptH->BaseOfData            数据基址
pOptH->SectionAlignment       块对齐
pOptH->FileAlignment          文件对齐
pOptH->Magic                  标志字
pOptH->Subsystem              子系统
pOptH->SizeOfHeaders         部首大小
pOptH->CheckSum              校验和
pOptH->NumberOfRvandSizes    RVA数及大小
pNtH->FileHeader.NumberOfSections     区段数目
pNtH->FileHeader.TimeDateStamp        日期时间标志
pNtH->FileHeader.Characteristics      特征值
pNtH->FileHeader.SizeOfOptionalHeader   可选头部大小

判断区段头
PIMAGE_SECTION_HEADER pSec= IMAGE_FIRST_SECTION(pNtH);
pSec->Name                  区段名字
pSec->VirtualAddress        区段起始的相对基址
pSec->Misc.VirtualSize       区段大小
pSec->PointerToRawDaata      区段的文件偏移
pSec->SizeOfRawData          区段在文件中的大小
pSec->Charavteristics        区段属性
.text   一般是代码段,这个是非常重要的
.data   一般是数据段
.bss    表示为初始化的数据,比如static变量,可能是在进入一个函数的时候才被初始化的
.rdata  表示只读的数据,比如字符串
.texebss 和代码有关,不是很清楚做什么用的
.IDAta和.edata    储存导入表和导出表的信息
.rsrc      存储资源的区段
.relcoc    存储重定位信息的区段

获取数据目录
PIMAGE_DATA_DIRECTORY pDatD = (pOptH->DataDirectory)
目录表的内容是连续的,定义为:
pDatD.VirtualAddress;
pDatD.Size;
获取导出表(目录表第一个)
DWORD RvaOffset(DWORD Rva)
{
        PIMAGE_SECTION_HEADER pSECH = IMAGE_FIRST_SECTION(pNtH);
        DWORD Num = pNtH->FileHeader.NumberOfSections;
        if (Rva<pSECH[0].PointerToRawData)
        {
                return Rva;
        }
        for (DWORD i = 0; i < Num;i++)
        {
                if (
                        (Rva >= pSECH.VirtualAddress) &&
                        (Rva <= pSECH.VirtualAddress + pSECH.Misc.VirtualSize)//是否在当前项区段的位置,防止蹿去其他区段
                        )
                {
                        return (Rva - pSECH.VirtualAddress + pSECH.PointerToRawData);//相对虚拟地址-相对虚拟区段头地址+原文件区段地址=原文件区段偏移
                }
        }
        return TRUE;
}

PIMAGE_EXPORT_DIRECTORY pExpD=(PIMAGE_EXPORT_DIRECTORY)(Buf + RvaOffset(pDatD[0]->VirtualAddress));
Buf + RvaOffset(pExpD->AddressOfFunctions);        //函数地址
Buf + RvaOffset(pExpD->AddressOfNames);        //函数名地址
Buf + RvaOffset(pExpD->AddressOfNameOrdinals);//函数序号地址
pExpD->NumberOfFunctions; //函数数量
pExpD->AddressOfNames;        //函数名称数量


获取导入表信息(目录第二个)
PIMAGE_IMPORT_DESCRIPTOR  pImpD=(PIMAGE_IMPORT_DESCRIPTOR)((long)Buf + RvaOffset(pDatD[1]->VirtualAddress));
通过DLL名遍历
while (pImpD->Name)
{
                //DLL名称相关
        CString str((AllPe.Buf + AllPe.RvaOffset(pImpD->Name)));   //导入表名字        
        m_InList1.InsertItem(i, str);                                    
        str.Format(L"%08X", pImpD->OriginalFirstThunk);            //指向一个结构数组的相对虚拟基址,   
                                                                   //结构体数组叫输入名称表
     m_InList1.SetItemText(i, 1, str);        
        str.Format(L"%08X", pImpD->TimeDateStamp);                 //文件建立时间
        m_InList1.SetItemText(i, 2, str);        
        str.Format(L"%08X", pImpD->ForwarderChain);                //转发机制用的到
        m_InList1.SetItemText(i, 3, str);               
        str.Format(L"%08X", pImpD->Name);                          //导入的PE文件的名字的相对虚拟RVA
        m_InList1.SetItemText(i, 4, str);        
        str.Format(L"%08X", pImpD->FirstThunk);                    //指向一个结构提数组的相对虚拟地址,
                                                               //结构体数组叫输入地址表
        m_InList1.SetItemText(i, 5, str);
        i++;
        pImpD++;
}

获取资源表
PIMAGE_RESOURCE_DIRECTORY pResD = (PIMAGE_RESOURCE_DIRECTORY)(Buf + RvaOffset(pDatD[2]->VirtualAddress));
DWORD ReSize = pResD->NumberOfIdEntries + pResD->NumberOfNamedEntries;
        PIMAGE_RESOURCE_DIRECTORY_ENTRY pResDE = (PIMAGE_RESOURCE_DIRECTORY_ENTRY)((long)pResD + sizeof(IMAGE_RESOURCE_DIRECTORY));
        
资源表分为3层
第一层
名称结构、大小
pResDE->NameIsStringReSize
HTREEITEM hItem;
        HTREEITEM hSubItem;
        CString str;
        for (DWORD FirstOrder = 0; FirstOrder < ReSize; FirstOrder++)
        {
                //第一层 假如是字符串标识
                if (pResDE->NameIsString == 1)
                {
                        PIMAGE_RESOURCE_DIR_STRING_U pREsDStrU = (PIMAGE_RESOURCE_DIR_STRING_U)((long)pResD + pResDE->NameOffset);
                        hItem = m_ResTree.InsertItem(pREsDStrU->NameString, NULL, NULL);///root就是节点的标题
                }
                else
                {
                        switch (pResDE->Name)
                        {
                        case 0x1:
                                hItem = m_ResTree.InsertItem(L"鼠标指针", NULL, NULL);
                                break;
                        case 0x2:
                                hItem = m_ResTree.InsertItem(L"位图", NULL, NULL);
                                break;
                        case 0x3:
                                hItem = m_ResTree.InsertItem(L"图标", NULL, NULL);
                                break;
                        case 0x4:
                                hItem = m_ResTree.InsertItem(L"菜单", NULL, NULL);
                                break;
                        case 0x5:
                                hItem = m_ResTree.InsertItem(L"对话框", NULL, NULL);
                                break;
                        case 0x6:
                                hItem = m_ResTree.InsertItem(L"字符串列表", NULL, NULL);
                                break;
                        case 0x7:
                                hItem = m_ResTree.InsertItem(L"字体目录", NULL, NULL);
                                break;
                        case 0x8:
                                hItem = m_ResTree.InsertItem(L"字体", NULL, NULL);
                                break;
                        case 0x9:
                                hItem = m_ResTree.InsertItem(L"快捷键", NULL, NULL);
                                break;
                        case 0xA:
                                hItem = m_ResTree.InsertItem(L"非格式化资源", NULL, NULL);
                                break;
                        case 0xB:
                                hItem = m_ResTree.InsertItem(L"消息列表", NULL, NULL);
                                break;
                        case 0xC:
                                hItem = m_ResTree.InsertItem(L"鼠标指针组", NULL, NULL);
                                break;
                        case 0xD:
                                hItem = m_ResTree.InsertItem(L"图标组", NULL, NULL);
                                break;
                        case 0xE:
                                hItem = m_ResTree.InsertItem(L"版本信息", NULL, NULL);
                                break;
                        default:
                                str.Format(L"%d", pResDE->Name);
                                hItem = m_ResTree.InsertItem(str, NULL, NULL);
                                break;
                        }
                }


第二层

PIMAGE_RESOURCE_DIRECTORY pResD2 = (PIMAGE_RESOURCE_DIRECTORY)((long)pResD + pResDE->OffsetToDirectory);
                
                DWORD ReSize2 = pResD2->NumberOfIdEntries + pResD2->NumberOfNamedEntries;
                PIMAGE_RESOURCE_DIRECTORY_ENTRY pResDE2 = (PIMAGE_RESOURCE_DIRECTORY_ENTRY)((long)pResD2 + sizeof(IMAGE_RESOURCE_DIRECTORY));

DWORD SecondOrder = 0;
                for (; SecondOrder < ReSize2; SecondOrder++)
                {
                        if (pResDE2->DataIsDirectory == 1)
                        {
                                //输出第二层资源的标识看是数字还是字符串
                                if (pResDE2->NameIsString == 1)
                                {
                                        PIMAGE_RESOURCE_DIR_STRING_U pREsDStrU2 = (PIMAGE_RESOURCE_DIR_STRING_U)((long)pResD + pResDE2->NameOffset);
                                        //输出资源类型名字
                                        //printf("第二层->资源类型名:%ls   ",pREsDStrU2->NameString);
                                        hSubItem = m_ResTree.InsertItem(pREsDStrU2->NameString, NULL, NULL, hItem);
                                        m_ResTree.SetItemData(hSubItem, SecondOrder);
                                }
                                else
                                {
                                        //printf_s("第二层->资源类型名ID:%d   ",pResDE2->Id);        
                                        str.Format(L"%d", pResDE2->Id);
                                        hSubItem = m_ResTree.InsertItem(str, NULL, NULL, hItem);
                                        m_ResTree.SetItemData(hSubItem, SecondOrder);
                                }


第三层
                  PIMAGE_RESOURCE_DIRECTORY pResD3 = (PIMAGE_RESOURCE_DIRECTORY)((long)pResD + pResDE2->OffsetToDirectory);
                                PIMAGE_RESOURCE_DIRECTORY_ENTRY pResDE3 = (PIMAGE_RESOURCE_DIRECTORY_ENTRY)((long)pResD3 + sizeof(IMAGE_RESOURCE_DIRECTORY));
                                PIMAGE_RESOURCE_DATA_ENTRY pResDataE = (PIMAGE_RESOURCE_DATA_ENTRY)((long)pResD + pResDE3->OffsetToData);
                                //根据第一层 也就是父节点 区分
                                ResThirdInfo.Rva = pResDataE->OffsetToData;
                                ResThirdInfo.Offset = (RvaOffset(pResDataE->OffsetToData));
                                ResThirdInfo.Size = pResDataE->Size;
                        }
                        else
                        {
                                break;
                        }
                        pResDE2++;
                }



获取重定位表信息
PIMAGE_BASE_RELOCATION pBasR = (PIMAGE_BASE_RELOCATION)((long)Buf + RvaOffset(pDatD[5]->VirtualAddress));
重定位有3个成员结构体:
/***************-重定位表-*****************/
//第一个成员的描述
typedef struct _RELOCINFO
{
        DWORD dwRelocRVA;                //需要重定位的相对虚拟地址
        DWORD dwOffset;                        //根据相对虚拟地址算出的文件属性
        BYTE bType;                                //重定位方式
        DWORD dwRelocValue;                //从算出的文件偏移取出的数据 这个数据就是虚拟地址(VA)
        BYTE bData[10];                        //用刚才的地址(VA)减去基址得到相对虚拟地址RVA 再算下文件偏移 将其中的数据取出 放到这个数组
}RELOCINFO, *PRELOCINFO;
//第二个成员的描述
typedef struct _RELOCAREAINFO
{
        CHAR szSectionName[8];  //区域所在的节名
        DWORD dwAreaRVA;                //区域基址
        DWORD NumberOfReloc;        //这个区域重定位的具体个数
        std::vector<RELOCINFO> VecRelocInfo;//这个区域重定位的具体信息
}RELOCAREAINFO, *PRELOCAREAINFO;
vector<RELOCAREAINFO> m_VecRelocAreaInfo;
//第三个成员的描述
typedef struct _TYPEOFFSET
{
        WORD Offset : 12;                //偏移值
        WORD Type : 4;                //重定位属性(方式)
}TYPEOFFSET, *PTYPEOFFSET;


重定位表信息需要根据区段信息来获取
DWORD RelCalcOffset(DWORD Rva, PIMAGE_NT_HEADERS32 pNtH, char *Tempbuf, PCHAR pName = NULL, PCHAR pData = NULL, int Flag = NULL)
{
        PIMAGE_SECTION_HEADER pSecHTemp = IMAGE_FIRST_SECTION(pNtH);//区段头
        int index = 0;

        while (!(Rva >= pSecHTemp->VirtualAddress&&
                Rva<pSecHTemp->VirtualAddress + pSecHTemp->SizeOfRawData))
        {
               
                if (index>pNtH->FileHeader.NumberOfSections)
                {
                        if (Flag == 2)
                        {
                                return Rva - pNtH->OptionalHeader.ImageBase;
                        }
                        return Rva;
                }
                ++index;
                ++pSecHTemp;
        }
        //获取区段名
        if (pName != NULL)
        {
                memcpy(pName, pSecHTemp->Name, 8);
        }
        v = Rva - pSecHTemp->VirtualAddress + pSecHTemp->PointerToRawData;;
        DWORD iiii = (long)Tempbuf + v;
        //获取数据
        if (pData != NULL)
        {
                if (Flag == 2)
                {
                        return Rva - pNtH->OptionalHeader.ImageBase;
                }
                memcpy(pData, PCHAR((long)Tempbuf + v), 10);
        }
        return v;
}

RELOCAREAINFO Temp = { 0 };
        int j = 0;//索引
        CString str;
        
        while (pBasR->VirtualAddress)
        {
                str.Format(L"%d", j + 1);
                m_ReList1.InsertItem(j, str);
                //区域的虚拟地址输出或获取到其他地方
                Temp.dwAreaRVA = pBasR->VirtualAddress;

                RelCalcOffset(Temp.dwAreaRVA, AllPe.pNtH, AllPe.Buf, Temp.szSectionName, NULL);
                CString str(Temp.szSectionName);
                m_ReList1.SetItemText(j, 1, str);
                str.Format(L"%08X", pBasR->VirtualAddress);
                m_ReList1.SetItemText(j, 2, str);
                Temp.NumberOfReloc = (pBasR->SizeOfBlock - sizeof(IMAGE_BASE_RELOCATION)) / 2;
                str.Format(L"%02X", Temp.NumberOfReloc);
                CString str1;
                str1.Format(L"%d", Temp.NumberOfReloc);
                m_ReList1.SetItemText(j, 3, str + L" " + str1);
                m_VecpBseRInfo.push_back(pBasR);        
                pBasR = (PIMAGE_BASE_RELOCATION)((long)pBasR + pBasR->SizeOfBlock);
                j++;
        }
        
获取TLS表信息

PIMAGE_TLS_DIRECTORY32 pTls = (PIMAGE_TLS_DIRECTORY32)((long)Buf + RvaOffset(pDatD[9]->VirtualAddress));
pTls->StartAddressOfRawData             //源数据起始位置
pTls->EndAddressOfRawData               //源数据终止位置
pTls->AddressOfIndex                    //保存TLS索引的位置
pTls->AddressOfCallBacks                //TLS回调函数的地址表的位置(VA)在.rdata节
pTls->SizeOfZeroFill                    //用0填充TLS变量区域的大小
pTls->Characteristics                   //保留,恒为0


PE解析.zip

25.31 KB, 下载次数: 36, 下载积分: 吾爱币 -1 CB

附上压缩文档

免费评分

参与人数 5吾爱币 +2 热心值 +5 收起 理由
vking + 1 + 1 谢谢@Thanks!
capnik + 1 + 1 我很赞同!
jinxiaoyun + 1 我很赞同!
yeyulang + 1 谢谢@Thanks!
寒枫雨雪 + 1 谢谢@Thanks!

查看全部评分

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

 楼主| Auller 发表于 2016-10-6 22:35 来自手机
Hmily 发表于 2016-10-6 22:02
编辑了下,去掉了字体大小的,当还是最好用代码框处理下代码,会好看很多。

谢谢,明天我修改一下
Very_good 发表于 2016-10-7 09:07
wjdxs1 发表于 2016-10-6 21:58
看PE结构的图会好得多。。。。。很直观了就

有时间帮忙看下悬赏  谢谢
Hmily 发表于 2016-10-6 21:16
 楼主| Auller 发表于 2016-10-6 21:19
Hmily 发表于 2016-10-6 21:16
从哪转的,注意下格式。

自己写的好吗

点评

我意思是从哪复制过来的,格式怎么这么乱了。  详情 回复 发表于 2016-10-6 21:58
 楼主| Auller 发表于 2016-10-6 21:23
附上压缩文档

PE解析.zip

25.31 KB, 下载次数: 3, 下载积分: 吾爱币 -1 CB

Very_good 发表于 2016-10-6 21:44
眼花缭乱了  
Zero丶冻结 发表于 2016-10-6 21:47
看的有点头晕。
anythink 发表于 2016-10-6 21:51
学习了!!
Hmily 发表于 2016-10-6 21:58

我意思是从哪复制过来的,格式怎么这么乱了。
SeriousSnow 发表于 2016-10-6 21:58

看PE结构的图会好得多。。。。。很直观了就
Hmily 发表于 2016-10-6 22:02
编辑了下,去掉了字体大小的,当还是最好用代码框处理下代码,会好看很多。
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则 警告:本版块禁止灌水或回复与主题无关内容,违者重罚!

快速回复 收藏帖子 返回列表 搜索

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-4-29 15:11

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表