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

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 715|回复: 6
收起左侧

[C&C++ 原创] pe后续结构解析

[复制链接]
JackLSQ 发表于 2024-1-17 22:38

续接上回,上篇文章中 主要展示了PE结构中的 DOS_HEAD,NT_FILE_HEAD,NT_OPTIONAL_HEAD,Section_head 中部分重要成员数据。这篇文章将介绍上篇文件中说到但是未详细介绍的部分。比如数据目录项中的导入表,导出表,重定位表。

数据目录项

在该项表中,这是一个_IMAGE_DATA_DIRECTORY 结构体,该结构体的组成如以下所示。

typedef struct _IMAGE_DATA_DIRECTORY {
    DWORD   VirtualAddress;
    DWORD   Size;
} IMAGE_DATA_DIRECTORY, *PIMAGE_DATA_DIRECTORY;

VirtualAddress 代表着对应序号在内存中的 虚拟地址,如果想正确的解析到对应项表的数据,需要将虚拟地址转化为文件地址
即 VA-->FOA: 这个是有个公式,公式如下所示:VA--->RVA-->FOA
VA--->RVA: RVA=VA-节首地址
RVA--->FOA:FOA=RVA+该VA地址节对应到文件中的偏移

在该数据项中一共有16个表

表名 表序号 Column 3
IMAGE_DIRECTORY_ENTRY_EXPORT 0 导出表
IMAGE_DIRECTORY_ENTRY_IMPORT 1 导入表
IMAGE_DIRECTORY_ENTRY_RESOURCE 2 资源表
IMAGE_DIRECTORY_ENTRY_EXCEPTION 3 异常
IMAGE_DIRECTORY_ENTRY_SECURITY 4 安全
IMAGE_DIRECTORY_ENTRY_BASERELOC 5 重定位
IMAGE_DIRECTORY_ENTRY_DEBUG 6 调试信息
IMAGE_DIRECTORY_ENTRY_COPYRIGHT 7 (X86 usage) 所有者 x86还在用
IMAGE_DIRECTORY_ENTRY_ARCHITECTURE 7 版权信息
IMAGE_DIRECTORY_ENTRY_GLOBALPTR 8 RVA of GP
IMAGE_DIRECTORY_ENTRY_TLS 9 TLS Directory
IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG 10 Load Configuration Directory
IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT 11 Bound Import Directory in headers
IMAGE_DIRECTORY_ENTRY_IAT 12 导入函数地址
IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT 13 Delay Load Import Descriptors
IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR 14 COM Runtime descriptor

下面就是遍历上述中 ,重要表项的代码

void displayDataDirectory(HANDLE imagebase)
{
    //遍历 DataDirectory
    PIMAGE_NT_HEADERS pNtHead = NULL;

    pNtHead = GetNtHead(imagebase);

    int data_size=pNtHead->OptionalHeader.NumberOfRvaAndSizes;
    printf("编号 \t 目录RVA \t 目录FOA \t Size长度(十进制) \t Size长度(16进制) \t 功能描述\n");

    for (int i = 0; i < data_size; i++) {
        printf("%03d \t 0x%08X \t 0x%08X \t %08d \t\t 0x%08X\t\t",
            i + 1,
            pNtHead->OptionalHeader.DataDirectory[i].VirtualAddress,
            RVA_TO_FOA(imagebase,pNtHead->OptionalHeader.DataDirectory[i].VirtualAddress),
            pNtHead->OptionalHeader.DataDirectory[i].Size,
            pNtHead->OptionalHeader.DataDirectory[i].Size
            );
        switch (i)
        {
        case 0:
            printf("Export sysmbols\n");
            break;
        case 1:
            printf("Import sysmbols\n");
            break;
        case 2:
            printf("Resoucres\n");
            break;
        case 3:
            printf("Exception\n");
            break;
        case 4:
            printf("Security\n");
            break;
        case 5:
            printf("base relocation\n");
            break;
        case 6:
            printf("Debug\n");
            break;
        case 7:
            printf("Copyright string \n");
            break;
        case 8:
            printf("Globalptr \n");
            break;
        case 9:
            printf("Thread loacl storage(TLS)\n");
            break;
        case 10:
            printf("Local Configuration\n");
            break;
        case 11:
            printf("Bound Import \n");
            break;
        case 12:
            printf("import address Table\n");
            break;
        case 13:
            printf("Delay Import\n");
            break;
        case 14:
            printf("COM descriptor\n");
            break;
        case 15:
            printf("NoUse\n");
            break;
        default:printf("none\n");
            break;
        }
    }
}

