<commit_before>/*
This file is part of HadesMem.
Copyright (C) 2011 <NAME> (a.k.a. RaptorFactor).
<http://www.raptorfactor.com/> <<EMAIL>>

HadesMem is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

HadesMem is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with HadesMem.  If not, see <http://www.gnu.org/licenses/>.
*/

// Hades
#include "Module.hpp"
#include "MemoryMgr.hpp"

namespace Hades
{
  namespace Memory
  {
    // RAII class for AsmJit
    class EnsureAsmJitFree : private boost::noncopyable
    {
    public:
      // Constructor
      EnsureAsmJitFree(PVOID Address) 
        : m_Address(Address)
      { }

      // Destructor
      ~EnsureAsmJitFree()
      {
        // Free memory if necessary
        if (m_Address)
        {
          AsmJit::MemoryManager::getGlobal()->free(m_Address);
        }
      }

      // Get address
      PVOID Get() const 
      {
        return m_Address;
      }

    private:
      // Address
      PVOID m_Address;
    };

    // Open process from process ID
    MemoryMgr::MemoryMgr(DWORD ProcID) 
      : m_Process(ProcID) 
    { }

    // Open process from process name
    MemoryMgr::MemoryMgr(std::wstring const& ProcName) 
      : m_Process(ProcName) 
    { }

    // Open process from window name and class
    MemoryMgr::MemoryMgr(std::wstring const& WindowName, 
      std::wstring const& ClassName) 
      : m_Process(WindowName, ClassName) 
    { }

