SuperProgram 发表于 2016-11-3 09:59

C++ 读取PE文件信息(读取PE导入表等)

今天突然想自己实现一个PEID小工具,无奈颈椎不好啊,写好了核心代码只好匆匆结束了,不敢独享,拿出来与诸位朋友共勉了。
// ReadPEInfo.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <Dbghelp.h>

void ReadNTPEInfo(PIMAGE_NT_HEADERS pImageNtPE);
ULONG RvaToOffset(IMAGE_NT_HEADERS * pNtHeader,ULONG Rva);

#define pNtHeaders pImageNtHeaders

int _tmain(int argc, _TCHAR* argv[])
{

        char file[]="win32.exe";

        //DOS头
        PIMAGE_DOS_HEADER pImageDosHeader;
        //NT头(包括PE标识+Image_File_Header+OptionHeader)
    PIMAGE_NT_HEADERS pImageNtHeaders;
        //标准PE头、
    PIMAGE_FILE_HEADER pImageFileHeader;

        //扩展PE头
        IMAGE_OPTIONAL_HEADER32 pImageOptionHeaders;


    HANDLE hFile;
    HANDLE hMapObject;
        //DOS头
    PUCHAR uFileMap;

        hFile= CreateFile(file,GENERIC_READ,0,NULL,OPEN_EXISTING,0,0);
        if(hFile==NULL)
        {
                printf("打开文件失败\n");
                system("pause");
                return 0;
        }

        hMapObject=CreateFileMapping(hFile,NULL,PAGE_READONLY,0,0,NULL);
        if(hMapObject==NULL)
        {
                printf("创建文件映射内核对对象失败\n");
                system("pause");
                return 0;
        }

        //PE基址
        uFileMap=(PUCHAR)MapViewOfFile(hMapObject,FILE_MAP_READ,0,0,0);
        if(uFileMap==NULL)
        {
                printf("映射到进程地址空间失败\n");
                system("pause");
                return 0;
        }

        pImageDosHeader=(PIMAGE_DOS_HEADER)uFileMap;
        if(pImageDosHeader->e_magic!=IMAGE_DOS_SIGNATURE)
        {
                printf("不是PE结构\n");
                system("pause");
                return 0;
        }

        //定位到NT PE头
        pImageNtHeaders=(PIMAGE_NT_HEADERS)((PUCHAR)uFileMap+pImageDosHeader->e_lfanew);
       
        //导入表的相对虚拟地址(RVA)
    ULONG rva_ofimporttable=pImageNtHeaders->OptionalHeader.DataDirectory.VirtualAddress;
    //根据相对虚拟(rva)地址计算偏移地址(offset)
    ULONG offset_importtable=RvaToOffset(pImageNtHeaders,rva_ofimporttable);
    if(!offset_importtable)
        {
                printf("获取导入表偏移地址失败\n");
                system("pause");
                return 0;
        }

        PIMAGE_THUNK_DATA s;
   
    //取得导入表的地址
    IMAGE_IMPORT_DESCRIPTOR *pImportTable=(IMAGE_IMPORT_DESCRIPTOR *)((char*)uFileMap+offset_importtable);


        IMAGE_IMPORT_DESCRIPTOR null_iid;
    IMAGE_THUNK_DATA null_thunk;
    memset(&null_iid, 0, sizeof(null_iid));
    memset(&null_thunk, 0, sizeof(null_thunk));

        //每个元素代表了一个引入的DLL。
    for(int i=0; memcmp(pImportTable + i, &null_iid, sizeof(null_iid))!=0; i++)
    {
                char *dllName= (char*)(uFileMap+RvaToOffset(pImageNtHeaders,pImportTable.Name));

      //拿到了DLL的名字

      printf("模块[%d]: %s\n", i, (char*)dllName);
                PIMAGE_THUNK_DATA32 pThunk=(PIMAGE_THUNK_DATA32)(uFileMap+RvaToOffset(pImageNtHeaders,pImportTable.FirstThunk));
               
                while(pThunk->u1.Ordinal!=NULL)
                {
                        PIMAGE_IMPORT_BY_NAME pname=(PIMAGE_IMPORT_BY_NAME)(uFileMap+RvaToOffset(pImageNtHeaders,pThunk->u1.AddressOfData));
                        printf("函数编号: %d 名称: %s\n",pname->Hint,pname->Name);
                        pThunk++;
                }
        }
        system("pause");
        return 0;
}


void ReadNTPEInfo(PIMAGE_NT_HEADERS pImageNtPE)
{
        printf("运行平台:   0x%04X\n",pImageNtPE->FileHeader.Machine);
        printf("节数量:   %d\n",pImageNtPE->FileHeader.NumberOfSections);
        printf("PE属性:   0x%04X\n",pImageNtPE->FileHeader.Characteristics);
}





//计算Offset
ULONG RvaToOffset(IMAGE_NT_HEADERS * pNtHeader,ULONG Rva)
{
        //PE节
    IMAGE_SECTION_HEADER *p_section_header;
    ULONG sNum,i;
    //取得节表项数目
    sNum=pNtHeader->FileHeader.NumberOfSections;
    //取得第一个节表项
    p_section_header=(IMAGE_SECTION_HEADER *)
                        ((BYTE *)pNtHeader+sizeof(IMAGE_NT_HEADERS));
    for(i=0;i<sNum;i++)
    {
                //printf("PE 节名称: %s\n",p_section_header->Name);
      if((p_section_header->VirtualAddress<=Rva)&&Rva<(p_section_header->VirtualAddress+p_section_header->SizeOfRawData))
                {
                        return Rva-p_section_header->VirtualAddress+p_section_header->PointerToRawData;
                }       
      p_section_header++;   
    }
    return 0;
}

StriveMario 发表于 2016-11-3 11:12

支持共享精神....

小虾米TC 发表于 2016-11-3 11:19

支持楼主

wanwanwanwan 发表于 2016-11-3 11:47

看上去不错的样子 支持 一下楼主 {:301_1003:}

mihacker 发表于 2016-11-3 12:00

    后排支持下楼主、

Nanson 发表于 2016-11-3 12:08

前排举爪支持,。

ynkyghty 发表于 2017-8-14 13:15


看上去不错的样子 支持 一下楼主{:17_1073:}
页: [1]
查看完整版本: C++ 读取PE文件信息(读取PE导入表等)