⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 pehandler.cpp

📁 7-Zip 是一款号称有着现今最高压缩比的压缩软件
💻 CPP
📖 第 1 页 / 共 2 页
字号:
// PeHandler.cpp

#include "StdAfx.h"

#include "../../../C/CpuArch.h"

#include "Common/Buffer.h"
#include "Common/ComTry.h"
#include "Common/IntToString.h"

#include "Windows/PropVariantUtils.h"
#include "Windows/Time.h"

#include "../Common/LimitedStreams.h"
#include "../Common/ProgressUtils.h"
#include "../Common/RegisterArc.h"
#include "../Common/StreamUtils.h"

#include "../Compress/Copy/CopyCoder.h"

#include "Common/DummyOutStream.h"

#define Get16(p) GetUi16(p)
#define Get32(p) GetUi32(p)
#define Get64(p) GetUi64(p)

using namespace NWindows;

namespace NArchive {
namespace NPe {

#define NUM_SCAN_SECTIONS_MAX (1 << 6)

#define PE_SIG 0x00004550
#define PE_OptHeader_Magic_32 0x10B
#define PE_OptHeader_Magic_64 0x20B

static AString GetDecString(UInt32 v)
{
  char sz[32];
  ConvertUInt64ToString(v, sz);
  return sz;
}

struct CVersion
{
  UInt16 Major;
  UInt16 Minor;

  void Parse(const Byte *buf);
  AString GetString() const { return GetDecString(Major) + '.' + GetDecString(Minor); }
};

void CVersion::Parse(const Byte *p)
{
  Major = Get16(p);
  Minor = Get16(p + 2);
}

static const UInt32 kHeaderSize =  4 + 20;

struct CHeader
{
  UInt16 NumSections;
  UInt32 Time;
  UInt32 PointerToSymbolTable;
  UInt32 NumSymbols;
  UInt16 OptHeaderSize;
  UInt16 Flags;
  UInt16 Machine;

  bool Parse(const Byte *buf);
};

bool CHeader::Parse(const Byte *p)
{
  if (Get32(p) != PE_SIG)
    return false;
  p += 4;
  Machine = Get16(p + 0);
  NumSections = Get16(p + 2);
  Time = Get32(p + 4);
  PointerToSymbolTable = Get32(p + 8);
  NumSymbols = Get32(p + 12);
  OptHeaderSize = Get16(p + 16);
  Flags = Get16(p + 18);
  return true;
}

struct CDirLink
{
  UInt32 Va;
  UInt32 Size;
  void Parse(const Byte *p);
};

void CDirLink::Parse(const Byte *p)
{
  Va = Get32(p);
  Size = Get32(p + 4);
};

enum
{
  kDirLink_Certificate = 4,
  kDirLink_Debug = 6
};

struct CDebugEntry
{
  UInt32 Flags;
  UInt32 Time;
  CVersion Ver;
  UInt32 Type;
  UInt32 Size;
  UInt32 Va;
  UInt32 Pa;
  
  void Parse(const Byte *p);
};

void CDebugEntry::Parse(const Byte *p)
{
  Flags = Get32(p);
  Time = Get32(p + 4);
  Ver.Parse(p + 8);
  Type = Get32(p + 12);
  Size = Get32(p + 16);
  Va = Get32(p + 20);
  Pa = Get32(p + 24);
}

static const UInt32 kNumDirItemsMax = 16;

struct COptHeader
{
  UInt16 Magic;
  Byte LinkerVerMajor;
  Byte LinkerVerMinor;

  UInt32 CodeSize;
  UInt32 InitDataSize;
  UInt32 UninitDataSize;
  
  // UInt32 AddressOfEntryPoint;
  // UInt32 BaseOfCode;
  // UInt32 BaseOfData32;
  // UInt64 ImageBase;

  UInt32 SectAlign;
  UInt32 FileAlign;

  CVersion OsVer;
  CVersion ImageVer;
  CVersion SubsysVer;
  
  UInt32 ImageSize;
  UInt32 HeadersSize;
  UInt32 CheckSum;
  UInt16 SubSystem;
  UInt16 DllCharacts;

  UInt64 StackReserve;
  UInt64 StackCommit;
  UInt64 HeapReserve;
  UInt64 HeapCommit;

  UInt32 NumDirItems;
  CDirLink DirItems[kNumDirItemsMax];

