0xAA55 发表于 2014-4-27 03:45:30

【C】新PE文件查看器PrintPE源代码及下载

这个和旧的PrintPE相比,多了很多内容,包括IAT、EAT(输入、输出表)以及资源表的读取。原先的只是简单地打印了PE头。这个有了更多功能。
旧帖:
【C】C语言写的打印PE文件头信息的程序
转载请明出处:
http://www.0xaa55.com/thread-530-1-1.html

用法和旧帖说的一样。运行如下命令:
PrintPE 某PE文件.后缀
就可以看到效果了。
但是因为这个版本功能比较全,打印的东西比较多,因此建议大家还是把结果重定向到一个文件比较好。
PrintPE 某PE文件.后缀>输出.txt
这样就能看到PE文件的所有信息了。包括输入表(这个PE引用了哪些DLL)、输出表(这个PE提供了哪些符号输出)、资源表等。功能比旧版强多了。
感谢@美俪女神 (Tesla.Angela)提供的技术资料。
其实我编写这个程序的时候,用的是无脑输出法,也就是,WINNT.H给的结构体有几个成员,我就输出多少信息。
不过为了让文件更直观,有些部分的信息我把它省略掉了。
源码://-----------------------------------------------------------------------------
//PrintPE:
//打印一个PE文件所有信息的程序。
//功能就是无脑把PE文件头的所有内容全部打印出来。
//代码不保证可读性。
//作者:0xAA55
//QQ:838816058
//论坛:http://www.0xaa55.com/
//本人所有技术资料都在“技术宅的结界”。欢迎大家参与交流。
//-----------------------------------------------------------------------------
#include<stdio.h>
#include<windows.h>

//-----------------------------------------------------------------------------
//全局变量
//-----------------------------------------------------------------------------
IMAGE_DOS_HEADER      g_DOSH;
IMAGE_FILE_HEADER       g_PEH;
void                  *g_pOPTBuffer=NULL;//可选头缓冲区
IMAGE_SECTION_HEADER    *g_pSecH=NULL;

//-----------------------------------------------------------------------------
//打印“用法”
//-----------------------------------------------------------------------------
void Usage()
{
    fputs(
      "USAGE:\n"
      "PrintPE PEFILE\n",stderr);
}

//-----------------------------------------------------------------------------
//读取PE文件最开始的头:DOS头
//-----------------------------------------------------------------------------
void ReadDOSH(FILE*fp)
{
    fread(&g_DOSH,1,sizeof(g_DOSH),fp);

    //一股脑的全部打印
    printf(
      "--------------------------------DOS .EXE header--------------------------------\n"
      "Magic number:0x%04X\n"
      "Bytes on last page of file:0x%04X\n"
      "Pages in file:0x%04X\n"
      "Relocations:0x%04X\n"
      "Size of header in paragraphs:0x%04X\n"
      "Minimum extra paragraphs needed:0x%04X\n"
      "Maximum extra paragraphs needed:0x%04X\n"
      "Initial (relative) SS value:0x%04X\n"
      "Initial SP value:0x%04X\n"
      "Checksum:0x%04X\n"
      "Initial IP value:0x%04X\n"
      "Initial (relative) CS value:0x%04X\n"
      "File address of relocation table:0x%04X\n"
      "Overlay number:0x%04X\n"
      "OEM identifier (for e_oeminfo):0x%04X\n"
      "OEM information; e_oemid specific:0x%04X\n"
      "File address of new exe header:0x%08X\n",
      g_DOSH.e_magic,                     // Magic number
      g_DOSH.e_cblp,                      // Bytes on last page of file
      g_DOSH.e_cp,                        // Pages in file
      g_DOSH.e_crlc,                      // Relocations
      g_DOSH.e_cparhdr,                   // Size of header in paragraphs
      g_DOSH.e_minalloc,                  // Minimum extra paragraphs needed
      g_DOSH.e_maxalloc,                  // Maximum extra paragraphs needed
      g_DOSH.e_ss,                        // Initial (relative) SS value
      g_DOSH.e_sp,                        // Initial SP value
      g_DOSH.e_csum,                      // Checksum
      g_DOSH.e_ip,                        // Initial IP value
      g_DOSH.e_cs,                        // Initial (relative) CS value
      g_DOSH.e_lfarlc,                  // File address of relocation table
      g_DOSH.e_ovno,                      // Overlay number
      g_DOSH.e_oemid,                     // OEM identifier (for e_oeminfo)
      g_DOSH.e_oeminfo,                   // OEM information, e_oemid specific
      g_DOSH.e_lfanew);                   // File address of new exe header

    if(g_DOSH.e_crlc)//如果DOS的EXE头有16位EXE的重定向表
    {
      WORD wRelocs=g_DOSH.e_crlc;
      DWORD*pdwRelocTable=(DWORD*)malloc(sizeof(DWORD)*wRelocs);
      fseek(fp,g_DOSH.e_lfarlc,SEEK_SET);//转到16位EXE的重定向表
      printf("DOS Relocations:\n");
      if(pdwRelocTable)//分配到了内存
      {
            DWORD*pPtr=pdwRelocTable;//DOS重定向表
            fread(pdwRelocTable,1,sizeof(DWORD)*wRelocs,fp);//一次性读取
            while(wRelocs--)
            {
                printf("0x%04X:0x%04X\n",(*pPtr>>16)&0xFFFF,*pPtr&0xFFFF);//打印远指针
                pPtr++;
            }
            free(pdwRelocTable);
      }
      else//没分配到内存
      {
            DWORD dwReloc;
            while(wRelocs--)
            {
                fread(&dwReloc,1,sizeof(dwReloc),fp);//读一个打印一个
                printf("0x%04X:0x%04X\n",(dwReloc>>16)&0xFFFF,dwReloc&0xFFFF);//打印远指针
            }
      }
    }
}

