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

📄 pehandler.cpp

📁 7-Zip 是一款号称有着现今最高压缩比的压缩软件
💻 CPP
📖 第 1 页 / 共 2 页
字号:
  kpidSubSystem,
  kpidDllCharacts,
  kpidStackReserve,
  kpidStackCommit,
  kpidHeapReserve,
  kpidHeapCommit,
};

STATPROPSTG kArcProps[] =
{
  { NULL, kpidCpu, VT_BSTR},
  { NULL, kpidBit64, VT_BOOL},
  { NULL, kpidCharacts, VT_BSTR},
  { NULL, kpidCTime, VT_FILETIME},
  { NULL, kpidPhySize, VT_UI4},
  { NULL, kpidHeadersSize, VT_UI4},
  { NULL, kpidChecksum, VT_UI4},
  { L"Image Size", kpidImageSize, VT_UI4},
  { L"Section Alignment", kpidSectAlign, VT_UI4},
  { L"File Alignment", kpidFileAlign, VT_UI4},
  { L"Code Size", kpidCodeSize, VT_UI4},
  { L"Initialized Data Size", kpidInitDataSize, VT_UI4},
  { L"Uninitialized Data Size", kpidUnInitDataSize, VT_UI4},
  { L"Linker Version", kpidLinkerVer, VT_BSTR},
  { L"OS Version", kpidOsVer, VT_BSTR},
  { L"Image Version", kpidImageVer, VT_BSTR},
  { L"Subsystem Version", kpidSubsysVer, VT_BSTR},
  { L"Subsystem", kpidSubSystem, VT_BSTR},
  { L"DLL Characteristics", kpidDllCharacts, VT_BSTR},
  { L"Stack Reserve", kpidStackReserve, VT_UI8},
  { L"Stack Commit", kpidStackCommit, VT_UI8},
  { L"Heap Reserve", kpidHeapReserve, VT_UI8},
  { L"Heap Commit", kpidHeapCommit, VT_UI8},
 };

STATPROPSTG kProps[] =
{
  { NULL, kpidPath, VT_BSTR},
  { NULL, kpidSize, VT_UI8},
  { NULL, kpidPackSize, VT_UI8},
  { NULL, kpidCharacts, VT_BSTR},
  { NULL, kpidOffset, VT_UI8},
  { NULL, kpidVa, VT_UI8}
};

IMP_IInArchive_Props
IMP_IInArchive_ArcProps_WITH_NAME

static void VerToProp(const CVersion &v, NCOM::CPropVariant &prop)
{
  StringToProp(v.GetString(), prop);
}

void TimeToProp(UInt32 unixTime, NCOM::CPropVariant &prop)
{
  if (unixTime != 0)
  {
    FILETIME ft;
    NTime::UnixTimeToFileTime(unixTime, ft);
    prop = ft;
  }
}

STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
{
  COM_TRY_BEGIN
  NCOM::CPropVariant prop;
  switch(propID)
  {
    case kpidSectAlign: prop = _optHeader.SectAlign; break;
    case kpidFileAlign: prop = _optHeader.FileAlign; break;
    case kpidLinkerVer:
    {
      CVersion v = { _optHeader.LinkerVerMajor, _optHeader.LinkerVerMinor };
      VerToProp(v, prop); break;
      break;
    }
  
    case kpidOsVer:  VerToProp(_optHeader.OsVer, prop); break;
    case kpidImageVer:  VerToProp(_optHeader.ImageVer, prop); break;
    case kpidSubsysVer:  VerToProp(_optHeader.SubsysVer, prop); break;
    case kpidCodeSize:  prop = _optHeader.CodeSize; break;
    case kpidInitDataSize:  prop = _optHeader.InitDataSize; break;
    case kpidUnInitDataSize:  prop = _optHeader.UninitDataSize; break;
    case kpidImageSize:  prop = _optHeader.ImageSize; break;
    case kpidPhySize:  prop = _totalSize; break;
    case kpidHeadersSize:  prop = _optHeader.HeadersSize; break;
    case kpidChecksum:  prop = _optHeader.CheckSum; break;
      
    case kpidCpu:  PAIR_TO_PROP(g_MachinePairs, _header.Machine, prop); break;
    case kpidBit64:  if (_optHeader.Is64Bit()) prop = true; break;
    case kpidSubSystem:  PAIR_TO_PROP(g_SubSystems, _optHeader.SubSystem, prop); break;

    case kpidMTime:
    case kpidCTime:  TimeToProp(_header.Time, prop); break;
    case kpidCharacts:  FLAGS_TO_PROP(g_HeaderCharacts, _header.Flags, prop); break;
    case kpidDllCharacts:  FLAGS_TO_PROP(g_DllCharacts, _optHeader.DllCharacts, prop); break;
    case kpidStackReserve: prop = _optHeader.StackReserve; break;
    case kpidStackCommit: prop = _optHeader.StackCommit; break;
    case kpidHeapReserve: prop = _optHeader.HeapReserve; break;
    case kpidHeapCommit: prop = _optHeader.HeapCommit; break;

    /*
    if (_optHeader.Is64Bit())
      s += " 64-bit";
    */
  }
  prop.Detach(value);
  return S_OK;
  COM_TRY_END
}

STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)
{
  COM_TRY_BEGIN
  NCOM::CPropVariant prop;
  const CSection &item = _sections[index];
  switch(propID)
  {
    case kpidPath:  StringToProp(item.Name, prop); break;
    case kpidSize:  prop = (UInt64)item.VSize; break;
    case kpidPackSize:  prop = (UInt64)item.GetPackSize(); break;
    case kpidOffset:  prop = item.Pa; break;
    case kpidVa:  if (item.IsRealSect) prop = item.Va; break;
    case kpidMTime:
    case kpidCTime:
      TimeToProp(item.IsDebug ? item.Time : _header.Time, prop); break;
    case kpidCharacts:  if (item.IsRealSect) FLAGS_TO_PROP(g_SectFlags, item.Flags, prop); break;
  }
  prop.Detach(value);
  return S_OK;
  COM_TRY_END
}

HRESULT CHandler::LoadDebugSections(IInStream *stream, bool &thereIsSection)
{
  thereIsSection = false;
  const CDirLink &debugLink = _optHeader.DirItems[kDirLink_Debug];
  if (debugLink.Size == 0)
    return S_OK;
  const unsigned kEntrySize = 28;
  UInt32 numItems = debugLink.Size / kEntrySize;
  if (numItems * kEntrySize != debugLink.Size || numItems > 16)
    return S_FALSE;
  
  UInt64 pa = 0;
  int i;
  for (i = 0; i < _sections.Size(); i++)
  {
    const CSection &sect = _sections[i];
    if (sect.Va < debugLink.Va && debugLink.Va + debugLink.Size <= sect.Va + sect.PSize)
    {
      pa = sect.Pa + (debugLink.Va - sect.Va);
      break;
    }
  }
  if (i == _sections.Size())
    return S_FALSE;
  
  CByteBuffer buffer;
  buffer.SetCapacity(debugLink.Size);
  Byte *buf = buffer;
  
  RINOK(stream->Seek(pa, STREAM_SEEK_SET, NULL));
  RINOK(ReadStream_FALSE(stream, buf, debugLink.Size));

  for (i = 0; i < (int)numItems; i++)
  {
    CDebugEntry de;
    de.Parse(buf);

    if (de.Size == 0)
      continue;
    
    CSection sect;
    sect.Name = ".debug" + GetDecString(i);
    
    sect.IsDebug = true;
    sect.Time = de.Time;
    sect.Va = de.Va;
    sect.Pa = de.Pa;
    sect.PSize = sect.VSize = de.Size;
    UInt32 totalSize = sect.Pa + sect.PSize;
    if (totalSize > _totalSize)
    {
      _totalSize = totalSize;
      _sections.Add(sect);
      thereIsSection = true;
    }
    buf += kEntrySize;
  }

  return S_OK;
}

