-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathmemory.h
143 lines (121 loc) · 4.92 KB
/
memory.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
#pragma once
#include <Windows.h> // for GetModuleHandleA, LPVOID
#include <cstddef> // for size_t, byte, NULL
#include <cstdint> // for int32_t, int64_t, uint32_t, uint64_t, uint8_t
#include <memory> // for unique_ptr
#include <string> // for string, string_literals
#include <string_view> // for string_view
#include <vector>
#include "search.h" // for find_after_bundle
using namespace std::string_literals;
class ExecutableMemory {
public:
ExecutableMemory(std::string_view raw_code);
ExecutableMemory() = default;
ExecutableMemory(const ExecutableMemory &) = delete;
ExecutableMemory(ExecutableMemory &&) noexcept = default;
ExecutableMemory &operator=(const ExecutableMemory &) = delete;
ExecutableMemory &operator=(ExecutableMemory &&) noexcept = default;
std::byte *get() const { return code.get(); }
template <class Ret, class... Args> using func_ptr = Ret (*)(Args...);
template <class Ret, class... Args>
explicit operator func_ptr<Ret, Args...>() const {
return (Ret(*)(Args...))(code.get());
}
private:
struct deleter_t {
void operator()(std::byte *mem) const;
};
using storage_t = std::unique_ptr<std::byte, deleter_t>;
storage_t code;
};
struct Memory {
size_t exe_ptr;
size_t after_bundle;
static Memory &get() {
static Memory mem{[]() {
auto exe = (size_t)GetModuleHandleA(NULL);
// Skipping bundle for faster memory search
auto after_bundle_ = find_after_bundle(exe);
return Memory{
exe,
after_bundle_,
};
}()};
return mem;
}
size_t at_exe(size_t offset) { return exe_ptr + offset; }
char *exe() { return (char *)exe_ptr; }
static size_t decode_call(size_t off) {
auto memory = get();
return off + (*(int32_t *)(&memory.exe()[off + 1])) + 5;
}
};
LPVOID alloc_mem_rel32(size_t addr, size_t size);
void write_mem_prot(size_t addr, std::string_view payload, bool prot);
void write_mem_prot(size_t addr, std::string payload, bool prot);
void write_mem(size_t addr, std::string payload);
size_t function_start(size_t off, uint8_t outside_byte = '\xcc');
void write_mem_recoverable(std::string name, size_t addr,
std::string_view payload, bool prot);
void recover_mem(std::string name, size_t addr = NULL);
bool mem_written(std::string name);
std::string get_nop(size_t size, bool true_nop = false);
// similar to ExecutableMemory but writes automatic jump from and back, moves
// the code it replaces etc. it needs at least 5 bytes to move, use just_nop =
// true to nuke the oryginal code make sure that the first 5 bytes are not a
// destination for some jump (it's fine if it's exacly at the addr)
size_t patch_and_redirect(size_t addr, size_t replace_size,
std::string_view payload, bool just_nop = false,
size_t return_to_addr = 0,
bool game_code_first = true);
template <typename T>
requires std::is_trivially_copyable_v<T>
std::string_view to_le_bytes(const T &payload) {
return std::string_view{reinterpret_cast<const char *>(&payload),
sizeof(payload)};
}
template <class T>
requires(std::is_trivially_copyable_v<T> &&
!std::is_same_v<T, std::string_view>)
void write_mem_recoverable(std::string name, size_t addr, const T &payload,
bool prot) {
write_mem_recoverable(name, addr, to_le_bytes(payload), prot);
}
template <class T>
requires(std::is_trivially_copyable_v<T> &&
!std::is_same_v<T, std::string_view>)
void write_mem_prot(size_t addr, const T &payload, bool prot) {
write_mem_prot(addr, to_le_bytes(payload), prot);
}
template <class T>
requires std::is_trivially_copyable_v<T>
void write_mem_prot(void *addr, const T &payload, bool prot) {
write_mem_prot((size_t)addr, to_le_bytes(payload), prot);
}
template <typename T> inline T memory_read(size_t addr) { return *(T *)(addr); }
template <class FunT, typename T> FunT *vtable_find(T *obj, size_t index) {
void ***ptr = reinterpret_cast<void ***>(obj);
if (!ptr[0])
return static_cast<FunT *>(nullptr);
return reinterpret_cast<FunT *>(&ptr[0][index]);
}
#define ONCE(type) \
static bool once = false; \
static type res; \
if (once) \
return res; \
once = true; \
if (false) \
; \
else
struct RecoverableMemory {
size_t address;
char *old_data;
size_t size;
bool prot_used;
};
struct EditedMemory {
std::vector<RecoverableMemory> mem;
bool dirty;
};