2402436533 发表于 2017-10-4 14:45:47

一个简易版的 PE View

没什么技术含量,就是学习PE结构写的一个小工具

// PE View.cpp : 定义控制台应用程序的入口点。
//
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// 头文件
#include "stdafx.h"
#include "stdio.h"
#include <time.h>
#include <malloc.h>
#include <Shlwapi.h>
#include <Windows.h>
#pragma comment( lib, "Shlwapi.lib")
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// 定义声明
using namespace std;

void GetMachine(WORD wMachine);//打印运行平台
void stamp_to_standard(int stampTime);//时间戳到标准时间
DWORD RVAToRAW(DWORD dwRVA);//转换到文件偏移
FILE *fpPeFile;
_TCHAR szFileName = {0};
IMAGE_DOS_HEADER DosHander;
IMAGE_NT_HEADERS32 NtHander32;        //x32 NT头
PIMAGE_SECTION_HEADER pSectionHander;//节区头指针

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//开始位置
int _tmain(int argc, _TCHAR* argv[])
{
#if _DEBUG        //调试环境下读取自身
        argv = argv;
        argc = 2;
#endif

        ////////////////////////////////////////////
        if (argc < 2)
        {
                printf("Not File Analysis\n");
                system("pause");
                exit(EXIT_FAILURE);
        }
        SetConsoleTitle(argv);
        strcpy_s(szFileName, argv);
        PathStripPath(szFileName);//取文件名
        fopen_s(&fpPeFile, argv, "rb");// 以二进制方式打开文件
        if (!fpPeFile)
        {
                fprintf (stderr, "Error Open File \n");
                exit (EXIT_FAILURE);
        }
        fread_s(&DosHander.e_magic,sizeof(DosHander), 1, sizeof(DosHander), fpPeFile);//读取DOS头
        if (DosHander.e_magic!=IMAGE_DOS_SIGNATURE)//DOS 签名 "MZ"
        {
                fprintf(stderr, "Error Dos e_magic \n");
                exit(EXIT_FAILURE);
        }

        fseek (fpPeFile, DosHander.e_lfanew, SEEK_SET);//移动文件指针到NT头
        fread_s(&NtHander32.Signature,sizeof(NtHander32), 1, sizeof(NtHander32), fpPeFile);//读取NT头
       
        if (NtHander32.Signature!=IMAGE_NT_SIGNATURE)//签名 "PE"
        {
                fprintf(stderr, "Error Signature \n");
                exit(EXIT_FAILURE);
        }
        //fseek(fpPeFile, sizeof(NtHander32), SEEK_CUR);//移动文件指针到节区头
        ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        //打印PE信息
        printf("File Name:%s \n", szFileName);//文件名

        if (NtHander32.OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC)        //PE
        {
                printf("File Type: PE \n");
        } else if (NtHander32.OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC){        //PE+
                printf("File Type: PE++ \n");
        }

        GetMachine(NtHander32.FileHeader.Machine);//运行平台
        printf("ImageBase:%08X\n",NtHander32.OptionalHeader.ImageBase);//基址
        printf("EntryPoint:%08X\n", NtHander32.OptionalHeader.AddressOfEntryPoint);//入口地址
        printf("SizeOfHeaders%08X\n",NtHander32.OptionalHeader.SizeOfHeaders);//PE大小
        printf("SectionAlignment:%08X\n",NtHander32.OptionalHeader.SectionAlignment);//节区在内存中对齐大小
        printf("FileAlignment%08X\n", NtHander32.OptionalHeader.FileAlignment);//节区在文件中对齐大小
        stamp_to_standard(NtHander32.FileHeader.TimeDateStamp);//时间戳打印标准时间
        printf("\n==================================SectionS=======================================\n=");
        //申请区段内存
        pSectionHander = (IMAGE_SECTION_HEADER*)malloc(NtHander32.FileHeader.NumberOfSections*sizeof(IMAGE_SECTION_HEADER));
        printf("\tName\t\tRVA\t\tV.Size\t\tOffset\t\tR.size\t=\n");
        for (int i = 0; i < NtHander32.FileHeader.NumberOfSections; i++)//区段数量
        {
                //fread_s(&SectionHander, sizeof(SectionHander), 1, sizeof(SectionHander), fpPeFile);//读取节区头
                fread_s(&pSectionHander, sizeof(IMAGE_SECTION_HEADER), 1, sizeof(IMAGE_SECTION_HEADER), fpPeFile);
                printf("=\t%-8s\t", pSectionHander.Name);//MSDN定义 8BYTE
                printf("%X\t\t", pSectionHander.VirtualAddress);
                printf("%X\t\t",pSectionHander.Misc.VirtualSize);
                printf("%X\t\t",pSectionHander.PointerToRawData);
                printf("%X\t=\n",pSectionHander.SizeOfRawData);
        }
        printf("==================================Section End====================================\n");
        system("pause");
        free(pSectionHander);
        fclose(fpPeFile);//关闭文件
        return 0;
}

