风扫春残雪 发表于 2020-6-26 19:11

【C++】PE头、区段块、输入表分析

刚刚开始学C++,想找个东西练练手。索性一不做二不休先拿PE格式开刀。
所以代码写得糊的地方欢迎各位大佬指正!

这份代码主要演示了PE头、区块段、输入表这三部分。窃以为是PE文件格式中最重要的。输出表、TLS、重定向等内容扫了一眼感觉没有输入表复杂。所以写完了输入表就告一段落了。以及为了方便移植到别的程序里,这份代码没有使用w32api。我总感觉读入和读出还有再优化的空间。如果移植的话可能要处理一下两个头文件的定义

最后,这段代码兼容了x64的PE格式,x64和x86大同小异,但其实有一些坑,比如x64在header里面没有BaseOfData,如果用x86的定义就会翻车。给一起学习的朋友提个醒

来52发的第一篇文章,请多指教!


// PEStudy.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//
#include <iostream>
#include <fstream>
#include <string>
#include <Windows.h>
#include <winnt.h>
void debugOut(std::string outstr);
char (*readFile(std::string strPath, int intStart, int intLength));


char (*readFile(std::string strPath, int intStart, int intLength)) {
    char* lpBuffer = new char;
    std::ifstream objInstream;
    objInstream.open(strPath, std::ios::in + std::ios::binary);
    objInstream.seekg(intStart, std::ios::beg);
    objInstream.read(lpBuffer, intLength);
    return lpBuffer;
}

void debugOut(std::string outstr, long value) {

    std::cout << outstr << std::hex << value << std::endl;
}

