BootSpy

Description

BootSpy (Bootleg Spy) is open source.
Credits: @zeroxx987 for the idea, He made a similar script for the server, Here’s
the url: https://scriptblox.com/script/Universal-Script-Remote-Spy-12957
Note:
To copy when an event happens of any sort, You can change the local Output = print to local Output = setclipboard or local Output = toclipboard
Release Version:
Log EVERY Client event
What i mean is, Whenever the server calls RemoteEvent:FireClient,
BindableEvent:Fire, RemoteFunction:InvokeClient, BindableFunction:Invoke
This script will log that!
This is just a worse version of simplespy, for executors with no
hookmetamethod or hook function support, This doesnt do the same thing but
it works for the client.


getgenv = getgenv or function() return getfenv(2) end
local Logger = {} -- Type = {LastCall=os.time(), CallsPerSec=number}
local Limits = { -- How many times an instance can fire per second
 BindableEvent = 3,
 BindableFunction = 3,
 RemoteFunction = 3,
 RemoteEvent = 3
}
local vers = '0.0.1b'
function keyF(a)
 return typeof(a) == 'number' and ('[%d] = '):format(a) or ('[\'%s\'] = '):format(tostring(a))
end
function keyE(a, b)
 if typeof(b):lower() == 'instance' then
  return b.Name:gsub(' ', '_')
 elseif typeof(b) == 'boolean' then return 'bool' .. tostring(a) elseif typeof(b) == 'string' then return 'str' .. tostring(a) elseif typeof(b) == 'number' then return 'num' .. tostring(a) elseif typeof(b) == 'table' then return 'tbl' .. tostring(a) else return typeof(b) .. tostring(a) end
end
local BootlegDebug = {}
local Output = print -- Change to setclipboard if you want remotes to be copied to your clipboard
function BootlegDebug.getinfo(thread)
 local CurrentLine = tonumber(debug.info(thread, 'l'))
 local Source = debug.info(thread, 's')
 local name = debug.info(thread, 'n')
 local numparams, isvrg = debug.info(thread, 'a')
 if #name == 0 then name = nil end
 local a, b = debug.info(thread, 'a')
 return {
  ['currentline'] = CurrentLine,
  ['Source'] = Source,
  ['name'] = tostring(name),
  ['numparams'] = tonumber(numparams),
  ['is_vararg'] = isvrg and 1 or 0,
  ['short_src'] = tostring(Source:sub(1, 60))
  }
end
function GetFullName(instance)
    local p = instance
    local lo = {}
    while (p ~= game and p.Parent ~= nil) do
        table.insert(lo, p)
        p = p.Parent
    end
    local fullName
    if #lo == 0 then
        return "nil --[[ PARENTED TO NIL OR DESTROYED ]]"
    end
    if lo[#lo].ClassName ~= "Workspace" then
        fullName = 'game:GetService("' .. lo[#lo].ClassName .. '")'
    else
        fullName = "workspace"
    end
    for i = #lo - 1, 1, -1 do
        fullName = fullName .. ':FindFirstChild("' .. lo[i].Name .. '")'
    end
    return fullName
end
function tableloop(tbl, indent, equal, meta)
    meta = meta or 0
    indent = indent or 0
    local result = (not equal and string.rep('  ', indent) or '') .. '{'
    equal = false
    if typeof(tbl) ~= 'table' then return Handle(tbl, indent) end
    local _AM = 0
    for key, value in pairs(tbl) do
        _AM = _AM + 1
        if typeof(value) == 'table' then
            if getmetatable(value) then
                result = result .. string.rep('  ', indent) .. 'local meta' .. (meta ~= 0 and tostring(meta) or '') .. ' = ' .. tableloop(getmetatable(value), indent, true, meta+1)
                meta = meta + 1
            else
                result = result .. '\n' .. (not equal and string.rep('  ', indent + 1) or '') .. keyF(key) .. tableloop(value, indent + 1, true, meta)
            end
        else
            result = result .. '\n' .. (not equal and string.rep('  ', indent + 1) or '') .. keyF(key) .. Handle(value, indent + 1, keyE(key, value)) .. ';'
        end
    end
    return _AM > 0 and (result .. '\n' .. string.rep('  ', indent) .. '}') or '{}'
end

function Handle(data, indent, identifier)
    local dataType = typeof(data)
    local constructors = {
        ['string'] = function(data) return "'" .. data .. "'" end,
        ['table'] = function(data) return tableloop(data, indent and indent + 1 or 1, identifier and true or false) end,
        ['function'] = function(data) return string.format('function(%s) --[[ i forgor the source? ]] end', BootlegDebug.getinfo(data).numparams) end,
        ['number'] = function(data) return tostring(data) end,
        ['Vector3'] = function(data) return string.format("Vector3.new(%f, %f, %f)", data.X, data.Y, data.Z) end,
        ['Vector2'] = function(data) return string.format("Vector2.new(%f, %f)", data.X, data.Y) end,
        ['UDim'] = function(data) return string.format("UDim.new(%f, %f)", data.Scale, data.Offset) end,
        ['UDim2'] = function(data) return string.format("UDim2.new(%f, %f, %f, %f)", data.X.Scale, data.X.Offset, data.Y.Scale, data.Y.Offset) end,
        ['CFrame'] = function(data) local components = {data:GetComponents()} return string.format("CFrame.new(%s)", table.concat(components, ", ")) end,
        ['Color3'] = function(data) return string.format("Color3.fromRGB(%d, %d, %d)", math.floor(data.R * 255), math.floor(data.G * 255), math.floor(data.B * 255)) end,
        ['BrickColor'] = function(data) return string.format("BrickColor.new('%s')", tostring(data)) end,
        ['Enum'] = function(data) return string.format("%s", tostring(data)) end,
        ['EnumItem'] = function(data) return string.format("%s", tostring(data)) end,
        ['Instance'] = function(data) return ('%s'):format(GetFullName(data)) end,
        ['buffer'] = function(data) return string.rep('  ', indent) .. ('buffer.create(%d)'):format(buffer.len(data)) end,
        ['boolean'] = function(data) return tostring(data) end
    }
    if constructors[dataType] then
        return constructors[dataType](data)
    else
        return tostring(typeof(data)) .. '.new(' .. tostring(data) .. ')'
    end
end
function GetEvents()
 local Events = {}
 for i, v in ipairs(game:GetDescendants()) do
  if v:IsA("RemoteEvent") or v:IsA("UnreliableRemoteEvent") then
   if v:IsDescendantOf(game:GetService('Players')) and v:IsDescendantOf(game:GetService("Players").LocalPlayer) then
    table.insert(Events, v)
   elseif not v:IsDescendantOf(game:GetService('Players')) then
    table.insert(Events, v)
   end
  end
 end
 return Events
end
function GetBEvents()
 local Events = {}
 for i, v in ipairs(game:GetDescendants()) do
  if v:IsA("BindableEvent") then
   if v:IsDescendantOf(game:GetService('Players')) and v:IsDescendantOf(game:GetService("Players").LocalPlayer) then
    table.insert(Events, v)
   elseif not v:IsDescendantOf(game:GetService('Players')) then
    table.insert(Events, v)
   end
  end
 end
 return Events
end
function GetFunctions()
 local Funcs = {}
 for i, v in ipairs(game:GetDescendants()) do
  if v:IsA("RemoteFunction") then
   if v:IsDescendantOf(game:GetService('Players')) and v:IsDescendantOf(game:GetService("Players").LocalPlayer) then
    table.insert(Funcs, v)
   elseif not v:IsDescendantOf(game:GetService('Players')) then
    table.insert(Funcs, v)
   end
  end
 end
 return Funcs
end
function GetBFunctions()
 local Funcs = {}
 for i, v in ipairs(game:GetDescendants()) do
  if v:IsA("BindableFunction") then
   if v:IsDescendantOf(game:GetService('Players')) and v:IsDescendantOf(game:GetService("Players").LocalPlayer) then
    table.insert(Funcs, v)
   elseif not v:IsDescendantOf(game:GetService('Players')) then
    table.insert(Funcs, v)
   end
  end
 end
 return Funcs
end
function EventMain(Event)
 Logger[Event] = 0
 Event.OnClientEvent:Connect(function(...)
  if Logger[Event] > Limits[Event.ClassName] then
    return
  end
  Logger[Event] = Logger[Event] + 1
  local StrArgs = tableloop({...})
  local FullData = string.format('--[[ Script generated by BootSpy v%s\nRemote Type: %s\n]]\nlocal args = %s\n\n--[[ THE FOLLOWING LINE CANNOT BE EXECUTED BY YOUR EXECUTOR, AS ITS JUST DEMONSTRATING WHAT THE SERVER DID. ]]\n\n%s:FireClient(game:GetService("Players").%s, unpack(args));', vers, Event.ClassName, StrArgs, GetFullName(Event), game:GetService("Players").LocalPlayer.Name)
  Output(FullData)
  task.delay(1, function()
   Logger[Event] = Logger[Event] - 1
  end)
 end)
end
function BEventMain(Event)
 Logger[Event] = 0
 Event.Event:Connect(function(...)
  if Logger[Event] > Limits[Event.ClassName] then
    return
  end
  Logger[Event] = Logger[Event] + 1
  local StrArgs = tableloop({...})
  local FullData = string.format('--[[ Script generated by BootSpy v%s\nRemote Type: %s\n]]\nlocal args = %s\n\n--[[ THE FOLLOWING LINE **CAN** BE EXECUTED BY YOUR EXECUTOR AS THE FOLLOWING REMOTE IS A BINDABLE EVENT. ]]\n\n%s:Fire(unpack(args));', vers, Event.ClassName, StrArgs, GetFullName(Event), game:GetService("Players").LocalPlayer.Name)
  task.delay(1, function()
   Logger[Event] = Logger[Event] - 1
  end)
  Output(FullData)
 end)
end
function FunctionMain(Func)
 -- We cannot obtain the old function of the RemoteFunction so we have to override it, Breaking SOME scripts and potentially getting you kicked
 Logger[Func] = 0
 Func.OnClientInvoke = function(...)
  if Logger[Func] > Limits[Func.ClassName] then
    return
  end
  Logger[Func] = Logger[Func] + 1
  local StrArgs = tableloop({...})
  local FullData = string.format('--[[ Script generated by BootSpy v%s\nRemote Type: %s\n]]\nlocal args = %s\n\n--[[ THE FOLLOWING LINE CANNOT BE EXECUTED BY YOUR EXECUTOR, AS ITS JUST DEMONSTRATING WHAT THE SERVER DID. ]]\n\n%s:InvokeClient(game:GetService("Players").%s, unpack(args));', vers, Func.ClassName, StrArgs, GetFullName(Func), game:GetService("Players").LocalPlayer.Name)
  Output(FullData)
  task.delay(1, function()
   Logger[Func] = Logger[Func] - 1
  end)
  return '1'
 end
end
function BFunctionMain(Func)
 -- We cannot obtain the old function of the BindableFunction so we have to override it, Breaking SOME scripts and potentially getting you kicked
 Logger[Func] = 0
 Func.OnInvoke = function(...)
  if Logger[Func] > Limits[Func.ClassName] then
    return
  end
  Logger[Func] = Logger[Func] + 1
  local StrArgs = tableloop({...})
  local FullData = string.format('--[[ Script generated by BootSpy v%s\nRemote Type: %s\n]]\nlocal args = %s\n\n--[[ THE FOLLOWING LINE **CAN** BE EXECUTED BY YOUR EXECUTOR, BUT A RETURN VALUE AND MAIN FUNCTIONALITY IS MISSING FOR THIS FUNCTIONS SO IT MIGHT NOT DO WHAT YOU EXPECT. ]]\n\n%s:Invoke(unpack(args));', vers, Func.ClassName, StrArgs, GetFullName(Func))
  Output(FullData)
  task.delay(1, function()
   Logger[Func] = Logger[Func] - 1
  end)
  return '1'
 end
end
local a, b, c, d = GetEvents(), GetFunctions(), GetBEvents(), GetBFunctions()
for _, v in pairs(a) do
 EventMain(v)
end
for _, v in pairs(b) do
 FunctionMain(v)
end
for _, v in pairs(c) do
 BEventMain(v)
end
for _, v in pairs(d) do
 BFunctionMain(v)
end

print('Successfully implemented BootSpy.')

⚠️ Warning: Do not download any extensions or anything other than .txt/.lua file, because script will download only in .txt/.lua format or It will redirect you to a pastebin link.

📋 Notice: If you find any of the scripts patched or not working, please report it to Forever4D through Discord. The script will be removed or marked as patched!