//-----------------------------------------------------------------------------
//读取PE头
//-----------------------------------------------------------------------------
void ReadPEH(FILE*fp)
{
    fread(&g_PEH,1,sizeof(g_PEH),fp);

    fputs(
      "----------------------------------PE Header------------------------------------\n"
      "Machine:",stdout);

    //打印机器类型
    switch(g_PEH.Machine)
    {
    default:
    case IMAGE_FILE_MACHINE_UNKNOWN:
      fputs("Unknown machine type\n",stdout);
      break;
    case IMAGE_FILE_MACHINE_I386:
      fputs("Intel 386.\n",stdout);
      break;
    case IMAGE_FILE_MACHINE_R3000:
      fputs("MIPS little-endian, 0x160 big-endian\n",stdout);
      break;
    case IMAGE_FILE_MACHINE_R4000:
      fputs("MIPS little-endian\n",stdout);
      break;
    case IMAGE_FILE_MACHINE_R10000:
      fputs("MIPS little-endian\n",stdout);
      break;
    case IMAGE_FILE_MACHINE_WCEMIPSV2:
      fputs("MIPS little-endian WCE v2\n",stdout);
      break;
    case IMAGE_FILE_MACHINE_ALPHA:
      fputs("Alpha_AXP\n",stdout);
      break;
    case IMAGE_FILE_MACHINE_POWERPC:
      fputs("IBM PowerPC Little-Endian\n",stdout);
      break;
    case IMAGE_FILE_MACHINE_SH3:
      fputs("SH3 little-endian\n",stdout);
      break;
    case IMAGE_FILE_MACHINE_SH3E:
      fputs("SH3E little-endian\n",stdout);
      break;
    case IMAGE_FILE_MACHINE_SH4:
      fputs("SH4 little-endian\n",stdout);
      break;
    case IMAGE_FILE_MACHINE_ARM:
      fputs("ARM Little-Endian\n",stdout);
      break;
    case IMAGE_FILE_MACHINE_THUMB:
      fputs("Thumb\n",stdout);
      break;
    case IMAGE_FILE_MACHINE_IA64:
      fputs("Intel 64\n",stdout);
      break;
    case IMAGE_FILE_MACHINE_MIPS16:
      fputs("MIPS 16\n",stdout);
      break;
    case IMAGE_FILE_MACHINE_MIPSFPU:
      fputs("MIPS FPU\n",stdout);
      break;
    case IMAGE_FILE_MACHINE_MIPSFPU16:
      fputs("MIPS FPU 16\n",stdout);
      break;
    case IMAGE_FILE_MACHINE_ALPHA64:
      fputs("ALPHA64\n",stdout);
      break;
    }

    printf(
      "Number of sections:0x%04X\n"
      "Time date stamp:0x%08X\n"
      "Pointer to symbol table:0x%08X\n"
      "Number of symbols:0x%08X\n"
      "Size of optional header:0x%04X\n"
      "Characteristics:0x%04X\n",
      g_PEH.NumberOfSections,
      g_PEH.TimeDateStamp,
      g_PEH.PointerToSymbolTable,
      g_PEH.NumberOfSymbols,
      g_PEH.SizeOfOptionalHeader,
      g_PEH.Characteristics);

    //打印“特性”
    if(g_PEH.Characteristics&IMAGE_FILE_RELOCS_STRIPPED)
      fputs("\tRelocation info stripped from file.\n",stdout);
    if(g_PEH.Characteristics&IMAGE_FILE_EXECUTABLE_IMAGE)
      fputs("\tFile is executable(i.e. no unresolved externel references).\n",stdout);
    if(g_PEH.Characteristics&IMAGE_FILE_LINE_NUMS_STRIPPED)
      fputs("\tLine numbers stripped from file.\n",stdout);
    if(g_PEH.Characteristics&IMAGE_FILE_LOCAL_SYMS_STRIPPED)
      fputs("\tLocal symbols stripped from file.\n",stdout);
    if(g_PEH.Characteristics&IMAGE_FILE_AGGRESIVE_WS_TRIM)
      fputs("\tAgressively trim working set\n",stdout);
    if(g_PEH.Characteristics&IMAGE_FILE_LARGE_ADDRESS_AWARE)
      fputs("\tApp can handle >2gb addresses\n",stdout);
    if(g_PEH.Characteristics&IMAGE_FILE_BYTES_REVERSED_LO)
      fputs("\tBytes of machine word are reversed.\n",stdout);
    if(g_PEH.Characteristics&IMAGE_FILE_32BIT_MACHINE)
      fputs("\t32 bit word machine.\n",stdout);
    if(g_PEH.Characteristics&IMAGE_FILE_DEBUG_STRIPPED)
      fputs("\tDebugging info stripped from file in .DBG file\n",stdout);
    if(g_PEH.Characteristics&IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP)
      fputs("\tIf Image is on removable media, copy and run from the swap file.\n",stdout);
    if(g_PEH.Characteristics&IMAGE_FILE_NET_RUN_FROM_SWAP)
      fputs("\tIf Image is on Net, copy and run from the swap file.\n",stdout);
    if(g_PEH.Characteristics&IMAGE_FILE_SYSTEM)
      fputs("\tSystem File.\n",stdout);
    if(g_PEH.Characteristics&IMAGE_FILE_DLL)
      fputs("\tFile is a DLL.\n",stdout);
    if(g_PEH.Characteristics&IMAGE_FILE_UP_SYSTEM_ONLY)
      fputs("\tFile should only be run on a UP machine\n",stdout);
    if(g_PEH.Characteristics&IMAGE_FILE_BYTES_REVERSED_HI)
      fputs("\tBytes of machine word are reversed.\n",stdout);
}

//-----------------------------------------------------------------------------
//目录表的描述字符串
//-----------------------------------------------------------------------------
const char*pDirTableDesc[]=
{
    "Export Directory",
    "Import Directory",
    "Resource Directory",
    "Exception Directory",
    "Security Directory",
    "Base Relocation Table",
    "Debug Directory",
    "Architecture Specific Data",
    "RVA of GP",
    "TLS Directory",
    "Load Configuration Directory",
    "Bound Import Directory in headers",
    "Import Address Table",
    "Delay Load Import Descriptors",
    "COM Runtime descriptor"
};