void GetMachine(WORD wMachine)
{
        _TCHAR szType;
        if (wMachine==IMAGE_FILE_MACHINE_UNKNOWN)
                strcpy_s(szType, "Machine: Unknwn \n");
        else if (wMachine==IMAGE_FILE_MACHINE_I386)
                strcpy_s(szType, "Machine: Intel x86 \n");
        else if (wMachine==IMAGE_FILE_MACHINE_IA64)
                strcpy_s(szType, "Machine: Intel x64 \n");
        else if (wMachine==IMAGE_FILE_MACHINE_AMD64)
                strcpy_s(szType, "Machine: AMD64 (K8) \n");
        printf("%s", szType);
        //cout << szType;
//其他未补充
/*
#define IMAGE_FILE_MACHINE_UNKNOWN         0
#define IMAGE_FILE_MACHINE_I386            0x014c// Intel 386.
#define IMAGE_FILE_MACHINE_R3000             0x0162// MIPS little-endian, 0x160 big-endian
#define IMAGE_FILE_MACHINE_R4000             0x0166// MIPS little-endian
#define IMAGE_FILE_MACHINE_R10000            0x0168// MIPS little-endian
#define IMAGE_FILE_MACHINE_WCEMIPSV2         0x0169// MIPS little-endian WCE v2
#define IMAGE_FILE_MACHINE_ALPHA             0x0184// Alpha_AXP
#define IMAGE_FILE_MACHINE_SH3               0x01a2// SH3 little-endian
#define IMAGE_FILE_MACHINE_SH3DSP            0x01a3
#define IMAGE_FILE_MACHINE_SH3E            0x01a4// SH3E little-endian
#define IMAGE_FILE_MACHINE_SH4               0x01a6// SH4 little-endian
#define IMAGE_FILE_MACHINE_SH5               0x01a8// SH5
#define IMAGE_FILE_MACHINE_ARM               0x01c0// ARM Little-Endian
#define IMAGE_FILE_MACHINE_THUMB             0x01c2// ARM Thumb/Thumb-2 Little-Endian
#define IMAGE_FILE_MACHINE_ARMNT             0x01c4// ARM Thumb-2 Little-Endian
#define IMAGE_FILE_MACHINE_AM33            0x01d3
#define IMAGE_FILE_MACHINE_POWERPC         0x01F0// IBM PowerPC Little-Endian
#define IMAGE_FILE_MACHINE_POWERPCFP         0x01f1
#define IMAGE_FILE_MACHINE_IA64            0x0200// Intel 64
#define IMAGE_FILE_MACHINE_MIPS16            0x0266// MIPS
#define IMAGE_FILE_MACHINE_ALPHA64         0x0284// ALPHA64
#define IMAGE_FILE_MACHINE_MIPSFPU         0x0366// MIPS
#define IMAGE_FILE_MACHINE_MIPSFPU16         0x0466// MIPS
#define IMAGE_FILE_MACHINE_AXP64             IMAGE_FILE_MACHINE_ALPHA64
#define IMAGE_FILE_MACHINE_TRICORE         0x0520// Infineon
#define IMAGE_FILE_MACHINE_CEF               0x0CEF
#define IMAGE_FILE_MACHINE_EBC               0x0EBC// EFI Byte Code
#define IMAGE_FILE_MACHINE_AMD64             0x8664// AMD64 (K8)
#define IMAGE_FILE_MACHINE_M32R            0x9041// M32R little-endian
#define IMAGE_FILE_MACHINE_CEE               0xC0EE*/
}
typedef struct times
{
        int Year;        //年
        int Mon;        //月
        int Day;        //日
        int Hour;        //时
        int Min;        //分
        int Second;        //秒
}Times;

