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 <iterator>
#include <spdlog/fmt/fmt.h>

#include "frozen.hpp"
#include "logging.hpp"
#include "PE/Structures.hpp"

#include "LIEF/Visitor.hpp"
#include "LIEF/BinaryStream/SpanStream.hpp"

#include "LIEF/PE/Section.hpp"
#include "LIEF/COFF/String.hpp"


namespace LIEF::PE {

static constexpr std::array CHARACTERISTICS_LIST = {
    Section::CHARACTERISTICS::TYPE_NO_PAD,
    Section::CHARACTERISTICS::CNT_CODE,
    Section::CHARACTERISTICS::CNT_INITIALIZED_DATA,
    Section::CHARACTERISTICS::CNT_UNINITIALIZED_DATA,
    Section::CHARACTERISTICS::LNK_OTHER,
    Section::CHARACTERISTICS::LNK_INFO,
    Section::CHARACTERISTICS::LNK_REMOVE,
    Section::CHARACTERISTICS::LNK_COMDAT,
    Section::CHARACTERISTICS::GPREL,
    Section::CHARACTERISTICS::MEM_PURGEABLE,
    Section::CHARACTERISTICS::MEM_16BIT,
    Section::CHARACTERISTICS::MEM_LOCKED,
    Section::CHARACTERISTICS::MEM_PRELOAD,
    Section::CHARACTERISTICS::ALIGN_1BYTES,
    Section::CHARACTERISTICS::ALIGN_2BYTES,
    Section::CHARACTERISTICS::ALIGN_4BYTES,
    Section::CHARACTERISTICS::ALIGN_8BYTES,
    Section::CHARACTERISTICS::ALIGN_16BYTES,
    Section::CHARACTERISTICS::ALIGN_32BYTES,
    Section::CHARACTERISTICS::ALIGN_64BYTES,
    Section::CHARACTERISTICS::ALIGN_128BYTES,
    Section::CHARACTERISTICS::ALIGN_256BYTES,
    Section::CHARACTERISTICS::ALIGN_512BYTES,
    Section::CHARACTERISTICS::ALIGN_1024BYTES,
    Section::CHARACTERISTICS::ALIGN_2048BYTES,
    Section::CHARACTERISTICS::ALIGN_4096BYTES,
    Section::CHARACTERISTICS::ALIGN_8192BYTES,
    Section::CHARACTERISTICS::LNK_NRELOC_OVFL,
    Section::CHARACTERISTICS::MEM_DISCARDABLE,
    Section::CHARACTERISTICS::MEM_NOT_CACHED,
    Section::CHARACTERISTICS::MEM_NOT_PAGED,
    Section::CHARACTERISTICS::MEM_SHARED,
    Section::CHARACTERISTICS::MEM_EXECUTE,
    Section::CHARACTERISTICS::MEM_READ,
    Section::CHARACTERISTICS::MEM_WRITE,
};

Section::Section(const details::pe_section& header) :
  virtual_size_{header.VirtualSize},
  pointer_to_relocations_{header.PointerToRelocations},
  pointer_to_linenumbers_{header.PointerToLineNumbers},
  number_of_relocations_{header.NumberOfRelocations},
  number_of_linenumbers_{header.NumberOfLineNumbers},
  characteristics_{header.Characteristics} {
  name_ = std::string(header.Name, sizeof(header.Name));
  virtual_address_ = header.VirtualAddress;
  size_ = header.SizeOfRawData;
  offset_ = header.PointerToRawData;
}

void Section::name(std::string name) {
  if (name.size() > MAX_SECTION_NAME) {
    LIEF_ERR("Section name too long: max {} vs {}", MAX_SECTION_NAME, name.size());
    return;
  }
  name_ = std::move(name);
}

uint32_t Section::sizeof_raw_data() const {
  return size();
}

uint32_t Section::pointerto_raw_data() const {
  return offset();
}

std::vector<Section::CHARACTERISTICS>
    Section::characteristics_to_list(uint32_t value) {
  std::vector<Section::CHARACTERISTICS> list;
  list.reserve(3);
  std::copy_if(CHARACTERISTICS_LIST.begin(), CHARACTERISTICS_LIST.end(),
               std::back_inserter(list),
               [value](CHARACTERISTICS c) { return (value & (uint32_t)c) != 0; });

  return list;
}

void Section::content(const std::vector<uint8_t>& data) {
  content_ = data;
}

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

std::unique_ptr<SpanStream> Section::stream() const {
  return std::make_unique<SpanStream>(content());
}

void Section::clear(uint8_t c) {
  std::fill(content_.begin(), content_.end(), c);
}

std::ostream& operator<<(std::ostream& os, const Section& section) {
  static constexpr auto WIDTH = 24;
  const auto& list = section.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); });

  std::vector<std::string> fullname_hex;
  fullname_hex.reserve(section.name().size());
  std::transform(section.fullname().begin(), section.fullname().end(),
                 std::back_inserter(fullname_hex),
                 [](const char c) { return fmt::format("{:02x}", c); });

  if (const COFF::String* coff_str = section.coff_string()) {
    os << fmt::format("{:{}} {} ({}, {})\n", "Name:", WIDTH, section.name(),
                      fmt::join(fullname_hex, " "), coff_str->str());
  } else {
    os << fmt::format("{:{}} {} ({})\n", "Name:", WIDTH, section.name(),
                      fmt::join(fullname_hex, " "));
  }

  os << fmt::format("{:{}} {:#x}\n", "Virtual Size", WIDTH, section.virtual_size())
     << fmt::format("{:{}} {:#x}\n", "Virtual Address", WIDTH,
                    section.virtual_address())
     << fmt::format("{:{}} [{:#010x}, {:#010x}]\n", "Range", WIDTH,
                    section.virtual_address(),
                    section.virtual_address() + section.virtual_size())
     << fmt::format("{:{}} {:#x}\n", "Size of raw data", WIDTH,
                    section.sizeof_raw_data())
     << fmt::format("{:{}} {:#x}\n", "Pointer to raw data", WIDTH,
                    section.pointerto_raw_data())
     << fmt::format("{:{}} [{:#010x}, {:#010x}]\n", "Range", WIDTH,
                    section.pointerto_raw_data(),
                    section.pointerto_raw_data() + section.sizeof_raw_data())
     << fmt::format("{:{}} {:#x}\n", "Pointer to relocations", WIDTH,
                    section.pointerto_relocation())
     << fmt::format("{:{}} {:#x}\n", "Pointer to line numbers", WIDTH,
                    section.pointerto_line_numbers())
     << fmt::format("{:{}} {:#x}\n", "Number of relocations", WIDTH,
                    section.numberof_relocations())
     << fmt::format("{:{}} {:#x}\n", "Number of lines", WIDTH,
                    section.numberof_line_numbers())
     << fmt::format("{:{}} {}", "Characteristics", WIDTH,
                    fmt::join(list_str, ", "));
  return os;
}


