<commit_before>// Copyright (C) 2010-2013 <NAME>.
// See the file COPYING for copying permission.

#include <windows.h>
#include <winnt.h>
#include <winternl.h>

#include <hadesmem/config.hpp>
#include <hadesmem/detail/winternl.hpp>
#include <hadesmem/find_procedure.hpp>
#include <hadesmem/module.hpp>
#include <hadesmem/patcher.hpp>
#include <hadesmem/process.hpp>

// TODO: Write a test app to exercise all the hooked APIs and information
// classes.

namespace winternl = hadesmem::detail::winternl;

std::unique_ptr<hadesmem::Process> g_process;

std::unique_ptr<hadesmem::PatchDetour> g_nt_query_system_information_hk;

class SystemProcessInformationEnum
{
public:
  explicit SystemProcessInformationEnum(
    winternl::SYSTEM_INFORMATION_CLASS info_class,
    void* buffer) HADESMEM_DETAIL_NOEXCEPT
    : buffer_(GetRealBuffer(info_class, buffer)),
      prev_(nullptr),
      info_class_(info_class),
      unlinked_(false)
  {
    HADESMEM_DETAIL_ASSERT(buffer_);
    HADESMEM_DETAIL_ASSERT(
      info_class == winternl::SystemProcessInformation ||
      info_class == winternl::SystemExtendedProcessInformation ||
      info_class == winternl::SystemSessionProcessInformation ||
      info_class == winternl::SystemFullProcessInformation);
  }

  SystemProcessInformationEnum(SystemProcessInformationEnum const&) = delete;

  SystemProcessInformationEnum& operator=(SystemProcessInformationEnum const&) =
    delete;

  void Advance() HADESMEM_DETAIL_NOEXCEPT
  {
    if (!unlinked_)
    {
      prev_ = buffer_;
    }

    unlinked_ = false;

    if (buffer_->NextEntryOffset)
    {
      buffer_ = reinterpret_cast<winternl::SYSTEM_PROCESS_INFORMATION*>(
        reinterpret_cast<DWORD_PTR>(buffer_) + buffer_->NextEntryOffset);
    }
    else
    {
      buffer_ = nullptr;
    }
  }

  bool Valid() const HADESMEM_DETAIL_NOEXCEPT
  {
    return buffer_ != nullptr;
  }

  void Unlink() HADESMEM_DETAIL_NOEXCEPT
  {
    HADESMEM_DETAIL_ASSERT(buffer_);

    HADESMEM_DETAIL_ASSERT(!unlinked_);

    if (prev_)
    {
      if (buffer_->NextEntryOffset)
      {
        prev_->NextEntryOffset += buffer_->NextEntryOffset;
      }
      else
      {
        prev_->NextEntryOffset = 0UL;
      }

      unlinked_ = true;
    }
    else
    {
      // Unlinking the first process is currently unsupported.
      // TODO: Fix this? It's always the System Idle Process so I'm not
      // sure if this is really useful...
      HADESMEM_DETAIL_ASSERT(false);
    }
  }

  bool HasName() const HADESMEM_DETAIL_NOEXCEPT
  {
    return buffer_->ImageName.Buffer != nullptr && buffer_->ImageName.Length;
  }

