SHOW:
|
|
- or go back to the newest paste.
1 | --[[ | |
2 | ||
3 | -Created by Vaeb. | |
4 | ||
5 | ]] | |
6 | ||
7 | _G.scanRemotes = true | |
8 | ||
9 | make_writeable(getrawmetatable(game)) | |
10 | local pseudoEnv = {} | |
11 | local gameMeta = getrawmetatable(game) | |
12 | ||
13 | local tabChar = " " | |
14 | ||
15 | local function getSmaller(a, b, notLast) | |
16 | local aByte = a:byte() or -1 | |
17 | local bByte = b:byte() or -1 | |
18 | if aByte == bByte then | |
19 | if notLast and #a == 1 and #b == 1 then | |
20 | return -1 | |
21 | elseif #b == 1 then | |
22 | return false | |
23 | elseif #a == 1 then | |
24 | return true | |
25 | else | |
26 | return getSmaller(a:sub(2), b:sub(2), notLast) | |
27 | end | |
28 | else | |
29 | return aByte < bByte | |
30 | end | |
31 | end | |
32 | ||
33 | local function parseData(obj, numTabs, isKey, overflow, noTables, forceDict) | |
34 | local objType = typeof(obj) | |
35 | local objStr = tostring(obj) | |
36 | if objType == "table" then | |
37 | if noTables then | |
38 | return objStr | |
39 | end | |
40 | local isCyclic = overflow[obj] | |
41 | overflow[obj] = true | |
42 | local out = {} | |
43 | local nextIndex = 1 | |
44 | local isDict = false | |
45 | local hasTables = false | |
46 | local data = {} | |
47 | ||
48 | for key, val in next, obj do | |
49 | if not hasTables and typeof(val) == "table" then | |
50 | hasTables = true | |
51 | end | |
52 | ||
53 | if not isDict and key ~= nextIndex then | |
54 | isDict = true | |
55 | else | |
56 | nextIndex = nextIndex + 1 | |
57 | end | |
58 | ||
59 | data[#data+1] = {key, val} | |
60 | end | |
61 | ||
62 | if isDict or hasTables or forceDict then | |
63 | out[#out+1] = (isCyclic and "Cyclic " or "") .. "{" | |
64 | table.sort(data, function(a, b) | |
65 | local aType = typeof(a[2]) | |
66 | local bType = typeof(b[2]) | |
67 | if bType == "string" and aType ~= "string" then | |
68 | return false | |
69 | end | |
70 | local res = getSmaller(aType, bType, true) | |
71 | if res == -1 then | |
72 | return getSmaller(tostring(a[1]), tostring(b[1])) | |
73 | else | |
74 | return res | |
75 | end | |
76 | end) | |
77 | for i = 1, #data do | |
78 | local arr = data[i] | |
79 | local nowKey = arr[1] | |
80 | local nowVal = arr[2] | |
81 | local parseKey = parseData(nowKey, numTabs+1, true, overflow, isCyclic) | |
82 | local parseVal = parseData(nowVal, numTabs+1, false, overflow, isCyclic) | |
83 | if isDict then | |
84 | local nowValType = typeof(nowVal) | |
85 | local preStr = "" | |
86 | local postStr = "" | |
87 | if i > 1 and (nowValType == "table" or typeof(data[i-1][2]) ~= nowValType) then | |
88 | preStr = "\n" | |
89 | end | |
90 | if i < #data and nowValType == "table" and typeof(data[i+1][2]) ~= "table" and typeof(data[i+1][2]) == nowValType then | |
91 | postStr = "\n" | |
92 | end | |
93 | out[#out+1] = preStr .. string.rep(tabChar, numTabs+1) .. parseKey .. " = " .. parseVal .. ";" .. postStr | |
94 | else | |
95 | out[#out+1] = string.rep(tabChar, numTabs+1) .. parseVal .. ";" | |
96 | end | |
97 | end | |
98 | out[#out+1] = string.rep(tabChar, numTabs) .. "}" | |
99 | else | |
100 | local data2 = {} | |
101 | for i = 1, #data do | |
102 | local arr = data[i] | |
103 | local nowVal = arr[2] | |
104 | local parseVal = parseData(nowVal, 0, false, overflow, isCyclic) | |
105 | data2[#data2+1] = parseVal | |
106 | end | |
107 | out[#out+1] = "{" .. table.concat(data2, ", ") .. "}" | |
108 | end | |
109 | ||
110 | return table.concat(out, "\n") | |
111 | else | |
112 | local returnVal = nil | |
113 | if (objType == "string" or objType == "Content") and (not isKey or tonumber(obj:sub(1, 1))) then | |
114 | local retVal = '"' .. objStr .. '"' | |
115 | if isKey then | |
116 | retVal = "[" .. retVal .. "]" | |
117 | end | |
118 | returnVal = retVal | |
119 | elseif objType == "EnumItem" then | |
120 | returnVal = "Enum." .. tostring(obj.EnumType) .. "." .. obj.Name | |
121 | elseif objType == "Enum" then | |
122 | returnVal = "Enum." .. objStr | |
123 | elseif objType == "Instance" then | |
124 | returnVal = obj.Parent and obj:GetFullName() or obj.ClassName | |
125 | elseif objType == "CFrame" then | |
126 | returnVal = "CFrame.new(" .. objStr .. ")" | |
127 | elseif objType == "Vector3" then | |
128 | returnVal = "Vector3.new(" .. objStr .. ")" | |
129 | elseif objType == "Vector2" then | |
130 | returnVal = "Vector2.new(" .. objStr .. ")" | |
131 | elseif objType == "UDim2" then | |
132 | returnVal = "UDim2.new(" .. objStr:gsub("[{}]", "") .. ")" | |
133 | elseif objType == "BrickColor" then | |
134 | returnVal = "BrickColor.new(\"" .. objStr .. "\")" | |
135 | elseif objType == "Color3" then | |
136 | returnVal = "Color3.new(" .. objStr .. ")" | |
137 | elseif objType == "NumberRange" then | |
138 | returnVal = "NumberRange.new(" .. objStr:gsub("^%s*(.-)%s*$", "%1"):gsub(" ", ", ") .. ")" | |
139 | elseif objType == "PhysicalProperties" then | |
140 | returnVal = "PhysicalProperties.new(" .. objStr .. ")" | |
141 | else | |
142 | returnVal = objStr | |
143 | end | |
144 | return returnVal | |
145 | end | |
146 | end | |
147 | ||
148 | function tableToString(t) | |
149 | return parseData(t, 0, false, {}, nil, false) | |
150 | end | |
151 | ||
152 | local detectClasses = { | |
153 | BindableEvent = false; | |
154 | BindableFunction = false; | |
155 | RemoteEvent = true; | |
156 | RemoteFunction = true; | |
157 | } | |
158 | ||
159 | local ignoreNames = { | |
160 | Event = true; | |
161 | MessagesChanged = true; | |
162 | } | |
163 | ||
164 | local classMethods = { | |
165 | BindableEvent = "Fire"; | |
166 | BindableFunction = "Invoke"; | |
167 | RemoteEvent = "FireServer"; | |
168 | RemoteFunction = "InvokeServer"; | |
169 | } | |
170 | ||
171 | local realMethods = {} | |
172 | ||
173 | for name, enabled in next, detectClasses do | |
174 | if enabled then | |
175 | realMethods[classMethods[name]] = Instance.new(name)[classMethods[name]] | |
176 | end | |
177 | end | |
178 | ||
179 | for key, value in next, gameMeta do pseudoEnv[key] = value end | |
180 | ||
181 | local incId = 0 | |
182 | ||
183 | gameMeta.__index, gameMeta.__namecall = function(self, key) | |
184 | if not realMethods[key] or ignoreNames[self.Name] or not _G.scanRemotes then return pseudoEnv.__index(self, key) end | |
185 | return function(_, ...) | |
186 | incId = incId + 1 | |
187 | local nowId = incId | |
188 | local strId = "[RemoteSpy_" .. nowId .. "]" | |
189 | ||
190 | local allPassed = {...} | |
191 | local returnValues = {realMethods[key](self, ...)} | |
192 | ||
193 | print("\n" .. strId .. " ClassName: " .. self.ClassName .. " | Path: " .. self:GetFullName() .. " | Method: " .. key .. "\n" .. strId .. " Packed Arguments: " .. tableToString(allPassed) .. "\n" .. strId .. " Packed Returned: " .. tableToString(returnValues) .. "\n") | |
194 | --copystr(tableToString(allPassed)) | |
195 | return unpack(returnValues) | |
196 | end | |
197 | end | |
198 | ||
199 | print("\nRan Vaeb's RemoteSpy\n") |