Загрузка данных
--[[
CLIENT EXPOSURE AUDITOR v2
Цель:
показать всё существенное, что уже доступно клиенту.
НЕ использует:
getgc / getsenv / debug registry / hooks / decompiler /
executor-specific API.
Подходит для построения threat model своего place.
]]
local HttpService = game:GetService("HttpService")
local CollectionService = game:GetService("CollectionService")
local Players = game:GetService("Players")
local localPlayer = Players.LocalPlayer
local MAX_INSTANCES = 100000
local MAX_OUTPUT_CHARS = 1500000
local lines = {}
local charCount = 0
local stats = {
instances = 0,
attributes = 0,
tags = 0,
values = 0,
remotes = 0,
interactables = 0,
localScripts = 0,
moduleScripts = 0,
clientScripts = 0,
unanchored = 0,
assets = 0,
riskMarkers = 0,
}
local suspiciousWords = {
"secret",
"token",
"password",
"private",
"apikey",
"api_key",
"admin",
"owner",
"moderator",
"money",
"cash",
"coin",
"currency",
"price",
"reward",
"damage",
"cooldown",
"inventory",
"item",
"weapon",
"level",
"xp",
"experience",
"config",
"settings",
"ban",
"anticheat",
"anti_cheat",
"remote",
"purchase",
"give",
"grant",
}
local function safeRead(object, property)
local ok, value = pcall(function()
return object[property]
end)
if ok then
return value
end
return nil
end
local function pathOf(object)
local ok, value = pcall(function()
return object:GetFullName()
end)
if ok then
return value
end
return object.Name
end
local function stringify(value)
local t = typeof(value)
if t == "Instance" then
return pathOf(value)
end
if t == "string" then
if #value > 500 then
value = value:sub(1, 500) .. "..."
end
return value
end
if t == "table" then
local ok, result = pcall(function()
return HttpService:JSONEncode(value)
end)
if ok then
return result
end
return "<table>"
end
return tostring(value)
end
local function suspicious(text)
text = string.lower(text)
for _, word in ipairs(suspiciousWords) do
if string.find(text, word, 1, true) then
return true
end
end
return false
end
local function addLine(category, path, key, value)
if charCount >= MAX_OUTPUT_CHARS then
return
end
local text =
"[" .. category .. "] "
.. path
if key then
text ..= " | " .. tostring(key)
end
if value ~= nil then
text ..= " = " .. stringify(value)
end
if suspicious(text) then
text = "[!] " .. text
stats.riskMarkers += 1
end
charCount += #text + 1
table.insert(lines, text)
end
--------------------------------------------------
-- PROPERTY AUDITING
--------------------------------------------------
local propertiesByClass = {
RemoteEvent = {
"Name",
},
RemoteFunction = {
"Name",
},
UnreliableRemoteEvent = {
"Name",
},
ProximityPrompt = {
"ActionText",
"ObjectText",
"Enabled",
"HoldDuration",
"MaxActivationDistance",
"RequiresLineOfSight",
"ClickablePrompt",
},
ClickDetector = {
"MaxActivationDistance",
"CursorIcon",
},
Tool = {
"RequiresHandle",
"CanBeDropped",
"ToolTip",
"Enabled",
},
Humanoid = {
"Health",
"MaxHealth",
"WalkSpeed",
"JumpPower",
"JumpHeight",
"HipHeight",
"AutoRotate",
"UseJumpPower",
},
Sound = {
"SoundId",
"Volume",
"PlaybackSpeed",
"Looped",
},
Animation = {
"AnimationId",
},
Decal = {
"Texture",
"Transparency",
},
Texture = {
"Texture",
"Transparency",
},
MeshPart = {
"MeshId",
"TextureID",
"Anchored",
"CanCollide",
"CanQuery",
"CanTouch",
"Massless",
},
SpecialMesh = {
"MeshId",
"TextureId",
},
ImageLabel = {
"Image",
},
ImageButton = {
"Image",
},
VideoFrame = {
"Video",
},
Shirt = {
"ShirtTemplate",
},
Pants = {
"PantsTemplate",
},
SurfaceAppearance = {
"ColorMap",
"NormalMap",
"MetalnessMap",
"RoughnessMap",
},
}
--------------------------------------------------
-- INSTANCE INSPECTION
--------------------------------------------------
local function inspect(object)
stats.instances += 1
local path = pathOf(object)
addLine(
"INSTANCE",
path,
"class",
object.ClassName
)
--------------------------------------------------
-- ATTRIBUTES
--------------------------------------------------
local okAttributes, attributes = pcall(function()
return object:GetAttributes()
end)
if okAttributes then
for name, value in pairs(attributes) do
stats.attributes += 1
addLine(
"ATTRIBUTE",
path,
name,
value
)
end
end
--------------------------------------------------
-- COLLECTIONSERVICE TAGS
--------------------------------------------------
local okTags, tags = pcall(function()
return CollectionService:GetTags(object)
end)
if okTags then
for _, tag in ipairs(tags) do
stats.tags += 1
addLine(
"TAG",
path,
nil,
tag
)
end
end
--------------------------------------------------
-- VALUE OBJECTS
--------------------------------------------------
if object:IsA("ValueBase") then
local value = safeRead(object, "Value")
stats.values += 1
addLine(
"VALUE",
path,
nil,
value
)
end
--------------------------------------------------
-- NETWORK SURFACE
--------------------------------------------------
if object:IsA("RemoteEvent")
or object:IsA("RemoteFunction")
or object:IsA("UnreliableRemoteEvent")
then
stats.remotes += 1
addLine(
"REMOTE",
path,
"type",
object.ClassName
)
end
--------------------------------------------------
-- INTERACTION SURFACE
--------------------------------------------------
if object:IsA("ProximityPrompt")
or object:IsA("ClickDetector")
or object:IsA("DragDetector")
then
stats.interactables += 1
addLine(
"INTERACTION",
path,
"type",
object.ClassName
)
end
--------------------------------------------------
-- REPLICATED CODE
--------------------------------------------------
if object:IsA("LocalScript") then
stats.localScripts += 1
addLine(
"CLIENT_CODE",
path,
"type",
"LocalScript"
)
elseif object:IsA("ModuleScript") then
stats.moduleScripts += 1
addLine(
"CLIENT_CODE",
path,
"type",
"ModuleScript"
)
elseif object:IsA("Script") then
local runContext = safeRead(object, "RunContext")
if runContext and tostring(runContext):find("Client") then
stats.clientScripts += 1
addLine(
"CLIENT_CODE",
path,
"RunContext",
runContext
)
end
end
--------------------------------------------------
-- PHYSICS ATTACK SURFACE
--------------------------------------------------
if object:IsA("BasePart") then
local anchored = safeRead(object, "Anchored")
if anchored == false then
stats.unanchored += 1
addLine(
"PHYSICS",
path,
"Anchored",
false
)
local massless = safeRead(object, "Massless")
addLine(
"PHYSICS",
path,
"Massless",
massless
end
end
end
--------------------------------------------------
-- CLASS-SPECIFIC PROPERTIES
--------------------------------------------------
for className, propertyList in pairs(propertiesByClass) do
if object:IsA(className) then
for _, property in ipairs(propertyList) do
local value = safeRead(object, property)
if value ~= nil and tostring(value) ~= "" then
if
property == "SoundId"
or property == "AnimationId"
or property == "Texture"
or property == "TextureID"
or property == "TextureId"
or property == "MeshId"
or property == "Image"
or property == "Video"
or property == "ShirtTemplate"
or property == "PantsTemplate"
or property == "ColorMap"
or property == "NormalMap"
or property == "MetalnessMap"
or property == "RoughnessMap"
then
stats.assets += 1
end
addLine(
"PROPERTY",
path,
property,
value
)
end
end
end
end
end
--------------------------------------------------
-- ENVIRONMENT
--------------------------------------------------
local streamingEnabled = false
pcall(function()
streamingEnabled = workspace.StreamingEnabled
end)
table.insert(lines, "=======================================")
table.insert(lines, "CLIENT EXPOSURE AUDITOR")
table.insert(lines, "=======================================")
table.insert(lines, "")
table.insert(lines, "PlaceId: " .. tostring(game.PlaceId))
table.insert(lines, "GameId: " .. tostring(game.GameId))
table.insert(lines, "JobId: " .. tostring(game.JobId))
table.insert(lines, "StreamingEnabled: " .. tostring(streamingEnabled))
table.insert(lines, "")
table.insert(lines, "Scanning client-visible DataModel...")
table.insert(lines, "")
--------------------------------------------------
-- FULL CLIENT DATAMODEL SCAN
--------------------------------------------------
local descendants = game:GetDescendants()
for i, object in ipairs(descendants) do
if stats.instances >= MAX_INSTANCES then
break
end
inspect(object)
if i % 500 == 0 then
task.wait()
end
end
--------------------------------------------------
-- SUMMARY
--------------------------------------------------
local summary = {
"",
"=======================================",
"SUMMARY",
"=======================================",
"Instances: " .. stats.instances,
"Attributes: " .. stats.attributes,
"Tags: " .. stats.tags,
"Value objects: " .. stats.values,
"Remotes: " .. stats.remotes,
"Interactables: " .. stats.interactables,
"LocalScripts: " .. stats.localScripts,
"ModuleScripts: " .. stats.moduleScripts,
"Client Scripts: " .. stats.clientScripts,
"Unanchored Parts:" .. stats.unanchored,
"Asset IDs: " .. stats.assets,
"Risk markers: " .. stats.riskMarkers,
"",
}
for _, line in ipairs(summary) do
table.insert(lines, line)
end
local report = table.concat(lines, "\n")
--------------------------------------------------
-- OUTPUT
--------------------------------------------------
print(report)
--------------------------------------------------
-- COPYABLE GUI
--------------------------------------------------
if localPlayer then
local playerGui = localPlayer:WaitForChild("PlayerGui")
local old = playerGui:FindFirstChild("client_exposure_auditor")
if old then
old:Destroy()
end
local gui = Instance.new("ScreenGui")
gui.Name = "client_exposure_auditor"
gui.ResetOnSpawn = false
gui.IgnoreGuiInset = true
gui.Parent = playerGui
local frame = Instance.new("Frame")
frame.Size = UDim2.new(0.94, 0, 0.9, 0)
frame.Position = UDim2.new(0.03, 0, 0.05, 0)
frame.BackgroundColor3 = Color3.fromRGB(15, 15, 18)
frame.Parent = gui
local corner = Instance.new("UICorner")
corner.CornerRadius = UDim.new(0, 12)
corner.Parent = frame
local title = Instance.new("TextLabel")
title.Size = UDim2.new(1, -70, 0, 45)
title.Position = UDim2.fromOffset(15, 5)
title.BackgroundTransparency = 1
title.Text = "CLIENT EXPOSURE AUDITOR"
title.Font = Enum.Font.Code
title.TextSize = 20
title.TextColor3 = Color3.new(1, 1, 1)
title.TextXAlignment = Enum.TextXAlignment.Left
title.Parent = frame
local close = Instance.new("TextButton")
close.Size = UDim2.fromOffset(45, 40)
close.Position = UDim2.new(1, -50, 0, 5)
close.BackgroundTransparency = 1
close.Text = "×"
close.TextSize = 26
close.TextColor3 = Color3.new(1, 1, 1)
close.Parent = frame
local box = Instance.new("TextBox")
box.Size = UDim2.new(1, -20, 1, -60)
box.Position = UDim2.fromOffset(10, 50)
box.BackgroundColor3 = Color3.fromRGB(8, 8, 10)
box.Font = Enum.Font.Code
box.TextSize = 13
box.TextColor3 = Color3.fromRGB(220, 220, 225)
box.TextXAlignment = Enum.TextXAlignment.Left
box.TextYAlignment = Enum.TextYAlignment.Top
box.MultiLine = true
box.ClearTextOnFocus = false
box.TextEditable = false
box.TextWrapped = false
box.Text = report
box.Parent = frame
local boxCorner = Instance.new("UICorner")
boxCorner.CornerRadius = UDim.new(0, 8)
boxCorner.Parent = box
close.MouseButton1Click:Connect(function()
gui:Destroy()
end)
end
warn("CLIENT EXPOSURE AUDIT COMPLETE")