HRESULT CHandler::Open2(IInStream *stream)
{
  const UInt32 kBufSize = 1 << 18;
  const UInt32 kSigSize = 2;

  CByteBuffer buffer;
  buffer.SetCapacity(kBufSize);
  Byte *buf = buffer;

  size_t processed = kSigSize;
  RINOK(ReadStream_FALSE(stream, buf, processed));
  if (buf[0] != 'M' || buf[1] != 'Z')
    return S_FALSE;
  processed = kBufSize - kSigSize;
  RINOK(ReadStream(stream, buf + kSigSize, &processed));
  processed += kSigSize;
  if (!Parse(buf, (UInt32)processed))
    return S_FALSE;
  bool thereISDebug;
  RINOK(LoadDebugSections(stream, thereISDebug));

  const CDirLink &certLink = _optHeader.DirItems[kDirLink_Certificate];
  if (certLink.Size != 0)
  {
    CSection sect;
    sect.Name = "CERTIFICATE";
    sect.Va = 0;
    sect.Pa = certLink.Va;
    sect.PSize = sect.VSize = certLink.Size;
    sect.UpdateTotalSize(_totalSize);
    _sections.Add(sect);
  }

  if (thereISDebug)
  {
    const UInt32 kAlign = 1 << 12;
    UInt32 alignPos = _totalSize & (kAlign - 1);
    if (alignPos != 0)
    {
      UInt32 size = kAlign - alignPos;
      RINOK(stream->Seek(_totalSize, STREAM_SEEK_SET, NULL));
      buffer.Free();
      buffer.SetCapacity(kAlign);
      Byte *buf = buffer;
      size_t processed = size;
      RINOK(ReadStream(stream, buf, &processed));
      size_t i;
      for (i = 0; i < processed; i++)
      {
        if (buf[i] != 0)
          break;
      }
      if (processed < size && processed < 100)
        _totalSize += (UInt32)processed;
      else if (((_totalSize + i) & 0x1FF) == 0 || processed < size)
        _totalSize += (UInt32)i;
    }
  }

  if (_header.NumSymbols > 0 && _header.PointerToSymbolTable >= 512)
  {
    if (_header.NumSymbols >= (1 << 24))
      return S_FALSE;
    CSection sect;
    sect.Name = "COFF_SYMBOLS";
    UInt32 size = _header.NumSymbols * 18;
    RINOK(stream->Seek((UInt64)_header.PointerToSymbolTable + size, STREAM_SEEK_SET, NULL));
    Byte buf[4];
    RINOK(ReadStream_FALSE(stream, buf, 4));
    UInt32 size2 = Get32(buf);
    if (size2 >= (1 << 28))
      return S_FALSE;
    size += size2;

    sect.Va = 0;
    sect.Pa = _header.PointerToSymbolTable;
    sect.PSize = sect.VSize = size;
    sect.UpdateTotalSize(_totalSize);
    _sections.Add(sect);
  }

  UInt64 fileSize;
  RINOK(stream->Seek(0, STREAM_SEEK_END, &fileSize));
  if (fileSize > _totalSize)
    return S_FALSE;
  _totalSizeLimited = (_totalSize < fileSize) ? _totalSize : (UInt32)fileSize;
  return S_OK;
}

HRESULT CalcCheckSum(ISequentialInStream *stream, UInt32 size, UInt32 excludePos, UInt32 &res)
{
  // size &= ~1;
  const UInt32 kBufSize = 1 << 23;
  CByteBuffer buffer;
  buffer.SetCapacity(kBufSize);
  Byte *buf = buffer;

  UInt32 sum = 0;
  UInt32 pos;
  for(pos = 0;;)
  {
    UInt32 rem = size - pos;
    if (rem > kBufSize)
      rem = kBufSize;
    if (rem == 0)
      break;
    size_t processed = rem;
    RINOK(ReadStream(stream, buf, &processed));
    
    /*
    */
    /*
    for (; processed < rem; processed++)
      buf[processed] = 0;
    */

    if ((processed & 1) != 0)
      buf[processed] = 0;

    for (int j = 0; j < 4; j++)
    {
      UInt32 p = excludePos + j;
      if (pos <= p && p < pos + processed)
        buf[p - pos] = 0;
    }

    for (size_t i = 0; i < processed; i += 2)
    {
      sum += Get16(buf + i);
      sum = (sum + (sum >> 16)) & 0xFFFF;
    }
    pos += (UInt32)processed;
    if (rem != processed)
      break;
  }
  sum += pos;
  res = sum;
  return S_OK;
}