const char* to_string(Section::CHARACTERISTICS e) {
  CONST_MAP(Section::CHARACTERISTICS, const char*, 35)
  enumStrings{
      {Section::CHARACTERISTICS::TYPE_NO_PAD, "TYPE_NO_PAD"},
      {Section::CHARACTERISTICS::CNT_CODE, "CNT_CODE"},
      {Section::CHARACTERISTICS::CNT_INITIALIZED_DATA, "CNT_INITIALIZED_DATA"},
      {Section::CHARACTERISTICS::CNT_UNINITIALIZED_DATA, "CNT_UNINITIALIZED_DATA"},
      {Section::CHARACTERISTICS::LNK_OTHER, "LNK_OTHER"},
      {Section::CHARACTERISTICS::LNK_INFO, "LNK_INFO"},
      {Section::CHARACTERISTICS::LNK_REMOVE, "LNK_REMOVE"},
      {Section::CHARACTERISTICS::LNK_COMDAT, "LNK_COMDAT"},
      {Section::CHARACTERISTICS::GPREL, "GPREL"},
      {Section::CHARACTERISTICS::MEM_PURGEABLE, "MEM_PURGEABLE"},
      {Section::CHARACTERISTICS::MEM_16BIT, "MEM_16BIT"},
      {Section::CHARACTERISTICS::MEM_LOCKED, "MEM_LOCKED"},
      {Section::CHARACTERISTICS::MEM_PRELOAD, "MEM_PRELOAD"},
      {Section::CHARACTERISTICS::ALIGN_1BYTES, "ALIGN_1BYTES"},
      {Section::CHARACTERISTICS::ALIGN_2BYTES, "ALIGN_2BYTES"},
      {Section::CHARACTERISTICS::ALIGN_4BYTES, "ALIGN_4BYTES"},
      {Section::CHARACTERISTICS::ALIGN_8BYTES, "ALIGN_8BYTES"},
      {Section::CHARACTERISTICS::ALIGN_16BYTES, "ALIGN_16BYTES"},
      {Section::CHARACTERISTICS::ALIGN_32BYTES, "ALIGN_32BYTES"},
      {Section::CHARACTERISTICS::ALIGN_64BYTES, "ALIGN_64BYTES"},
      {Section::CHARACTERISTICS::ALIGN_128BYTES, "ALIGN_128BYTES"},
      {Section::CHARACTERISTICS::ALIGN_256BYTES, "ALIGN_256BYTES"},
      {Section::CHARACTERISTICS::ALIGN_512BYTES, "ALIGN_512BYTES"},
      {Section::CHARACTERISTICS::ALIGN_1024BYTES, "ALIGN_1024BYTES"},
      {Section::CHARACTERISTICS::ALIGN_2048BYTES, "ALIGN_2048BYTES"},
      {Section::CHARACTERISTICS::ALIGN_4096BYTES, "ALIGN_4096BYTES"},
      {Section::CHARACTERISTICS::ALIGN_8192BYTES, "ALIGN_8192BYTES"},
      {Section::CHARACTERISTICS::LNK_NRELOC_OVFL, "LNK_NRELOC_OVFL"},
      {Section::CHARACTERISTICS::MEM_DISCARDABLE, "MEM_DISCARDABLE"},
      {Section::CHARACTERISTICS::MEM_NOT_CACHED, "MEM_NOT_CACHED"},
      {Section::CHARACTERISTICS::MEM_NOT_PAGED, "MEM_NOT_PAGED"},
      {Section::CHARACTERISTICS::MEM_SHARED, "MEM_SHARED"},
      {Section::CHARACTERISTICS::MEM_EXECUTE, "MEM_EXECUTE"},
      {Section::CHARACTERISTICS::MEM_READ, "MEM_READ"},
      {Section::CHARACTERISTICS::MEM_WRITE, "MEM_WRITE"}
  };
  const auto it = enumStrings.find(e);
  return it == enumStrings.end() ? "UNKNOWN" : it->second;
}

}