Загрузка данных
local PREFIX = "[AUDIT LITE]"
local function log(msg)
local line = PREFIX .. " " .. tostring(msg)
pcall(function() print(line) end)
pcall(function()
if type(rconsoleprint) == "function" then
rconsoleprint(line .. "\n")
end
end)
end
local function warnlog(msg)
local line = PREFIX .. " " .. tostring(msg)
pcall(function() warn(line) end)
pcall(function()
if type(rconsolewarn) == "function" then
rconsolewarn(line)
elseif type(rconsoleprint) == "function" then
rconsoleprint(line .. "\n")
end
end)
end
log("01 script entered")
local Players = game:GetService("Players")
local CollectionService = game:GetService("CollectionService")
local RunService = game:GetService("RunService")
log("02 services resolved")
local player = Players.LocalPlayer
if not player then
warnlog("FATAL LocalPlayer is nil")
return
end
log("03 LocalPlayer=" .. player.Name)
local playerGui = player:WaitForChild("PlayerGui", 10)
if not playerGui then
warnlog("FATAL PlayerGui timeout")
return
end
log("04 PlayerGui ready")
local old = playerGui:FindFirstChild("audit_lite_gui")
if old then
old:Destroy()
end
local gui = Instance.new("ScreenGui")
gui.Name = "audit_lite_gui"
gui.ResetOnSpawn = false
gui.IgnoreGuiInset = true
gui.DisplayOrder = 999999
gui.Parent = playerGui
local button = Instance.new("TextButton")
button.Name = "audit_button"
button.Size = UDim2.fromOffset(160, 54)
button.Position = UDim2.fromOffset(20, 100)
button.BackgroundColor3 = Color3.fromRGB(60, 115, 235)
button.BorderSizePixel = 0
button.Text = "AUDIT"
button.TextColor3 = Color3.new(1, 1, 1)
button.TextSize = 18
button.Font = Enum.Font.GothamBold
button.ZIndex = 100
button.Parent = gui
log("05 AUDIT button created")
local busy = false
local function fullname(obj)
local ok, value = pcall(function()
return obj:GetFullName()
end)
if ok then
return value
end
return obj.Name
end
local function read(obj, property)
local ok, value = pcall(function()
return obj[property]
end)
if ok then
return value
end
return nil
end
local function isa(obj, className)
local ok, value = pcall(function()
return obj:IsA(className)
end)
return ok and value == true
end
local function containsRiskWord(text)
local s = string.lower(tostring(text))
local words = {
"admin", "owner", "moderator", "money", "cash", "coin", "currency",
"reward", "price", "damage", "inventory", "weapon", "purchase", "buy",
"sell", "give", "grant", "teleport", "trade", "loot", "pickup", "claim",
"redeem", "save", "ban", "kick", "anticheat", "anti_cheat", "token",
"secret", "password", "apikey", "api_key"
}
for _, word in ipairs(words) do
if string.find(s, word, 1, true) then
return true, word
end
end
return false, nil
end
local function valueText(value)
local t = typeof(value)
if t == "Instance" then
return fullname(value)
end
if t == "string" then
if #value > 160 then
return value:sub(1, 160) .. "..."
end
return value
end
return tostring(value)
end
local function runScan()
if busy then
warnlog("scan already running")
return
end
busy = true
button.Text = "SCANNING..."
log("============================================================")
log("SCAN START")
local ok, err = pcall(function()
log("PlaceId=" .. tostring(game.PlaceId))
log("GameId=" .. tostring(game.GameId))
log("JobId=" .. tostring(game.JobId))
log("StreamingEnabled=" .. tostring(read(workspace, "StreamingEnabled")))
local list = game:GetDescendants()
log("Visible descendants=" .. tostring(#list))
local remotes = 0
local clientCode = 0
local suspiciousState = 0
local interactions = 0
local physics = 0
local assets = 0
local objectErrors = 0
for i, obj in ipairs(list) do
local objectOk, objectErr = pcall(function()
local path = fullname(obj)
local risky, word = containsRiskWord(path)
if isa(obj, "RemoteEvent") or isa(obj, "RemoteFunction") or isa(obj, "UnreliableRemoteEvent") then
remotes = remotes + 1
if risky then
warnlog("REMOTE REVIEW | " .. path .. " | matched=" .. tostring(word) .. " | " .. obj.ClassName)
else
log("REMOTE | " .. path .. " | " .. obj.ClassName)
end
end
if isa(obj, "LocalScript") or isa(obj, "ModuleScript") then
clientCode = clientCode + 1
log("CLIENT CODE | " .. path .. " | " .. obj.ClassName)
elseif isa(obj, "Script") then
local rc = read(obj, "RunContext")
if rc and string.find(tostring(rc), "Client", 1, true) then
clientCode = clientCode + 1
log("CLIENT CODE | " .. path .. " | Script RunContext=" .. tostring(rc))
end
end
if isa(obj, "ValueBase") and risky then
suspiciousState = suspiciousState + 1
local value = read(obj, "Value")
warnlog("STATE REVIEW | " .. path .. " | value=" .. valueText(value))
end
local attrs = obj:GetAttributes()
for name, value in pairs(attrs) do
local attrRisk, attrWord = containsRiskWord(path .. "." .. tostring(name))
if attrRisk then
suspiciousState = suspiciousState + 1
warnlog("ATTRIBUTE REVIEW | " .. path .. "." .. tostring(name) .. " | matched=" .. tostring(attrWord) .. " | value=" .. valueText(value))
end
end
local tags = CollectionService:GetTags(obj)
for _, tag in ipairs(tags) do
local tagRisk, tagWord = containsRiskWord(path .. "." .. tag)
if tagRisk then
suspiciousState = suspiciousState + 1
warnlog("TAG REVIEW | " .. path .. " | tag=" .. tag .. " | matched=" .. tostring(tagWord))
end
end
if isa(obj, "ProximityPrompt") then
interactions = interactions + 1
log("PROMPT | " .. path .. " | Action=" .. valueText(read(obj, "ActionText")) .. " | Distance=" .. valueText(read(obj, "MaxActivationDistance")) .. " | Hold=" .. valueText(read(obj, "HoldDuration")))
elseif isa(obj, "ClickDetector") then
interactions = interactions + 1
log("CLICK | " .. path .. " | Distance=" .. valueText(read(obj, "MaxActivationDistance")))
elseif isa(obj, "DragDetector") then
interactions = interactions + 1
log("DRAG | " .. path)
end
if isa(obj, "BasePart") then
local anchored = read(obj, "Anchored")
if anchored == false and risky then
physics = physics + 1
warnlog("PHYSICS REVIEW | " .. path .. " | unanchored | matched=" .. tostring(word))
end
end
if isa(obj, "Sound") and read(obj, "SoundId") ~= "" then assets = assets + 1 end
if isa(obj, "Animation") and read(obj, "AnimationId") ~= "" then assets = assets + 1 end
if isa(obj, "Decal") and read(obj, "Texture") ~= "" then assets = assets + 1 end
if isa(obj, "Texture") and read(obj, "Texture") ~= "" then assets = assets + 1 end
if isa(obj, "MeshPart") then assets = assets + 1 end
if isa(obj, "ImageLabel") or isa(obj, "ImageButton") then assets = assets + 1 end
end)
if not objectOk then
objectErrors = objectErrors + 1
if objectErrors <= 10 then
warnlog("OBJECT ERROR #" .. tostring(objectErrors) .. " index=" .. tostring(i) .. " | " .. tostring(objectErr))
end
end
if i % 300 == 0 then
log("progress " .. tostring(i) .. "/" .. tostring(#list))
RunService.Heartbeat:Wait()
end
end
log("---------------- SUMMARY ----------------")
log("Remotes=" .. tostring(remotes))
log("ClientCode=" .. tostring(clientCode))
log("SuspiciousState=" .. tostring(suspiciousState))
log("Interactions=" .. tostring(interactions))
log("SuspiciousPhysics=" .. tostring(physics))
log("VisibleAssets=" .. tostring(assets))
log("ObjectErrors=" .. tostring(objectErrors))
if read(workspace, "StreamingEnabled") == true then
warnlog("LIMITATION: StreamingEnabled=true, so Workspace results are only what this client currently has streamed")
end
warnlog("LIMITATION: client scan cannot inspect server-only code or prove OnServerEvent/OnServerInvoke validation")
log("SCAN COMPLETE")
log("============================================================")
end)
busy = false
if ok then
button.Text = "AUDIT AGAIN"
else
button.Text = "AUDIT ERROR"
warnlog("FATAL SCAN ERROR: " .. tostring(err))
end
end
button.Activated:Connect(function()
log("06 AUDIT clicked")
runScan()
end)
log("READY - press AUDIT")