> PE文件结构在windows安全中是必须了解的 > 本程序是一个通用分析32位PE文件的程序

程序包括分析DOS头,PE头中的文件映像头、可选映像头、数据目录项分析,节表分析以及导出表、导出函数分析 可修改宏改变打开的pe文件名 必须是32位PE

#include <stdio.h>
#include<windows.h>
#include<iostream>
#include<String>
#include<vector>

#define CLEN 20
#define ELEN 25
#define NLEN 6
#define DLLNAME "Your_Path\kernel32.dll"

void showData(const char Chinese[], const char English[],unsigned char * dataAddress, int len);
unsigned long long HexStringToLong(unsigned char * a, int len);
void showDataS(unsigned char * dataAddress, int len);
void showDataH(unsigned char * dataAddress, int len);
void showData1(unsigned char * buf, int len);
long long calcOffset(long long RVA);

using namespace std;

class section {
public:
    int SectionsRVA;
    int PointerToRawData;
    int SizeOFRawData;
    section() {
        SectionsRVA = 0;
        PointerToRawData = 0;
        SizeOFRawData = 0;
    }
    ~section() {
    }
    ;
};

int NumOfSections = 0; //节表个数
int ExportTableRVA = 0; //导出表RVA
int ExportTablePointer = 0; //导出表文件偏移

vector<section> Sections;
int main() {
    FILE *fp;

    unsigned char buffer[512];
    if ((fp = fopen(DLLNAME,"rb")) != NULL) {
        fread(buffer, sizeof(unsigned char), 0x40, fp);
        /*------------------------------------DOS头-------------------------------------------*/
        printf("DOS头分析:\n");
        showData("PE头偏移", "e_lfanew", &buffer[0x3c], 1);
        //将指针指向PE头开始
        fseek(fp, buffer[0x3c], 0); //当前读取指针指向PE头
        fread(buffer, sizeof(unsigned char), 0x88, fp);
        //showData1(buffer,0x88);
        /*------------------------------------PE头-------------------------------------------*/
        //映像文件头
        printf("映像文件头分析:\n");
        showData("运行环境及平台", "Machine", &buffer[0x4], 2);
        showData("节个数", "NumOfSections", &buffer[0x6], 2);
        NumOfSections = HexStringToLong(&buffer[0x6], 2);
        showData("文件建立时间戳", "TimeDateStamp", &buffer[0x8], 4);
        showData("标志集合", "Characteristics", &buffer[0x16], 2);
        //可选映像头
        printf("可选映像头分析:\n");
        showData("代码入口RVA", "AddressSOfEntryPoint", &buffer[0x28], 4);
        showData("模块首选载入RVA", "ImageBase", &buffer[0x34], 4);
        showData("节内存中对齐", "SectionAlignment", &buffer[0x38], 4);
        showData("节文件中对齐", "FileAlignment", &buffer[0x3c], 4);
        showData("调入内存大小", "SizeOfImage", &buffer[0x50], 4);
        showData("文件头大小之和", "SizeOfHeaders", &buffer[0x54], 4);
        showData("数据目录项项数", "NumberOfRvaAndSizes", &buffer[0x74], 4);
        //数据目录项
        printf("数据目录项分析:\n");
        showData("导出表地址", "ExportTableRVA", &buffer[0x78], 4);
        ExportTableRVA = HexStringToLong(&buffer[0x78], 4);
        showData("导出表大小", "ExportTableSize", &buffer[0x78 + 4], 4);
        showData("导入表地址", "ImportTableRVA", &buffer[0x78 + 8], 4);
        showData("导入表大小", "ImportTableSize", &buffer[0x78 + 12], 4);
        //将指针指向PE头开始
        fseek(fp, 0x70, 1); //当前读取指针指向节表头

        fread(buffer, sizeof(unsigned char), NumOfSections * 0x28, fp);
        /*------------------------------------节表-------------------------------------------*/
        printf("节表分析:\n");
        section Section;
        for (int i = 0; i < NumOfSections; i++) {
            showData("节表名字", "NameOfSectionTable", &buffer[i * 0x28], 0);
            showDataS(&buffer[i * 0x28], 8);

            showData("节表RVA", "VirtualAddress", &buffer[i * 0x28 + 12], 4);
            Section.SectionsRVA = HexStringToLong(&buffer[i * 0x28 + 12], 4);

            showData("文件对齐后尺寸", "SizeOFRawData", &buffer[i * 0x28 + 16], 4);
            Section.SizeOFRawData = HexStringToLong(&buffer[i * 0x28 + 16], 4);

            showData("数据在文件中的位置", "PointerToRawData", &buffer[i * 0x28 + 20],4);
            Section.PointerToRawData = HexStringToLong(&buffer[i * 0x28 + 20],4);

            printf("\t=================================================================\n");
            Sections.push_back(Section);

        }
        //计算导出表文件偏移
        ExportTablePointer = calcOffset(ExportTableRVA);


        /*------------------------------------导出表-------------------------------------------*/
        printf("导出表分析:\n");
        unsigned char buff[512];
        int base = 0; //导出表基数
        int NumOfFunctions = 0; //函数个数
        int NumOfNames = 0; //函数名字个数
        int AddressOfFunctions = 0; //函数RVA
        int AddressOfNames = 0; //函数名字RVA
        int AddressOfNameOrdinals = 0; //函数名字序号RVA

        //跳转到导出表目录头 IMAGE_EXPORT_DIRETORY
        fseek(fp, ExportTablePointer, 0);
        fread(buffer, sizeof(unsigned char), 40, fp);

        showData("DLL名字", "DLLName", &buffer[12], 0);
        fseek(fp, (int) calcOffset(HexStringToLong(&buffer[12], 4)), 0);
        fread(buff, sizeof(unsigned char), sizeof(buff), fp);
        printf("%s\n", buff);
        //showData1(buffer,512);
        showData("基数", "NumOfFunctions", &buffer[16], 4);
        base = HexStringToLong(&buffer[16], 4);
        showData("函数个数", "NumOfFunctions", &buffer[20], 4);
        NumOfFunctions = HexStringToLong(&buffer[20], 4);
        showData("函数名字个数", "NumOfNames", &buffer[24], 4);
        NumOfNames = HexStringToLong(&buffer[24], 4);
        showData("函数RVA", "AddressOfFunctions", &buffer[28], 4);
        AddressOfFunctions = HexStringToLong(&buffer[28], 4);
        showData("函数名字RVA", "AddressOfNames", &buffer[32], 4);
        AddressOfNames = HexStringToLong(&buffer[32], 4);
        showData("函数名字序号RVA", "AddressOfNameOrdinals", &buffer[36], 4);
        AddressOfNameOrdinals = HexStringToLong(&buffer[36], 4);
        printf("导出表函数:\n");
        printf("\n\t%-29s%-28s%s", "序号", "函数名", "函数RVA\n");
        //函数序号
        unsigned char nameBuff[1024];
        unsigned char nameBuffer[1024];
        int count = 0;
        for (int i = 0; i < NumOfNames / 256 + (NumOfNames % 256 != 0); i++) {

            fseek(fp, calcOffset(AddressOfNameOrdinals) + i * sizeof(buffer),0);
            fread(buffer, sizeof(unsigned char), sizeof(buffer), fp);

            fseek(fp, calcOffset(AddressOfNames) + i * sizeof(nameBuffer), 0);
            fread(nameBuffer, sizeof(unsigned char), sizeof(nameBuffer), fp);

            for (int j = 0; j < 512 / 2 && count < NumOfNames; j++) {
                printf("\t%-20X  ",(int) HexStringToLong(&buffer[j * 2], 2) + base);
                fseek(fp,(int) calcOffset(AddressOfFunctions)+ HexStringToLong(&buffer[j * 2], 2) * 4, 0);
                fread(buff, sizeof(unsigned char), 512, fp);

                fseek(fp, calcOffset(HexStringToLong(&nameBuffer[j * 4], 4)),0);
                fread(nameBuff, sizeof(unsigned char), sizeof(nameBuff), fp);
                printf("%-35s", nameBuff);
                showDataH(buff, 4);
                count++;
            }
        }
    }
    fclose(fp);
    return 0;
}