STDMETHODIMP CHandler::Open(IInStream *inStream,
    const UInt64 * /* maxCheckStartPosition */,
    IArchiveOpenCallback * /* openArchiveCallback */)
{
  COM_TRY_BEGIN
  Close();
  RINOK(Open2(inStream));
  _inStream = inStream;
  return S_OK;
  COM_TRY_END
}

STDMETHODIMP CHandler::Close()
{
  _inStream.Release();
  _sections.Clear();

  return S_OK;
}

STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems)
{
  *numItems = _sections.Size();
  return S_OK;
}

STDMETHODIMP CHandler::Extract(const UInt32* indices, UInt32 numItems,
    Int32 _aTestMode, IArchiveExtractCallback *extractCallback)
{
  COM_TRY_BEGIN
  bool testMode = (_aTestMode != 0);
  bool allFilesMode = (numItems == UInt32(-1));
  if (allFilesMode)
    numItems = _sections.Size();
  if (numItems == 0)
    return S_OK;
  UInt64 totalSize = 0;
  UInt32 i;
  for (i = 0; i < numItems; i++)
    totalSize += _sections[allFilesMode ? i : indices[i]].GetPackSize();
  extractCallback->SetTotal(totalSize);

  UInt64 currentTotalSize = 0;
  UInt64 currentItemSize;
  
  NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder();
  CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec;

  CLocalProgress *lps = new CLocalProgress;
  CMyComPtr<ICompressProgressInfo> progress = lps;
  lps->Init(extractCallback, false);

  bool checkSumOK = true;
  if (_optHeader.CheckSum != 0 && (int)numItems == _sections.Size())
  {
    UInt32 checkSum = 0;
    RINOK(_inStream->Seek(0, STREAM_SEEK_SET, NULL));
    CalcCheckSum(_inStream, _totalSizeLimited, _peOffset + kHeaderSize + 64, checkSum);
    checkSumOK = (checkSum == _optHeader.CheckSum);
  }

  CLimitedSequentialInStream *streamSpec = new CLimitedSequentialInStream;
  CMyComPtr<ISequentialInStream> inStream(streamSpec);
  streamSpec->SetStream(_inStream);

  CDummyOutStream *outStreamSpec = new CDummyOutStream;
  CMyComPtr<ISequentialOutStream> outStream(outStreamSpec);

  for (i = 0; i < numItems; i++, currentTotalSize += currentItemSize)
  {
    lps->InSize = lps->OutSize = currentTotalSize;
    RINOK(lps->SetCur());
    Int32 askMode = testMode ?
        NArchive::NExtract::NAskMode::kTest :
        NArchive::NExtract::NAskMode::kExtract;
    UInt32 index = allFilesMode ? i : indices[i];
    const CSection &item = _sections[index];
    currentItemSize = item.GetPackSize();
    {
      CMyComPtr<ISequentialOutStream> realOutStream;
      RINOK(extractCallback->GetStream(index, &realOutStream, askMode));
      if (!testMode && (!realOutStream))
        continue;
      outStreamSpec->SetStream(realOutStream);
      outStreamSpec->Init();
    }
      
    RINOK(extractCallback->PrepareOperation(askMode));
    RINOK(_inStream->Seek(item.Pa, STREAM_SEEK_SET, NULL));
    streamSpec->Init(currentItemSize);
    RINOK(copyCoder->Code(inStream, outStream, NULL, NULL, progress));
    outStreamSpec->ReleaseStream();
    RINOK(extractCallback->SetOperationResult((copyCoderSpec->TotalSize == currentItemSize) ?
      checkSumOK ?
        NArchive::NExtract::NOperationResult::kOK:
        NArchive::NExtract::NOperationResult::kCRCError:
        NArchive::NExtract::NOperationResult::kDataError));
  }
  return S_OK;
  COM_TRY_END
}

static IInArchive *CreateArc() { return new CHandler; }

static CArcInfo g_ArcInfo =
  { L"PE", L"", 0, 0xDD, { 0 }, 0, false, CreateArc, 0 };

REGISTER_ARC(Pe)

}}

⌨️ 快捷键说明

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