  bool Is64Bit() const { return Magic == PE_OptHeader_Magic_64; }
  bool Parse(const Byte *p, UInt32 size);
};

bool COptHeader::Parse(const Byte *p, UInt32 size)
{
  Magic = Get16(p);
  switch (Magic)
  {
    case PE_OptHeader_Magic_32:
    case PE_OptHeader_Magic_64:
      break;
    default:
      return false;
  }
  LinkerVerMajor = p[2];
  LinkerVerMinor = p[3];
  
  bool hdr64 = Is64Bit();
  
  CodeSize = Get32(p + 4);
  InitDataSize = Get32(p + 8);
  UninitDataSize = Get32(p + 12);

  // AddressOfEntryPoint = Get32(p + 16);
  // BaseOfCode = Get32(p + 20);
  // BaseOfData32 = Get32(p + 24);
  // ImageBase = hdr64 ? GetUi64(p + 24) :Get32(p + 28);

  SectAlign = Get32(p + 32);
  FileAlign = Get32(p + 36);

  OsVer.Parse(p + 40);
  ImageVer.Parse(p + 44);
  SubsysVer.Parse(p + 48);

  // reserved = Get32(p + 52);

  ImageSize = Get32(p + 56);
  HeadersSize = Get32(p + 60);
  CheckSum = Get32(p + 64);
  SubSystem = Get16(p + 68);
  DllCharacts = Get16(p + 70);

  if (hdr64)
  {
    StackReserve = Get64(p + 72);
    StackCommit = Get64(p + 80);
    HeapReserve = Get64(p + 88);
    HeapCommit = Get64(p + 96);
  }
  else
  {
    StackReserve = Get32(p + 72);
    StackCommit = Get32(p + 76);
    HeapReserve = Get32(p + 80);
    HeapCommit = Get32(p + 84);
  }
  UInt32 pos = (hdr64 ? 108 : 92);
  NumDirItems = Get32(p + pos);
  pos += 4;
  if (pos + 8 * NumDirItems != size)
    return false;
  for (UInt32 i = 0; i < NumDirItems && i < kNumDirItemsMax; i++)
    DirItems[i].Parse(p + pos + i * 8);
  return true;
}

static const UInt32 kSectionSize = 40;

struct CSection
{
  AString Name;

  UInt32 VSize;
  UInt32 Va;
  UInt32 PSize;
  UInt32 Pa;
  UInt32 Flags;
  UInt32 Time;
  // UInt16 NumRelocs;
  bool IsDebug;
  bool IsRealSect;

  CSection(): IsRealSect(false), IsDebug(false) {}
  UInt64 GetPackSize() const { return PSize; }