int main()
{
    IMAGE_DOS_HEADER* lpDosheader;
    IMAGE_NT_HEADERS* lpNtheader;
    IMAGE_NT_HEADERS64* lpNtheader64;
    IMAGE_SECTION_HEADER* lpSection;
    IMAGE_IMPORT_DESCRIPTOR* lpImport;
    IMAGE_THUNK_DATA* lpThunk = NULL;
    IMAGE_THUNK_DATA64* lpThunk64 = NULL;
    IMAGE_IMPORT_BY_NAME* lpImportByName;

    int intNumberofSection = 0;
    int intSectiontablePointer = 0;
    int intImportVA = 0;
    int intImportDiff = 0; //the difference of VA and file_offset in the section that Import-Table belongs to.
    int intImportTableLoc = 0;
    int intImportSize = 0;
    int i = 0;
    int j = 0;
    std::string strPath = "d:\\temp\\Display.dll";

    lpDosheader = (IMAGE_DOS_HEADER*)readFile(strPath, 0, sizeof(IMAGE_DOS_HEADER));
    debugOut("DOSHeader->e_lfanew: ", (*lpDosheader).e_lfanew);

   
    lpNtheader = (IMAGE_NT_HEADERS*)readFile(strPath, (*lpDosheader).e_lfanew, sizeof(IMAGE_NT_HEADERS));
    debugOut("NTheader->Signature: ", (*lpNtheader).Signature);
    if ((*lpNtheader).OptionalHeader.Magic == 0x10) {
      //x86
      std::cout << " x86" << std::endl;
      debugOut("NTheader->FileHeader->NumberOfSections: ", (*lpNtheader).FileHeader.NumberOfSections);
      debugOut("NTheader->FileHeader->Characteristics: ", (*lpNtheader).FileHeader.Characteristics);
      debugOut("NTheader->OptionalHeader->Magic (x86/x64: )", (*lpNtheader).OptionalHeader.Magic);
      debugOut("NTheader->OptionalHeader->BaseOfCode: ", (*lpNtheader).OptionalHeader.BaseOfCode);
      debugOut("NTheader->OptionalHeader->BaseOfData: ", (*lpNtheader).OptionalHeader.BaseOfData);
      debugOut("NTheader->OptionalHeader->ImageBase: ", (*lpNtheader).OptionalHeader.ImageBase);
      debugOut("NTheader->OptionalHeader->SectionAlignment: ", (*lpNtheader).OptionalHeader.SectionAlignment);
      debugOut("NTheader->OptionalHeader->FileAlignment: ", (*lpNtheader).OptionalHeader.FileAlignment);
      debugOut("NTheader->OptionalHeader->DataDirectory.Size (Import Table Size):", (*lpNtheader).OptionalHeader.DataDirectory.Size);
      debugOut("NTheader->OptionalHeader->DataDirectory.VA (Import Table VA):", (*lpNtheader).OptionalHeader.DataDirectory.VirtualAddress);
      intSectiontablePointer = (*lpDosheader).e_lfanew + sizeof(IMAGE_NT_HEADERS32);
      intNumberofSection = (*lpNtheader).FileHeader.NumberOfSections;
      intImportVA = (*lpNtheader).OptionalHeader.DataDirectory.VirtualAddress;
      intImportSize = (*lpNtheader).OptionalHeader.DataDirectory.Size;
    }
    else {
      //x64 slightly different from x86
      std::cout << " x64" << std::endl;
      lpNtheader64 = (IMAGE_NT_HEADERS64*)lpNtheader;
      debugOut("NTheader->FileHeader->NumberOfSections: ", (*lpNtheader64).FileHeader.NumberOfSections);
      debugOut("NTheader->FileHeader->Characteristics: ", (*lpNtheader64).FileHeader.Characteristics);
      debugOut("NTheader->OptionalHeader->Magic (x86/x64: )", (*lpNtheader64).OptionalHeader.Magic);
      debugOut("NTheader->OptionalHeader->BaseOfCode: ", (*lpNtheader64).OptionalHeader.BaseOfCode);
      debugOut("NTheader->OptionalHeader->ImageBase: ", (*lpNtheader64).OptionalHeader.ImageBase);
      debugOut("NTheader->OptionalHeader->SectionAlignment: ", (*lpNtheader64).OptionalHeader.SectionAlignment);
      debugOut("NTheader->OptionalHeader->FileAlignment: ", (*lpNtheader64).OptionalHeader.FileAlignment);
      debugOut("NTheader->OptionalHeader->DataDirectory.Size (Import Table Size):", (*lpNtheader64).OptionalHeader.DataDirectory.Size);
      debugOut("NTheader->OptionalHeader->DataDirectory.VA (Import Table VA):", (*lpNtheader64).OptionalHeader.DataDirectory.VirtualAddress);
      intSectiontablePointer = (*lpDosheader).e_lfanew + sizeof(IMAGE_NT_HEADERS64);
      intNumberofSection = (*lpNtheader64).FileHeader.NumberOfSections;
      intImportVA = (*lpNtheader64).OptionalHeader.DataDirectory.VirtualAddress;
      intImportSize = (*lpNtheader64).OptionalHeader.DataDirectory.Size;
    }
    lpSection = (IMAGE_SECTION_HEADER*)readFile(strPath, intSectiontablePointer, intNumberofSection * sizeof(IMAGE_SECTION_HEADER));
    std::cout << "--Section--" << std::endl;
    for (int i = 0; i < intNumberofSection; i++) {
      std::cout <<"Name:" << lpSection.Name << std::endl;
      std::cout << "VirtualAddress: " << lpSection.VirtualAddress << std::endl;
      std::cout << "PointerToRawdata: " << lpSection.PointerToRawData << std::endl;
      std::cout << "Characteristics: " << lpSection.Characteristics << std::endl;
    }
    std::cout << "--Import Table--" << std::endl;
    //Step1: Get Location of Import Table in Sections
    int intFlag = 0;
    for (i = 0; i < intNumberofSection; i++) {
      if ((lpSection.VirtualAddress <= intImportVA) && (intImportVA <= lpSection.VirtualAddress + lpSection.SizeOfRawData)) {
            intFlag = i;
            break;
      }
    }
    std::cout << "Import Table in section: " << lpSection.Name << std::endl;
    //Step2: Calculate the diff of VA and file_offset
    intImportDiff = lpSection.VirtualAddress - lpSection.PointerToRawData;
    //Step3: Calculate the file_offset of Import-Table
    intImportTableLoc = intImportVA - intImportDiff;
    lpImport = (IMAGE_IMPORT_DESCRIPTOR*)readFile(strPath, intImportTableLoc, intImportSize);
    i = 0;
    do {
      std::cout << "IID #" << i << std::endl;
      debugOut("IID->OriginalFirstThunk(file_offset): ", lpImport.OriginalFirstThunk - intImportDiff);
      std::cout << "IID->Name: " << readFile(strPath, lpImport.Name - intImportDiff, 255) << std::endl; //may memoryleak
      debugOut("IID->FirstChunk(file_offset): ", lpImport.FirstThunk - intImportDiff);


      lpThunk = (IMAGE_THUNK_DATA*)readFile(strPath, lpImport.FirstThunk - intImportDiff, 2000); //may bug
      lpThunk64 = (IMAGE_THUNK_DATA64*)lpThunk;

            j = 0;
            if ((*lpNtheader).OptionalHeader.Magic == 0x10) {
                //x86
                do {
                  if (lpThunk.u1.AddressOfData & IMAGE_ORDINAL_FLAG32) {
                        //the top digit equaling 1 indicates that the THUNK_DATA is ordinal
                        debugOut("->By Ordinal, value = ", lpThunk.u1.AddressOfData & 0xfffffff);
                  }
                  else {
                        lpImportByName = (IMAGE_IMPORT_BY_NAME*)readFile(strPath, lpThunk.u1.AddressOfData - intImportDiff, 257); //note: may bug when import table isn't located in the same section as thunk, which is rare.
                        std::cout << "#" << (*lpImportByName).Hint << " -> " << (*lpImportByName).Name << std::endl;
                  }
                  
                  j++;
                } while (lpThunk.u1.AddressOfData != 0);
            }
            else {
                //x64
                do {
                  if (lpThunk64.u1.AddressOfData & IMAGE_ORDINAL_FLAG64) {
                        //the top digit equaling 1 indicates that the THUNK_DATA is ordinal
                        debugOut("->By Ordinal, value = ", lpThunk64.u1.AddressOfData & 0xfffffffffffffff);
                  }
                  else {
                        lpImportByName = (IMAGE_IMPORT_BY_NAME*)readFile(strPath, lpThunk64.u1.AddressOfData - intImportDiff, 257); //note: may bug when import table isn't located in the same section as thunk, which is rare.
                        std::cout << "#" << (*lpImportByName).Hint << " -> " << (*lpImportByName).Name << std::endl;
                  }

                  j++;
                } while (lpThunk64.u1.AddressOfData != 0);
            }
      i++;
    } while (lpImport.Name != 0);




   

    delete lpSection;
    delete lpDosheader;
    delete lpNtheader;
}
页: [1]
查看完整版本: 【C++】PE头、区段块、输入表分析