//-----------------------------------------------------------------------------
//读取32位可选头
//-----------------------------------------------------------------------------
void ReadOPT32(FILE*fp)
{
    UINT uDirEntry;
    IMAGE_OPTIONAL_HEADER32*pOPT32=(IMAGE_OPTIONAL_HEADER32*)g_pOPTBuffer;

    printf(
      "Major linker version:0x%02X\n"
      "Minor linker version:0x%02X\n"
      "Size of code:0x%08X\n"
      "Size of initialized data:0x%08X\n"
      "Size of uninitialized data:0x%08X\n"
      "Address of entry point:0x%08X\n"
      "Base of code:0x%08X\n"
      "Base of data:0x%08X\n"
      "Image base:0x%08X\n"
      "Section alignment:0x%08X\n"
      "File alignment:0x%08X\n"
      "Major operating system version:0x%04X\n"
      "Minor operating system version:0x%04X\n"
      "Major image version:0x%04X\n"
      "Minor image version:0x%04X\n"
      "Major subsystem version:0x%04X\n"
      "Minor subsystem version:0x%04X\n"
      "Win32 version value:0x%08X\n"
      "Size of image:0x%08X\n"
      "Size of headers:0x%08X\n"
      "Check sum:0x%08X\n"
      "Subsystem:0x%04X\n",
      pOPT32->MajorLinkerVersion,
      pOPT32->MinorLinkerVersion,
      pOPT32->SizeOfCode,
      pOPT32->SizeOfInitializedData,
      pOPT32->SizeOfUninitializedData,
      pOPT32->AddressOfEntryPoint,
      pOPT32->BaseOfCode,
      pOPT32->BaseOfData,
      pOPT32->ImageBase,
      pOPT32->SectionAlignment,
      pOPT32->FileAlignment,
      pOPT32->MajorOperatingSystemVersion,
      pOPT32->MinorOperatingSystemVersion,
      pOPT32->MajorImageVersion,
      pOPT32->MinorImageVersion,
      pOPT32->MajorSubsystemVersion,
      pOPT32->MinorSubsystemVersion,
      pOPT32->Win32VersionValue,
      pOPT32->SizeOfImage,
      pOPT32->SizeOfHeaders,
      pOPT32->CheckSum,
      pOPT32->Subsystem);

    //打印子系统
    switch(pOPT32->Subsystem)
    {
    default:
    case IMAGE_SUBSYSTEM_UNKNOWN:
      fputs("\tUnknown subsystem.\n",stdout);
      break;
    case IMAGE_SUBSYSTEM_NATIVE:
      fputs("\tImage doesn't require a subsystem.\n",stdout);
      break;
    case IMAGE_SUBSYSTEM_WINDOWS_GUI:
      fputs("\tImage runs in the Windows GUI subsystem.\n",stdout);
      break;
    case IMAGE_SUBSYSTEM_WINDOWS_CUI:
      fputs("\tImage runs in the Windows character subsystem.\n",stdout);
      break;
    case IMAGE_SUBSYSTEM_OS2_CUI:
      fputs("\timage runs in the OS/2 character subsystem.\n",stdout);
      break;
    case IMAGE_SUBSYSTEM_POSIX_CUI:
      fputs("\timage runs in the Posix character subsystem.\n",stdout);
      break;
    case IMAGE_SUBSYSTEM_NATIVE_WINDOWS:
      fputs("\timage is a native Win9x driver.\n",stdout);
      break;
    case IMAGE_SUBSYSTEM_WINDOWS_CE_GUI:
      fputs("\tImage runs in the Windows CE subsystem.\n",stdout);
      break;
    }

    //打印DLL特性
    printf("Dll characteristics:0x%04X\n",pOPT32->DllCharacteristics);
    if(pOPT32->DllCharacteristics&1)
      fputs("\tDLL_PROCESS_ATTACH\n",stdout);
    if(pOPT32->DllCharacteristics&2)
      fputs("\tDLL_THREAD_ATTACH\n",stdout);
    if(pOPT32->DllCharacteristics&4)
      fputs("\tDLL_THREAD_DETACH\n",stdout);
    if(pOPT32->DllCharacteristics&8)
      fputs("\tDLL_PROCESS_DETACH\n",stdout);
    if(pOPT32->DllCharacteristics&IMAGE_DLLCHARACTERISTICS_WDM_DRIVER)
      fputs("\tWDM_Driver\n",stdout);

    printf(
      "Size of stack reserve:0x%08X\n"
      "Size of stack commit:0x%08X\n"
      "Size of heap reserve:0x%08X\n"
      "Size of heap commit:0x%08X\n"
      "Loader flags:0x%08X\n"
      "Number of RVA and sizes:0x%08X\n"
      "Data directories:\n",
      pOPT32->SizeOfStackReserve,
      pOPT32->SizeOfStackCommit,
      pOPT32->SizeOfHeapReserve,
      pOPT32->SizeOfHeapCommit,
      pOPT32->LoaderFlags,
      pOPT32->NumberOfRvaAndSizes);

    //打印目录表
    for(uDirEntry=0;uDirEntry<pOPT32->NumberOfRvaAndSizes;uDirEntry++)
    {
      printf(
            "%s:\n"
            "Virtual address:0x%08X\tSize:0x%08X\n",
            uDirEntry<sizeof(pDirTableDesc)/sizeof(char*)?
                pDirTableDesc:"Unknown",
            pOPT32->DataDirectory.VirtualAddress,
            pOPT32->DataDirectory.Size);
    }
}

//-----------------------------------------------------------------------------
//读取64位可选头
//-----------------------------------------------------------------------------
void ReadOPT64(FILE*fp)
{
    UINT uDirEntry;
    IMAGE_OPTIONAL_HEADER64*pOPT64=(IMAGE_OPTIONAL_HEADER64*)g_pOPTBuffer;

    printf(
      "Major linker version=0x%02X\n"
      "Minor linker version=0x%02X\n"
      "Size of code=0x%08X\n"
      "Size of initialized data=0x%08X\n"
      "Size of uninitialized data=0x%08X\n"
      "Address of entry point=0x%08X\n"
      "Base of code=0x%08X\n"
      "Image base=0x%016I64X\n"
      "Section alignment=0x%08X\n"
      "File alignment=0x%08X\n"
      "Major operating system version=0x%04X\n"
      "Minor operating system version=0x%04X\n"
      "Major image version=0x%04X\n"
      "Minor image version=0x%04X\n"
      "Major subsystem version=0x%04X\n"
      "Minor subsystem version=0x%04X\n"
      "Win32 version value=0x%08X\n"
      "Size of image=0x%08X\n"
      "Size of headers=0x%08X\n"
      "Check sum=0x%08X\n"
      "Subsystem=0x%04X\n",
      pOPT64->MajorLinkerVersion,
      pOPT64->MinorLinkerVersion,
      pOPT64->SizeOfCode,
      pOPT64->SizeOfInitializedData,
      pOPT64->SizeOfUninitializedData,
      pOPT64->AddressOfEntryPoint,
      pOPT64->BaseOfCode,
      pOPT64->ImageBase,
      pOPT64->SectionAlignment,
      pOPT64->FileAlignment,
      pOPT64->MajorOperatingSystemVersion,
      pOPT64->MinorOperatingSystemVersion,
      pOPT64->MajorImageVersion,
      pOPT64->MinorImageVersion,
      pOPT64->MajorSubsystemVersion,
      pOPT64->MinorSubsystemVersion,
      pOPT64->Win32VersionValue,
      pOPT64->SizeOfImage,
      pOPT64->SizeOfHeaders,
      pOPT64->CheckSum,
      pOPT64->Subsystem);

    //打印子系统
    switch(pOPT64->Subsystem)
    {
    default:
    case IMAGE_SUBSYSTEM_UNKNOWN:
      fputs("\tUnknown subsystem.\n",stdout);
      break;
    case IMAGE_SUBSYSTEM_NATIVE:
      fputs("\tImage doesn't require a subsystem.\n",stdout);
      break;
    case IMAGE_SUBSYSTEM_WINDOWS_GUI:
      fputs("\tImage runs in the Windows GUI subsystem.\n",stdout);
      break;
    case IMAGE_SUBSYSTEM_WINDOWS_CUI:
      fputs("\tImage runs in the Windows character subsystem.\n",stdout);
      break;
    case IMAGE_SUBSYSTEM_OS2_CUI:
      fputs("\timage runs in the OS/2 character subsystem.\n",stdout);
      break;
    case IMAGE_SUBSYSTEM_POSIX_CUI:
      fputs("\timage runs in the Posix character subsystem.\n",stdout);
      break;
    case IMAGE_SUBSYSTEM_NATIVE_WINDOWS:
      fputs("\timage is a native Win9x driver.\n",stdout);
      break;
    case IMAGE_SUBSYSTEM_WINDOWS_CE_GUI:
      fputs("\tImage runs in the Windows CE subsystem.\n",stdout);
      break;
    }

    //打印DLL特性
    printf("Dll characteristics:0x%04X\n",pOPT64->DllCharacteristics);
    if(pOPT64->DllCharacteristics&1)
      fputs("\tDLL_PROCESS_ATTACH\n",stdout);
    if(pOPT64->DllCharacteristics&2)
      fputs("\tDLL_THREAD_ATTACH\n",stdout);
    if(pOPT64->DllCharacteristics&4)
      fputs("\tDLL_THREAD_DETACH\n",stdout);
    if(pOPT64->DllCharacteristics&8)
      fputs("\tDLL_PROCESS_DETACH\n",stdout);
    if(pOPT64->DllCharacteristics&IMAGE_DLLCHARACTERISTICS_WDM_DRIVER)
      fputs("\tWDM_Driver\n",stdout);
    printf(
      "Size of stack reserve=0x%016I64X\n"
      "Size of stack commit=0x%016I64X\n"
      "Size of heap reserve=0x%016I64X\n"
      "Size of heap commit=0x%016I64X\n"
      "Loader flags=0x%08X\n"
      "Number of RVA and sizes=0x%08X\n",
      pOPT64->SizeOfStackReserve,
      pOPT64->SizeOfStackCommit,
      pOPT64->SizeOfHeapReserve,
      pOPT64->SizeOfHeapCommit,
      pOPT64->LoaderFlags,
      pOPT64->NumberOfRvaAndSizes);

    //打印目录表
    for(uDirEntry=0;uDirEntry<pOPT64->NumberOfRvaAndSizes;uDirEntry++)
    {
      printf(
            "%s:\n"
            "Virtual address:0x%08X\tSize:0x%08X\n",
            uDirEntry<sizeof(pDirTableDesc)/sizeof(char*)?
                pDirTableDesc:"Unknown",
            pOPT64->DataDirectory.VirtualAddress,
            pOPT64->DataDirectory.Size);
    }
}