//遍历导入表
void displayImportTable(HANDLE imageBase)
{
    PIMAGE_NT_HEADERS pNtHead = GetNtHead(imageBase);
    //获得导入表的RVA地址
    DWORD importTableRVA=pNtHead->OptionalHeader.DataDirectory[1].VirtualAddress;

    auto importTable = (PIMAGE_IMPORT_DESCRIPTOR)(RVA_TO_FOA(imageBase, importTableRVA) + (DWORD)imageBase);

    while (importTable->Name) {
        char* dllName = (char*)(RVA_TO_FOA(imageBase, importTable->Name) + (DWORD)imageBase);
        printf("Hint 值\t\t API序号 \t 文件RVA \t VA地址 \t 函数名称 \t 模块:[ %s ] \n", dllName);

        auto Iat = (PIMAGE_THUNK_DATA)(RVA_TO_FOA(imageBase, importTable->FirstThunk) + (DWORD)imageBase);
        auto Int=(PIMAGE_THUNK_DATA)(RVA_TO_FOA(imageBase, importTable->OriginalFirstThunk) + (DWORD)imageBase);

        //遍历IAT表
        while (Iat->u1.Ordinal != 0) {
            //判断是否有名字
            if (Iat->u1.AddressOfData & 0x80000000) {
                // 序号导入,直接输出
                printf("[%5d] \t [None] \n", LOWORD(Iat->u1.AddressOfData));
            }
            else {
                auto name = (PIMAGE_IMPORT_BY_NAME)(RVA_TO_FOA(imageBase, Iat->u1.AddressOfData) + (DWORD)imageBase);

                DWORD imagebase = pNtHead->OptionalHeader.ImageBase;

                DWORD VA = Iat->u1.AddressOfData + imagebase;
                printf("[%5d] \t %09d \t %08x \t %08x \t %s \n",
                    name->Hint,
                    Iat->u1.Ordinal,
                    RVA_TO_FOA(imageBase,Iat->u1.AddressOfData),
                    VA,
                    name->Name
                );
            }
            Iat++;
        }
        importTable++;
        printf("\n");
    }

}

//导出表项只有在dll中存在
void displayExportTable(HANDLE imageBase)
{
    PIMAGE_NT_HEADERS pNtHead = GetNtHead(imageBase);

    DWORD imagebase = pNtHead->OptionalHeader.ImageBase;

    //获得导出表的RVA地址
    DWORD RVA = pNtHead->OptionalHeader.DataDirectory[0].VirtualAddress;  

    auto exportTable = (PIMAGE_EXPORT_DIRECTORY)(RVA_TO_FOA(imageBase, RVA) + (DWORD)imageBase);

    //获取有名字的函数个数和函数总个数
    DWORD nameCount = exportTable->NumberOfNames;
    DWORD funcCount = exportTable->NumberOfFunctions;

    //获取三张表 地址表 名称表 序号表

    DWORD* addr_table = (DWORD*)(RVA_TO_FOA(imageBase, exportTable->AddressOfFunctions) + (DWORD)imageBase);
    DWORD* name_table = (DWORD*)(RVA_TO_FOA(imageBase, exportTable->AddressOfNames) + (DWORD)imageBase);
    WORD* id_table = (WORD*)(RVA_TO_FOA(imageBase, exportTable->AddressOfNameOrdinals) + (DWORD)imageBase);

    printf("序号 \t 导出RVA地址 \t 导出VA地址 \t 导出FOA地址 \t 导出函数 \t \n");

    //遍历地址表
    for (DWORD i = 0; i < funcCount; i++) {
        bool haveName = false;

        for (DWORD j = 0; j < nameCount; j++) {
            if (i == id_table[j]) {
                haveName = TRUE;
                char* name = (char*)(RVA_TO_FOA(imageBase, name_table[j]) + (DWORD)imageBase);
                printf("%5d \t %10p \t 0x%08x \t 0x%08x \t %-35s \n",
                    i+exportTable->Base,
                    addr_table[i],
                    imagebase+addr_table[i],
                    RVA_TO_FOA(imageBase,addr_table[i]),
                    name
                    );
                break;
            }
        }

        //如果全部找完还没有名字
        if (haveName == false) {
            printf("%5d \t %10p \t 0x%08X \t 0x%08X \t None \n",
                i + exportTable->Base,
                addr_table[i],
                imagebase +addr_table[i], 
                RVA_TO_FOA(imageBase, addr_table[i])
            );
        }

    }

}

