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/runtime/windows/PEB.hpp"
#include "LIEF/runtime/windows/Process.hpp"

#include <cstddef>
#include <cstdint>

#include <Windows.h>

namespace LIEF::runtime::windows {
namespace details {

template<class T>
struct peb_layout {
  uint8_t Reserved1[2];
  uint8_t BeingDebugged;
  uint8_t Reserved2[1];
  T Reserved3[2];
  T Ldr;
  T ProcessParameters;
  T Reserved4[3];
  T AtlThunkSListPtr;
  T Reserved5;
  uint32_t Reserved6;
  T Reserved7;
  uint32_t Reserved8;
  uint32_t AtlThunkSListPtr32;
  T Reserved9[45];
  uint8_t Reserved10[96];
  T PostProcessInitRoutine;
  uint8_t Reserved11[128];
  T Reserved12[1];
  uint32_t SessionId;
};

static_assert(offsetof(peb_layout<uint64_t>, BeingDebugged) == 0x02,
              "Invalid layout");
static_assert(offsetof(peb_layout<uint64_t>, SessionId) == 0x2C0,
              "Invalid layout");
static_assert(offsetof(peb_layout<uint32_t>, BeingDebugged) == 0x02,
              "Invalid layout");
static_assert(offsetof(peb_layout<uint32_t>, SessionId) == 0x1D4,
              "Invalid layout");
using peb_layout_t = peb_layout<uintptr_t>;

class peb {
  public:
  explicit peb(const peb_layout_t* raw) :
    raw_(raw) {}

  const peb_layout_t& raw() const {
    return *raw_;
  }

  private:
  const peb_layout_t* raw_ = nullptr;
};

}

// Return the address of the PEB of the current process.
//
// The PEB pointer is stored within the TEB which
// can be accessed through a per-architecture mechanism abstracted by the
// `NtCurrentTeb()` intrinsic:
// - x86_64: `GS:[0x30]`
// - x86: `FS:[0x18]`
// - ARM64: `x18`
static uintptr_t current_peb() {
  constexpr uintptr_t PEB_OFFSET =
      sizeof(uintptr_t) == sizeof(uint64_t) ? 0x60 : 0x30;

  auto teb = reinterpret_cast<uintptr_t>(NtCurrentTeb());
  if (teb == 0) {
    return 0;
  }

  return *reinterpret_cast<const uintptr_t*>(teb + PEB_OFFSET);
}

std::unique_ptr<PEB> PEB::create() {
  const uintptr_t addr = current_peb();
  if (addr == 0) {
    return nullptr;
  }

  auto impl = std::make_unique<details::peb>(
      reinterpret_cast<const details::peb_layout_t*>(addr)
  );

  return std::unique_ptr<PEB>(new PEB(std::move(impl)));
}

bool PEB::being_debugged() const {
  return impl_->raw().BeingDebugged != 0;
}

uintptr_t PEB::ldr() const {
  return impl_->raw().Ldr;
}

uintptr_t PEB::process_parameters() const {
  return impl_->raw().ProcessParameters;
}

uintptr_t PEB::atl_thunk_slist_ptr() const {
  return impl_->raw().AtlThunkSListPtr;
}

uint32_t PEB::atl_thunk_slist_ptr32() const {
  return impl_->raw().AtlThunkSListPtr32;
}

uintptr_t PEB::post_process_init_routine() const {
  return impl_->raw().PostProcessInitRoutine;
}

uint32_t PEB::session_id() const {
  return impl_->raw().SessionId;
}

PEB::PEB(std::unique_ptr<details::peb> impl) :
  impl_(std::move(impl)) {}

PEB::PEB(PEB&&) noexcept = default;
PEB& PEB::operator=(PEB&&) noexcept = default;

PEB::~PEB() = default;
}