· 4 years ago · Dec 18, 2020, 06:00 AM
1--[[
2
3Last Updated: 12/17/2020
4[
5 Loader Code
6 if not __hooks then
7 ----- LOAD HOOK API -----
8 local Script = game:HttpGet('https://pastebin.com/raw/YJbQRmzT', true)
9 getgenv().__hooks = loadstring(Script)()
10 -------------------------------
11 end
12]
13
14---------------------------------------------------
15 -- >> DOCUMENTATION << --
16---------------------------------------------------
17 [
18 ** NOTES **
19 * One hook per property
20 * You can create a blank hook instead of using the canwrite function
21 * MethodHooks refer to any property/function that returns a function
22 (i.e. if it returns a function.. it's considered a method hook)
23 * If a hookfunction isn't passed to a regular hook... It returns the value, if the value isn't the same type, it returns the real value
24 * tostring hooking only works on instances
25 * `Name` hooks automatically include tostring hooks
26 ]
27
28 [
29 Example Handler Args
30
31 * Regular Hook *
32 ** Inst <The Current Object>
33 ** Value <The Real Property Value>
34 ** newValue <Property Value Being Attempted>
35 *
36 Ex: handler(Inst, Value, newValue)
37
38 * Method Hook *
39 ** Inst <The Current Object>
40 ** realFunction <The True Function>
41 ** ...*Args* <A tuple of passed arguments>
42 *
43 Ex: handler(Inst, realFunction, ...*Args*)
44 ]
45
46 [
47 Example Hook Table
48 {
49 [1] = *function* < The hooking function >,
50 [2] = *boolean* < isHookDisabled >,
51 [3] = *boolean* < writeDisabled (Can this property be overwritten)) >,
52 MainToggle = *boolean*,
53 MainWrite = *boolean*
54
55 }
56
57 Notes:
58 * MainToggle is used instead of `[2]` when no specific property is provided
59 * MainWrite is used instead of `[3]` when no specific property is provided
60 * ^ These are used to disable all hooks/writing to properties of one Inst/Class
61 ]
62
63 (Raw Functions | Bypass Hooking API)
64 :: rawget
65 - Instance [Inst]
66 - Property [Str]
67
68 :: rawset
69 - Instance [Inst]
70 - Property [Str]
71 - Value [ALL]
72
73 :: rawcall
74 - Instance [Inst]
75 - Arguments [...*Args*]
76 - Method [Str]
77
78 (API Functions)
79 [
80 Examples (get):
81 get(Instance)
82 ]
83 :: get (Get a hook's table)
84 - Instance [Inst]
85 ClassName [Str]
86 Method [Func]
87 - Property [Str] (Optional)
88
89 [
90 Examples (set):
91 set(Instance, property, hookfunction)
92 set(Instance, {properties}, hookfunction)
93 set(ClassName, property, hookfunction)
94 set(ClassName, {properties}, hookfunction)
95 set(Function, hookfunction)
96 ]
97 :: set (Create a hook)
98 - Instance [Inst] | ClassName [Str] | Method [Func]
99 - Property [Str] | PropertyList [Array] | MethodHook [Func] (Inst, Func, ...*Args*)
100 - HookFunction [Func] (Inst, Func, ...*Args*)
101
102 [
103 Examples (toggle)
104 toggle(Instance, Property, boolean)
105 toggle(ClassName, Property, boolean)
106 toggle(Instance, boolean) // Toggles all properties
107 toggle(Classname, boolean) // Toggles all properties
108 ]
109 :: toggle (Toggle hooks)
110 - Instance [Inst]
111 ClassName [Str]
112 Method [Func]
113 - Property [Str]
114 PropertyList [Array]
115 - Debounce [Bool]
116
117 [
118 Examples (canwrite)
119 canwrite(Instance, Property, boolean)
120 canwrite(ClassName, Property, boolean)
121 canwrite(Instance, boolean) // Toggles all properties
122 canwrite(Classname, boolean) // Toggles all properties
123 ]
124 :: canwrite (Toggle writing abilities)
125 - Instance [Inst]
126 ClassName [Str]
127 - Property [Str]
128 PropertyList [Array]
129 - Debounce [Bool]
130
131 [
132 Examples (showtostring)
133 showtostring(Instance, string)
134 ]
135 :: showtostring (Mask tostring)
136
137 [
138 Examples (hidetostring)
139 hidetostring(Instance)
140 ]
141 :: hidetostring (Unmask tostring)
142
143
144-----------------------------------------------
145 ---- >>> END <<< ----
146-----------------------------------------------
147]]
148
149local newcclosure = newcclosure or (function(f)
150 return f
151 end)
152local getnamecallmethod = getnamecallmethod or get_namecall_method
153local getrawmetatable = getrawmetatable or debug.getrawmetatable
154local setreadonly = function(t, b)
155 if setreadonly then
156 setreadonly(t, b)
157 elseif make_writable then
158 make_writable(t, not b)
159 elseif fullaccess then
160 fullaccess(t, not b)
161 end
162end
163
164if not getrawmetatable then
165 return "Methods not available."
166end
167
168local Metatable = getrawmetatable(game)
169local MetatableIndex = Metatable.__index
170local MetatableCall = Metatable.__namecall
171local MetatableNew = Metatable.__newindex
172local MetatableTo = Metatable.__tostring
173local IsA = game.IsA
174
175local CanWrite = true
176local hooks, Hooks = {},
177 {
178 ToStrings = {},
179 Globals = {},
180 Funcs = {},
181 Insts = {}
182 }
183
184local function Get(i)
185 local Type = typeof(i)
186 return (((Type == "string") and "Globals") or ((Type == "function") and "Funcs") or
187 ((Type == "Instance") and "Insts"))
188end
189
190-- Automatically wrap hookfunctions in CClosures
191local function Check(t, ...)
192 local Args, Ret = {...}
193 local Recurse
194 do
195 function Recurse(r, i)
196 if not Args[i] then
197 return Ret
198 end
199 if not r[Args[i]] then
200 r[Args[i]] =
201 setmetatable(
202 {},
203 {
204 __newindex = function(s, i, v)
205 if (i == 1) and (typeof(v) == "function") then
206 rawset(s, i, newcclosure(v))
207 else
208 rawset(s, i, v)
209 end
210 end
211 }
212 )
213 end
214
215 Ret = r[Args[i]]
216 return Recurse(Ret, i + 1)
217 end
218 end
219
220 return Recurse(t, 1)
221end
222
223hooks.get =
224 newcclosure(
225 function(Index, Property)
226 local Act = Get(Index)
227 if not Act then
228 return
229 end
230
231 local Target = Hooks[Act]
232 if (Act == "Globals") or (Act == "Insts") then
233 return Check(Target, Index, Property)
234 elseif (Act == "Funcs") then
235 return Check(Hooks.Funcs, Index)
236 end
237 end
238)
239
240----------------------------------------
241--------------- HOOK API ---------------
242----------------------------------------
243
244hooks.set =
245 newcclosure(
246 function(Index, Props, Func)
247 local Action, Act = typeof(Props), Get(Index)
248 if not Act then
249 return
250 end
251
252 if ((Act == "Globals") or (Act == "Insts")) and (Action == "table") then
253 for __, Property in next, (Props) do
254 local Old = hooks.get(Index, Property)
255 Old[1] = (function()
256 if typeof(Func) == "function" then
257 if (Act == "Insts") and (Property == "Name") then
258 hooks.showtostring(Index, Func())
259 end
260 return Func
261 else
262 if (Act == "Insts") and (Property == "Name") then
263 hooks.showtostring(Index, Func)
264 end
265 return function()
266 return Func
267 end
268 end
269 end)()
270 end
271 elseif ((Act == "Globals") or (Act == "Insts")) and (Action == "string") then
272 local Old = hooks.get(Index, Props)
273 Old[1] = (function()
274 if typeof(Func) == "function" then
275 if (Act == "Insts") and (Props == "Name") then
276 hooks.showtostring(Index, Func())
277 end
278 return Func
279 else
280 if (Act == "Insts") and (Props == "Name") then
281 hooks.showtostring(Index, Func)
282 end
283 return function()
284 return Func
285 end
286 end
287 end)()
288 elseif (Act == "Funcs") and (Action == "function") then
289 local Old = hooks.get(Index)
290 Old[1] = Props
291 end
292 end
293)
294
295hooks.toggle =
296 newcclosure(
297 function(Index, ...)
298 local Args, Act = {...}, Get(Index)
299 local Action = typeof(Args[1])
300 if not Act then
301 return
302 end
303
304 if ((Act == "Globals") or (Act == "Insts")) and (#Args > 1) and (Action == "table") then
305 for __, Property in next, (Args[1]) do
306 local Old = hooks.get(Index, Property)
307 Old[2] = not Args[2]
308 end
309 elseif (typeof(Act) == "string") and (#Args == 1) then
310 local Old = hooks.get(Index)
311 Old.MainToggle = not Args[1]
312 elseif (Action == "string") and (#Args > 1) then
313 local Old = hooks.get(Index, Args[1])
314 Old[2] = not Args[2]
315 end
316 end
317)
318
319hooks.rawget =
320 newcclosure(
321 function(...)
322 return MetatableIndex(...)
323 end
324)
325
326hooks.rawset =
327 newcclosure(
328 function(...)
329 MetatableNew(...)
330 end
331)
332
333hooks.rawcall =
334 newcclosure(
335 function(...)
336 return MetatableCall(...)
337 end
338)
339
340hooks.canwrite =
341 newcclosure(
342 function(Index, ...)
343 local Args, Act = {...}, Get(Index)
344 local Action = typeof(Args[1])
345 if not Act then
346 return
347 end
348
349 if ((Act == "Globals") or (Act == "Insts")) and (#Args > 1) and (Action == "table") then
350 for __, Property in next, (Args[1]) do
351 local Old = hooks.get(Index, Property)
352 Old[3] = not Args[2]
353 end
354 elseif (typeof(Act) == "string") and (#Args == 1) then
355 local Old = hooks.get(Index)
356 Old.MainWrite = not Args[1]
357 elseif (Action == "string") and (#Args > 1) then
358 local Old = hooks.get(Index, Args[1])
359 Old[3] = not Args[2]
360 end
361 end
362)
363
364hooks.showtostring =
365 newcclosure(
366 function(Obj, Value)
367 if (typeof(Value) == "string") then
368 Hooks.ToStrings[Obj] = Value
369 end
370 end
371)
372
373hooks.hidetostring =
374 newcclosure(
375 function(Obj)
376 local StrHook = Hooks.ToStrings[Obj]
377 if StrHook then
378 Hooks.ToStrings[Obj] = nil
379 end
380 end
381)
382
383
384---------------------------------------------
385--------------- HOOK FUNCTIONS --------------
386---------------------------------------------
387
388---- MethodHook
389local function PropertyHook(Return, Obj, Index)
390 local IsMethod = (type(Return) == "function")
391 if (Index == "MainToggle") or (Index == "MainWrite") then
392 return Return
393 end
394
395 local InstHook = Hooks.Insts[Obj]
396 if InstHook and not InstHook.MainToggle then
397 local Prop = InstHook[Index]
398 if Prop and Prop[1] and not Prop[2] then
399 if IsMethod then return Prop[1] end
400
401 local mask = Prop[1](Obj, Return)
402 if (typeof(mask) == typeof(Return)) then
403 return mask
404 end
405
406 return Return
407 end
408 end
409
410 for Class, Hook in next, (Hooks.Globals) do
411 if IsA(Obj, Class) and not Hook.MainToggle then
412 local ClassHook = Hook[Index]
413 if ClassHook and ClassHook[1] and not ClassHook[2] then
414 if IsMethod then return ClassHook[1] end
415
416 local mask = ClassHook[1](Obj, Return)
417 if (typeof(mask) == typeof(Return)) then
418 return mask
419 end
420
421 return Return
422 end
423 end
424 end
425
426 return Return
427end
428
429---- MethodHook
430local function MethodHook(Obj, ...)
431 local Args = {...}
432 local Method = getnamecallmethod()
433
434 local MethodFunc = MetatableIndex(Obj, Method)
435 if (Method == "MainToggle") or (Method == "MainWrite") then
436 return MetatableCall(Obj, ...)
437 end
438
439 local FuncHook = Hooks.Funcs[MethodFunc]
440 if FuncHook and FuncHook[1] and not FuncHook[2] then
441 return FuncHook[1](Obj, MethodFunc, unpack(Args))
442 end
443
444 return MetatableCall(Obj, ...)
445end
446
447
448---- StringHook
449local function StringHook(Obj)
450 local StrHook = Hooks.ToStrings[Obj]
451 if StrHook then
452 return StrHook
453 end
454
455 return MetatableTo(Obj)
456end
457
458
459------------------------------------------------------
460--------------- ATTACH METATABLE HOOKS ---------------
461------------------------------------------------------
462setreadonly(Metatable, false)
463
464----- NAMECALL -----
465Metatable.__namecall = newcclosure(MethodHook)
466
467----- TOSTRING -----
468Metatable.__tostring = newcclosure(StringHook)
469
470----- INDEX -----
471Metatable.__index =
472 newcclosure(
473 function(Parent, Index)
474 local Return = MetatableIndex(Parent, Index)
475 return PropertyHook(Return, Parent, Index)
476 end
477)
478
479----- NEWINDEX -----
480Metatable.__newindex =
481 newcclosure(
482 function(Obj, Index, Value)
483 local Success, Return = pcall(function()
484 return MetatableIndex(Obj, Index)
485 end)
486
487 if not Success or (typeof(Return) ~= typeof(Value)) then
488 return MetatableNew(Obj, Index, Value)
489 end
490
491 local InstHook = Hooks.Insts[Obj]
492 if InstHook then
493 local Prop = InstHook[Index]
494
495 -- If hook exists call it instead
496 if Prop and (typeof(Return) == typeof(Value)) and Prop[1] and not Prop[2] then
497 Prop[1](Obj, Return, Value)
498 return
499 end
500
501 if InstHook.MainWrite or (Prop and Prop[3]) then
502 return
503 end
504 end
505
506 for Class, Hook in next, (Hooks.Globals) do
507 if IsA(Obj, Class) then
508 local ClassHook = Hook[Index]
509
510 -- If hook exists call it instead
511 if ClassHook and (typeof(Return) == typeof(Value)) and ClassHook[1] and not ClassHook[2] then
512 ClassHook[1](Obj, Return, Value)
513 return
514 end
515
516 if Hook.MainWrite or (ClassHook and ClassHook[3]) then
517 return
518 end
519 end
520 end
521
522 return MetatableNew(Obj, Index, Value)
523 end
524)
525
526---------------------------------------
527--------------- CLEANUP ---------------
528---------------------------------------
529setreadonly(Metatable, true)
530
531return hooks
532