-- WARNING: HOLY AI💀🙏 -- loadstringChecker_full.lua -- Full output-only loadstring inspector (no GUI). Designed for executor use. -- Features: -- - Prints up to SHOW_LINES_LIMIT lines of the remote script (streamed with task.wait(0)) to avoid locking. -- - Performs static analysis: counts local declarations/variables, functions, Instance.new usage, token/API counts. -- - Attempts to detect compile-time errors and runtime traceback (if you enable execution). -- - Shows context around an error line and gives suggestions to fix common issues. -- - Calculates a heuristic "danger score" and maps to levels: [ Peaceful ], [ Low ], [ Mid ], [ High ], [ Insane ], [ Danger ]. -- If level is High or above, it refuses to run the remote code. -- - Reports elapsed time for different phases and a final "Completed Time" in seconds. -- -- USAGE: -- - Set url to the raw file URL you want to inspect. -- - Configure flags below (PREVIEW, SHOW_LINES_LIMIT, AUTO_EXECUTE). -- - Run as a LocalScript in your executor. All output is printed to Output (print/warn). -- - By default AUTO_EXECUTE = false (script will NOT execute remote code). -- -- WARNING: -- - Printing up to 40,000 lines will produce very large Output. Use with caution. -- - This tool is heuristic-based. It gives guidance but not perfect proof of maliciousness. -- - Do NOT enable AUTO_EXECUTE unless you trust the source and threat level is low/peaceful. -- ========== CONFIG ========== local url = "" -- <<< PUT RAW FILE URL HERE (required) local PREVIEW = false -- if true, only scan a head portion first (see PREVIEW_LINES) local PREVIEW_LINES = 5000 -- number of lines to analyze in preview mode (PLEASE PUT THE NUMBER LINE AT THE END OF SCRIPT IN YOU RAW FOR MORE DETECTION ACCURACY | Ex. Your script has 482 line then put the line in the nill) local RUN_FULL_AFTER_PREVIEW = false -- if true, after preview the script will continue to full scan local SHOW_LINES_LIMIT = 40000 -- how many lines to print (user wanted 40000 limit) local AUTO_EXECUTE = false -- if true and threat level allows, it will run the chunk (CAUTION) local CONTEXT_LINES = 8 -- context lines to show around reported error local PROGRESS_INTERVAL = 1000 -- emit progress every N lines during full scan local YIELD_PER_LINE = true -- yield (task.wait(0)) per line while printing to avoid locking; set false to be faster (may lock) -- ============================ -- simple print wrappers local function info(...) pcall(print, "[CHECKER]", table.concat({...}, " ")) end local function warnInfo(...) pcall(warn, "[CHECKER]", table.concat({...}, " ")) end local t0_total = tick() info("Starting loadstringChecker_full. url=", url) if not url or url == "" then warnInfo("ERROR: url is empty. Set url to the raw file you want to inspect.") return end -- download local ok, body_or_err = pcall(function() return game:HttpGet(url) end) if not ok then warnInfo("HttpGet failed:", tostring(body_or_err)) return end local src = tostring(body_or_err) if not src or #src == 0 then warnInfo("Downloaded source is empty.") return end info("Downloaded bytes:", #src) -- split into lines array local lines = {} for ln in src:gmatch("([^\n]*)\n?") do table.insert(lines, ln) end local totalLines = #lines info("Total lines in remote script:", totalLines) -- decide scan range local scanFrom, scanTo = 1, totalLines if PREVIEW then scanTo = math.min(PREVIEW_LINES, totalLines) info("Preview mode: scanning lines 1.." .. tostring(scanTo)) end -- helpers for analysis local function stripInlineComments(line) -- very simple: remove trailing -- comments; does NOT handle block comments robustly return line:gsub("%-%-.*$", "") end local function countLocalVars(decl) local left = decl:match("^%s*local%s+(.+)$") or "" left = left:match("^(.-)%s*=") or left left = left:gsub("%b()", "") -- strip parentheses local cnt = 0 for v in left:gmatch("[^,]+") do if v:match("%S") then cnt = cnt + 1 end end return cnt end -- data collectors local tokenPatterns = { loadstring = "%f[%w]loadstring%f[%W]", load = "%f[%w]load%f[%W]", dofile = "%f[%w]dofile%f[%W]", require = "%f[%w]require%f[%W]", HttpGet = "HttpGet%s*%(", gameHttpGet = "game%s*:%s*HttpGet", xpcall = "%f[%w]xpcall%f[%W]", pcall = "%f[%w]pcall%f[%W]", coroutine = "%f[%w]coroutine%f[%W]", task_spawn = "%f[%w]task%.spawn%f[%W]", spawn = "%f[%w]spawn%f[%W]", setmetatable = "%f[%w]setmetatable%f[%W]", getfenv = "%f[%w]getfenv%f[%W]", debug = "%f[%w]debug%f[%W]", XMLHttp = "XMLHttpRequest", Instance_new = "Instance%.new%s*%(", SetParent = "%:SetParent%(", ParentAssign = "%.%s*Parent%s*=", HttpService = "HttpService", CoreGui = "CoreGui", GetService = "GetService", } local counts = {} local totalLocalDeclLines = 0 local totalLocalVars = 0 local totalFunctionDefs = 0 local topFunctions = {} -- frames: {name, startLine, endLine, locals, localDeclLines} local funcStack = {} local inBlockComment = false local instanceTypes = {} -- map classname -> count local instancesCount = 0 -- helpers for function frames local function pushFunc(name, ln) totalFunctionDefs = totalFunctionDefs + 1 local f = { name = name or (""), startLine = ln, endLine = nil, locals = 0, localDeclLines = 0 } table.insert(funcStack, f) return f end local function popFunc(ln) local f = table.remove(funcStack) if not f then return end f.endLine = ln table.insert(topFunctions, f) return f end local function addToken(k, n) counts[k] = (counts[k] or 0) + (n or 1) end -- function name extractor (best-effort) local function extractFunctionName(line) local name = line:match("^%s*local%s+function%s+([%w_%.:]+)") if name then return name end name = line:match("^%s*function%s+([%w_%.:]+)%s*%(") if name then return name end name = line:match("^%s*local%s+([%w_]+)%s*=%s*function%s*%(") if name then return name end return nil end -- scanning loop (streamed) for the selected range local t0_scan = tick() info("Beginning scan of lines", scanFrom, "to", scanTo) for i = scanFrom, scanTo do if YIELD_PER_LINE then task.wait(0) end local raw = lines[i] or "" local line = raw -- handle block comments rudimentarily if inBlockComment then local s, e = line:find("%]%]") if s then line = line:sub(e+1) inBlockComment = false else line = "" -- skip end end local startBlock = line:find("%-%-%[%[") if startBlock then -- If block ends on same line, remove it; else cut and mark inBlockComment true local s,e = line:find("%]%]", startBlock+4) if s then line = line:sub(1, startBlock-1) .. (line:sub(e+1) or "") else line = line:sub(1, startBlock-1) inBlockComment = true end end -- strip inline comments line = stripInlineComments(line) -- token counts for k, pat in pairs(tokenPatterns) do if line:find(pat) then addToken(k) end end -- Instance.new("ClassName") detection for cls in line:gmatch('Instance%.new%s*%(%s*["\']([%w_%:%.%-]+)["\']%s*%)') do instancesCount = instancesCount + 1 instanceTypes[cls] = (instanceTypes[cls] or 0) + 1 end if line:find("Instance%.new") then -- count generic occurrence as well instancesCount = instancesCount + 0 end -- function detection if line:find("%f[%w]function%f[%W]") then local fname = extractFunctionName(line) pushFunc(fname, i) totalFunctionDefs = totalFunctionDefs + 0 -- already incremented inside pushFunc end -- local declarations if line:find("^%s*local%s+") then local vars = countLocalVars(line) totalLocalDeclLines = totalLocalDeclLines + 1 totalLocalVars = totalLocalVars + vars if #funcStack > 0 then local top = funcStack[#funcStack] top.locals = top.locals + vars top.localDeclLines = top.localDeclLines + 1 end end -- balance ends (basic) local ends = 0 for _ in line:gmatch("%f[%w]end%f[%W]") do ends = ends + 1 end for _ = 1, ends do if #funcStack > 0 then popFunc(i) end end end local t1_scan = tick() info("Scan phase completed in", string.format("%.3f", t1_scan - t0_scan), "seconds") -- If PREVIEW mode and we should skip the rest: if PREVIEW and not RUN_FULL_AFTER_PREVIEW then info("Preview-only run requested. The preview scan has completed and summary will be shown. Full scan skipped.") end -- Print the script content up to SHOW_LINES_LIMIT (streamed) local printLimit = math.min(totalLines, SHOW_LINES_LIMIT) info(("Printing script lines 1..%d (limit=%d). This may produce a lot of Output."):format(printLimit, SHOW_LINES_LIMIT)) local t0_print = tick() for i = 1, printLimit do if YIELD_PER_LINE then task.wait(0) end pcall(print, string.format("%6d: %s", i, lines[i] or "")) end local t1_print = tick() local printElapsed = t1_print - t0_print info("Printing phase completed in", string.format("%.3f", printElapsed), "seconds") -- Collate summary local summary = { total_lines = totalLines, scanned_lines = (scanTo - scanFrom + 1), local_decl_lines = totalLocalDeclLines, local_variables = totalLocalVars, function_defs = #topFunctions, instance_new_literal_types = instanceTypes, instance_new_total_literals = 0, token_counts = counts, scan_time = t1_scan - t0_scan, print_time = printElapsed, } for k,v in pairs(instanceTypes) do summary.instance_new_total_literals = summary.instance_new_total_literals + v end -- Top functions by locals table.sort(topFunctions, function(a,b) if a.locals == b.locals then return (a.endLine - a.startLine) > (b.endLine - b.startLine) end return a.locals > b.locals end) -- Print summary info("=== Analysis Summary ===") info("Total lines:", summary.total_lines) info("Scanned lines:", summary.scanned_lines) info("Local declaration lines:", summary.local_decl_lines) info("Total local variables (approx):", summary.local_variables) info("Functions detected (approx):", summary.function_defs) info("Instance.new(\"Class\") literal types detected (top):") local ct = 0 for cls,c in pairs(summary.instance_new_literal_types) do ct = ct + 1 info(string.format(" %s : %d", tostring(cls), c)) if ct >= 30 then break end end info("Token/API counts (top):") local toklist = {} for k,v in pairs(summary.token_counts) do table.insert(toklist, {k=k,v=v}) end table.sort(toklist, function(a,b) return a.v > b.v end) for _,t in ipairs(toklist) do info(string.format(" %-18s : %d", t.k, t.v)) end info("Top functions by local variable count (approx):") for i=1, math.min(12, #topFunctions) do local f = topFunctions[i] info(string.format(" %2d) %s locals=%d localDeclLines=%d range=%d-%d", i, tostring(f.name), f.locals, f.localDeclLines, f.startLine, f.endLine)) end -- Heuristic danger scoring local score = 0 -- weights (tunable) local weights = { loadstring = 35, gameHttpGet = 20, HttpGet = 10, require = 8, xpcall = 6, pcall = 2, debug = 25, getfenv = 30, setmetatable = 6, XMLHttp = 40, coroutine = 4, task_spawn = 3, spawn = 6, Instance_new = 1, Instance_risky_classes = 5, -- e.g., Sound/Image with remote ids (not deeply detected here) } -- accumulate token-based score for k,v in pairs(counts) do local w = weights[k] or 1 score = score + (w * v) end -- big local counts or giant top function locals add risk of 'Out of local registers' if summary.local_variables > 400 then score = score + 40 end for _,f in ipairs(topFunctions) do if f.locals >= 150 then score = score + 50 end end -- map score to level local level = "[ Peaceful ]" local level_key = "peaceful" if score < 20 then level = "[ Peaceful ]"; level_key = "peaceful" elseif score < 60 then level = "[ Low ]"; level_key = "low" elseif score < 150 then level = "[ Mid ]"; level_key = "mid" elseif score < 300 then level = "[ High ]"; level_key = "high" elseif score < 600 then level = "[ Insane ]"; level_key = "insane" else level = "[ Danger ]"; level_key = "danger" end info("Danger heuristic score:", score, "Level:", level) -- Suggest whether it's safe to run local canRun = true if level_key == "high" or level_key == "insane" or level_key == "danger" then canRun = false warnInfo("AUTORUN DENIED: Threat level is", level, " - DO NOT EXECUTE this script automatically.") else info("Threat level", level, "- script may be executed if you trust the source and manual review passed.") end -- Attempt compilation to detect parse errors and report context & suggestions local t0_compile = tick() local chunk, compileErr = loadstring(src) local t1_compile = tick() info("Compile attempt time:", string.format("%.3f", t1_compile - t0_compile), "seconds") if not chunk then warnInfo("Compile error detected:", tostring(compileErr)) -- try to extract line number local lineno = tonumber(compileErr:match("%[string \"[^\"]*\"%]:(%d+):")) or tonumber(compileErr:match(":(%d+):")) if lineno then warnInfo("Compile error appears at line", lineno, "- showing context +/-", CONTEXT_LINES) local startL = math.max(1, lineno - CONTEXT_LINES) local endL = math.min(totalLines, lineno + CONTEXT_LINES) for j = startL, endL do local mark = (j == lineno) and ">>" or " " pcall(print, string.format("%s %6d: %s", mark, j, lines[j] or "")) end -- Suggest fixes (basic) warnInfo("Suggested fixes:") if compileErr:find("unexpected symbol") or compileErr:find("near") then warnInfo(" - Check for missing or extra symbols (commas, parentheses, 'end').") end if compileErr:find("unfinished long string") or compileErr:find("unfinished long comment") then warnInfo(" - Check multi-line strings/comments (look for matching [[ and ]]).") end if compileErr:find("function arguments expected") or compileErr:find("malformed") then warnInfo(" - Check function declaration syntax around the marked lines.") end else warnInfo("Could not extract line number from compile error. Full error:") pcall(print, compileErr) end else info("No compile-time parse errors detected.") end -- If AUTO_EXECUTE requested and allowed by threat level, run the chunk under xpcall if AUTO_EXECUTE and chunk then if not canRun then warnInfo("AUTO_EXECUTE requested but threat level", level, "prohibits automatic execution.") else info("AUTO_EXECUTE true and threat level acceptable -> executing chunk under xpcall") local t0_run = tick() local function onErr(err) local tb = (debug and debug.traceback) and debug.traceback(err, 2) or tostring(err) warnInfo("Runtime error (traceback):") pcall(print, tb) -- try to find first occurrence of line reference into the chunk local lineno = tonumber(tb:match("%[string \"[^\"]*\"%]:(%d+):")) or tonumber(tb:match(":(%d+):")) if lineno and lineno >= 1 and lineno <= totalLines then warnInfo("Runtime error reported at line", lineno, "- showing context +/-", CONTEXT_LINES) local startL = math.max(1, lineno - CONTEXT_LINES) local endL = math.min(totalLines, lineno + CONTEXT_LINES) for j = startL, endL do local mark = (j == lineno) and ">>" or " " pcall(print, string.format("%s %6d: %s", mark, j, lines[j] or "")) end warnInfo("Suggestion: Inspect the code around the reported line. Common runtime causes: nil indexing, calling missing functions, invalid arguments or mismatched types.") end return err end local ok2, res = xpcall(chunk, onErr) local t1_run = tick() info("Execution finished. success:", ok2, "time:", string.format("%.3f", t1_run - t0_run), "seconds") end end -- final completed time local t_end = tick() local total_elapsed = t_end - t0_total info("Completed Time (total):", string.format("%.3f", total_elapsed), "seconds") -- Export results for programmatic consumption _G.LastLoadstringCheckFull = { url = url, summary = summary, top_functions = topFunctions, score = score, level = level, canRun = canRun, compile_error = compileErr, scanned_range = { from = scanFrom, to = scanTo }, printed_lines = printLimit, timings = { scan = t1_scan - t0_scan, print = printElapsed, compile = t1_compile - t0_compile, total = total_elapsed }, } info("Results stored in _G.LastLoadstringCheckFull") -- End of script