forked from RbxStu/RbxStu
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Hook.cpp
231 lines (197 loc) · 9.85 KB
/
Hook.cpp
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
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
//
// Created by Dottik on 4/4/2024.
//
#include "Hook.hpp"
#include <Log.hpp>
#include <lstate.h>
#include <mutex>
#include "Closures.hpp"
#include "Execution.hpp"
#include "Scheduler.hpp"
#include "Security.hpp"
#include "Utilities.hpp"
#include "cstdlib"
#include "ltable.h"
#include "lualib.h"
Hook *Hook::g_hookSingleton = nullptr;
void Hook::freeblock__detour(lua_State *L, uint32_t sizeClass, void *block) {
if (reinterpret_cast<std::uintptr_t>(block) > 0x00007FF000000000) {
wprintf(L"\r\n\r\n--- CALL INSTRUMENTATION ::freeblock @ RBX ---\r\n");
wprintf(L"--- SUSPICIOUS BLOCK ADDRESS CAUGHT ---\r\n");
wprintf(L"--- CALL INSTRUMENTATION ::freeblock @ RBX ---\r\n\r\n");
wprintf(L"lua state : 0x%p\r\n", L);
wprintf(L"sizeClass : 0x%lx\r\n", sizeClass);
wprintf(L"block : 0x%p\r\n", block);
wprintf(L"*(block - 8): 0x%p\r\n",
*reinterpret_cast<uintptr_t **>(reinterpret_cast<std::uintptr_t>(block) - 8));
wprintf(L"\r\n\r\n--- END CALL INSTRUMENTATION ::freeblock @ RBX ---\r\n\r\n");
wprintf(L"\r\nIN ORDER TO AVOID A CRASH. THIS CALL HAS BEEN OMITTED DUE TO BLOCK APPEARING TO BE A STACK "
L"ADDRESS! POSSIBLE MEMORY LEAK MAY INSUE!\r\n");
return;
}
if (!Module::Utilities::is_pointer_valid(static_cast<std::uintptr_t *>(block)) ||
!Module::Utilities::is_pointer_valid(
reinterpret_cast<std::uintptr_t **>(reinterpret_cast<std::uintptr_t>(block) - 8)) ||
!Module::Utilities::is_pointer_valid(*reinterpret_cast<std::uintptr_t **>(
reinterpret_cast<std::uintptr_t>(block) -
8))) { // It is actually a lua_Page*, but the type is not exposed on Luaus' lgc.h.
wprintf(L"\r\n\r\n--- CALL INSTRUMENTATION ::freeblock @ RBX ---\r\n");
wprintf(L"--- SUSPICIOUS BLOCK ADDRESS CAUGHT ---\r\n");
wprintf(L"--- CALL INSTRUMENTATION ::freeblock @ RBX ---\r\n\r\n");
wprintf(L"lua state : 0x%p\r\n", L);
wprintf(L"sizeClass : 0x%lx\r\n", sizeClass);
wprintf(L"block : 0x%p\r\n", block);
wprintf(L"*(block - 8): 0x%p\r\n",
*reinterpret_cast<uintptr_t **>(reinterpret_cast<std::uintptr_t>(block) - 8));
wprintf(L"\r\n\r\n--- END CALL INSTRUMENTATION ::freeblock @ RBX ---\r\n\r\n");
wprintf(L"\r\nIN ORDER TO AVOID A CRASH. THIS CALL HAS BEEN OMITTED DUE TO BLOCK APPEARING TO BE AN INVALID "
L"POINTER!"
L" POSSIBLE MEMORY LEAK MAY INSUE!\r\n");
return;
}
return Hook::get_singleton()->get_freeblock_original()(L, sizeClass, block);
}
std::mutex mutx{};
long long tries = 0;
void *Hook::pseudo2addr__detour(lua_State *L, int idx) {
mutx.lock();
auto scheduler{Scheduler::get_singleton()};
if (!scheduler->is_initialized() && rand() % 0xff == 0) {
// Randomness for more entropy when getting lua_State*, helped get a valid state faster.
auto ignoreChecks = false;
char buf[(0xff)];
if (tries > 30) {
wprintf(L"You seem to be having issues trying to obtain a lua_State*, make sure to publish your game, at "
L"least privately, else this tool will NOT work!\r\n");
wprintf(L"Validation checks on the lua_State* will be ignored this time. But please remember to publish "
L"privately if you wanna use this tool without being an unstable mess!\r\n");
ignoreChecks = true;
}
if (GetWindowTextA(GetForegroundWindow(), buf, sizeof(buf))) {
if (strstr(buf, ":\\") != nullptr && strstr(buf, "- Roblox Studio") != nullptr &&
strstr(buf, ".rbxl") != nullptr) {
wprintf(L"WARNING: You seem to have a local file open. This tool does not support them correctly, and "
L"the grabbed state may not be correct!\r\n");
ignoreChecks = true;
}
}
auto ud = static_cast<RBX::Lua::ExtraSpace *>(L->userdata);
wprintf(L"Target Lua State ExtraSpace:\r\n");
wprintf(L"Identity: 0x%p\r\n", ud->identity);
wprintf(L"Capabilities: 0x%p\r\n", ud->capabilities);
wprintf(L"Please select your Roblox Studio window if you are using a local file!\r\n");
wprintf(L"Attempting to initialize scheduler... \n");
if (L->singlestep) {
wprintf(L"Not eligible at all. Singlestep detected.\r\n");
tries++;
mutx.unlock();
return Hook::get_singleton()->get_pseudo_original()(L, idx);
}
if (!ignoreChecks) {
auto originalTop = lua_gettop(L);
lua_getglobal(L, "game");
if (lua_isnil(L, -1)) {
lua_settop(L, originalTop); // Reset stack.
wprintf(L"No DataModel found, lua_State* ignored.\r\n");
tries++;
mutx.unlock();
return Hook::get_singleton()->get_pseudo_original()(L, idx);
}
lua_getfield(L, -1, "PlaceId");
const auto placeId = luaL_optinteger(L, -1, -1);
lua_settop(L, originalTop); // Reset stack.
lua_getglobal(L, "game");
lua_getfield(L, -1, "GameId");
const auto gameId = luaL_optinteger(L, -1, -1);
lua_settop(L, originalTop); // Reset stack.
if (placeId == 0 && gameId == 0) {
wprintf(L"PlaceId and GameId are 0, lua_State* ignored.\r\n");
lua_settop(L, originalTop);
tries++;
mutx.unlock();
return Hook::get_singleton()->get_pseudo_original()(L, idx);
}
if (placeId == 0) {
wprintf(L"PlaceId is 0, lua_State* ignored.\r\n");
lua_settop(L, originalTop);
tries++;
mutx.unlock();
return Hook::get_singleton()->get_pseudo_original()(L, idx);
}
if (gameId == 0) {
wprintf(L"GameId is 0, lua_State* ignored.\r\n");
lua_settop(L, originalTop);
tries++;
mutx.unlock();
return Hook::get_singleton()->get_pseudo_original()(L, idx);
}
} else {
wprintf(L"[[Hook]] Checks ignored: You seem to have a local file opened as a place. This is not fully "
L"supported, please use a Place uploaded to RBX.\r\n");
}
auto oldTop = lua_gettop(L);
auto oldObf = static_cast<RBX::Identity>(RBX::Security::to_obfuscated_identity(ud->identity));
RBX::Security::Bypasses::set_thread_security(L, RBX::Identity::Eight_Seven);
auto nL = RBX::Studio::Functions::rlua_newthread(L);
lua_ref(L, -1); // Avoid dying.
auto rL = RBX::Studio::Functions::rlua_newthread(L);
nL->gt = luaH_clone(L, L->gt);
rL->gt = luaH_clone(L, L->global->mainthread->gt);
lua_ref(L, -1); // Avoid dying.
lua_pop(L, 2);
// RBX::Security::Bypasses::SetLuastateCapabilities(L, oldObf);
RBX::Studio::Functions::rFromLuaState(L, nL);
RBX::Security::Bypasses::set_thread_security(L, oldObf);
RBX::Security::Bypasses::reallocate_extraspace(nL);
RBX::Security::Bypasses::set_thread_security(nL, RBX::Identity::Eight_Seven);
lua_settop(L, oldTop);
// auto L_userdata = reinterpret_cast<RBX::Lua::ExtraSpace *>(L->userdata);
// auto nL_userdata = reinterpret_cast<RBX::Lua::ExtraSpace *>(nL->userdata);
// nL_userdata->sharedExtraSpace = L_userdata->sharedExtraSpace;
lua_newtable(nL);
lua_setglobal(nL, "_G");
lua_getglobal(nL, "_G");
lua_setglobal(nL, "shared");
scheduler->initialize_with(nL, rL);
}
mutx.unlock();
return Hook::get_singleton()->get_pseudo_original()(L, idx);
}
Hook *Hook::get_singleton() noexcept {
if (g_hookSingleton == nullptr)
g_hookSingleton = new Hook();
return g_hookSingleton;
}
FunctionTypes::rFreeBlock Hook::get_freeblock_original() const { return this->__original__freeblock__hook; }
FunctionTypes::pseudo2addr Hook::get_pseudo_original() const { return this->__original__pseudo2addr__hook; }
MH_STATUS Hook::remove_hook() const {
LOG_TO_FILE_AND_CONSOLE("remove_hook", "Disabling pseudo2addr hook...");
return MH_DisableHook(reinterpret_cast<void *>(RBX::Studio::Offsets::pseudo2addr));
}
void Hook::wait_until_initialised() {
const auto scheduler{Scheduler::get_singleton()};
LOG_TO_FILE_AND_CONSOLE("wait_until_initialised", "Spin locking until Scheduler is initialized...");
do {
_mm_pause();
} while (!scheduler->is_initialized());
LOG_TO_FILE_AND_CONSOLE("wait_until_initialised", "Scheduler has been initialized.");
}
void Hook::initialize() {
LOG_TO_FILE_AND_CONSOLE("initialize", "Initializing MinHook");
MH_Initialize(); // init mh.
}
MH_STATUS Hook::install_hook() {
LOG_TO_FILE_AND_CONSOLE("install_hook", "Installing pseudo2addr hook...");
MH_CreateHook(reinterpret_cast<void *>(RBX::Studio::Offsets::pseudo2addr), pseudo2addr__detour,
reinterpret_cast<void **>(
const_cast<lua_TValue *(**) (lua_State *, int32_t)>(&__original__pseudo2addr__hook)));
LOG_TO_FILE_AND_CONSOLE("install_hook", "Enabling psuedo2addr hook...");
return MH_EnableHook(reinterpret_cast<void *>(RBX::Studio::Offsets::pseudo2addr));
}
MH_STATUS Hook::install_additional_hooks() {
LOG_TO_FILE_AND_CONSOLE("install_additional_hooks", "Installing freeblock hook...");
MH_CreateHook(reinterpret_cast<void *>(RBX::Studio::Offsets::rFreeBlock), freeblock__detour,
reinterpret_cast<LPVOID *>(&this->__original__freeblock__hook));
LOG_TO_FILE_AND_CONSOLE("install_additional_hooks", "Enabling freeblock hook...");
return MH_EnableHook(reinterpret_cast<void *>(RBX::Studio::Offsets::rFreeBlock));
}