  std::wstring GetName() const
  {
    // TODO: I think SystemFullProcessInformation may return the
    // full path rather than just the image name. Need to reverse
    // engineer it further and handle this case if appliciable.
    auto const str_end =
      std::find(buffer_->ImageName.Buffer,
                buffer_->ImageName.Buffer + buffer_->ImageName.Length,
                L'\0');
    return {buffer_->ImageName.Buffer, str_end};
  }

private:
  winternl::SYSTEM_PROCESS_INFORMATION*
    GetRealBuffer(winternl::SYSTEM_INFORMATION_CLASS info_class,
                  void* buffer) const HADESMEM_DETAIL_NOEXCEPT
  {
    if (info_class == winternl::SystemProcessInformation ||
        info_class == winternl::SystemExtendedProcessInformation ||
        info_class == winternl::SystemFullProcessInformation)
    {
      return static_cast<winternl::SYSTEM_PROCESS_INFORMATION*>(buffer);
    }
    else if (info_class == winternl::SystemSessionProcessInformation)
    {
      return static_cast<winternl::SYSTEM_PROCESS_INFORMATION*>(
        static_cast<winternl::SYSTEM_SESSION_PROCESS_INFORMATION*>(buffer)
          ->Buffer);
    }
    else<commit_msg>* [Cerberus] Improve SystemFullProcessInformation handling.<commit_after>// Copyright (C) 2010-2013 <NAME>.
// See the file COPYING for copying permission.

#include <string>
#include <iterator>

#include <windows.h>
#include <winnt.h>
#include <winternl.h>

#include <hadesmem/config.hpp>
#include <hadesmem/detail/winternl.hpp>
#include <hadesmem/find_procedure.hpp>
#include <hadesmem/module.hpp>
#include <hadesmem/patcher.hpp>
#include <hadesmem/process.hpp>

// TODO: Write a test app to exercise all the hooked APIs and information
// classes.

namespace winternl = hadesmem::detail::winternl;

std::unique_ptr<hadesmem::Process> g_process;

std::unique_ptr<hadesmem::PatchDetour> g_nt_query_system_information_hk;

class SystemProcessInformationEnum
{
public:
  explicit SystemProcessInformationEnum(
    winternl::SYSTEM_INFORMATION_CLASS info_class,
    void* buffer) HADESMEM_DETAIL_NOEXCEPT
    : buffer_(GetRealBuffer(info_class, buffer)),
      prev_(nullptr),
      info_class_(info_class),
      unlinked_(false)
  {
    HADESMEM_DETAIL_ASSERT(buffer_);
    HADESMEM_DETAIL_ASSERT(
      info_class == winternl::SystemProcessInformation ||
      info_class == winternl::SystemExtendedProcessInformation ||
      info_class == winternl::SystemSessionProcessInformation ||
      info_class == winternl::SystemFullProcessInformation);
  }

  SystemProcessInformationEnum(SystemProcessInformationEnum const&) = delete;

  SystemProcessInformationEnum& operator=(SystemProcessInformationEnum const&) =
    delete;

  void Advance() HADESMEM_DETAIL_NOEXCEPT
  {
    if (!unlinked_)
    {
      prev_ = buffer_;
    }

    unlinked_ = false;

    if (buffer_->NextEntryOffset)
    {
      buffer_ = reinterpret_cast<winternl::SYSTEM_PROCESS_INFORMATION*>(
        reinterpret_cast<DWORD_PTR>(buffer_) + buffer_->NextEntryOffset);
    }
    else
    {
      buffer_ = nullptr;
    }
  }

  bool Valid() const HADESMEM_DETAIL_NOEXCEPT
  {
    return buffer_ != nullptr;
  }

  void Unlink() HADESMEM_DETAIL_NOEXCEPT
  {
    HADESMEM_DETAIL_ASSERT(buffer_);

    HADESMEM_DETAIL_ASSERT(!unlinked_);

    if (prev_)
    {
      if (buffer_->NextEntryOffset)
      {
        prev_->NextEntryOffset += buffer_->NextEntryOffset;
      }
      else
      {
        prev_->NextEntryOffset = 0UL;
      }

      unlinked_ = true;
    }
    else
    {
      // Unlinking the first process is unsupported.
      HADESMEM_DETAIL_ASSERT(false);
    }
  }

  bool HasName() const HADESMEM_DETAIL_NOEXCEPT
  {
    return buffer_->ImageName.Buffer != nullptr && buffer_->ImageName.Length;
  }

  // TODO: Remove dependency on std::wstring, we shouldn't need to allocate
  // and copy here. This should be a noexcept function returning a range over
  // the existing string buffer.
  std::wstring GetName() const
  {
    auto const str_end =
      std::find(buffer_->ImageName.Buffer,
                buffer_->ImageName.Buffer + buffer_->ImageName.Length,
                L'\0');
    // SystemFullProcessInformation returns the full path rather than just the
    // image name.
    if (info_class_ == winternl::SystemFullProcessInformation)
    {
      auto const name_beg =
        std::find(std::reverse_iterator<wchar_t*>(str_end),
                  std::reverse_iterator<wchar_t*>(buffer_->ImageName.Buffer),
                  L'\\');
      return {name_beg.base(), str_end};
    }
    else
    {
      return {buffer_->ImageName.Buffer, str_end};
    }
  }

private:
  winternl::SYSTEM_PROCESS_INFORMATION*
    GetRealBuffer(winternl::SYSTEM_INFORMATION_CLASS info_class,
                  void* buffer) const HADESMEM_DETAIL_NOEXCEPT
  {
    if (info_class == winternl::SystemProcessInformation ||
        info_class == winternl::SystemExtendedProcessInformation ||
        info_class == winternl::SystemFullProcessInformation)
    {
      return static_cast<winternl::SYSTEM_PROCESS_INFORMATION*>(buffer);
    }
    else if (info_class == winternl::SystemSessionProcessInformation)
    {
      return static_cast<winternl::SYSTEM_PROCESS_INFORMATION*>(
        static_cast<winternl::SYSTEM_SESSION_PROCESS_INFORMATION*>(buffer)
          ->Buffer);
    }
    else
{'fraction_non_alphanumeric': 0.10025188916876575, 'fraction_numerical': 0.0025188916876574307, 'mean_word_length': 3.504254112308565, 'pattern_counts': {'":': 0, '<': 41, '<?xml version=': 0, '>': 68, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '89778', 'n_tokens_mistral': 2530, 'n_tokens_neox': 2397, 'n_words': 462}