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 "LIEF/PE/Relocation.hpp"
#include "LIEF/PE/RelocationEntry.hpp"
#include "LIEF/PE/LoadConfigurations/DynamicRelocation/FunctionOverrideInfo.hpp"

#include "LIEF/BinaryStream/SpanStream.hpp"

#include "logging.hpp"

namespace LIEF::PE {

FunctionOverrideInfo::FunctionOverrideInfo(uint32_t original_rva,
                                           uint32_t bdd_offset,
                                           uint32_t base_reloc_size) :
  original_rva_(original_rva),
  bdd_offset_(bdd_offset),
  base_relocsz_(base_reloc_size) {}

FunctionOverrideInfo::FunctionOverrideInfo(const FunctionOverrideInfo& other) :
  original_rva_(other.original_rva_),
  bdd_offset_(other.bdd_offset_),
  base_relocsz_(other.base_relocsz_),
  rvas_(other.rvas_) {
  if (!other.relocations_.empty()) {
    relocations_.reserve(other.relocations_.size());
    std::transform(other.relocations_.begin(), other.relocations_.end(),
                   std::back_inserter(relocations_),
                   [](const std::unique_ptr<Relocation>& R) {
                     return std::make_unique<Relocation>(*R);
                   });
  }
}

FunctionOverrideInfo&
    FunctionOverrideInfo::operator=(const FunctionOverrideInfo& other) {
  if (&other == this) {
    return *this;
  }

  original_rva_ = other.original_rva_;
  bdd_offset_ = other.bdd_offset_;
  base_relocsz_ = other.base_relocsz_;
  rvas_ = other.rvas_;

  if (!other.relocations_.empty()) {
    relocations_.reserve(other.relocations_.size());
    std::transform(other.relocations_.begin(), other.relocations_.end(),
                   std::back_inserter(relocations_),
                   [](const std::unique_ptr<Relocation>& R) {
                     return std::make_unique<Relocation>(*R);
                   });
  }

  return *this;
}

FunctionOverrideInfo::FunctionOverrideInfo(FunctionOverrideInfo&&) = default;
FunctionOverrideInfo&
    FunctionOverrideInfo::operator=(FunctionOverrideInfo&&) = default;

FunctionOverrideInfo::~FunctionOverrideInfo() = default;

std::string FunctionOverrideInfo::to_string() const {
  std::ostringstream oss;
  oss << fmt::format("Original RVA:   {:#010x}\n", original_rva())
      << fmt::format("BDD Offset:     {:#010x}\n", bdd_offset())
      << fmt::format("RVA array size: {}\n", rva_size())
      << fmt::format("Reloc size:     {:#06x}\n", base_reloc_size());
  if (!rvas_.empty()) {
    oss << "RVAs:\n";
    for (size_t i = 0; i < rvas_.size(); ++i) {
      oss << fmt::format("  [{:04d}]: {:#010x}\n", i, rvas_[i]);
    }
  }
  if (!relocations_.empty()) {
    oss << "Fixup RVAs:\n";
    for (size_t i = 0; i < relocations_.size(); ++i) {
      const Relocation& R = *relocations_[i];
      oss << fmt::format("  [{:04d}]: RVA: {:#010x}\n", i, R.virtual_address());
      for (const RelocationEntry& E : R.entries()) {
        oss << fmt::format("    {:#010x} ({})\n", E.address(),
                           PE::to_string(E.type()));
      }
    }
  }
  return oss.str();
}

std::unique_ptr<FunctionOverrideInfo>
    FunctionOverrideInfo::parse(Parser& ctx, SpanStream& strm) {
  auto OriginalRva = strm.read<uint32_t>();
  if (!OriginalRva) {
    LIEF_DEBUG(
        "Failed to read IMAGE_FUNCTION_OVERRIDE_DYNAMIC_RELOCATION.OriginalRva"
    );
    return nullptr;
  }

  auto BDDOffset = strm.read<uint32_t>();
  if (!BDDOffset) {
    LIEF_DEBUG(
        "Failed to read IMAGE_FUNCTION_OVERRIDE_DYNAMIC_RELOCATION.BDDOffset"
    );
    return nullptr;
  }

  auto RvaSize = strm.read<uint32_t>();
  if (!RvaSize) {
    LIEF_DEBUG(
        "Failed to read IMAGE_FUNCTION_OVERRIDE_DYNAMIC_RELOCATION.RvaSize"
    );
    return nullptr;
  }

  auto BaseRelocSize = strm.read<uint32_t>();
  if (!BaseRelocSize) {
    LIEF_DEBUG(
        "Failed to read IMAGE_FUNCTION_OVERRIDE_DYNAMIC_RELOCATION.BaseRelocSize"
    );
    return nullptr;
  }

  auto func_override_info =
      std::make_unique<FunctionOverrideInfo>(*OriginalRva, *BDDOffset,
                                             *BaseRelocSize);


  LIEF_DEBUG("OriginalRva: {:#010x}", *OriginalRva);

  if (*RvaSize % sizeof(uint32_t) != 0) {
    LIEF_WARN(
        "IMAGE_FUNCTION_OVERRIDE_DYNAMIC_RELOCATION.RvaSize misaligned: {:#010x}",
        *RvaSize
    );
  }

  const size_t count = *RvaSize / sizeof(uint32_t);
  const size_t reserved = std::min<size_t>(count, 100);
  func_override_info->rvas_.reserve(reserved);

  for (size_t i = 0; i < count; ++i) {
    auto RVA = strm.read<uint32_t>();
    if (!RVA) {
      LIEF_WARN(
          "Failed to read IMAGE_FUNCTION_OVERRIDE_DYNAMIC_RELOCATION.RVAs[{}]", i
      );
      return func_override_info;
    }
    LIEF_DEBUG("IMAGE_FUNCTION_OVERRIDE_DYNAMIC_RELOCATION.RVA[{}]: {:#010x}", i,
               *RVA);
    func_override_info->rvas_.push_back(*RVA);
  }

  auto BaseRelocs = strm.slice(strm.pos(), *BaseRelocSize);
  if (!BaseRelocs) {
    LIEF_WARN(
        "Failed to slice IMAGE_FUNCTION_OVERRIDE_DYNAMIC_RELOCATION.BaseRelocs"
    );
    return func_override_info;
  }

  strm.increment_pos(*BaseRelocSize);

  Relocation::relocations_t relocations = Relocation::parse(ctx, *BaseRelocs);
  func_override_info->relocations_ = std::move(relocations);
  return func_override_info;
}

}