    // Call remote function
    std::pair<DWORD_PTR, DWORD> MemoryMgr::Call(PVOID Address, 
      std::vector<PVOID> const& Args, 
      CallConv MyCallConv) const 
    {
      // Get number of arguments
      std::size_t NumArgs = Args.size();

      // Create Assembler.
      AsmJit::Assembler MyJitFunc;

      // Allocate memory for return value
      AllocAndFree const ReturnValueRemote(*this, sizeof(DWORD_PTR));

      // Allocate memory for thread's last-error code
      AllocAndFree const LastErrorRemote(*this, sizeof(DWORD));
      
      // Get address of Kernel32.dll
      Module K32Mod(*this, L"kernel32.dll");
      PVOID pGetLastError = GetRemoteProcAddress(K32Mod.GetBase(), 
        L"kernel32.dll", "GetLastError");

#if defined(_M_AMD64) 
      // Check calling convention
      if (MyCallConv != CallConv_X64 && MyCallConv != CallConv_Default)
      {
        BOOST_THROW_EXCEPTION(Error() << 
          ErrorFunction("MemoryMgr::Call") << 
          ErrorString("Invalid calling convention."));
      }

      // Prologue
      MyJitFunc.push(AsmJit::rbp);
      MyJitFunc.mov(AsmJit::rbp, AsmJit::rsp);

      // Allocate ghost space
      MyJitFunc.sub(AsmJit::rsp, AsmJit::Imm(0x20));

      // Set up first 4 parameters
      MyJitFunc.mov(AsmJit::rcx, NumArgs > 0 ? reinterpret_cast<DWORD_PTR>(
        Args[0]) : 0);
      MyJitFunc.mov(AsmJit::rdx, NumArgs > 1 ? reinterpret_cast<DWORD_PTR>(
        Args[1]) : 0);
      MyJitFunc.mov(AsmJit::r8, NumArgs > 2 ? reinterpret_cast<DWORD_PTR>(
        Args[2]) : 0);
      MyJitFunc.mov(AsmJit::r9, NumArgs > 3 ? reinterpret_cast<DWORD_PTR>(
        Args[3]) : 0);

      // Handle remaining parameters (if any)
      if (NumArgs > 4)
      {
        std::for_each(Args.crbegin(), Args.crend() - 4, 
          [&MyJitFunc] (PVOID Arg)
        {
          MyJitFunc.mov(AsmJit::rax, reinterpret_cast<DWORD_PTR>(Arg));
          MyJitFunc.push(AsmJit::rax);
        });
      }

      // Call target
      MyJitFunc.mov(AsmJit::rax, reinterpret_cast<DWORD_PTR>(Address));
      MyJitFunc.call(AsmJit::rax);
      
      // Write return value to memory
      MyJitFunc.mov(AsmJit::rcx, reinterpret_cast<DWORD_PTR>(
        ReturnValueRemote.GetAddress()));
      MyJitFunc.mov(AsmJit::dword_ptr(AsmJit::rcx), AsmJit::rax);

      // Call kernel32.dll!GetLastError
      MyJitFunc.mov(AsmJit::rax, reinterpret_cast<DWORD_PTR>(pGetLastError));
      MyJitFunc.call(AsmJit::rax);
      
      // Write error code to memory
      MyJitFunc.mov(AsmJit::rcx, reinterpret_cast<DWORD_PTR>(
        LastErrorRemote.GetAddress()));
      MyJitFunc.mov(AsmJit::dword_ptr(AsmJit::rcx), AsmJit::rax);

      // Cleanup ghost space
      MyJitFunc.add(AsmJit::rsp, AsmJit::Imm(0x20));

      // Clean up remaining stack space<commit_msg>* Fix x64 build.<commit_after>/*
This file is part of HadesMem.
Copyright (C) 2011 <NAME> (a.k.a. RaptorFactor).
<http://www.raptorfactor.com/> <<EMAIL>>

HadesMem is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

HadesMem is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with HadesMem.  If not, see <http://www.gnu.org/licenses/>.
*/

// Hades
#include "Module.hpp"
#include "MemoryMgr.hpp"

namespace Hades
{
  namespace Memory
  {
    // RAII class for AsmJit
    class EnsureAsmJitFree : private boost::noncopyable
    {
    public:
      // Constructor
      EnsureAsmJitFree(PVOID Address) 
        : m_Address(Address)
      { }

      // Destructor
      ~EnsureAsmJitFree()
      {
        // Free memory if necessary
        if (m_Address)
        {
          AsmJit::MemoryManager::getGlobal()->free(m_Address);
        }
      }

      // Get address
      PVOID Get() const 
      {
        return m_Address;
      }

    private:
      // Address
      PVOID m_Address;
    };

    // Open process from process ID
    MemoryMgr::MemoryMgr(DWORD ProcID) 
      : m_Process(ProcID) 
    { }

    // Open process from process name
    MemoryMgr::MemoryMgr(std::wstring const& ProcName) 
      : m_Process(ProcName) 
    { }

    // Open process from window name and class
    MemoryMgr::MemoryMgr(std::wstring const& WindowName, 
      std::wstring const& ClassName) 
      : m_Process(WindowName, ClassName) 
    { }

    // Call remote function
    std::pair<DWORD_PTR, DWORD> MemoryMgr::Call(PVOID Address, 
      std::vector<PVOID> const& Args, 
      CallConv MyCallConv) const 
    {
      // Get number of arguments
      std::size_t NumArgs = Args.size();

      // Create Assembler.
      AsmJit::Assembler MyJitFunc;

      // Allocate memory for return value
      AllocAndFree const ReturnValueRemote(*this, sizeof(DWORD_PTR));

      // Allocate memory for thread's last-error code
      AllocAndFree const LastErrorRemote(*this, sizeof(DWORD));
      
      // Get address of Kernel32.dll
      Module K32Mod(*this, L"kernel32.dll");
      PVOID pGetLastError = GetRemoteProcAddress(K32Mod.GetBase(), 
        L"kernel32.dll", "GetLastError");

#if defined(_M_AMD64) 
      // Check calling convention
      if (MyCallConv != CallConv_X64 && MyCallConv != CallConv_Default)
      {
        BOOST_THROW_EXCEPTION(Error() << 
          ErrorFunction("MemoryMgr::Call") << 
          ErrorString("Invalid calling convention."));
      }

      // Prologue
      MyJitFunc.push(AsmJit::rbp);
      MyJitFunc.mov(AsmJit::rbp, AsmJit::rsp);

      // Allocate ghost space
      MyJitFunc.sub(AsmJit::rsp, AsmJit::Imm(0x20));

      // Set up first 4 parameters
      MyJitFunc.mov(AsmJit::rcx, NumArgs > 0 ? reinterpret_cast<DWORD_PTR>(
        Args[0]) : 0);
      MyJitFunc.mov(AsmJit::rdx, NumArgs > 1 ? reinterpret_cast<DWORD_PTR>(
        Args[1]) : 0);
      MyJitFunc.mov(AsmJit::r8, NumArgs > 2 ? reinterpret_cast<DWORD_PTR>(
        Args[2]) : 0);
      MyJitFunc.mov(AsmJit::r9, NumArgs > 3 ? reinterpret_cast<DWORD_PTR>(
        Args[3]) : 0);

      // Handle remaining parameters (if any)
      if (NumArgs > 4)
      {
        std::for_each(Args.crbegin(), Args.crend() - 4, 
          [&MyJitFunc] (PVOID Arg)
        {
          MyJitFunc.mov(AsmJit::rax, reinterpret_cast<DWORD_PTR>(Arg));
          MyJitFunc.push(AsmJit::rax);
        });
      }

      // Call target
      MyJitFunc.mov(AsmJit::rax, reinterpret_cast<DWORD_PTR>(Address));
      MyJitFunc.call(AsmJit::rax);
      
      // Write return value to memory
      MyJitFunc.mov(AsmJit::rcx, reinterpret_cast<DWORD_PTR>(
        ReturnValueRemote.GetBase()));
      MyJitFunc.mov(AsmJit::dword_ptr(AsmJit::rcx), AsmJit::rax);

      // Call kernel32.dll!GetLastError
      MyJitFunc.mov(AsmJit::rax, reinterpret_cast<DWORD_PTR>(pGetLastError));
      MyJitFunc.call(AsmJit::rax);
      
      // Write error code to memory
      MyJitFunc.mov(AsmJit::rcx, reinterpret_cast<DWORD_PTR>(
        LastErrorRemote.GetBase()));
      MyJitFunc.mov(AsmJit::dword_ptr(AsmJit::rcx), AsmJit::rax);

      // Cleanup ghost space
      MyJitFunc.add(AsmJit::rsp, AsmJit::Imm(0x20));

      // Clean up remaining stack space
{'fraction_non_alphanumeric': 0.11498220256714486, 'fraction_numerical': 0.00970769064825801, 'mean_word_length': 2.686679920477137, 'pattern_counts': {'":': 0, '<': 43, '<?xml version=': 0, '>': 47, 'https://': 0, 'lorem ipsum': 0, 'www.': 4, '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': '7635609', 'n_tokens_mistral': 3214, 'n_tokens_neox': 3060, 'n_words': 702}