//重定位表
void displayRelocTable(HANDLE imageBase)
{
    PIMAGE_NT_HEADERS pNtHead = GetNtHead(imageBase);

    DWORD base = pNtHead->OptionalHeader.ImageBase;

    DWORD relocRVA = pNtHead->OptionalHeader.DataDirectory[5].VirtualAddress;

    PIMAGE_BASE_RELOCATION reloc = (PIMAGE_BASE_RELOCATION)((DWORD)imageBase + RVA_TO_FOA(imageBase, relocRVA));

    printf("映像基址: %08X 虚拟偏移: %08X 重定位表基址: %p \n",base,relocRVA,reloc);

    while (reloc->SizeOfBlock != 0) {
        DWORD Size = (reloc->SizeOfBlock - sizeof(IMAGE_BASE_RELOCATION)) / 2;
        printf("起始RVA: %08X \t 块长度: %04d \t 重定位个数:%04d \n",
            reloc->VirtualAddress,
            reloc->SizeOfBlock,
            Size
            );
        reloc = (PIMAGE_BASE_RELOCATION)(reloc->SizeOfBlock + (DWORD)reloc);
    }

}
//重定位表详细信息
void displayRelocTableDetail(HANDLE imageBase)
{
    PIMAGE_NT_HEADERS pNtHead = GetNtHead(imageBase);

    DWORD base = pNtHead->OptionalHeader.ImageBase;

    DWORD relocRVA = pNtHead->OptionalHeader.DataDirectory[5].VirtualAddress;

    PIMAGE_BASE_RELOCATION reloc = (PIMAGE_BASE_RELOCATION)((DWORD)imageBase + RVA_TO_FOA(imageBase, relocRVA));

    //printf("映像基址: %08X 虚拟偏移: %08X 重定位表基址: %p \n", base, relocRVA, reloc);

    printf("起始RVA \t 类型 \t 重定位RVA \t 重定位地址 \t 修正RVA \n");
    //遍历重定位表中的重定位块 ,以0结尾
    while (reloc->SizeOfBlock != 0) {

        //找到重定位项
        auto offset = (TypeOffset*)(reloc + 1);

        //计算重定位项数目
        DWORD Size = (reloc->SizeOfBlock - sizeof(IMAGE_BASE_RELOCATION)) / 2;

        //遍历所有的重定位项
        for (DWORD i = 0; i < Size; i++) {
            //获取重定位类型
            DWORD type = offset[i].type;

            //获取重定位的偏移
            DWORD _offset = offset[i].offset;

            // 获取要重定位的地址所在的RVA: offset+virtualaddress
            DWORD rva = _offset + reloc->VirtualAddress;

            // 获取要重定位的地址所在的FOA
            DWORD foa = RVA_TO_FOA(imageBase, rva);

            // 获取要重定位的地址所在的fa
            DWORD fa = foa + (DWORD)imageBase;

            // 获取要重定位的地址
            DWORD addr = *(DWORD*)fa;

            // 计算重定位后的数据: addr - oldbase + newbase
            DWORD new_addr = addr - base;
            printf("%08X \t %d \t %08X \t %08X \t%08X \n", reloc->VirtualAddress, type, rva, addr, new_addr);
        }
        // 找到下一个重定位块
        reloc = (PIMAGE_BASE_RELOCATION)(reloc->SizeOfBlock + (DWORD)reloc);
    }

}

//使用方式
HANDLE lpMapAddress = NULL;
wchar_t exePath[] = L"./x32dbg.exe";
lpMapAddress = OpenPeByName(exePath);

printf("================================================\n");
printf("Nt Optional head Data Directory info:\n");
displayDataDirectory(lpMapAddress);

printf("================================================\n");
printf("displayImportTable info:\n");
displayImportTable(lpMapAddress);

printf("================================================\n");
printf("displayRelocTable info:\n");
displayRelocTable(lpMapAddress);

printf("================================================\n");
printf("displayRelocTableDetail info:\n");
displayRelocTableDetail(lpMapAddress);

最后这是遍历结果



peRead.jpg

免费评分

参与人数 5吾爱币 +10 热心值 +5 收起 理由
timeni + 1 + 1 用心讨论,共获提升!
wushaominkk + 7 + 1 欢迎分析讨论交流,吾爱破解论坛有你更精彩!
vaycore + 1 谢谢@Thanks!
cogi + 1 + 1 谢谢@Thanks!
太子爷_振 + 1 + 1 用心讨论,共获提升!

查看全部评分

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

turmasi1234 发表于 2024-1-18 07:39
膜拜呆佬,学习一下
mxn007 发表于 2024-1-18 07:50
ztqddj007 发表于 2024-1-18 08:31
kingmaxking11 发表于 2024-1-18 09:12
学习学习,谢谢分享。
zhhayu 发表于 2024-1-18 09:25
不是一般的难
w759003376 发表于 2024-1-18 09:47
这个还是得耐心点,多次数啊,不然第一次有点难学
您需要登录后才可以回帖 登录 | 注册[Register]

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

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

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

GMT+8, 2024-4-29 09:19

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

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