  void UpdateTotalSize(UInt32 &totalSize)
  {
    UInt32 t = Pa + PSize;
    if (t > totalSize)
      totalSize = t;
  }
  void Parse(const Byte *p);
};

static AString GetName(const Byte *name)
{
  const int kNameSize = 8;
  AString res;
  char *p = res.GetBuffer(kNameSize);
  memcpy(p, name, kNameSize);
  p[kNameSize] = 0;
  res.ReleaseBuffer();
  return res;
}

void CSection::Parse(const Byte *p)
{
  Name = GetName(p);
  VSize = Get32(p + 8);
  Va = Get32(p + 12);
  PSize = Get32(p + 16);
  Pa = Get32(p + 20);
  // NumRelocs = Get16(p + 32);
  Flags = Get32(p + 36);
}

static const CUInt32PCharPair g_HeaderCharacts[] =
{
  { 1 << 1, "Executable" },
  { 1 << 13, "DLL" },
  { 1 << 8, "32-bit" },
  { 1 << 5, "LargeAddress" },
  { 1 << 0, "NoRelocs" },
  { 1 << 2, "NoLineNums" },
  { 1 << 3, "NoLocalSyms" },
  { 1 << 4, "AggressiveWsTrim" },
  { 1 << 9, "NoDebugInfo" },
  { 1 << 10, "RemovableRun" },
  { 1 << 11, "NetRun" },
  { 1 << 12, "System" },
  { 1 << 14, "UniCPU" },
  { 1 << 7, "Little-Endian" },
  { 1 << 15, "Big-Endian" }
};

static const CUInt32PCharPair g_DllCharacts[] =
{
  { 1 << 6, "Relocated" },
  { 1 << 7, "Integrity" },
  { 1 << 8, "NX-Compatible" },
  { 1 << 9, "NoIsolation" },
  { 1 << 10, "NoSEH" },
  { 1 << 11, "NoBind" },
  { 1 << 13, "WDM" },
  { 1 << 15, "TerminalServerAware" }
};

static const CUInt32PCharPair g_SectFlags[] =
{
  { 1 << 3, "NoPad" },
  { 1 << 5, "Code" },
  { 1 << 6, "InitializedData" },
  { 1 << 7, "UninitializedData" },
  { 1 << 9, "Comments" },
  { 1 << 11, "Remove" },
  { 1 << 12, "COMDAT" },
  { 1 << 15, "GP" },
  { 1 << 24, "ExtendedRelocations" },
  { 1 << 25, "Discardable" },
  { 1 << 26, "NotCached" },
  { 1 << 27, "NotPaged" },
  { 1 << 28, "Shared" },
  { 1 << 29, "Execute" },
  { 1 << 30, "Read" },
  { (UInt32)1 << 31, "Write" }
};

static const CUInt32PCharPair g_MachinePairs[] =
{
  { 0x014C, "x86" },
  { 0x0162, "MIPS-R3000" },
  { 0x0166, "MIPS-R4000" },
  { 0x0168, "MIPS-R10000" },
  { 0x0169, "MIPS-V2" },
  { 0x0184, "Alpha" },
  { 0x01A2, "SH3" },
  { 0x01A3, "SH3-DSP" },
  { 0x01A4, "SH3E" },
  { 0x01A6, "SH4" },
  { 0x01A8, "SH5" },
  { 0x01C0, "ARM" },
  { 0x01C2, "ARM-Thumb" },
  { 0x01F0, "PPC" },
  { 0x01F1, "PPC-FP" },
  { 0x0200, "IA-64" },
  { 0x0284, "Alpha-64" },
  { 0x0200, "IA-64" },
  { 0x0366, "MIPSFPU" },
  { 0x8664, "x64" },
  { 0x0EBC, "EFI" }
};

static const CUInt32PCharPair g_SubSystems[] =
{
  { 0, "Unknown" },
  { 1, "Native" },
  { 2, "Windows GUI" },
  { 3, "Windows CUI" },
  { 7, "Posix" },
  { 9, "Windows CE" },
  { 10, "EFI" },
  { 11, "EFI Boot" },
  { 12, "EFI Runtime" },
  { 13, "EFI ROM" },
  { 14, "XBOX" }
};

class CHandler:
  public IInArchive,
  public CMyUnknownImp
{
  CMyComPtr<IInStream> _inStream;
  CObjectVector<CSection> _sections;
  UInt32 _peOffset;
  CHeader _header;
  COptHeader _optHeader;
  UInt32 _totalSize;
  UInt32 _totalSizeLimited;
  HRESULT LoadDebugSections(IInStream *stream, bool &thereIsSection);
  HRESULT Open2(IInStream *stream);
  bool Parse(const Byte *buf, UInt32 size);
public:
  MY_UNKNOWN_IMP1(IInArchive)
  INTERFACE_IInArchive(;)
};

bool CHandler::Parse(const Byte *buf, UInt32 size)
{
  UInt32 i;
  if (size < 512)
    return false;
  _peOffset = Get32(buf + 0x3C);
  if (_peOffset >= 0x1000 || _peOffset + 512 > size || (_peOffset & 7) != 0)
    return false;

  UInt32 pos = _peOffset;
  if (!_header.Parse(buf + pos))
    return false;
  if (_header.OptHeaderSize > 512 || _header.NumSections > NUM_SCAN_SECTIONS_MAX)
    return false;
  pos += kHeaderSize;

  if (!_optHeader.Parse(buf + pos, _header.OptHeaderSize))
    return false;

  pos += _header.OptHeaderSize;
  _totalSize = pos;

  for (i = 0; i < _header.NumSections; i++, pos += kSectionSize)
  {
    CSection sect;
    if (pos + kSectionSize > size)
      return false;
    sect.Parse(buf + pos);
    sect.IsRealSect = true;
    sect.UpdateTotalSize(_totalSize);
    _sections.Add(sect);
  }

  return true;
}

enum
{
  kpidSectAlign = kpidUserDefined,
  kpidFileAlign,
  kpidLinkerVer,
  kpidOsVer,
  kpidImageVer,
  kpidSubsysVer,
  kpidCodeSize,
  kpidImageSize,
  kpidInitDataSize,
  kpidUnInitDataSize,
  kpidHeadersSizeUnInitDataSize,

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -