
Universal Script – ADV REMOTE SPY TOOL
--[[
▄▄▄ ▄▄▄▄▄▄▄ ▄▄▄ ▄▄▄
███ ███▀▀▀▀▀ ████▄████
███ ███▄▄ ▀█████▀
███ ███ ▄███████▄
████████ ▀███████ ███▀ ▀███
+------------------------------------------------+
| LEX REMOTE SPY TOOL :: |
| MADE BY LEX |
| VERSION: 0.1.1 |
| Open Source |
+--------------------------------------------+
--]]
local env = getgenv and getgenv() or _G
if env.__LEXSPY_CLEANUP then pcall(env.__LEXSPY_CLEANUP) end
env.__LEXSPY_LOADED = true
local t0 = os.clock()
local Players=game:GetService('Players')
local RunService = game:GetService("RunService")
local UIS = game:GetService("UserInputService")
local RS=game:GetService("ReplicatedStorage")
local CoreGui = game:GetService("CoreGui")
local TS = game:GetService('TweenService')
local plr = Players.LocalPlayer
local TAG = "[Lex Remote Spy] "
local unpack = table.unpack or unpack
local function isfn(f) return type(f) == "function" end
local can={
hooks = isfn(getrawmetatable) and isfn(getnamecallmethod),
setnc = isfn(setnamecallmethod),
readonly=isfn(setreadonly),
cclosure = isfn(newcclosure),
cbvalue=isfn(getcallbackvalue),
writefile=isfn(writefile),
folders = isfn(isfolder) and isfn(makefolder),
loadstr = isfn(loadstring),
fire=isfn(firesignal),
hui = isfn(gethui),
}
local function weak() return setmetatable({}, {__mode = "k"}) end
local remFolder = RS:FindFirstChild("Remotes")
local isBB = remFolder ~= nil and remFolder:FindFirstChild("ParryButtonPress") ~= nil
local S={
on = true,
paused = false,
dir = "All",
query="",
bbOnly = false,
autoscroll = true,
cap=600,
log = {},
nextId = 1,
sel = nil,
blocked={},
ignored={},
dirty=true,
maxQueue = 5000,
muted=weak(),
listeners=weak(),
nListen = 0,
wrapped = weak(),
conns = {},
hooked=false,
dead = false,
}
local BB_NAMES = {
ParryButtonPress = "Parry Request",
AbilityButtonPress = "Ability Request",
ParrySuccess = "Parry Success (server → client)",
ParryFailed = "Parry Failed",
ActivateSuper="Activate Super",
DefensiveMove = "Defensive Move",
TeleportToStandardGame = "Teleport To Standard Game",
Emotes="Emotes Remote",
}
local function friendly(path)
if not path then return end
for key, label in pairs(BB_NAMES) do
if path:find(key, 1, true) then return label end
end
end
local function buildPath(inst)
local chain = {}
local p = inst
while p and p ~= game do
table.insert(chain, 1, p)
p = p.Parent
end
if p ~= game or #chain == 0 then return nil end
local out, from
if chain[2]==plr then
out='game:GetService("Players").LocalPlayer'
from = 3
else
local root=chain[1]
local svc = false
pcall(function() svc = game:GetService(root.ClassName) == root end)
if svc then
out = ("game:GetService(%q)"):format(root.ClassName)
else
out = ("game:WaitForChild(%q)"):format(root.Name)
end
from = 2
end
for i = from, #chain do
out = out .. (":WaitForChild(%q)"):format(chain[i].Name)
end
return out
end
local function pathExpr(inst)
local ok, res = pcall(buildPath, inst)
if ok and res then return res end
local cls, nm = "Instance", "?"
pcall(function() cls, nm = inst.ClassName, inst.Name end)
return "nil --[[" .. tostring(cls) .. " " .. (tostring(nm):gsub("%]%]", "] ]")) .. " (not in game)]]"
end
local OTHER = {
BrickColor = function(v) return ("BrickColor.new(%q)"):format(v.Name) end,
UDim = function(v) return ("UDim.new(%.4f, %d)"):format(v.Scale, v.Offset) end,
Rect = function(v) return ("Rect.new(%g, %g, %g, %g)"):format(v.Min.X, v.Min.Y, v.Max.X, v.Max.Y) end,
NumberRange = function(v) return ("NumberRange.new(%s, %s)"):format(tostring(v.Min),tostring(v.Max)) end,
NumberSequence = function() return "NumberSequence.new(...)" end,
ColorSequence = function() return "ColorSequence.new(...)" end,
EnumItem = tostring,
}
local function ser(v, depth, seen, maxd, code)
depth = depth or 0
seen = seen or {}
maxd = maxd or 6
local t = typeof(v)
if t == "nil" or t == "boolean" then return tostring(v) end
if t == "number" then
if v ~= v then return "0/0" end
if v == math.huge then return "math.huge" end
if v == -math.huge then return "-math.huge" end
if v % 1==0 and math.abs(v) < 1e15 then return tostring(v) end
return ("%.6f"):format(v)
end
if t == "string" then return ("%q"):format(v) end
if t == "Vector3" then
return ("Vector3.new(%.4f, %.4f, %.4f)"):format(v.X,v.Y, v.Z)
elseif t == "Vector2" then
return ("Vector2.new(%.4f, %.4f)"):format(v.X, v.Y)
elseif t == "CFrame" then
local c = {v:GetComponents()}
for i = 1, #c do c[i] = ("%.5f"):format(c[i]) end
return "CFrame.new(" .. table.concat(c, ", ") .. ")"
elseif t == "Color3" then
return ("Color3.fromRGB(%d, %d, %d)"):format(math.floor(v.R*255+0.5),math.floor(v.G*255+0.5), math.floor(v.B*255+0.5))
elseif t == "UDim2" then
return ("UDim2.new(%.4f, %d, %.4f, %d)"):format(v.X.Scale, v.X.Offset, v.Y.Scale, v.Y.Offset)
elseif OTHER[t] then
return OTHER[t](v)
end
if t=="Instance" then
if code then return pathExpr(v) end
local ok, name = pcall(function() return v:GetFullName() end)
if ok then return name end
return "[" .. v.ClassName .. "]"
end
if t == "RBXScriptSignal" then
return code and "nil --[[RBXScriptSignal]]" or "RBXScriptSignal"
end
if t == "function" then
if code then return "nil --[[function]]" end
local ok, src = pcall(debug.info, v, "s")
return "function" .. (ok and (" --[[" .. tostring(src) .. "]]") or "")
end
if t == "thread" then
return code and "nil --[[thread]]" or "coroutine"
end
if t ~= "table" then return tostring(v) end
if seen[v] then return code and "nil --[[cycle]]" or "--[[cycle]]" end
if depth >= maxd then return code and "nil --[[max depth]]" or "--[[max depth]]" end
seen[v]=true
local parts = {}
local n = #v
local shown = math.min(n, 200)
for i = 1, shown do
table.insert(parts, ser(v[i], depth + 1,seen, maxd, code))
end
if n > shown then
table.insert(parts, "--[[+" .. (n - shown) .. " more]]")
end
local extra = 0
for k, val in pairs(v) do
if not (type(k) == "number" and k>=1 and k <= n) then
extra = extra + 1
if extra > 60 then
parts[#parts+1] = "--[[...]]"
break
end
local key
if type(k) == "string" and k:match("^[%a_][%w_]*$") then
key=k
else
key = "[" .. ser(k, depth+1, seen, maxd, code) .. "]"
end
parts[#parts+1] = key .. " = " .. ser(val, depth + 1, seen, maxd, code)
end
end
seen[v] = nil
return "{" .. table.concat(parts, ", ") .. "}"
end
local function fullPath(r)
local ok,p = pcall(function() return r:GetFullName() end)
if ok then return p end
return "[" .. tostring(r) .. "]"
end
local function shortPath(full)
if not full then return "?" end
local bits = {}
for b in full:gmatch("[^%.]+") do bits[#bits+1] = b end
if #bits <= 2 then return full end
return bits[#bits-1] .. "." .. bits[#bits]
end
local function preview(args, n)
if not args then return "()" end
n=n or args.n or #args
if n == 0 then return "()" end
local out = {}
for i = 1, math.min(n, 3) do
local s = ser(args[i], 0, {}, 2)
if #s > 42 then s = s:sub(1, 39) .. "..." end
out[#out+1]=s
end
if n > 3 then out[#out+1] = "..." end
return "(" .. table.concat(out, ", ") .. ")"
end
local queue = {}
local function push(dir, remote, method, args)
if not S.on or S.paused or S.ignored[remote] then return end
if #queue >= S.maxQueue then return end
queue[#queue+1] = {
dir = dir, remote = remote, method = method, args = args,
n = args and args.n or 0,
stamp=os.date("%H:%M:%S"),
blocked = S.blocked[remote] == true,
}
end
local function trimLog()
local extra = #S.log - S.cap
if extra > 0 then
S.log = table.move(S.log, extra + 1, #S.log,1,{})
end
end
local EVENTS = {RemoteEvent = true, UnreliableRemoteEvent = true}
local REMOTES = {RemoteEvent = true, UnreliableRemoteEvent = true, RemoteFunction = true}
local function classOf(r)
local ok, c = pcall(function() return r.ClassName end)
if ok then return c end
end
local function isEvent(r) return EVENTS[classOf(r)] == true end
local function isFunc(r) return classOf(r) == "RemoteFunction" end
local old_namecall,old_newindex,hookedMt
local function wrapInvoke(remote, orig)
local w=function(...)
local args = table.pack(...)
pcall(push, "in", remote, "OnClientInvoke",args)
return orig(unpack(args, 1, args.n))
end
S.wrapped[w]=true
return w
end
local function installHooks()
if not can.hooks then
return false, "executor is missing getrawmetatable / getnamecallmethod"
end
local mt = getrawmetatable(game)
hookedMt = mt
old_namecall = mt.__namecall
old_newindex = mt.__newindex
if can.readonly then pcall(setreadonly, mt,false) end
local function nc(self, ...)
local method = getnamecallmethod()
if (method == "FireServer" or method == "InvokeServer")
and typeof(self) == "Instance"
and not S.muted[coroutine.running()]
and REMOTES[self.ClassName] then
local blocked=S.blocked[self]
if blocked or (S.on and not S.paused and not S.ignored[self]) then
pcall(push, "out",self, method, table.pack(...))
if can.setnc then setnamecallmethod(method) end
if blocked then return nil end
end
end
return old_namecall(self, ...)
end
local function ni(self, key, value)
if key == "OnClientInvoke" and type(value) == "function"
and not S.wrapped[value]
and typeof(self) == "Instance" and self.ClassName == "RemoteFunction" then
return old_newindex(self, key,wrapInvoke(self, value))
end
return old_newindex(self, key, value)
end
local wrap = (can.cclosure and newcclosure) or function(f) return f end
local ok, err = pcall(function()
mt.__namecall = wrap(nc)
mt.__newindex = wrap(ni)
end)
if not ok then
pcall(function()
mt.__namecall = old_namecall
mt.__newindex = old_newindex
end)
end
if can.readonly then pcall(setreadonly, mt, true) end
if not ok then
hookedMt = nil
return false, "couldn't write metatable: " .. tostring(err)
end
return true
end
local function removeHooks()
if not hookedMt then return end
if can.readonly then pcall(setreadonly, hookedMt, false) end
if old_namecall then pcall(function() hookedMt.__namecall = old_namecall end) end
if old_newindex then pcall(function() hookedMt.__newindex=old_newindex end) end
if can.readonly then pcall(setreadonly, hookedMt, true) end
hookedMt = nil
end
local function wrapExisting(remote)
if not (S.hooked and can.cbvalue) then return end
local ok, cb=pcall(getcallbackvalue, remote, "OnClientInvoke")
if ok and type(cb) == "function" and not S.wrapped[cb] then
pcall(function() remote.OnClientInvoke = cb end)
end
end
local function track(inst)
if S.dead then return end
local c=inst.ClassName
if EVENTS[c] then
if S.listeners[inst] then return end
S.listeners[inst]=inst.OnClientEvent:Connect(function(...)
push("in",inst, "OnClientEvent",table.pack(...))
end)
S.nListen += 1
elseif c == "RemoteFunction" then
wrapExisting(inst)
end
end
local function startTracking()
table.insert(S.conns, game.DescendantAdded:Connect(function(inst)
pcall(track, inst)
end))
task.spawn(function()
local ok, all = pcall(game.GetDescendants, game)
if not ok then return end
for i, inst in ipairs(all) do
if S.dead then return end
pcall(track, inst)
if i%2500 == 0 then task.wait() end
end
end)
end
local function disconnectAll()
for _, c in ipairs(S.conns) do pcall(c.Disconnect, c) end
S.conns = {}
for _,c in pairs(S.listeners) do pcall(c.Disconnect, c) end
S.listeners=weak()
S.nListen = 0
end
local function copy(text)
text = tostring(text)
local tries = {setclipboard, toclipboard, writeclipboard, syn and syn.write_clipboard}
for i = 1, 4 do
local f = tries[i]
if isfn(f) and pcall(f, text) then return true end
end
return false
end
local function saveFile(name, body)
if not can.writefile then return false, "writefile unavailable" end
if can.folders then
pcall(function() if not isfolder("LexSpy") then makefolder("LexSpy") end end)
end
local path="LexSpy/" .. name
local ok = pcall(writefile, path, body)
if ok then return true, path end
return false, "writefile failed"
end
local function quiet(fn)
local co = coroutine.running()
S.muted[co] = true
local res = table.pack(pcall(fn))
S.muted[co] = nil
return res
end
local function flash(btn,msg, back)
if not btn then return end
btn.Text = msg
task.delay(1.2, function() btn.Text = back end)
end
local function argList(e)
local out = {}
for i = 1, e.n do out[i] = ser(e.args[i], 0, {}, 10,true) end
return table.concat(out, ", ")
end
local function callText(e)
local path, m = pathExpr(e.remote), e.method
local params = e.n > 0 and "..." or ""
if m == "OnClientEvent" then
return ("%s.OnClientEvent:Connect(function(%s)\n -- captured %s\nend)"):format(path, params, e.stamp)
end
if m == "OnClientInvoke" then
return ("%s.OnClientInvoke = function(%s)\n -- captured %s\nend"):format(path, params,e.stamp)
end
return ("%s:%s(%s)"):format(path, m, argList(e))
end
local function editText(e)
if e.dir == "in" and e.method == "OnClientEvent" and can.fire then
local a = argList(e)
return ("firesignal(%s.OnClientEvent%s)"):format(pathExpr(e.remote), a ~= "" and (", " .. a) or "")
end
return callText(e)
end
local function detailText(e)
local path = fullPath(e.remote)
local L = {
"Remote : " .. path,
"Class : " .. e.remote.ClassName,
"Method : " .. e.method,
"Direction: " .. (e.dir == "in" and "INCOMING (server → client)" or "OUTGOING (client → server)"),
"Time : " .. e.stamp,
}
local nice = friendly(path)
if nice then table.insert(L, "Friendly : " .. nice) end
if e.blocked then table.insert(L,"Status : BLOCKED") end
table.insert(L,"")
table.insert(L, ("Arguments (%d):"):format(e.n))
if e.n == 0 then
table.insert(L, " (none)")
else
for i = 1, e.n do
table.insert(L, (" [%d] (%s)"):format(i, typeof(e.args[i])))
table.insert(L, " " .. ser(e.args[i]))
end
end
table.insert(L, "")
table.insert(L, "Generated:")
table.insert(L,callText(e))
return table.concat(L, "\n")
end
local renderDetail, genScript
local function selected()
if not S.sel then return end
for _, e in ipairs(S.log) do
if e.id == S.sel then return e end
end
end
local UI = {}
local C = {
bg = Color3.fromRGB(18, 18, 22),
bgAlt = Color3.fromRGB(24, 24, 30),
panel = Color3.fromRGB(28, 28, 35),
row = Color3.fromRGB(32, 32, 40),
rowSel = Color3.fromRGB(48, 70,110),
accent = Color3.fromRGB(90, 150, 255),
incoming = Color3.fromRGB(80, 220, 140),
outgoing = Color3.fromRGB(255, 170,60),
text = Color3.fromRGB(230, 230, 235),
dim = Color3.fromRGB(150, 150, 160),
danger=Color3.fromRGB(255, 80, 80),
gold = Color3.fromRGB(255,200,60),
}
local function new(class, props, parent)
local o = Instance.new(class)
for k, v in pairs(props or {}) do o[k] = v end
if parent then o.Parent = parent end
return o
end
local function corner(p, r)
return new("UICorner", {CornerRadius = UDim.new(0, r or 6)}, p)
end
local function stroke(p, color, thick, trans)
return new("UIStroke", {
Color = color or C.accent,
Thickness = thick or 1,
Transparency = trans or 0.5,
ApplyStrokeMode = Enum.ApplyStrokeMode.Border,
}, p)
end
local function btn(parent, text, color, size, pos)
local b = new("TextButton", {
Text = text, Font=Enum.Font.GothamBold, TextSize = 12, TextColor3 = C.text,
BackgroundColor3 = color or C.panel, BackgroundTransparency=0.15,
BorderSizePixel = 0, TextTruncate = Enum.TextTruncate.AtEnd,
Size=size, Position = pos,
}, parent)
corner(b, 5)
stroke(b, C.accent, 1,0.7)
return b
end
local W, H = 820, 540
local TB_H = 68
local EDIT_H, GRID_H=62, 86
local function attach(gui, opener)
local targets={}
if typeof(CoreGui) == "Instance" then table.insert(targets, CoreGui) end
if can.hui then
local ok, h = pcall(gethui)
if ok and typeof(h) == "Instance" then table.insert(targets, h) end
end
local pg = plr and (plr:FindFirstChild("PlayerGui") or plr:WaitForChild("PlayerGui",5))
if pg then table.insert(targets, pg) end
for _, t in ipairs(targets) do
for _, n in ipairs({"LexRemoteSpy", "LexRemoteSpyOpener"}) do
local old = t:FindFirstChild(n)
if old then pcall(old.Destroy, old) end
end
end
for _, t in ipairs(targets) do
pcall(function() gui.Parent = t end)
if gui.Parent == t then
pcall(function() opener.Parent = t end)
return true
end
end
return false
end
local function refreshStatus()
if not UI.status then return end
local txt,col
if not S.on then
txt, col = "OFF", C.danger
elseif S.paused then
txt,col = "PAUSED", C.outgoing
else
txt, col = "ACTIVE", C.incoming
end
UI.status.Text = txt
UI.status.TextColor3 = col
UI.dot.BackgroundColor3 = col
end
local function resetDetail()
S.sel=nil
UI.detailBox.Text = ""
UI.detailTitle.Text = "Select an entry"
UI.editBox.Text = ""
UI.editId = nil
end
local function buildUI()
local gui = new("ScreenGui", {
Name = "LexRemoteSpy", ResetOnSpawn = false, DisplayOrder=999,
ZIndexBehavior = Enum.ZIndexBehavior.Sibling,
})
local opener = new("ScreenGui",{
Name = "LexRemoteSpyOpener", ResetOnSpawn = false, DisplayOrder = 999,
ZIndexBehavior = Enum.ZIndexBehavior.Sibling, Enabled = false,
})
UI.gui = gui
UI.opener=opener
local tab = new("TextButton", {
Text = "LEX", Font = Enum.Font.GothamBlack, TextSize = 12, TextColor3 = C.text,
BackgroundColor3 = C.bgAlt, BorderSizePixel = 0,
Size = UDim2.fromOffset(44, 28), Position = UDim2.new(0, 8, 0.5, -14),
}, opener)
corner(tab, 6)
stroke(tab, C.accent, 1, 0.4)
UI.setOpen = function(v)
gui.Enabled = v
opener.Enabled = not v
end
tab.MouseButton1Click:Connect(function() UI.setOpen(true) end)
local main = new("Frame", {
Name="Main", Size = UDim2.fromOffset(W,H),
Position = UDim2.new(0.5,-W/2, 0.5,-H/2),
BackgroundColor3 = C.bg, BorderSizePixel = 0, Active=true, Draggable = true,
}, gui)
corner(main, 10)
stroke(main, C.accent, 1, 0.4)
local hdr = new("Frame",{
Size = UDim2.new(1, 0, 0, 40), BackgroundColor3 = C.bgAlt, BorderSizePixel = 0,
}, main)
corner(hdr, 10)
new("TextLabel", {
Text = " REMOTE SPY", Font = Enum.Font.GothamBlack,TextSize = 16,TextColor3 = C.text,
BackgroundTransparency = 1, TextXAlignment = Enum.TextXAlignment.Left,
Size=UDim2.new(0, 160, 1, 0), Position = UDim2.new(0, 8,0, 0),
}, hdr)
UI.dot = new("Frame", {
Size = UDim2.fromOffset(10, 10),Position = UDim2.new(0, 172, 0.5, -5),
BackgroundColor3 = C.incoming, BorderSizePixel=0,
}, hdr)
corner(UI.dot, 5)
UI.status = new("TextLabel", {
Text = "ACTIVE",Font = Enum.Font.GothamBold, TextSize = 12,TextColor3 = C.incoming,
BackgroundTransparency = 1, TextXAlignment = Enum.TextXAlignment.Left,
Size = UDim2.new(0, 100, 1, 0), Position = UDim2.new(0, 188, 0, 0),
}, hdr)
local mode = isBB and "BB MODE" or "UNIVERSAL MODE"
if not S.hooked then mode = mode .. " (IN ONLY)" end
new("TextLabel", {
Text = mode, Font = Enum.Font.GothamBold,TextSize = 11,
TextColor3 = isBB and C.gold or C.dim,BackgroundTransparency = 1,
Size = UDim2.new(0, 240, 1, 0), Position=UDim2.new(0.5,-120, 0, 0),
TextXAlignment = Enum.TextXAlignment.Center,
}, hdr)
local closeBtn = new("TextButton", {
Text = "✕", Font = Enum.Font.GothamBold, TextSize = 16, TextColor3 = C.danger,
BackgroundTransparency = 1, Size = UDim2.fromOffset(40, 40), Position = UDim2.new(1,-40, 0, 0),
}, hdr)
local minBtn = new("TextButton",{
Text = "—", Font = Enum.Font.GothamBold, TextSize = 16, TextColor3 = C.dim,
BackgroundTransparency = 1,Size = UDim2.fromOffset(40, 40), Position = UDim2.new(1, -80,0, 0),
}, hdr)
local unloadBtn = new("TextButton", {
Text = "Unload", Font = Enum.Font.GothamBold,TextSize = 11, TextColor3 = C.dim,
BackgroundTransparency = 1, Size = UDim2.fromOffset(60,40), Position = UDim2.new(1, -150, 0, 0),
}, hdr)
local tb = new("Frame", {
Name = "Toolbar",Size = UDim2.new(1, 0, 0, TB_H), Position = UDim2.new(0, 0, 0, 40),
BackgroundColor3 = C.bgAlt, BorderSizePixel = 0,
},main)
local search = new("TextBox", {
Size = UDim2.new(0, 200, 0, 26), Position = UDim2.new(0, 8,0, 6),
BackgroundColor3 = C.panel, BorderSizePixel = 0, Text = "",
PlaceholderText = "Search remote name...", PlaceholderColor3 = C.dim,
Font = Enum.Font.Gotham, TextSize = 12, TextColor3 = C.text,
TextXAlignment = Enum.TextXAlignment.Left, ClearTextOnFocus = false,
},tb)
corner(search, 5)
stroke(search, C.accent, 1, 0.7)
search:GetPropertyChangedSignal("Text"):Connect(function()
S.query=search.Text
S.dirty = true
end)
UI.dirBtn = btn(tb, "All", C.panel, UDim2.fromOffset(80, 26), UDim2.new(0, 216, 0, 6))
UI.bbBtn = btn(tb, "BB Only", C.panel, UDim2.fromOffset(80, 26), UDim2.new(0, 302, 0, 6))
UI.pauseBtn = btn(tb, "Pause", C.panel, UDim2.fromOffset(70, 26), UDim2.new(0,388, 0, 6))
UI.scrollBtn = btn(tb, "AutoScroll ✓", C.rowSel,UDim2.fromOffset(90, 26), UDim2.new(0,464, 0,6))
if not S.autoscroll then
UI.scrollBtn.Text = "AutoScroll"
UI.scrollBtn.BackgroundColor3=C.panel
end
local exportBtn = btn(tb, "Export",C.panel, UDim2.fromOffset(70, 26), UDim2.new(1,-258, 0, 6))
local copyAllBtn = btn(tb, "Copy All", C.panel, UDim2.fromOffset(80,26), UDim2.new(1, -178,0,6))
local clearBtn = btn(tb, "Clear",C.panel, UDim2.fromOffset(70, 26), UDim2.new(1, -90, 0, 6))
local unignoreBtn = btn(tb, "Unignore All", C.panel, UDim2.fromOffset(100, 26), UDim2.new(0, 8, 0, 36))
local unblockBtn = btn(tb, "Unblock All", C.panel, UDim2.fromOffset(100, 26), UDim2.new(0, 114, 0, 36))
local capBtn = btn(tb,"Max: " .. S.cap, C.panel, UDim2.fromOffset(86, 26),UDim2.new(0, 220, 0, 36))
local body = new("Frame", {
Name = "Content", Size = UDim2.new(1, 0, 1, -40 - TB_H - 24),
Position = UDim2.new(0, 0, 0, 40 + TB_H), BackgroundColor3 = C.bg, BorderSizePixel = 0,
}, main)
local listBox=new("Frame", {
Size = UDim2.new(0.58, -8, 1, -8), Position = UDim2.new(0, 6, 0, 4),
BackgroundColor3 = C.bgAlt, BorderSizePixel = 0,
}, body)
corner(listBox, 8)
UI.list = new("ScrollingFrame", {
Size = UDim2.new(1, -8, 1, -8), Position = UDim2.new(0, 4, 0, 4),
BackgroundTransparency=1, BorderSizePixel = 0, ScrollBarThickness=6,
ScrollBarImageColor3 = C.accent, CanvasSize = UDim2.new(),
AutomaticCanvasSize = Enum.AutomaticSize.Y,
}, listBox)
new("UIListLayout", {Padding = UDim.new(0, 3),SortOrder = Enum.SortOrder.LayoutOrder}, UI.list)
new("UIPadding", {PaddingTop = UDim.new(0, 2), PaddingLeft = UDim.new(0, 2), PaddingRight = UDim.new(0, 2)}, UI.list)
local right = new("Frame", {
Size = UDim2.new(0.42, -8, 1,-8), Position = UDim2.new(0.58, 2, 0, 4),
BackgroundColor3 = C.bgAlt, BorderSizePixel = 0,
},body)
corner(right, 8)
UI.detailTitle=new("TextLabel", {
Text = "Select an entry", Font = Enum.Font.GothamBold, TextSize = 13, TextColor3 = C.text,
BackgroundTransparency = 1, TextXAlignment = Enum.TextXAlignment.Left,
Size = UDim2.new(1, -12,0, 26), Position = UDim2.new(0, 6, 0, 4),
}, right)
local scroll = new("ScrollingFrame", {
Size = UDim2.new(1, -12, 1, -(30 + 4+EDIT_H+4 + GRID_H + 4)),
Position = UDim2.new(0, 6, 0, 30), BackgroundColor3 = C.panel, BorderSizePixel = 0,
ScrollBarThickness = 6,ScrollBarImageColor3 = C.accent, CanvasSize = UDim2.new(),
AutomaticCanvasSize = Enum.AutomaticSize.Y,
},right)
corner(scroll, 6)
UI.detailBox=new("TextBox", {
Size = UDim2.new(1, -8, 0, 0), Position = UDim2.new(0, 4, 0, 4), BackgroundTransparency = 1,
Text="",Font = Enum.Font.Code, TextSize = 12, TextColor3 = C.text, TextWrapped = true,
TextXAlignment = Enum.TextXAlignment.Left, TextYAlignment = Enum.TextYAlignment.Top,
TextEditable = false, ClearTextOnFocus = false, AutomaticSize = Enum.AutomaticSize.Y,
}, scroll)
UI.editBox = new("TextBox", {
Name = "Editor", Size=UDim2.new(1, -12, 0, EDIT_H),
Position = UDim2.new(0, 6, 1, -(GRID_H + 8 + EDIT_H)),
BackgroundColor3 = C.panel, BorderSizePixel = 0,Text = "",
PlaceholderText = "Select an entry to load its call here, edit it, then press Run Edited",
PlaceholderColor3 = C.dim, Font = Enum.Font.Code, TextSize = 11, TextColor3 = C.text,
TextWrapped = true, MultiLine = true, ClearTextOnFocus = false, ClipsDescendants = true,
TextXAlignment = Enum.TextXAlignment.Left, TextYAlignment = Enum.TextYAlignment.Top,
}, right)
corner(UI.editBox,6)
stroke(UI.editBox, C.accent, 1,0.7)
local grid = new("Frame", {
Size = UDim2.new(1, -12, 0, GRID_H), Position = UDim2.new(0, 6, 1, -(GRID_H + 4)),
BackgroundTransparency = 1,
}, right)
new("UIGridLayout", {
CellSize = UDim2.new(1/3, -4,0, 26), CellPadding = UDim2.new(0, 6, 0, 4),
SortOrder = Enum.SortOrder.LayoutOrder,
}, grid)
UI.copyCall = btn(grid, "Copy Call")
UI.copyArgs = btn(grid, "Copy Args")
UI.copyPath = btn(grid, "Copy Path")
UI.fireBtn = btn(grid, "Fire Again")
UI.invokeBtn = btn(grid, "Invoke Again")
UI.runBtn = btn(grid, "Run Edited")
UI.blockBtn = btn(grid, "Block")
UI.ignoreBtn = btn(grid, "Ignore")
UI.onlyBtn = btn(grid, "Only This")
UI.removeBtn = btn(grid, "Remove", C.danger)
UI.fireLabel = "Fire Again"
UI.invokeBtn.Visible = false
local footer=new("Frame", {
Name = "Footer", Size = UDim2.new(1, 0, 0, 24), Position = UDim2.new(0, 0, 1, -24),
BackgroundColor3 = C.bgAlt, BorderSizePixel = 0,
}, main)
UI.stats = new("TextLabel", {
Text = "0 total | 0 in | 0 out | 0 blocked",Font=Enum.Font.Gotham,TextSize = 11,
TextColor3 = C.dim, BackgroundTransparency = 1, TextXAlignment = Enum.TextXAlignment.Left,
Size = UDim2.new(1, -16, 1, 0), Position = UDim2.new(0, 8, 0, 0),
}, footer)
closeBtn.MouseButton1Click:Connect(function() UI.setOpen(false) end)
local armed = false
unloadBtn.MouseButton1Click:Connect(function()
if not armed then
armed = true
unloadBtn.Text = "Sure?"
unloadBtn.TextColor3=C.danger
task.delay(2, function()
armed = false
unloadBtn.Text = "Unload"
unloadBtn.TextColor3 = C.dim
end)
return
end
if env.__LEXSPY_CLEANUP then env.__LEXSPY_CLEANUP() end
end)
minBtn.MouseButton1Click:Connect(function()
local open = main.Size.Y.Offset ~= 40
TS:Create(main, TweenInfo.new(0.18), {Size = UDim2.fromOffset(W, open and 40 or H)}):Play()
body.Visible = not open
footer.Visible = not open
tb.Visible = not open
end)
UI.dirBtn.MouseButton1Click:Connect(function()
local order = {"All","Incoming", "Outgoing"}
local at = table.find(order, S.dir) or 1
S.dir=order[at % #order+1]
UI.dirBtn.Text = S.dir
S.dirty = true
end)
UI.bbBtn.MouseButton1Click:Connect(function()
S.bbOnly = not S.bbOnly
UI.bbBtn.Text = S.bbOnly and "BB Only ✓" or "BB Only"
UI.bbBtn.BackgroundColor3 = S.bbOnly and C.rowSel or C.panel
S.dirty = true
end)
UI.pauseBtn.MouseButton1Click:Connect(function()
S.paused = not S.paused
UI.pauseBtn.Text = S.paused and "Resume" or "Pause"
UI.pauseBtn.BackgroundColor3 = S.paused and C.rowSel or C.panel
refreshStatus()
end)
UI.scrollBtn.MouseButton1Click:Connect(function()
S.autoscroll = not S.autoscroll
UI.scrollBtn.Text = S.autoscroll and "AutoScroll ✓" or "AutoScroll"
UI.scrollBtn.BackgroundColor3 = S.autoscroll and C.rowSel or C.panel
end)
clearBtn.MouseButton1Click:Connect(function()
S.log = {}
queue = {}
S.dirty = true
resetDetail()
end)
exportBtn.MouseButton1Click:Connect(function()
local fname = "remote_log_" .. os.date("%Y%m%d_%H%M%S") .. ".lua"
local ok, where = saveFile(fname, genScript(S.log))
if ok then print(TAG .. "saved " .. tostring(where)) end
flash(exportBtn, ok and "Saved ✓" or "No writefile", "Export")
end)
unignoreBtn.MouseButton1Click:Connect(function()
S.ignored = {}
S.dirty = true
renderDetail()
flash(unignoreBtn, "Done ✓", "Unignore All")
end)
unblockBtn.MouseButton1Click:Connect(function()
S.blocked = {}
S.dirty = true
renderDetail()
flash(unblockBtn, "Done ✓", "Unblock All")
end)
capBtn.MouseButton1Click:Connect(function()
local sizes={200, 600, 1500, 3000}
local at = table.find(sizes, S.cap) or 0
S.cap = sizes[at%#sizes + 1]
capBtn.Text = "Max: " .. S.cap
trimLog()
S.dirty = true
end)
copyAllBtn.MouseButton1Click:Connect(function()
flash(copyAllBtn, copy(genScript(S.log)) and "Copied ✓" or "No clipboard", "Copy All")
end)
UI.copyCall.MouseButton1Click:Connect(function()
local e = selected()
if not e then return end
flash(UI.copyCall, copy(callText(e)) and "Copied ✓" or "No clipboard", "Copy Call")
end)
UI.copyArgs.MouseButton1Click:Connect(function()
local e = selected()
if not e then return end
local parts = {}
for i = 1, e.n do parts[i] = ser(e.args[i], 0, {}, 10, true) end
flash(UI.copyArgs, copy(table.concat(parts, ",\n")) and "Copied ✓" or "No clipboard", "Copy Args")
end)
UI.copyPath.MouseButton1Click:Connect(function()
local e = selected()
if not e then return end
flash(UI.copyPath, copy(fullPath(e.remote)) and "Copied ✓" or "No clipboard", "Copy Path")
end)
UI.fireBtn.MouseButton1Click:Connect(function()
local e = selected()
if not e or not isEvent(e.remote) then return end
local res
if e.dir=="in" then
if not can.fire then return end
res = quiet(function() firesignal(e.remote.OnClientEvent, unpack(e.args, 1, e.n)) end)
else
res = quiet(function() e.remote:FireServer(unpack(e.args, 1, e.n)) end)
end
flash(UI.fireBtn,res[1] and "Fired ✓" or "Error", UI.fireLabel)
end)
UI.invokeBtn.MouseButton1Click:Connect(function()
local e = selected()
if not e or e.dir ~= "out" or not isFunc(e.remote) then return end
local res = quiet(function() return e.remote:InvokeServer(unpack(e.args, 1, e.n)) end)
if S.sel==e.id then
if res[1] then
local out = {}
for i = 2, res.n do table.insert(out, ser(res[i])) end
UI.detailBox.Text = UI.detailBox.Text .. "\n\n-- InvokeServer returned:\n" .. (#out > 0 and table.concat(out, ",\n") or "(nothing)")
else
UI.detailBox.Text = UI.detailBox.Text .. "\n\n-- InvokeServer error:\n" .. tostring(res[2])
end
end
flash(UI.invokeBtn, res[1] and "Invoked ✓" or "Error", "Invoke Again")
end)
UI.runBtn.MouseButton1Click:Connect(function()
local src = UI.editBox.Text
if not src:find("%S") then return end
if not can.loadstr then
flash(UI.runBtn, "No loadstring", "Run Edited")
return
end
local id = S.sel
local fn, cerr = loadstring(src)
if not fn then
if S.sel == id then
UI.detailBox.Text = UI.detailBox.Text .. "\n\n-- Run Edited: syntax error\n" .. tostring(cerr)
end
flash(UI.runBtn, "Syntax error", "Run Edited")
return
end
local res = quiet(fn)
if S.sel == id then
if res[1] then
local out = {}
for i = 2, res.n do out[#out+1] = ser(res[i]) end
UI.detailBox.Text = UI.detailBox.Text .. "\n\n-- Run Edited: ok" .. (#out > 0 and ("\n" .. table.concat(out, ",\n")) or "")
else
UI.detailBox.Text = UI.detailBox.Text .. "\n\n-- Run Edited: error\n" .. tostring(res[2])
end
end
flash(UI.runBtn,res[1] and "Ran ✓" or "Error", "Run Edited")
end)
UI.blockBtn.MouseButton1Click:Connect(function()
local e = selected()
if not e then return end
if S.blocked[e.remote] then
S.blocked[e.remote] = nil
else
S.blocked[e.remote]=true
end
S.dirty = true
renderDetail()
end)
UI.ignoreBtn.MouseButton1Click:Connect(function()
local e = selected()
if not e then return end
S.ignored[e.remote] = not S.ignored[e.remote] or nil
S.dirty = true
renderDetail()
end)
UI.onlyBtn.MouseButton1Click:Connect(function()
local e = selected()
if not e then return end
local nm=""
pcall(function() nm=e.remote.Name end)
search.Text = nm
end)
UI.removeBtn.MouseButton1Click:Connect(function()
local e = selected()
if not e then return end
for i, v in ipairs(S.log) do
if v.id == e.id then
table.remove(S.log, i)
break
end
end
S.dirty = true
resetDetail()
end)
table.insert(S.conns,UIS.InputBegan:Connect(function(input, gp)
if gp then return end
if input.KeyCode==Enum.KeyCode.RightControl then
UI.setOpen(not gui.Enabled)
end
end))
if not attach(gui, opener) then
pcall(gui.Destroy, gui)
pcall(opener.Destroy, opener)
UI.gui = nil
UI.opener = nil
error("no usable GUI parent (CoreGui / gethui / PlayerGui all refused)")
end
end
local function passes(e)
if S.dir == "Incoming" and e.dir ~= "in" then return false end
if S.dir == "Outgoing" and e.dir ~= "out" then return false end
if S.bbOnly and not fullPath(e.remote):find("ReplicatedStorage.Remotes", 1, true) then
return false
end
if S.query ~= "" then
local q = S.query:lower()
if not (fullPath(e.remote):lower():find(q, 1, true) or e.method:lower():find(q, 1, true)) then
return false
end
end
return true
end
local rows = {}
local function getRow(i)
if rows[i] then return rows[i] end
local row = new("TextButton", {
Size=UDim2.new(1, -4, 0, 26), BackgroundColor3 = C.row, BorderSizePixel = 0,
Text = "", AutoButtonColor = false,
},UI.list)
corner(row, 4)
local stripe = new("Frame",{
Size = UDim2.fromOffset(3, 18), Position=UDim2.new(0, 4,0.5, -9),
BackgroundColor3 = C.incoming, BorderSizePixel = 0,
}, row)
corner(stripe, 2)
local txt = new("TextLabel", {
Size = UDim2.new(1, -16, 1, 0), Position = UDim2.new(0, 12, 0, 0), BackgroundTransparency = 1,
Text = "", Font = Enum.Font.Gotham,TextSize = 11, TextColor3 = C.text,
TextXAlignment = Enum.TextXAlignment.Left, TextTruncate = Enum.TextTruncate.AtEnd,
}, row)
local item = {row = row, stripe=stripe, txt = txt}
row.MouseButton1Click:Connect(function()
if item.id then
S.sel = item.id
S.dirty=true
renderDetail()
end
end)
rows[i] = item
return item
end
local function rebuildList()
if not UI.list then return end
local shown = {}
for i=#S.log, 1,-1 do
if passes(S.log[i]) then shown[#shown+1] = S.log[i] end
end
local count = math.min(#shown, 250)
for i = 1, count do
local e = shown[i]
local item = getRow(i)
item.row.Visible = true
item.row.LayoutOrder = i
item.row.BackgroundColor3 = e.id == S.sel and C.rowSel or C.row
item.stripe.BackgroundColor3 = e.dir == "in" and C.incoming or C.outgoing
item.id = e.id
if not e.rowText then
local path = fullPath(e.remote)
e.nice = friendly(path) ~= nil
e.rowText = ("[%s] %s %s %s %s"):format(e.dir == "in" and "IN " or "OUT",e.stamp,shortPath(path), e.method, preview(e.args, e.n))
end
local text = e.rowText
if e.nice then text = "★ " .. text end
if e.blocked then text="[BLOCKED] " .. text end
item.txt.Text = text
end
for i = count + 1, #rows do rows[i].row.Visible = false end
if S.autoscroll then UI.list.CanvasPosition = Vector2.new(0, 0) end
local nIn,nOut, nBlocked = 0, 0, 0
for _,e in ipairs(S.log) do
if e.dir == "in" then nIn += 1 else nOut += 1 end
if S.blocked[e.remote] then nBlocked += 1 end
end
UI.stats.Text=("%d total | %d in | %d out | %d blocked | %d shown | out-hook: %s | listening: %d"):format(
#S.log, nIn, nOut, nBlocked, count,S.hooked and "on" or "OFF", S.nListen)
end
function renderDetail()
local e=selected()
if not e then
UI.detailTitle.Text = "Select an entry"
UI.detailBox.Text = ""
if UI.editBox then
UI.editBox.Text = ""
UI.editId = nil
end
return
end
local path = fullPath(e.remote)
UI.detailTitle.Text = (friendly(path) or shortPath(path)) .. " — " .. e.method
UI.detailBox.Text = detailText(e)
UI.blockBtn.Text = S.blocked[e.remote] and "Unblock" or "Block"
UI.ignoreBtn.Text = S.ignored[e.remote] and "Unignore" or "Ignore"
local out = e.dir == "out"
UI.fireLabel=out and "Fire Again" or "Fire Client"
UI.fireBtn.Text = UI.fireLabel
UI.fireBtn.Visible = isEvent(e.remote) and (out or can.fire)
UI.invokeBtn.Visible = out and isFunc(e.remote)
if UI.editId ~= e.id then
UI.editBox.Text = editText(e)
UI.editId = e.id
end
end
function genScript(list)
local L={"-- Generated by LEX Remote Spy", "-- " .. os.date("%Y-%m-%d %H:%M:%S"), ""}
for _, e in ipairs(list) do
if passes(e) then
table.insert(L,"-- [" .. e.stamp .. "] " .. e.method)
table.insert(L, callText(e))
table.insert(L, "")
end
end
return table.concat(L,"\n")
end
local lastDraw=0
local function drain()
if #queue == 0 then return end
local batch = queue
queue = {}
for _, raw in ipairs(batch) do
table.insert(S.log, {
id=S.nextId, dir = raw.dir, remote = raw.remote, method = raw.method,
args = raw.args, n = raw.n, stamp=raw.stamp,
blocked = S.blocked[raw.remote] == true,
})
S.nextId += 1
end
trimLog()
S.dirty = true
end
local beat = RunService.Heartbeat:Connect(function()
drain()
local now = os.clock()
if S.dirty and now - lastDraw > 0.12 then
lastDraw = now
S.dirty = false
pcall(rebuildList)
end
end)
env.LexSpy = {
Toggle = function(state)
S.on = state ~= false
refreshStatus()
end,
Clear = function()
S.log = {}
queue = {}
S.sel = nil
S.dirty=true
end,
GetLog = function()
local out = {}
for i, e in ipairs(S.log) do out[i]=e end
return out
end,
Block = function(r) S.blocked[r] = true end,
Unblock = function(r) S.blocked[r] = nil end,
Ignore = function(r) S.ignored[r] = true end,
Unignore = function(r) S.ignored[r]=nil end,
GenerateScript = function() return genScript(S.log) end,
SaveLog = function(name) return saveFile(name or "remote_log.lua",genScript(S.log)) end,
SetFilter = function(f) S.dir = f; S.dirty = true end,
SetBBOnly = function(v) S.bbOnly = v; S.dirty = true end,
Show = function(v) if UI.setOpen then UI.setOpen(v ~= false) end end,
Unload = function() if env.__LEXSPY_CLEANUP then env.__LEXSPY_CLEANUP() end end,
}
env.__LEXSPY_CLEANUP=function()
env.__LEXSPY_LOADED = false
S.on = false
S.dead=true
if beat then pcall(beat.Disconnect, beat) end
disconnectAll()
removeHooks()
if UI.gui then pcall(UI.gui.Destroy, UI.gui) end
if UI.opener then pcall(UI.opener.Destroy, UI.opener) end
queue = {}
rows = {}
S.log = {}
env.LexSpy = nil
print(TAG .. "unloaded")
end
do
local called, ok, err = pcall(installHooks)
if not called then
err = ok
ok = false
end
S.hooked = ok == true
if not S.hooked then
warn(TAG .. "hook install failed (incoming still works): " .. tostring(err))
end
local uiOk, uiErr = pcall(buildUI)
if not uiOk then warn(TAG .. "UI build failed: " .. tostring(uiErr)) end
local trOk, trErr = pcall(startTracking)
if not trOk then warn(TAG .. "remote tracking failed: " .. tostring(trErr)) end
task.defer(function()
S.dirty = true
pcall(rebuildList)
end)
print(("%sloaded in %.0fms | bb: %s | out-hook: %s"):format(TAG, (os.clock() - t0)*1000,tostring(isBB), tostring(S.hooked)))
endHow to Execute Universal Script – ADV REMOTE SPY TOOL
Step 1: Copy Code: Click the Copy Code button in the viewer above to grab the clean Lua loadstring.
Step 2: Launch Executor: Open a compatible, unpatched executor. If you need one, check our Roblox Executors Directory.
Step 3: Join Experience: Launch Roblox and join Universal Script.
Step 4: Attach & Run: Attach/inject your executor into the Roblox process, paste the code into the script tab, and press Execute.
Created By
View Author ProfileFeatures & Information
Script Changelog (1)
Community Comments (3)
Frequently Asked Questions
How do I execute Universal Script – ADV REMOTE SPY TOOL in Roblox?
To run Universal Script – ADV REMOTE SPY TOOL, copy the Lua loadstring from the code viewer above, launch Roblox and join Universal Script, attach a working executor (such as Potassium, Solara, or Delta from our Executors directory), paste the code into your executor console, and click Execute.
Is Universal Script – ADV REMOTE SPY TOOL keyless or does it require an access key?
Universal Script – ADV REMOTE SPY TOOL requires an access key. You can retrieve the official key directly using the Get Script Key link provided above.
Is Universal Script – ADV REMOTE SPY TOOL currently safe and working?
This script is active and operational. Always test scripts using a secondary (alt) Roblox account to safeguard your main profile against anti-cheat bans.


![Ez Hub [Open Source] [150+ games] - Verified script for Universal Script](https://media.kocakz.me/b74a9ac15370ba766b2fa9531f17c9dad2c0befb2b951693ae723e4c7d2c3fb6.webp)

![[KEYLESS] Moondiety Script | 20+ supported Games - Verified script for Universal Script](https://media.kocakz.me/6834c33a36c9fbe66afae4c6754c2b80386ce636b2f972464a95866f4b6a42eb.webp)


dont really helpfull cause of out hooking off mode
@ca3andr Hey! thank you for the review. This was a quick script publish. I am so sorry to hear the issues that you have experienced and I assure you that this issue will be resolved promptly. For your support, you will be featured as Bug/Issue Finder in the Credits of LEXBLADE Upon later release. Thank you for your time and your patience it is all appreciated :)
@MADEBYLEXX hey, absolutely no worries, don't sweat it.Somewhere 90 Remote Spy here on Roblox Scripts are some kind of useless and unreadable shi yk, project here is worth it so it's all good. Honestly, look at this not as a fail, but as a solid lesson for the next time. Good luck polishing it up, and honestly, it'll be honor to be in the credits! Keep it up!