用C写的一个PE分析工具(含源码)
程序功能概述:可以显示DOS头,PE头,区块表,输入表,输出表

欢迎兄弟们反馈BUG,多多提意见 


代码:
//**************************************************************
//Name:PE Info Detector
//Code:by 鹭影依凌
//**************************************************************
#include "stdio.h"
#include "windows.h"

//**************************************************************
//全局变量声明
//**************************************************************
FILE *p;                  //文件对象
UINT myCurFileOffset;     //当前指针
UINT myCurVirtOffset;     //虚拟地址
UINT i;                   //循环计数器

//**************************************************************
//全局函数声明
//**************************************************************
//@ChgRvaToFileOffset:    功能:虚拟地址转化为文件的物理地址
//VirtualOffset:          虚拟地址
//sectionVirtOffset:      当前节的虚拟地址
//sectionFileOffset:      当前节的物理地址       
//@NumOfFunc:             区段的数目
UINT ChgRvaToFileOffset(UINT VirtualOffset,UINT sectionVirtOffset[],UINT sectionFileOffset[],UINT NumOfFunc);


//**************************************************************
//主函数Main
//**************************************************************
int main()
{  
  //---------------------------
  //PE头变量
  //---------------------------
  IMAGE_DOS_HEADER myDosHeader;                     //DOS头
  
  IMAGE_FILE_HEADER myFileHeader;                   //PE头
    IMAGE_OPTIONAL_HEADER32 myOptionalHeader;         //PE头
  
    //区块表和区块
  IMAGE_SECTION_HEADER mySectionHeader;            //区块表
  
  //数据目录树
  IMAGE_EXPORT_DIRECTORY myExportTable;             //[00]输出表
  IMAGE_IMPORT_DESCRIPTOR myImportTable;            //[01]输入表
  
  
  //***********************************************************
  //打开文件,获取文件对象指针
  //***********************************************************
  char filename[20] = "";                           //文件名
  
  printf("请输入文件名:");
  gets(filename);
  printf("\n");
  p = fopen(filename,"r+b");                        //打开文件
  
  if(p==NULL)
  {
    MessageBox(NULL,"没有找到目标文件","提示",MB_OK);
    return 0;
  }
  
  
  //***********************************************************
  //监测Dos Signature
  //***********************************************************
  WORD myDosSignature;
  
    fseek(p,0,SEEK_SET);
    fread(&myDosSignature,sizeof(WORD),1,p);
  
    if(myDosSignature != IMAGE_DOS_SIGNATURE)
  {
    MessageBox(NULL,"DOS头错误","提示",MB_OK);
    return 0;
  }
  
  
  //***********************************************************
  //读取Dos Header
  //***********************************************************
    fseek(p,0,SEEK_SET);
  fread(&myDosHeader,sizeof(myDosHeader),1,p);  
  //***********************************************************
    printf(";===================================================;\n");
  printf("DOS头结构:\n");
  printf(";---------------------------------------------------;\n");
  printf("e_mageic   : %04X\n",myDosHeader.e_magic);
  printf("e_cblp     : %04X\n",myDosHeader.e_cblp);
  printf("e_cp       : %04X\n",myDosHeader.e_cp);
  printf("e_crlc     : %04X\n",myDosHeader.e_crlc);
  printf("e_cparhdr  : %04X\n",myDosHeader.e_cparhdr);
  printf("e_minalloc : %04X\n",myDosHeader.e_minalloc);
  printf("e_maxalloc : %04X\n",myDosHeader.e_maxalloc);
  printf("e_ss       : %04X\n",myDosHeader.e_ss);
  printf("e_sp       : %04X\n",myDosHeader.e_sp);
  printf("e_csum     : %04X\n",myDosHeader.e_csum);
  printf("e_ip       : %04X\n",myDosHeader.e_ip);
  printf("e_cs       : %04X\n",myDosHeader.e_cs);
  printf("e_lfarlc   : %04X\n",myDosHeader.e_lfarlc);
  printf("e_ovno     : %04X\n",myDosHeader.e_ovno);
  printf("e_res      : %04X\n",myDosHeader.e_res);
  printf("e_oemid    : %04X\n",myDosHeader.e_oemid);
  printf("e_oeminfo  : %04X\n",myDosHeader.e_oeminfo);
  printf("e_res2     : %04X\n",myDosHeader.e_res2);
  printf("e_lfanew   : %04X\n",myDosHeader.e_lfanew);
  
  
  //***********************************************************
  //读取NT SignNature
  //***********************************************************  
  DWORD myNtSignature;
  
  myCurFileOffset = myDosHeader.e_lfanew;                    //修改指针,指向NtHeader.
  
    fseek(p,myCurFileOffset,SEEK_SET);
  fread(&myNtSignature,sizeof(DWORD),1,p);
  
  if(myNtSignature != IMAGE_NT_SIGNATURE)
  {
    MessageBox(NULL,"不是有效PE文件","提示",MB_OK);
    return 0;
  }
  
  
    //***********************************************************
  //读取File Header
  //***********************************************************  
    myCurFileOffset = myDosHeader.e_lfanew + sizeof(DWORD);    //修改指针,指向FileHeader.
  
    fseek(p,myCurFileOffset,SEEK_SET);
  fread(&myFileHeader,sizeof(IMAGE_FILE_HEADER),1,p);
  
    printf(";===================================================;\n");
    printf("IMAGE_File_HEADER 结构:\n");
  printf(";---------------------------------------------------;\n");
  printf("Machine             :%04X \n",myFileHeader.Machine);
  printf("NumberOfSections    :%04X \n",myFileHeader.NumberOfSections);
  printf("TimeDateStamp       :%08X \n",myFileHeader.TimeDateStamp);
  printf("PointerToSymbolTable:%08X \n",myFileHeader.PointerToSymbolTable);
  printf("NumberOfSymbols     :%08X \n",myFileHeader.NumberOfSymbols);
  printf("SizeOfOptionalHeader:%04X \n",myFileHeader.SizeOfOptionalHeader);
  printf("Characteristics     :%04X \n",myFileHeader.Characteristics);
  
  
    //***********************************************************
  //读取Optional Header
  //***********************************************************  
  myCurFileOffset += sizeof(IMAGE_FILE_HEADER);             //修改指针,指向optional header
  
    fseek(p,myCurFileOffset,SEEK_SET);
  fread(&myOptionalHeader,sizeof(myOptionalHeader),1,p);
  
    printf(";===================================================;\n");
    printf("IMAGE_OPTIONAL_HEADER 结构:\n");
  printf(";---------------------------------------------------;\n");
  printf("Magic                       :%04X\n",myOptionalHeader.Magic);
  printf("MajorLinkerVersion          :%04X\n",myOptionalHeader.MajorLinkerVersion);
  printf("MinorLinkerVersion          :%04X\n",myOptionalHeader.MinorLinkerVersion);
    printf("SizeOfCode                  :%04X\n",myOptionalHeader.SizeOfCode);
    printf("SizeOfInitializedData       :%04X\n",myOptionalHeader.SizeOfInitializedData);
    printf("SizeOfUninitializedData     :%04X\n",myOptionalHeader.SizeOfUninitializedData);
    printf("AddressOfEntryPoint         :%04X\n",myOptionalHeader.AddressOfEntryPoint);
    printf("BaseOfCode                  :%04X\n",myOptionalHeader.BaseOfCode);
    printf("BaseOfData                  :%04X\n",myOptionalHeader.BaseOfData);
    // NT additional fields.
    printf("ImageBase                   :%04X\n",myOptionalHeader.ImageBase);
    printf("SectionAlignment            :%04X\n",myOptionalHeader.SectionAlignment);//内存对齐尺寸
    printf("FileAlignment               :%04X\n",myOptionalHeader.FileAlignment);//文件对齐尺寸
    printf("MajorOperatingSystemVersion :%04X\n",myOptionalHeader.MajorOperatingSystemVersion);
    printf("MinorOperatingSystemVersion :%04X\n",myOptionalHeader.MinorOperatingSystemVersion);
    printf("MajorImageVersion           :%04X\n",myOptionalHeader.MajorImageVersion);
    printf("MinorImageVersion           :%04X\n",myOptionalHeader.MinorImageVersion);
    printf("MajorSubsystemVersion       :%04X\n",myOptionalHeader.MajorSubsystemVersion);
    printf("MinorSubsystemVersion       :%04X\n",myOptionalHeader.MinorSubsystemVersion);
    printf("Win32VersionValue           :%04X\n",myOptionalHeader.Win32VersionValue);
    printf("MinorLinkerVersion          :%04X\n",myOptionalHeader.SizeOfImage);
    printf("SizeOfImage                 :%04X\n",myOptionalHeader.SizeOfHeaders);
    printf("CheckSum                    :%04X\n",myOptionalHeader.CheckSum);
    printf("Subsystem                   :%04X\n",myOptionalHeader.Subsystem);
    printf("DllCharacteristics          :%04X\n",myOptionalHeader.DllCharacteristics);
    printf("SizeOfStackReserve          :%04X\n",myOptionalHeader.SizeOfStackReserve);
    printf("SizeOfStackCommit           :%04X\n",myOptionalHeader.SizeOfStackCommit);
    printf("MinorLinkerVersion          :%04X\n",myOptionalHeader.SizeOfHeapReserve);
    printf("SizeOfHeapReserve           :%04X\n",myOptionalHeader.SizeOfHeapCommit);
    printf("LoaderFlags                 :%04X\n",myOptionalHeader.LoaderFlags);
    printf("NumberOfRvaAndSizes         :%04X\n",myOptionalHeader.NumberOfRvaAndSizes);
  
  
    //***********************************************************
  //读取Data Directory
  //***********************************************************
    printf(";===================================================;\n");
  printf("数据目录树结构:\n");
  printf(";---------------------------------------------------;\n");
  for( i=0;i<16;i++)                                         //循环输出数据目录树
  {
    printf("DataDirectory[%x]->",i);
    printf("VirtualAddress: %08X  ",myOptionalHeader.DataDirectory[i].VirtualAddress);
    
    printf("Size:%04X  ",myOptionalHeader.DataDirectory[i].Size);
    printf("\n");
  }
  
  
    //***********************************************************
  //读取Section Header
  //***********************************************************
  UINT sectionVirtOffset[20] = {0,0,0,0,0,0,0,0,0,0};        //虚拟地址 
  UINT sectionFileOffset[20] = {0,0,0,0,0,0,0,0,0,0};        //文件地址
  UINT NumOfFunc = myFileHeader.NumberOfSections;
  
  myCurFileOffset +=  myFileHeader.SizeOfOptionalHeader;     //修改指针,指向第一个Section Table;
  
    fseek(p,myCurFileOffset,SEEK_SET);
  fread(&mySectionHeader,sizeof(IMAGE_SECTION_HEADER),1,p);
  
  printf(";============================================================;\n");
  printf("区段信息:\n");
  printf(";------------------------------------------------------------;\n");  
  printf(" name    |VOffset   |VSize     |ROffset   |RSize     |Flags    \n");
  
  for(i = 0; i < myFileHeader.NumberOfSections; i++)
  {
    printf("%-6s   ",mySectionHeader.Name);               //区段名字 
    printf("%08X   ",mySectionHeader.VirtualAddress);     //虚拟偏移
    printf("%08X   ",mySectionHeader.Misc.VirtualSize);   //虚拟大小  
        printf("%08X   ",mySectionHeader.PointerToRawData);   //文件偏移
    printf("%08X   ",mySectionHeader.SizeOfRawData);    //文件大小
    printf("%08X   ",mySectionHeader.Characteristics);
    
        sectionVirtOffset[i] = mySectionHeader.VirtualAddress;
    sectionFileOffset[i] = mySectionHeader.PointerToRawData;
    
    printf("\n");
    
        fseek(p,myCurFileOffset + (i+1)*sizeof(IMAGE_SECTION_HEADER),SEEK_SET);
    fread(&mySectionHeader,sizeof(IMAGE_SECTION_HEADER),1,p);
  }  
  
  
  //***********************************************************
  //读取“[0]输出表”
  //***********************************************************  
    myCurVirtOffset = myOptionalHeader.DataDirectory[0].VirtualAddress;//修改指针,指向输出表
  myCurFileOffset = ChgRvaToFileOffset(myCurVirtOffset,sectionVirtOffset,sectionFileOffset,NumOfFunc);
  
  //若存在输入表,则输出  
  if(myCurVirtOffset > 0)
  {
    fseek(p,myCurFileOffset,SEEK_SET);
    fread(&myExportTable,sizeof(IMAGE_EXPORT_DIRECTORY),1,p);
    
    printf(";============================================================;\n");
    printf("输出表结构:\n");  
    printf(";------------------------------------------------------------;\n");
    printf("Characteristics       %08X\n",myExportTable.Characteristics);
    printf("TimeDateStamp         %08X\n",myExportTable.TimeDateStamp);
    printf("MajorVersion          %08X\n",myExportTable.MajorVersion);
    printf("MinorVersion          %08X\n",myExportTable.MinorVersion);
    printf("Name                  %08X\n",myExportTable.Name);
    printf("Base                  %08X\n",myExportTable.Base);
    printf("NumberOfFunctions     %08X\n",myExportTable.NumberOfFunctions);
    printf("NumberOfNames         %08X\n",myExportTable.NumberOfNames);
    printf("AddressOfFunctions    %08X\n",myExportTable.AddressOfFunctions);
    printf("AddressOfNameOrdinals %08X\n",myExportTable.AddressOfNameOrdinals);
    printf("AddressOfNames        %08X\n",myExportTable.AddressOfNames);    
    
    printf(";************************************************************;\n");
    printf("输出函数:\n");
    printf(";------------------------------------------------------------;\n");  
    printf("Ordinal     RVA         Offset         Name                   \n");
    printf(";------------------------------------------------------------;\n"); 
    
    for(i = 0;i < myExportTable.NumberOfNames;i++)
    {
      //一些壳对PE做了修改,做下校验(32 lite)
      if(myExportTable.AddressOfNames == 0)
        break;
            //-------------------------------------------------------|
           printf("number[%d]   ",i+1);                          //序号   
            //-------------------------------------------------------|
          UINT arrayVirtOffset = myExportTable.AddressOfFunctions + i * sizeof(DWORD);//数组地址的RVA
      UINT arrayFileOffset = ChgRvaToFileOffset(arrayVirtOffset,sectionVirtOffset,sectionFileOffset,NumOfFunc);
      fseek(p,arrayFileOffset,SEEK_SET);
      UINT arrayData =0;
      fread(&arrayData,sizeof(DWORD),1,p);  
        printf("%08X  ",arrayData);                            //RVA
            //-------------------------------------------------------|
            UINT OffsetExpFuc = ChgRvaToFileOffset(arrayData,sectionVirtOffset,sectionFileOffset,NumOfFunc);
        printf("%08X    ",OffsetExpFuc);                         //Offset
            //-------------------------------------------------------|
      char myExportDll[40];
      UINT virtOffsetExpName  = myExportTable.AddressOfNames + i * sizeof(DWORD);//数组地址的RVA
      UINT fileOffsetExpName = ChgRvaToFileOffset(virtOffsetExpName,sectionVirtOffset,sectionFileOffset,NumOfFunc);//数组在文件中地址  
      fseek(p,fileOffsetExpName,SEEK_SET);
      UINT expTemp =0;
      fread(&expTemp,40,1,p);  
      UINT addresAnother = ChgRvaToFileOffset(expTemp,sectionVirtOffset,sectionFileOffset,NumOfFunc);
      fseek(p,addresAnother,SEEK_SET);
      fread(&myExportDll,40,1,p);  
      printf("%s\n",myExportDll);                          //API Name
            //-------------------------------------------------------|
    }
    
    printf("\n");  
  }    
  
    
  //************************************************************
  //读取“[1]输入表”
  //************************************************************  
  myCurVirtOffset = myOptionalHeader.DataDirectory[1].VirtualAddress;//修改指针,指向输出入表
  myCurFileOffset = ChgRvaToFileOffset(myCurVirtOffset,sectionVirtOffset,sectionFileOffset,NumOfFunc);

  //读取输入表
  fseek(p,myCurFileOffset,SEEK_SET);
  fread(&myImportTable,sizeof(IMAGE_IMPORT_DESCRIPTOR),1,p);
  
  printf(";=======================================================================================;\n");
  printf("输入表结构\n");
  printf(";---------------------------------------------------------------------------------------;\n");
  printf("DllName         |OriginalFirstThunk |TimeDateStamp |ForwarderChain |Name     |FirstThunk\n");
  printf(";---------------------------------------------------------------------------------------;\n");
  i = 0;
  
  //循环输出
   while(myImportTable.FirstThunk != NULL)
  {
    char mydllname[20];
    UINT mychar = ChgRvaToFileOffset(myImportTable.Name,sectionVirtOffset,sectionFileOffset,NumOfFunc);
    
    fseek(p,mychar,SEEK_SET);
    fread(&mydllname,sizeof(IMAGE_IMPORT_DESCRIPTOR),1,p);
    
    printf("%-12s     ",         mydllname);  
    printf("%08X            ",myImportTable.OriginalFirstThunk);
    printf("%08X       ",     myImportTable.TimeDateStamp);
    printf("%08X        ",    myImportTable.ForwarderChain);  
    printf("%08X  ",          myImportTable.Name);
    printf("%08X   \n",       myImportTable.FirstThunk);
    
    fseek(p,myCurFileOffset+(i+1) * sizeof(IMAGE_IMPORT_DESCRIPTOR),SEEK_SET);
    fread(&myImportTable,sizeof(IMAGE_IMPORT_DESCRIPTOR),1,p);
    i++;  
  }
      
  printf("\n");
  
  //***********************************************************
  //IAT函数
  //***********************************************************  
  myCurVirtOffset = myOptionalHeader.DataDirectory[1].VirtualAddress;//修改指针,指向输出入表
  myCurFileOffset = ChgRvaToFileOffset(myCurVirtOffset,sectionVirtOffset,sectionFileOffset,NumOfFunc);  
      
      
  printf(";=======================================================================================;\n");
  printf("IAT相关函数\n");
  printf(";***************************************************************************************;\n");
  i = 0;
      
  //读取输入表
  fseek(p,myCurFileOffset,SEEK_SET);
  fread(&myImportTable,sizeof(IMAGE_IMPORT_DESCRIPTOR),1,p);
      
  while(myImportTable.FirstThunk != NULL)
  {
    char mydllname[20];
    UINT fileOffsetImpName = ChgRvaToFileOffset(myImportTable.Name,sectionVirtOffset,sectionFileOffset,NumOfFunc);
        
    fseek(p,fileOffsetImpName,SEEK_SET);
    fread(&mydllname,sizeof(IMAGE_IMPORT_DESCRIPTOR),1,p);
        
    //printf("DllName         |OriginalFirstThunk |TimeDateStamp |ForwarderChain |Name     |FirstThunk\n");
        
    printf("%-12s     ",      mydllname);  
    printf("%08X            ",myImportTable.OriginalFirstThunk);
    printf("%08X       ",     myImportTable.TimeDateStamp);
    printf("%08X        ",    myImportTable.ForwarderChain);  
    printf("%08X  ",          myImportTable.Name);
    printf("%08X   \n",       myImportTable.FirstThunk);
        
    printf(";---------------------------------------------------------------------------------------;\n");
        
        
    UINT fileOffsetIAT = ChgRvaToFileOffset(myImportTable.FirstThunk,sectionVirtOffset,sectionFileOffset,NumOfFunc);    
        
    printf("@Thunk RVA   @Thunk Offset   @Tank Value   @hint/OrDinal  @API NAME\n");
        
    unsigned int k = 0;      
    while(true)
    {
      //判断是否终结
      UINT myTankValue = 0;
      fseek(p,fileOffsetIAT + k*sizeof(DWORD),SEEK_SET);
      fread(&myTankValue,sizeof(DWORD),1,p);      
      if(myTankValue == 0)
        break;      
      
      //----------------------------------------------------------------|
      printf(" %08X    ", myImportTable.FirstThunk + k * sizeof(DWORD));//虚拟地址
      printf("%08X         ",fileOffsetIAT + k * sizeof(WORD));             //文件地址
      printf("%08X     ",myTankValue);                              //ThankVALUE    
            //----------------------------------------------------------------|
      UINT impTemp =0;
      UINT myTankWordVale = ChgRvaToFileOffset(myTankValue,sectionVirtOffset,sectionFileOffset,NumOfFunc);
      fseek(p,myTankWordVale,SEEK_SET);
      fread(&impTemp,sizeof(WORD),1,p);      
      printf(" %04X          ",impTemp);                                //OrDinal      
      //----------------------------------------------------------------|
      UINT myFucOffset = ChgRvaToFileOffset(myTankValue,sectionVirtOffset,sectionFileOffset,NumOfFunc);
      
      char myFucName[40];
      int m = 0;
      for(m=0;m<100;m++)
      {
        BYTE myByte = 0;
        fseek(p,myFucOffset,SEEK_SET);
        fread(&myByte,sizeof(BYTE),1,p);
        if(myByte>=0x20 && myByte <= 0x7F)
        {    
          fseek(p,myFucOffset+1,SEEK_SET);
          fread(&myByte,sizeof(BYTE),1,p);
          
          if(myByte<0x20)
            myFucOffset++;
          else
            break;
        }
        else
          myFucOffset++;
      }
      
      fseek(p,myFucOffset,SEEK_SET);
      fread(&myFucName,40,1,p);
      
      printf(" %-s  \n",myFucName);                                     //API NAME
      k++;
      
    }
    
    printf("                                                                                         \n");
    printf(";***************************************************************************************;\n");
    
    fseek(p,myCurFileOffset+(i+1) * sizeof(IMAGE_IMPORT_DESCRIPTOR),SEEK_SET);
    fread(&myImportTable,sizeof(IMAGE_IMPORT_DESCRIPTOR),1,p);
    i++;
    
  }
    
  fclose(p);  
      
    system("pause");
      
  return 0;
}


UINT ChgRvaToFileOffset(UINT VirtualOffset,UINT sectionVirtOffset[],UINT sectionFileOffset[],UINT NumOfFunc)
{
  int temp = 0;
  UINT counter;
  for(counter =0;counter < NumOfFunc-1;counter++)
  {
    //依次排查
    if((VirtualOffset >= sectionVirtOffset[counter]) && (VirtualOffset < sectionVirtOffset[counter+1]))
    {
      if(sectionFileOffset[counter] == 0)
        return 0;
      else
      {
        temp = sectionVirtOffset[counter] - sectionFileOffset[counter];
        break;
      }
    }
    
  }
  //落在最后一个区段的情形
  if(counter == (NumOfFunc-1))
    temp = sectionVirtOffset[counter] - sectionFileOffset[counter];
  
  return (VirtualOffset - temp);
}
附件下载地址:http://www.rapidshare.com.cn/download.php?id=ED34AE611