Skip to content

Commit

Permalink
Add Process::Watch && Process::Freeze
Browse files Browse the repository at this point in the history
- For this, I had to implement the Variable class, which is not the nicest underneath...
  • Loading branch information
visuve committed Mar 30, 2024
1 parent a5dd564 commit 14f9eba
Show file tree
Hide file tree
Showing 5 changed files with 372 additions and 7 deletions.
3 changes: 2 additions & 1 deletion HackLib/HackLib.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,5 @@
#include "SHA256.hpp"
#include "StrConvert.hpp"
#include "System.hpp"
#include "VirtualMemory.hpp"
#include "Variable.hpp"
#include "VirtualMemory.hpp"
83 changes: 83 additions & 0 deletions HackLib/Process.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,89 @@ Process::~Process()
_targetProcess.Reset();
}

void Process::Watch(const std::set<Variable>& variables, std::chrono::milliseconds interval)
{
auto readPtr = static_cast<void(Process::*)(size_t, void*, size_t) const>(&Process::Read);
auto readFunction = std::bind(readPtr, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3);

auto watchFunction = [=](const Win32Event& event)->uint32_t
{
try
{
std::vector<Variable> copy(variables.begin(), variables.end()); // Sigh... a copy of a copy

while (event.Wait(interval) == WAIT_TIMEOUT)
{
for (Variable& variable : copy)
{
variable.Read(readFunction);

LogInfo << variable;
}
}

return 0;
}
catch (const std::system_error& e)
{
LogError << e.what();
return e.code().value();
}
};

_threads.emplace(watchFunction);
}

void Process::Watch(const Variable& variable, std::chrono::milliseconds interval)
{
const std::set<Variable> variables = { variable };
Watch(std::move(variables), interval);
}

void Process::Freeze(const std::set<Variable>& variables, std::chrono::milliseconds interval)
{
auto writePtr = static_cast<void(Process::*)(size_t, const void*, size_t) const>(&Process::Write);
auto writeFunction = std::bind(writePtr, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3);

auto readPtr = static_cast<void(Process::*)(size_t, void*, size_t) const>(&Process::Read);
auto readFunction = std::bind(readPtr, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3);

auto freezeFunction = [=](const Win32Event& event)->uint32_t
{
try
{
while (event.Wait(interval) == WAIT_TIMEOUT)
{
for (const Variable& variable : variables)
{
variable.Write(writeFunction);

Sleep(1);

Variable copy(variable);
copy.Read(readFunction);
LogInfo << copy;
}
}

return 0;
}
catch (const std::system_error& e)
{
LogError << e.what();
return e.code().value();
}
};

_threads.emplace(freezeFunction);
}

void Process::Freeze(const Variable& variable, std::chrono::milliseconds interval)
{
const std::set<Variable> variables = { variable };
Freeze(std::move(variables), interval);
}

void Process::WaitForIdle()
{
DWORD result = 0;
Expand Down
30 changes: 24 additions & 6 deletions HackLib/Process.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#include "MemoryRegion.hpp"
#include "OpCodes.hpp"
#include "System.hpp"
#include "Variable.hpp"
#include "VirtualMemory.hpp"
#include "Win32Process.hpp"
#include "Win32Thread.hpp"
Expand Down Expand Up @@ -49,13 +50,18 @@ class Process
return ResolvePointer(Address(base), offsets...);
}

void Read(Pointer pointer, auto* value, size_t size) const
inline void Read(Pointer pointer, void* value, size_t size) const
{
size_t bytesRead = _targetProcess.ReadProcessMemory(pointer, value, size);
_ASSERT_EXPR(bytesRead == size, L"ReadProcessMemory size mismatch!");
LogDebug << "Read" << bytesRead << "bytes from" << pointer;
}

inline void Read(size_t offset, void* value, size_t size) const
{
Read(Address(offset), value, size);
}

template<std::semiregular T, size_t N = sizeof(T)>
T Read(Pointer pointer) const
{
Expand All @@ -77,21 +83,28 @@ class Process
return bytes;
}

inline void Write(Pointer pointer, const auto* value, size_t size) const
inline void Write(Pointer pointer, const void* value, size_t size) const
{
size_t bytesWritten = _targetProcess.WriteProcessMemory(pointer, value, size);
_ASSERT_EXPR(bytesWritten == size, L"WriteProcessMemory size mismatch!");
LogDebug << "Wrote" << bytesWritten << "bytes at" << pointer;
}

inline void Write(Pointer pointer, const auto& value) const
inline void Write(size_t offset, const void* value, size_t size) const
{
Write(pointer, &value, sizeof(value));
Write(Address(offset), value, size);
}

template <typename T>
inline void Write(Pointer pointer, const T& value) const
{
Write(pointer, &value, sizeof(T));
}

inline void Write(size_t offset, const auto& value) const
template <typename T>
inline void Write(size_t offset, const T& value) const
{
Write(Address(offset), value);
Write<T>(Address(offset), value);
}

inline void WriteBytes(Pointer pointer, std::span<uint8_t> bytes) const
Expand Down Expand Up @@ -191,6 +204,11 @@ class Process
ChangeBytes(Address(module, offset), from, to);
}

void Watch(const std::set<Variable>& variables, std::chrono::milliseconds interval = 1000ms);
void Watch(const Variable& variable, std::chrono::milliseconds interval = 1000ms);
void Freeze(const std::set<Variable>& variables, std::chrono::milliseconds interval = 1000ms);
void Freeze(const Variable& variable, std::chrono::milliseconds interval = 1000ms);

void WaitForIdle();

bool Verify(std::string_view expectedSHA256) const;
Expand Down
216 changes: 216 additions & 0 deletions HackLib/Variable.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,216 @@
#include "Variable.hpp"
#include "TypeHelp.hpp"