void showData1(unsigned char * buf, int len) {
    for (int i = 0; i < len; i++) {
        printf("%02X", buf[i]);
    }
    printf("\n");
}

long long calcOffset(long long RVA) {

    for (int i = 0; i < NumOfSections; i++) {
        if (Sections[i].SectionsRVA < RVA
                && RVA < Sections[i].SizeOFRawData + Sections[i].SectionsRVA) {
            return RVA - Sections[i].SectionsRVA + Sections[i].PointerToRawData;
        }
    }
    return 0;

}

void showData(const char Chinese[], const char English[],
        unsigned char * dataAddress, int len) {
    int flag = 0;

    printf("\t%-*s     %-*s=>    ", CLEN, Chinese, ELEN, English);

    for (int i = len - 1; i >= 0; i--) {
        if (flag) {
            printf("%02X", *(dataAddress + i));
        } else if (*(dataAddress + i) != 0) {
            flag = 1;
            printf("%X", *(dataAddress + i));
        }

    }
    if (len != 0) {
        printf("\n");
        if (flag == 0)

            printf("0");
    }
}

void showDataS(unsigned char * dataAddress, int len) {
    printf("%-*.*s\n", len, len, dataAddress);
}

void showDataH(unsigned char * dataAddress, int len) {
    int flag = 0;
    for (int i = len - 1; i >= 0; i--) {
        if (flag) {
            printf("%02X", *(dataAddress + i));
        } else if (*(dataAddress + i) != 0) {
            flag = 1;
            printf("%X", *(dataAddress + i));
        }
    }
    if (len != 0) {
        printf("\n");
        if (flag == 0)

            printf("0");
    }
}

unsigned long long HexStringToLong(unsigned char * a, int len) {
    unsigned long long num = 0, t = 0;
    for (int i = 0; i < len; i++) {
        t = a[i];
        for (int j = i; j > 0; j--) {
            t *= 256;
        }
        num += t;
    }
    return num;
}

运行结果个人认为还是比较美观的