//-----------------------------------------------------------------------------
//读取ROM的可选头
//-----------------------------------------------------------------------------
void ReadROMOPT(FILE*fp)
{
    IMAGE_ROM_OPTIONAL_HEADER*pROMOPT=(IMAGE_ROM_OPTIONAL_HEADER*)g_pOPTBuffer;
    printf(
      "Major linker version=0x%02X\n"
      "Minor linker version=0x%02X\n"
      "Size of code=0x%08X\n"
      "Size of initializedData=0x%08X\n"
      "Size of uninitializedData=0x%08X\n"
      "Address of entry point=0x%08X\n"
      "Base of code=0x%08X\n"
      "Base of data=0x%08X\n"
      "Base of bss=0x%08X\n"
      "Gpr mask=0x%08X\n"
      "Cpr mask:\n"
      "\t0x%08X\n"
      "\t0x%08X\n"
      "\t0x%08X\n"
      "\t0x%08X\n"
      "Gp value0x%08X\n",
      "MajorLinkerVersion=0x%02X\n",
      pROMOPT->MinorLinkerVersion,
      pROMOPT->SizeOfCode,
      pROMOPT->SizeOfInitializedData,
      pROMOPT->SizeOfUninitializedData,
      pROMOPT->AddressOfEntryPoint,
      pROMOPT->BaseOfCode,
      pROMOPT->BaseOfData,
      pROMOPT->BaseOfBss,
      pROMOPT->GprMask,
      pROMOPT->CprMask,
      pROMOPT->CprMask,
      pROMOPT->CprMask,
      pROMOPT->CprMask,
      pROMOPT->GpValue);
}