void stamp_to_standard(int stampTime)
{
        time_t tick = (time_t)stampTime;
        struct tm tm;
        char s;
        Times standard;

        //tick = time(NULL);
        localtime_s(&tm,&tick);
        strftime(s, sizeof(s), "Create Date: %Y-%m-%d %H:%M:%S", &tm);
        printf("%s\n", s);


        standard.Year = atoi(s);
        standard.Mon = atoi(s + 5);
        standard.Day = atoi(s + 8);
        standard.Hour = atoi(s + 11);
        standard.Min = atoi(s + 14);
        standard.Second = atoi(s + 17);

        /*wsprintf(szBuffer, "%d-%d-%d %d:%d:%d",
                standard.Year,
                standard.Mon,
                standard.Day,
                standard.Hour,
                standard.Min,
                standard.Second);*/
}

IAT和EAT的话用这个函数获取到它的RVA 在转换到RAW读取就是了
//转换到文件偏移
DWORD RVAToRAW(DWORD dwRVA)
{
        DWORD dwOffset;
        DWORD dwRAW;
        for (int i = 1; i < NtHander32.FileHeader.NumberOfSections; i++)
        {
                if (pSectionHander.VirtualAddress>dwRVA&&i>0)
                {
                        if (pSectionHander.VirtualAddress<=dwRVA)
                        {
                                //        //RAW=RVA-VirtualAddress+PointerToRawData
                                dwOffset = dwRVA - pSectionHander.VirtualAddress;
                                dwRAW = dwOffset + pSectionHander.PointerToRawData;
                                return dwRAW;
                        }
                }
        }
        return -1;
}

如获得INI表第一个函数名就这样写:
        //设置文件指针为导入表起始地址
        fseek(fpPeFile, RVAToRAW(NtHander32.OptionalHeader.DataDirectory.VirtualAddress), SEEK_SET);
        //读取导入表
        fread_s(&ImportDescpiptor, sizeof(IMAGE_IMPORT_DESCRIPTOR), 1, sizeof(IMAGE_IMPORT_DESCRIPTOR), fpPeFile);
        dwThunkINI = RVAToRAW(ImportDescpiptor.OriginalFirstThunk);
        //设置文件指针为INI地址
        fseek(fpPeFile, dwThunkINI, SEEK_SET);
        DWORD addr;
        fread_s(&addr, sizeof(addr), 1, sizeof(addr), fpPeFile);
        addr = RVAToRAW(addr);
        fseek(fpPeFile, addr, SEEK_SET);
        struct MyStruct
        {
                WORD Hint;
                CHAR Name;
        }TEST;
        fread_s(&TEST, sizeof(TEST), 1, sizeof(TEST), fpPeFile);
        printf("%s\n", TEST.name);

到时候我整理一下个人学习PE结构的资料分享给各位坛友!!

不破不立 发表于 2017-10-4 16:49:29

前排学习

gujin162 发表于 2017-10-5 10:50:47


向楼主学习!向楼主致敬!

hcg777 发表于 2017-10-6 18:43:03

楼主很厉害,加油

longfei 发表于 2017-10-8 10:43:19

前排支持一下

xiaolong65 发表于 2017-10-12 09:09:13

楼主是高人啊
页: [1]
查看完整版本: 一个简易版的 PE View