current commit
260929.11 · deps: update lief to 1.0.0
/* Copyright 2017 - 2026 R. Thomas
 * Copyright 2017 - 2026 Quarkslab
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
#include <algorithm>

#include "frozen.hpp"

#include "LIEF/PE/hash.hpp"
#include "LIEF/PE/OptionalHeader.hpp"
#include "LIEF/PE/EnumToString.hpp"
#include "PE/Structures.hpp"

#include <spdlog/fmt/fmt.h>
#include <spdlog/fmt/ranges.h>


namespace LIEF::PE {

static constexpr std::array DLL_CHARACTERISTICS_LIST = {
    OptionalHeader::DLL_CHARACTERISTICS::HIGH_ENTROPY_VA,
    OptionalHeader::DLL_CHARACTERISTICS::DYNAMIC_BASE,
    OptionalHeader::DLL_CHARACTERISTICS::FORCE_INTEGRITY,
    OptionalHeader::DLL_CHARACTERISTICS::NX_COMPAT,
    OptionalHeader::DLL_CHARACTERISTICS::NO_ISOLATION,
    OptionalHeader::DLL_CHARACTERISTICS::NO_SEH,
    OptionalHeader::DLL_CHARACTERISTICS::NO_BIND,
    OptionalHeader::DLL_CHARACTERISTICS::APPCONTAINER,
    OptionalHeader::DLL_CHARACTERISTICS::WDM_DRIVER,
    OptionalHeader::DLL_CHARACTERISTICS::GUARD_CF,
    OptionalHeader::DLL_CHARACTERISTICS::TERMINAL_SERVER_AWARE,
};

OptionalHeader::OptionalHeader(const details::pe32_optional_header& header) :
  magic_(static_cast<PE_TYPE>(header.Magic)),
  major_linker_version_(header.MajorLinkerVersion),
  minor_linker_version_(header.MinorLinkerVersion),
  sizeof_code_(header.SizeOfCode),
  sizeof_initialized_data_(header.SizeOfInitializedData),
  sizeof_uninitialized_data_(header.SizeOfUninitializedData),
  entrypoint_(header.AddressOfEntryPoint),
  baseof_code_(header.BaseOfCode),
  baseof_data_(header.BaseOfData),
  imagebase_(header.ImageBase),
  section_align_(header.SectionAlignment),
  file_align_(header.FileAlignment),
  major_os_version_(header.MajorOperatingSystemVersion),
  minor_os_version_(header.MinorOperatingSystemVersion),
  major_image_version_(header.MajorImageVersion),
  minor_image_version_(header.MinorImageVersion),
  major_subsys_version_(header.MajorSubsystemVersion),
  minor_subsys_version_(header.MinorSubsystemVersion),
  win32_version_value_(header.Win32VersionValue),
  sizeof_image_(header.SizeOfImage),
  sizeof_headers_(header.SizeOfHeaders),
  checksum_(header.CheckSum),
  subsystem_(static_cast<SUBSYSTEM>(header.Subsystem)),
  dll_characteristics_(header.DLLCharacteristics),
  sizeof_stack_reserve_(header.SizeOfStackReserve),
  sizeof_stack_commit_(header.SizeOfStackCommit),
  sizeof_heap_reserve_(header.SizeOfHeapReserve),
  sizeof_heap_commit_(header.SizeOfHeapCommit),
  loader_flags_(header.LoaderFlags),
  nb_rva_size_(header.NumberOfRvaAndSize) {}

OptionalHeader::OptionalHeader(const details::pe64_optional_header& header) :
  magic_(static_cast<PE_TYPE>(header.Magic)),
  major_linker_version_(header.MajorLinkerVersion),
  minor_linker_version_(header.MinorLinkerVersion),
  sizeof_code_(header.SizeOfCode),
  sizeof_initialized_data_(header.SizeOfInitializedData),
  sizeof_uninitialized_data_(header.SizeOfUninitializedData),
  entrypoint_(header.AddressOfEntryPoint),
  baseof_code_(header.BaseOfCode),

  imagebase_(header.ImageBase),
  section_align_(header.SectionAlignment),
  file_align_(header.FileAlignment),
  major_os_version_(header.MajorOperatingSystemVersion),
  minor_os_version_(header.MinorOperatingSystemVersion),
  major_image_version_(header.MajorImageVersion),
  minor_image_version_(header.MinorImageVersion),
  major_subsys_version_(header.MajorSubsystemVersion),
  minor_subsys_version_(header.MinorSubsystemVersion),
  win32_version_value_(header.Win32VersionValue),
  sizeof_image_(header.SizeOfImage),
  sizeof_headers_(header.SizeOfHeaders),
  checksum_(header.CheckSum),
  subsystem_(static_cast<SUBSYSTEM>(header.Subsystem)),
  dll_characteristics_(header.DLLCharacteristics),
  sizeof_stack_reserve_(header.SizeOfStackReserve),
  sizeof_stack_commit_(header.SizeOfStackCommit),
  sizeof_heap_reserve_(header.SizeOfHeapReserve),
  sizeof_heap_commit_(header.SizeOfHeapCommit),
  loader_flags_(header.LoaderFlags),
  nb_rva_size_(header.NumberOfRvaAndSize) {}


OptionalHeader OptionalHeader::create(PE_TYPE type) {
  OptionalHeader header;
  header.magic(type);
  header.section_alignment(0x1000);
  header.file_alignment(0x200);
  header.numberof_rva_and_size(16);
  header.subsystem(SUBSYSTEM::WINDOWS_CUI);
  header.major_linker_version(9);
  header.major_operating_system_version(6);
  header.major_subsystem_version(6);
  header.sizeof_stack_reserve(0x100000);
  header.sizeof_stack_commit(0x1000);
  header.sizeof_heap_reserve(0x100000);
  header.sizeof_heap_commit(0x1000);
  header.sizeof_headers(0x400);

  header.imagebase(type == PE_TYPE::PE32 ? 0x400000 : 0x140000000);
  return header;
}

std::vector<OptionalHeader::DLL_CHARACTERISTICS>
    OptionalHeader::dll_characteristics_list() const {
  std::vector<DLL_CHARACTERISTICS> characteristics;
  characteristics.reserve(3);
  std::copy_if(DLL_CHARACTERISTICS_LIST.begin(), DLL_CHARACTERISTICS_LIST.end(),
               std::back_inserter(characteristics),
               [this](DLL_CHARACTERISTICS f) { return has(f); });

  return characteristics;
}

void OptionalHeader::accept(LIEF::Visitor& visitor) const {
  visitor.visit(*this);
}

std::ostream& operator<<(std::ostream& os, const OptionalHeader& entry) {
  const std::vector<OptionalHeader::DLL_CHARACTERISTICS> list =
      entry.dll_characteristics_list();
  std::vector<std::string> list_str;
  list_str.reserve(list.size());
  std::transform(list.begin(), list.end(), std::back_inserter(list_str),
                 [](const auto c) { return to_string(c); });

  os << fmt::format("Magic:                      {:#06x} ({})\n",
                    (uint32_t)entry.magic(), to_string(entry.magic()))
     << fmt::format("Linker version:             {}.{}\n",
                    entry.major_linker_version(), entry.minor_linker_version())
     << fmt::format("Size of code:               {:#x}\n", entry.sizeof_code())
     << fmt::format("Size of initialized data:   {:#x}\n",
                    entry.sizeof_initialized_data())
     << fmt::format("Size of uninitialized data: {:#x}\n",
                    entry.sizeof_uninitialized_data())
     << fmt::format("Entrypoint:                 {:#x}\n",
                    entry.addressof_entrypoint())
     << fmt::format("Base of code:               {:#x}\n", entry.baseof_code())
     << fmt::format("Base of data:               {:#x}\n", entry.baseof_data())
     << fmt::format("Imagebase:                  {:#x}\n", entry.imagebase())
     << fmt::format("Section alignment:          {:#x}\n",
                    entry.section_alignment())
     << fmt::format("File alignment:             {:#x}\n", entry.file_alignment())
     << fmt::format("Operating system version:   {}.{}\n",
                    entry.major_operating_system_version(),
                    entry.minor_operating_system_version())
     << fmt::format("Image version:              {}.{}\n",
                    entry.major_image_version(), entry.minor_image_version())
     << fmt::format("Subsystem version:          {}.{}\n",
                    entry.major_subsystem_version(),
                    entry.minor_subsystem_version())
     << fmt::format("Win32 Version Value:        {:#x}\n",
                    entry.win32_version_value())
     << fmt::format("Size of image:              {:#x}\n", entry.sizeof_image())
     << fmt::format("Size of headers:            {:#x}\n", entry.sizeof_headers())
     << fmt::format("Checksum:                   {:#x}\n", entry.checksum())
     << fmt::format("Subsystem:                  {}\n",
                    to_string(entry.subsystem()))
     << fmt::format("Dll characteristics:        {}\n", fmt::join(list_str, ", "))
     << fmt::format("Size of stack reserve:      {:#x}\n",
                    entry.sizeof_stack_reserve())
     << fmt::format("Size of stack commit:       {:#x}\n",
                    entry.sizeof_stack_commit())
     << fmt::format("Size of heap reserve:       {:#x}\n",
                    entry.sizeof_heap_reserve())
     << fmt::format("Size of heap commit:        {:#x}\n",
                    entry.sizeof_heap_commit())
     << fmt::format("Loader flags:               {:#x}\n", entry.loader_flags())
     << fmt::format("Number of directories:      {}\n",
                    entry.numberof_rva_and_size());
  return os;
}

const char* to_string(OptionalHeader::DLL_CHARACTERISTICS e) {
  CONST_MAP(OptionalHeader::DLL_CHARACTERISTICS, const char*, 11)
  enumStrings{
      {OptionalHeader::DLL_CHARACTERISTICS::HIGH_ENTROPY_VA, "HIGH_ENTROPY_VA"},
      {OptionalHeader::DLL_CHARACTERISTICS::DYNAMIC_BASE, "DYNAMIC_BASE"},
      {OptionalHeader::DLL_CHARACTERISTICS::FORCE_INTEGRITY, "FORCE_INTEGRITY"},
      {OptionalHeader::DLL_CHARACTERISTICS::NX_COMPAT, "NX_COMPAT"},
      {OptionalHeader::DLL_CHARACTERISTICS::NO_ISOLATION, "NO_ISOLATION"},
      {OptionalHeader::DLL_CHARACTERISTICS::NO_SEH, "NO_SEH"},
      {OptionalHeader::DLL_CHARACTERISTICS::NO_BIND, "NO_BIND"},
      {OptionalHeader::DLL_CHARACTERISTICS::APPCONTAINER, "APPCONTAINER"},
      {OptionalHeader::DLL_CHARACTERISTICS::WDM_DRIVER, "WDM_DRIVER"},
      {OptionalHeader::DLL_CHARACTERISTICS::GUARD_CF, "GUARD_CF"},
      {OptionalHeader::DLL_CHARACTERISTICS::TERMINAL_SERVER_AWARE,
       "TERMINAL_SERVER_AWARE"},
  };
  const auto it = enumStrings.find(e);
  return it == enumStrings.end() ? "UNKNOWN" : it->second;
}

const char* to_string(OptionalHeader::SUBSYSTEM e) {
  CONST_MAP(OptionalHeader::SUBSYSTEM, const char*, 15)
  enumStrings{
      {OptionalHeader::SUBSYSTEM::UNKNOWN, "UNKNOWN"},
      {OptionalHeader::SUBSYSTEM::NATIVE, "NATIVE"},
      {OptionalHeader::SUBSYSTEM::WINDOWS_GUI, "WINDOWS_GUI"},
      {OptionalHeader::SUBSYSTEM::WINDOWS_CUI, "WINDOWS_CUI"},
      {OptionalHeader::SUBSYSTEM::OS2_CUI, "OS2_CUI"},
      {OptionalHeader::SUBSYSTEM::POSIX_CUI, "POSIX_CUI"},
      {OptionalHeader::SUBSYSTEM::NATIVE_WINDOWS, "NATIVE_WINDOWS"},
      {OptionalHeader::SUBSYSTEM::WINDOWS_CE_GUI, "WINDOWS_CE_GUI"},
      {OptionalHeader::SUBSYSTEM::EFI_APPLICATION, "EFI_APPLICATION"},
      {OptionalHeader::SUBSYSTEM::EFI_BOOT_SERVICE_DRIVER,
       "EFI_BOOT_SERVICE_DRIVER"},
      {OptionalHeader::SUBSYSTEM::EFI_RUNTIME_DRIVER, "EFI_RUNTIME_DRIVER"},
      {OptionalHeader::SUBSYSTEM::EFI_ROM, "EFI_ROM"},
      {OptionalHeader::SUBSYSTEM::XBOX, "XBOX"},
      {OptionalHeader::SUBSYSTEM::WINDOWS_BOOT_APPLICATION,
       "WINDOWS_BOOT_APPLICATION"},
      {OptionalHeader::SUBSYSTEM::XBOX_CODE_CATALOG, "XBOX_CODE_CATALOG"},
  };
  const auto it = enumStrings.find(e);
  return it == enumStrings.end() ? "UNKNOWN" : it->second;
}

}