//-----------------------------------------------------------------------------
//读取段落头(会分配内存给段落头)
//-----------------------------------------------------------------------------
void ReadSegH(FILE*fp)
{
    char szBuf={0};
    WORD wSeg=g_PEH.NumberOfSections;

    g_pSecH=(IMAGE_SECTION_HEADER*)malloc(g_PEH.NumberOfSections*sizeof(IMAGE_SECTION_HEADER));
    if(g_pSecH)
    {
      IMAGE_SECTION_HEADER*pSecH=g_pSecH;
      while(wSeg--)//读取所有段落头
      {
            fread(pSecH,1,sizeof(IMAGE_SECTION_HEADER),fp);
            memcpy(szBuf,pSecH->Name,IMAGE_SIZEOF_SHORT_NAME);//复制名字

            printf(
                "--------------------------------Section headers--------------------------------\n"
                "Name:%s\n"
                "Physical address\\Virtual size:0x%08X\n"
                "Virtual address:0x%08X\n"
                "Size of raw data:0x%08X\n"
                "Pointer to raw data:0x%08X\n"
                "Pointer to relocations:0x%08X\n"
                "Pointer to linenumbers:0x%08X\n"
                "Number of relocations:0x%04X\n"
                "Number of linenumbers:0x%04X\n"
                "Characteristics:0x%08X\n",
                szBuf,
                pSecH->Misc.PhysicalAddress,
                pSecH->VirtualAddress,
                pSecH->SizeOfRawData,
                pSecH->PointerToRawData,
                pSecH->PointerToRelocations,
                pSecH->PointerToLinenumbers,
                pSecH->NumberOfRelocations,
                pSecH->NumberOfLinenumbers,
                pSecH->Characteristics);

            //打印段落特性
            if(pSecH->Characteristics&IMAGE_SCN_TYPE_NO_PAD)
                fputs("IMAGE_SCN_TYPE_NO_PAD\n",stdout);
            if(pSecH->Characteristics&IMAGE_SCN_CNT_CODE)
                fputs("IMAGE_SCN_CNT_CODE\n",stdout);
            if(pSecH->Characteristics&IMAGE_SCN_CNT_INITIALIZED_DATA)
                fputs("IMAGE_SCN_CNT_INITIALIZED_DATA\n",stdout);
            if(pSecH->Characteristics&IMAGE_SCN_CNT_UNINITIALIZED_DATA)
                fputs("IMAGE_SCN_CNT_UNINITIALIZED_DATA\n",stdout);
            if(pSecH->Characteristics&IMAGE_SCN_LNK_OTHER)
                fputs("IMAGE_SCN_LNK_OTHER\n",stdout);
            if(pSecH->Characteristics&IMAGE_SCN_LNK_INFO)
                fputs("IMAGE_SCN_LNK_INFO\n",stdout);
            if(pSecH->Characteristics&IMAGE_SCN_LNK_REMOVE)
                fputs("IMAGE_SCN_LNK_REMOVE\n",stdout);
            if(pSecH->Characteristics&IMAGE_SCN_LNK_COMDAT)
                fputs("IMAGE_SCN_LNK_COMDAT\n",stdout);
            if(pSecH->Characteristics&IMAGE_SCN_NO_DEFER_SPEC_EXC)
                fputs("IMAGE_SCN_NO_DEFER_SPEC_EXC\n",stdout);
            if(pSecH->Characteristics&IMAGE_SCN_GPREL)
                fputs("IMAGE_SCN_GPREL\n",stdout);
            if(pSecH->Characteristics&IMAGE_SCN_MEM_FARDATA)
                fputs("IMAGE_SCN_MEM_FARDATA\n",stdout);
            if(pSecH->Characteristics&IMAGE_SCN_MEM_PURGEABLE)
                fputs("IMAGE_SCN_MEM_PURGEABLE\n",stdout);
            if(pSecH->Characteristics&IMAGE_SCN_MEM_16BIT)
                fputs("IMAGE_SCN_MEM_16BIT\n",stdout);
            if(pSecH->Characteristics&IMAGE_SCN_MEM_LOCKED)
                fputs("IMAGE_SCN_MEM_LOCKED\n",stdout);
            if(pSecH->Characteristics&IMAGE_SCN_MEM_PRELOAD)
                fputs("IMAGE_SCN_MEM_PRELOAD\n",stdout);
            if(pSecH->Characteristics&IMAGE_SCN_ALIGN_1BYTES)
                fputs("IMAGE_SCN_ALIGN_1BYTES\n",stdout);
            if(pSecH->Characteristics&IMAGE_SCN_ALIGN_2BYTES)
                fputs("IMAGE_SCN_ALIGN_2BYTES\n",stdout);
            if(pSecH->Characteristics&IMAGE_SCN_ALIGN_4BYTES)
                fputs("IMAGE_SCN_ALIGN_4BYTES\n",stdout);
            if(pSecH->Characteristics&IMAGE_SCN_ALIGN_8BYTES)
                fputs("IMAGE_SCN_ALIGN_8BYTES\n",stdout);
            if(pSecH->Characteristics&IMAGE_SCN_ALIGN_16BYTES)
                fputs("IMAGE_SCN_ALIGN_16BYTES\n",stdout);
            if(pSecH->Characteristics&IMAGE_SCN_ALIGN_32BYTES)
                fputs("IMAGE_SCN_ALIGN_32BYTES\n",stdout);
            if(pSecH->Characteristics&IMAGE_SCN_ALIGN_64BYTES)
                fputs("IMAGE_SCN_ALIGN_64BYTES\n",stdout);
            if(pSecH->Characteristics&IMAGE_SCN_ALIGN_128BYTES)
                fputs("IMAGE_SCN_ALIGN_128BYTES\n",stdout);
            if(pSecH->Characteristics&IMAGE_SCN_ALIGN_256BYTES)
                fputs("IMAGE_SCN_ALIGN_256BYTES\n",stdout);
            if(pSecH->Characteristics&IMAGE_SCN_ALIGN_512BYTES)
                fputs("IMAGE_SCN_ALIGN_512BYTES\n",stdout);
            if(pSecH->Characteristics&IMAGE_SCN_ALIGN_1024BYTES)
                fputs("IMAGE_SCN_ALIGN_1024BYTES\n",stdout);
            if(pSecH->Characteristics&IMAGE_SCN_ALIGN_2048BYTES)
                fputs("IMAGE_SCN_ALIGN_2048BYTES\n",stdout);
            if(pSecH->Characteristics&IMAGE_SCN_ALIGN_4096BYTES)
                fputs("IMAGE_SCN_ALIGN_4096BYTES\n",stdout);
            if(pSecH->Characteristics&IMAGE_SCN_ALIGN_8192BYTES)
                fputs("IMAGE_SCN_ALIGN_8192BYTES\n",stdout);
            if(pSecH->Characteristics&IMAGE_SCN_LNK_NRELOC_OVFL)
                fputs("IMAGE_SCN_LNK_NRELOC_OVFL\n",stdout);
            if(pSecH->Characteristics&IMAGE_SCN_MEM_DISCARDABLE)
                fputs("IMAGE_SCN_MEM_DISCARDABLE\n",stdout);
            if(pSecH->Characteristics&IMAGE_SCN_MEM_NOT_CACHED)
                fputs("IMAGE_SCN_MEM_NOT_CACHED\n",stdout);
            if(pSecH->Characteristics&IMAGE_SCN_MEM_NOT_PAGED)
                fputs("IMAGE_SCN_MEM_NOT_PAGED\n",stdout);
            if(pSecH->Characteristics&IMAGE_SCN_MEM_SHARED)
                fputs("IMAGE_SCN_MEM_SHARED\n",stdout);
            if(pSecH->Characteristics&IMAGE_SCN_MEM_EXECUTE)
                fputs("IMAGE_SCN_MEM_EXECUTE\n",stdout);
            if(pSecH->Characteristics&IMAGE_SCN_MEM_READ)
                fputs("IMAGE_SCN_MEM_READ\n",stdout);
            if(pSecH->Characteristics&IMAGE_SCN_MEM_WRITE)
                fputs("IMAGE_SCN_MEM_WRITE\n",stdout);
            pSecH++;
      }
    }
}

//-----------------------------------------------------------------------------
//把RVA转换成文件内偏移的函数
//需要给出所有的段落头,以及段落头数量
//-----------------------------------------------------------------------------
DWORD RvaToFileOffset(DWORD dwRVA,IMAGE_SECTION_HEADER*pSecHeaders,DWORD dwNbSections)
{
    while(dwNbSections--)//遍历所有段
    {
      if(dwRVA>=pSecHeaders->VirtualAddress &&
            dwRVA<=pSecHeaders->VirtualAddress+pSecHeaders->SizeOfRawData)//在段内
            return dwRVA+pSecHeaders->PointerToRawData-pSecHeaders->VirtualAddress;//取得文件内偏移
      pSecHeaders++;//找下一个段
    }
    return dwRVA;//不在所有的段内,则返回原数值。
}

void ReadExport(FILE*fp,IMAGE_DATA_DIRECTORY*pDir);
void ReadImport(FILE*fp,IMAGE_DATA_DIRECTORY*pDir);
void ReadResource(FILE*fp,IMAGE_DATA_DIRECTORY*pDir);

//-----------------------------------------------------------------------------
//读取目录表
//-----------------------------------------------------------------------------
void ReadDirEntry(FILE*fp,DWORD dwNumRvaAndSizes,IMAGE_DATA_DIRECTORY*pDir)
{
    if(dwNumRvaAndSizes>IMAGE_DIRECTORY_ENTRY_EXPORT)//如果有输出表
      ReadExport(fp,pDir++);//读取输出表
    if(dwNumRvaAndSizes>IMAGE_DIRECTORY_ENTRY_IMPORT)//如果有输入表
      ReadImport(fp,pDir++);//读取输入表
    if(dwNumRvaAndSizes>IMAGE_DIRECTORY_ENTRY_RESOURCE)//如果有资源表
      ReadResource(fp,pDir++);//读取资源表
}