Variable::Variable(const Variable& other) :
Offset(other.Offset),
Name(other.Name),
_value(other._value)
{
}

Variable::Variable(Variable&& other) :
Offset(other.Offset),
Name(other.Name),
_value(std::move(other._value))
{
}

std::type_index Variable::Type() const
{
return _value.type();
}

bool Variable::operator == (const Variable& other) const
{
// The name is irrelevant;
// I do not want to have multiple Variables in a set with the same offset and type
return Offset == other.Offset && Type() == other.Type();
}

std::strong_ordering Variable::operator <=> (const Variable& other) const
{
std::strong_ordering offsetCompare = Offset <=> other.Offset;

if (offsetCompare != 0)
{
return offsetCompare;
}

return HacklibOrder(Type()) <=> HacklibOrder(other.Type());
}

void Variable::Read(std::function<void(size_t, void*, size_t)> readFunction)
{
if (Type() == typeid(uint8_t))
{
uint8_t value = 0;
readFunction(Offset, &value, sizeof(uint8_t));
_value = value;
}
else if (Type() == typeid(uint16_t))
{
uint16_t value = 0;
readFunction(Offset, &value, sizeof(uint16_t));
_value = value;
}
else if (Type() == typeid(uint32_t))
{
uint32_t value = 0;
readFunction(Offset, &value, sizeof(uint32_t));
_value = value;
}
else if (Type() == typeid(uint64_t))
{
uint64_t value = 0;
readFunction(Offset, &value, sizeof(uint64_t));
_value = value;
}
else if (Type() == typeid(int8_t))
{
int8_t value = 0;
readFunction(Offset, &value, sizeof(int8_t));
_value = value;
}
else if (Type() == typeid(int16_t))
{
int16_t value = 0;
readFunction(Offset, &value, sizeof(int16_t));
_value = value;
}
else if (Type() == typeid(int32_t))
{
int32_t value = 0;
readFunction(Offset, &value, sizeof(int32_t));
_value = value;
}
else if (Type() == typeid(int64_t))
{
int64_t value = 0;
readFunction(Offset, &value, sizeof(int64_t));
_value = value;
}
else if (Type() == typeid(float))
{
float value = 0;
readFunction(Offset, &value, sizeof(float));
_value = value;
}
else if (Type() == typeid(double))
{
double value = 0;
readFunction(Offset, &value, sizeof(double));
_value = value;
}
else
{
throw ArgumentException("Unsupported type");
}
}

void Variable::Write(std::function<void(size_t, const void*, size_t)> writeFunction) const
{
if (Type() == typeid(uint8_t))
{
const auto value = std::any_cast<uint8_t>(_value);
writeFunction(Offset, &value, sizeof(uint8_t));
}
else if (Type() == typeid(uint16_t))
{
const auto value = std::any_cast<uint16_t>(_value);
writeFunction(Offset, &value, sizeof(uint16_t));
}
else if (Type() == typeid(uint32_t))
{
const auto value = std::any_cast<uint32_t>(_value);
writeFunction(Offset, &value, sizeof(uint32_t));
}
else if (Type() == typeid(uint64_t))
{
const auto value = std::any_cast<uint64_t>(_value);
writeFunction(Offset, &value, sizeof(uint64_t));
}
else if (Type() == typeid(int8_t))
{
const auto value = std::any_cast<int8_t>(_value);
writeFunction(Offset, &value, sizeof(int8_t));
}
else if (Type() == typeid(int16_t))
{
const auto value = std::any_cast<int16_t>(_value);
writeFunction(Offset, &value, sizeof(int16_t));
}
else if (Type() == typeid(int32_t))
{
const auto value = std::any_cast<int32_t>(_value);
writeFunction(Offset, &value, sizeof(int32_t));
}
else if (Type() == typeid(int64_t))
{
const auto value = std::any_cast<int64_t>(_value);
writeFunction(Offset, &value, sizeof(int64_t));
}
else if (Type() == typeid(float))
{
const auto value = std::any_cast<float>(_value);
writeFunction(Offset, &value, sizeof(float));
}
else if (Type() == typeid(double))
{
const auto value = std::any_cast<double>(_value);
writeFunction(Offset, &value, sizeof(double));
}
else
{
throw ArgumentException("Unsupported type");
}
}

std::ostream& operator << (std::ostream& os, const Variable& variable)
{
if (variable.Type() == typeid(uint8_t))
{
os << variable.Name << '=' << variable.Value<uint8_t>();
}
else if (variable.Type() == typeid(uint16_t))
{
os << variable.Name << '=' << variable.Value<uint16_t>();
}
else if (variable.Type() == typeid(uint32_t))
{
os << variable.Name << '=' << variable.Value<uint32_t>();
}
else if (variable.Type() == typeid(uint64_t))
{
os << variable.Name << '=' << variable.Value<uint64_t>();
}
else if (variable.Type() == typeid(int8_t))
{
os << variable.Name << '=' << variable.Value<int8_t>();
}
else if (variable.Type() == typeid(int16_t))
{
os << variable.Name << '=' << variable.Value<int16_t>();
}
else if (variable.Type() == typeid(int32_t))
{
os << variable.Name << '=' << variable.Value<int32_t>();
}
else if (variable.Type() == typeid(int64_t))
{
os << variable.Name << '=' << variable.Value<int64_t>();
}
else if (variable.Type() == typeid(float))
{
os << variable.Name << '=' << variable.Value<float>();
}
else if (variable.Type() == typeid(double))
{
os << variable.Name << '=' << variable.Value<double>();
}
else
{
throw ArgumentException("Unsupported type");
}

return os;
}
Loading

0 comments on commit 14f9eba

Please sign in to comment.