//-----------------------------------------------------------------------------
//读取输出表
//-----------------------------------------------------------------------------
void ReadExport(FILE*fp,IMAGE_DATA_DIRECTORY*pDir)
{
    long lCurPos=ftell(fp);//记住当前文件指针
    IMAGE_EXPORT_DIRECTORY ExpDir;
    char    szName;
    DWORD   *pFuncAddr=NULL,
            *pNameAddr=NULL;
    WORD    *pOrdinalAddr=NULL;
    long    SizeOfFuncAddrs,
            SizeOfNameAddrs,
            SizeOfOrdinalAddrs;

    if(!pDir->VirtualAddress||!pDir->Size)
      return;

    fseek(fp,RvaToFileOffset(pDir->VirtualAddress,g_pSecH,g_PEH.NumberOfSections),SEEK_SET);
    fread(&ExpDir,1,sizeof(ExpDir),fp);//先读取IMAGE_EXPORT_DIRECTORY这个结构体

    printf(
      "-------------------------------Export directory--------------------------------\n"
      "Characteristics=0x%08X\n"
      "Time date stamp=0x%08X\n"
      "Major version=0x%04X\n"
      "Minor version=0x%04X\n"
      "Name=0x%08X\n"
      "Base=0x%08X\n"
      "Number of functions=0x%08X\n"
      "Number of names=0x%08X\n"
      "Address of functions=0x%08X\n"
      "Address of names=0x%08X\n"
      "Address of name ordinals=0x%08X\n",
      ExpDir.Characteristics,
      ExpDir.TimeDateStamp,
      ExpDir.MajorVersion,
      ExpDir.MinorVersion,
      ExpDir.Name,
      ExpDir.Base,
      ExpDir.NumberOfFunctions,
      ExpDir.NumberOfNames,
      ExpDir.AddressOfFunctions,
      ExpDir.AddressOfNames,
      ExpDir.AddressOfNameOrdinals);

    //打印名字
    fseek(fp,RvaToFileOffset(ExpDir.Name,g_pSecH,g_PEH.NumberOfSections),SEEK_SET);
    fgets(szName,sizeof(szName),fp);
    printf("Export name:%s\n",szName);

    pFuncAddr=malloc(SizeOfFuncAddrs=ExpDir.NumberOfFunctions*sizeof(DWORD));//函数地址表
    pNameAddr=malloc(SizeOfNameAddrs=ExpDir.NumberOfNames*sizeof(DWORD));//函数名表
    pOrdinalAddr=malloc(SizeOfOrdinalAddrs=ExpDir.NumberOfNames*sizeof(WORD));
    if(pFuncAddr&&pNameAddr&&pOrdinalAddr)//分配到了内存
    {
      DWORD i;

      fseek(fp,RvaToFileOffset(ExpDir.AddressOfFunctions,g_pSecH,g_PEH.NumberOfSections),SEEK_SET);
      fread(pFuncAddr,1,SizeOfFuncAddrs,fp);//读取函数地址表

      fseek(fp,RvaToFileOffset(ExpDir.AddressOfNames,g_pSecH,g_PEH.NumberOfSections),SEEK_SET);
      fread(pNameAddr,1,SizeOfNameAddrs,fp);//读取名称地址表

      fseek(fp,RvaToFileOffset(ExpDir.AddressOfNameOrdinals,g_pSecH,g_PEH.NumberOfSections),SEEK_SET);
      fread(pOrdinalAddr,1,SizeOfOrdinalAddrs,fp);//读取名称地址表

      fputs("Index\t\tAddress\t\tName\n",stdout);
      for(i=0;i<ExpDir.NumberOfNames;i++)//打印所有函数的序号、地址、名称
      {
            char szFunction;
            DWORD dwIndex=pOrdinalAddr;
            fseek(fp,RvaToFileOffset(pNameAddr,g_pSecH,g_PEH.NumberOfSections),SEEK_SET);
            fgets(szFunction,sizeof(szFunction),fp);//读取函数名
            printf("0x%04X\t0x%08X\t%s\n",dwIndex+1,pFuncAddr,szFunction);
      }
      while(i<ExpDir.NumberOfFunctions)//打印剩余没有名称的函数的序号、地址
      {
            printf("<??? >\t0x%08X\t<No name>\n",pFuncAddr);
            i++;
      }
    }
    else
      fputs("No enough memory.\n",stderr);
    free(pFuncAddr);
    free(pNameAddr);
    free(pOrdinalAddr);

    fseek(fp,lCurPos,SEEK_SET);//恢复文件指针
}

//-----------------------------------------------------------------------------
//读取输入表
//-----------------------------------------------------------------------------
void ReadImport(FILE*fp,IMAGE_DATA_DIRECTORY*pDir)
{
    long lCurPos=ftell(fp);//记住当前文件指针
    DWORD dwStartOffset=RvaToFileOffset(pDir->VirtualAddress,g_pSecH,g_PEH.NumberOfSections);//输入表的开始位置

    if(!pDir->VirtualAddress||!pDir->Size)
      return;

    for(;;)//有多个输入表需要顺序读取
    {
      IMAGE_IMPORT_DESCRIPTOR ImpDir;//输入表
      char szName;//名字
      DWORD dwThunkDataBegin;//输入表起始位置
      DWORD dwThunkAddressBegin;//输入表函数起始位置

      fseek(fp,dwStartOffset,SEEK_SET);
      fread(&ImpDir,1,sizeof(ImpDir),fp);//读取输入表

      if( !ImpDir.OriginalFirstThunk &&
            !ImpDir.TimeDateStamp &&
            !ImpDir.ForwarderChain &&
            !ImpDir.Name &&
            !ImpDir.FirstThunk)//如果没有表了
            break;//退出循环

      printf(
            "-------------------------------Import Descriptor-------------------------------\n"
            "RVA to original unbound IAT:0x%08X\n"
            "Date/time stamp of DLL bound to:0x%08X\n"
            "Forwarder chain:0x%08X\n"
            "Name:0x%08X\n"
            "First thunk:0x%08X\n",
            ImpDir.OriginalFirstThunk,
            ImpDir.TimeDateStamp,
            ImpDir.ForwarderChain,
            ImpDir.Name,
            ImpDir.FirstThunk);//打印表的信息

      //输出导入的DLL的名字
      fseek(fp,RvaToFileOffset(ImpDir.Name,g_pSecH,g_PEH.NumberOfSections),SEEK_SET);
      fgets(szName,sizeof(szName),fp);
      printf("Name:%s\n",szName);

      //读取IMAGE_THUNK_DATA
      dwThunkDataBegin=RvaToFileOffset(ImpDir.OriginalFirstThunk,g_pSecH,g_PEH.NumberOfSections);
      dwThunkAddressBegin=RvaToFileOffset(ImpDir.FirstThunk,g_pSecH,g_PEH.NumberOfSections);

      //32位和64位有不同的处理方式
      switch(*(WORD*)g_pOPTBuffer)
      {
      case IMAGE_NT_OPTIONAL_HDR32_MAGIC://读取32位的IMAGE_THUNK_DATA
            fputs("Ordinal\tAddress\t\tName\n",stdout);
            for(;;dwThunkDataBegin+=sizeof(IMAGE_THUNK_DATA32),dwThunkAddressBegin+=sizeof(IMAGE_THUNK_DATA32))
            {
                IMAGE_THUNK_DATA32 ThunkData;
                IMAGE_THUNK_DATA32 ThunkAddress;

                fseek(fp,dwThunkDataBegin,SEEK_SET);
                fread(&ThunkData,1,sizeof(ThunkData),fp);

                if(!ThunkData.u1.Ordinal)//如果没有表了
                  break;//退出循环

                if(ThunkData.u1.Ordinal&IMAGE_ORDINAL_FLAG32)//如果是通过序号导入的
                {
                  fseek(fp,dwThunkAddressBegin,SEEK_SET);//找到地址
                  fread(&ThunkAddress,1,sizeof(ThunkAddress),fp);//读取地址

                  printf("0x%04X\t0x%08X\t<No name>\n",IMAGE_ORDINAL32(ThunkData.u1.Ordinal),ThunkAddress.u1.Function);//显示序号
                }
                else//否则是通过名称导入的
                {
                  WORD wHint;
                  char szFunc;

                  fseek(fp,RvaToFileOffset((DWORD)(ThunkData.u1.AddressOfData),g_pSecH,g_PEH.NumberOfSections),SEEK_SET);
                  fread(&wHint,1,sizeof(wHint),fp);//读取序号
                  fgets(szFunc,sizeof(szFunc),fp);//读取名字

                  fseek(fp,dwThunkAddressBegin,SEEK_SET);//找到地址
                  fread(&ThunkAddress,1,sizeof(ThunkAddress),fp);//读取地址

                  printf("0x%04X\t0x%08X\t%s\n",wHint,ThunkAddress.u1.Function,szFunc);
                }
            }
            break;
      case IMAGE_NT_OPTIONAL_HDR64_MAGIC://读取64位的IMAGE_THUNK_DATA
            fputs("Ordinal\tAddress\t\tName\n",stdout);
            for(;;dwThunkDataBegin+=sizeof(IMAGE_THUNK_DATA64),dwThunkAddressBegin+=sizeof(IMAGE_THUNK_DATA64))
            {
                IMAGE_THUNK_DATA64 ThunkData;
                IMAGE_THUNK_DATA64 ThunkAddress;

                fseek(fp,dwThunkDataBegin,SEEK_SET);
                fread(&ThunkData,1,sizeof(ThunkData),fp);

                if(!ThunkData.u1.Ordinal)//如果没有表了
                  break;//退出循环

                if(ThunkData.u1.Ordinal&IMAGE_ORDINAL_FLAG64)//如果是通过序号导入的
                {
                  fseek(fp,dwThunkAddressBegin,SEEK_SET);//找到地址
                  fread(&ThunkAddress,1,sizeof(ThunkAddress),fp);//读取地址

                  printf("0x%04X\t0x%08X\t<No name>\n",IMAGE_ORDINAL64(ThunkData.u1.Ordinal),ThunkAddress.u1.Function);//显示序号
                }
                else//否则是通过名称导入的
                {
                  WORD wHint;
                  char szFunc;

                  fseek(fp,RvaToFileOffset((DWORD)(ThunkData.u1.AddressOfData),g_pSecH,g_PEH.NumberOfSections),SEEK_SET);
                  fread(&wHint,1,sizeof(wHint),fp);//读取序号
                  fgets(szFunc,sizeof(szFunc),fp);//读取名字

                  fseek(fp,dwThunkAddressBegin,SEEK_SET);//找到地址
                  fread(&ThunkAddress,1,sizeof(ThunkAddress),fp);//读取地址

                  printf("0x%04X\t0x%016I64X\t%s\n",wHint,(ULONGLONG)(ThunkAddress.u1.Function),szFunc);
                }
            }
            break;
      }
      dwStartOffset+=sizeof(IMAGE_IMPORT_DESCRIPTOR);//准备读取下一个输入表
    }
    fseek(fp,lCurPos,SEEK_SET);//恢复文件指针
}

void ReadResDirEntry(FILE*fp,DWORD dwResourceBegin,DWORD dwOffset,UINT uLevel);
#define TREE_TAB    4   /*资源树的缩进量*/
#define TREE_CHAR   ' ' /*资源树的缩进字符*/

//-----------------------------------------------------------------------------
//读取整个资源表
//-----------------------------------------------------------------------------
void ReadResource(FILE*fp,IMAGE_DATA_DIRECTORY*pDir)
{
    long lCurPos=ftell(fp);//记住当前文件指针

    if(!pDir->VirtualAddress||!pDir->Size)
      return;

    fputs("-----------------------------Resource Directory--------------------------------\n",stdout);
    //因为是树形结构所以需要递归读取
    ReadResDirEntry(fp,RvaToFileOffset(pDir->VirtualAddress,g_pSecH,g_PEH.NumberOfSections),0,0);

    fseek(fp,lCurPos,SEEK_SET);//恢复文件指针
}

//-----------------------------------------------------------------------------
//读取资源树形结构
//-----------------------------------------------------------------------------
void ReadResDirEntry(FILE*fp,DWORD dwResourceBegin,DWORD dwOffset,UINT uLevel)
{
    IMAGE_RESOURCE_DIRECTORY RcDir;
    DWORD dwEntries,dwNbEntries;
    long lBeginOfEntry;
    char*szLevelPrefix;
    unsigned uTabs=uLevel*TREE_TAB;

    fseek(fp,dwResourceBegin+dwOffset,SEEK_SET);
    fread(&RcDir,1,sizeof(RcDir),fp);//先读取IMAGE_RESOURCE_DIRECTORY这个结构体

    szLevelPrefix=(char*)malloc(uTabs+1);//分级的一个前缀
    if(!szLevelPrefix)//在这个尴尬的时候内存不足的话不好处理,所以直接退出
    {
      fputs("No enough memory.\n",stderr);
      return;
    }

    memset(szLevelPrefix,TREE_CHAR,uTabs);//前面填充空格
    szLevelPrefix=0;//结尾的\0

    printf(
      "%sCharacteristics:0x%08X\n"
      "%sTime date stamp:0x%08X\n"
      "%sMajor version:0x%04X\n"
      "%sMinor version:0x%04X\n"
      "%sNumber of named entries:0x%04X\n"
      "%sNumber of id entries:0x%04X\n",
      szLevelPrefix,RcDir.Characteristics,
      szLevelPrefix,RcDir.TimeDateStamp,
      szLevelPrefix,RcDir.MajorVersion,
      szLevelPrefix,RcDir.MinorVersion,
      szLevelPrefix,RcDir.NumberOfNamedEntries,
      szLevelPrefix,RcDir.NumberOfIdEntries);//打印结构体

    //紧接着这个结构体的是名字项和ID项
    lBeginOfEntry=ftell(fp);
    dwNbEntries=RcDir.NumberOfNamedEntries+RcDir.NumberOfIdEntries;//取得总项数

    //读取所有项
    for(dwEntries=0;dwEntries<dwNbEntries;dwEntries++)
    {
      IMAGE_RESOURCE_DIRECTORY_ENTRY RcDirEntry;

      fseek(fp,lBeginOfEntry+dwEntries*sizeof(RcDirEntry),SEEK_SET);//先读取项
      fread(&RcDirEntry,1,sizeof(RcDirEntry),fp);

      //先打印资源的名字或ID
      if(RcDirEntry.NameIsString)//如果是名字
      {
            WORD wLength;
            WCHAR*pszName;

            //读取名称长度
            fseek(fp,dwResourceBegin+RcDirEntry.NameOffset,SEEK_SET);
            fread(&wLength,1,sizeof(wLength),fp);

            //分配内存读取名称
            pszName=(WCHAR*)malloc((wLength+1)*sizeof(WCHAR));
            if(pszName)
            {
                pszName=0;
                fread(pszName,1,wLength*sizeof(WCHAR),fp);
                printf("%sName:%S\n",szLevelPrefix,pszName);
                free(pszName);
            }
            else
                fputs("No enough memory.\n",stderr);
      }
      else//否则是ID
            printf("%sID:0x%08X\n",szLevelPrefix,RcDirEntry.Id);

      //然后打印资源的下一级内容
      if(RcDirEntry.DataIsDirectory)//如果下一级是一个子目录表
            ReadResDirEntry(fp,dwResourceBegin,RcDirEntry.OffsetToDirectory,uLevel+1);//递归查找
      else
      {
            //指向数据。
            IMAGE_RESOURCE_DATA_ENTRY DataEntry;

            //读取数据表
            fseek(fp,dwResourceBegin+RcDirEntry.OffsetToData,SEEK_SET);
            fread(&DataEntry,1,sizeof(DataEntry),fp);

            //打印数据信息
            printf(
                "%sOffsetToData:0x%08X\n"
                "%sSize:0x%08X\n"
                "%sCodePage:0x%08X\n",
                szLevelPrefix,DataEntry.OffsetToData,
                szLevelPrefix,DataEntry.Size,
                szLevelPrefix,DataEntry.CodePage);
      }
    }
    free(szLevelPrefix);
}

//-----------------------------------------------------------------------------
//程序入口点
//-----------------------------------------------------------------------------
int main(int argc,char**argv)
{
    FILE*fp;
    if(argc<2)
    {
      Usage();
      return 1;
    }
    fp=fopen(argv,"rb");
    if(!fp)
    {
      printf("Unable to open %s.\n",argv);
      return 1;
    }

    //PE文件第一个文件头:DOS EXE头
    ReadDOSH(fp);

    //PE文件第二个头:PE头
    if(g_DOSH.e_lfanew)//如果有新EXE头(PE、LE、NE等)
    {
      DWORD dwMagicNumber;
      fseek(fp,g_DOSH.e_lfanew,SEEK_SET);//转到新EXE头
      fread(&dwMagicNumber,1,sizeof(dwMagicNumber),fp);//读取标记
      if(dwMagicNumber==IMAGE_NT_SIGNATURE)//如果是PE头
      {
            //PE头
            ReadPEH(fp);

            //PE可选标头
            if(g_PEH.SizeOfOptionalHeader)//如果有可选标头
            {
                g_pOPTBuffer=malloc(g_PEH.SizeOfOptionalHeader);
                if(g_pOPTBuffer)
                {
                  fputs("Optional header:\n",stdout);
                  fread(g_pOPTBuffer,1,g_PEH.SizeOfOptionalHeader,fp);//读取
                  switch(*(WORD*)g_pOPTBuffer)//读取魔法数字
                  {
                  case IMAGE_NT_OPTIONAL_HDR32_MAGIC:
                        fputs("-----------------------------32 bit optional header----------------------------\n",stdout);
                        ReadOPT32(fp);
                        break;
                  case IMAGE_NT_OPTIONAL_HDR64_MAGIC:
                        fputs("-----------------------------64 bit optional header----------------------------\n",stdout);
                        ReadOPT64(fp);
                        break;
                  case IMAGE_ROM_OPTIONAL_HDR_MAGIC:
                        fputs("-----------------------------Rom optional header-------------------------------\n",stdout);
                        ReadROMOPT(fp);
                        break;
                  default:
                        fputs("Unknown optional header.\n",stdout);
                        break;
                  }
                  ReadSegH(fp);//读取区段
                  switch(*(WORD*)g_pOPTBuffer)//读取导入、导出表(需要在读取区段后读取。)
                  {
                  case IMAGE_NT_OPTIONAL_HDR32_MAGIC:
                        ReadDirEntry(fp,((IMAGE_OPTIONAL_HEADER32*)g_pOPTBuffer)->NumberOfRvaAndSizes,((IMAGE_OPTIONAL_HEADER32*)g_pOPTBuffer)->DataDirectory);
                        break;
                  case IMAGE_NT_OPTIONAL_HDR64_MAGIC:
                        ReadDirEntry(fp,((IMAGE_OPTIONAL_HEADER64*)g_pOPTBuffer)->NumberOfRvaAndSizes,((IMAGE_OPTIONAL_HEADER64*)g_pOPTBuffer)->DataDirectory);
                        break;
                  }
                  free(g_pOPTBuffer);g_pOPTBuffer=NULL;
                  free(g_pSecH);g_pSecH=NULL;
                }
                else
                  fputs("No enough memory for reading the optional header.\n",stderr);
            }
      }
      else
            fputs("PrintPE is only for PE files.\n",stderr);
    }
    fclose(fp);
    return 0;
}
代码有点长。。。
下载地址:**** Hidden Message *****

0xAA55 发表于 2014-4-27 03:55:07

二楼放出PrintPE对一些经典的PE文件进行解析的结果。
Kernel32.dll(32位)
User32.dll(32位)
GDI32.dll(32位)
shell32.dll(32位。这个资源多)
虽然都是重定向得到的TXT,但是因为文本实在太大,没敢放上来。

其中分析耗时最大的是shell32.dll,输出需要大约0.5秒(重定向到文件的话)。

Golden Blonde 发表于 2014-4-27 08:05:06

先顶一下,清醒之后再看代码。

元始天尊 发表于 2014-4-27 10:58:54

顶了

FFFFFFFE 发表于 2014-5-3 23:00:28

学习一下

Maing 发表于 2014-5-9 14:10:35

真的假的,不过还是先谢了

0xAA55 发表于 2014-5-9 14:23:11

mayl8822 发表于 2014-5-9 06:10
真的假的,不过还是先谢了

这个时候我发个假的做什么?

__star__ 发表于 2014-6-9 10:04:02

这个真不错,很详细,AA55费心了

tomatogege 发表于 2014-9-2 23:00:58

下载来看看

Battle 发表于 2014-11-16 22:57:40

好东西,顶起来看看!

唐凌 发表于 2017-9-15 23:22:50

路过。。。

oshi 发表于 2017-9-19 06:06:23

好长的代码.功能强大

oshi 发表于 2017-9-19 06:09:59

问题是想下载宅币它不足够呀.

0xAA55 发表于 2017-9-19 08:25:52

oshi 发表于 2017-9-19 06:09
问题是想下载宅币它不足够呀.

源码都直接贴出来了你还要下载工程干啥?

bigwind 发表于 2017-9-19 17:53:51

代码有点长

dsm 发表于 2018-1-18 15:49:49

很好,学习下

watermelon 发表于 2019-2-16 11:05:12

顶,orz。

loading 发表于 2023-5-8 19:49:06

我来学习新姿势了:handshake

gujin163 发表于 2023-5-9 17:46:18


感谢楼主分享,顶贴支持
页: [1]
查看完整版本: 【C】新PE文件查看器PrintPE源代码及下载