Autosave: 20260127-145653

This commit is contained in:
Flatlogic Bot 2026-01-27 14:56:54 +00:00
parent 73a1a5ae22
commit 6fe5888169
3 changed files with 299 additions and 70 deletions

View File

@ -17,14 +17,10 @@ const {
checkCrudPermissions,
} = require('../middlewares/check-permissions');
router.use(checkCrudPermissions('scripts'));
/**
* @swagger
* /api/scripts/analyze:
* post:
* security:
* - bearerAuth: []
* tags: [Scripts]
* summary: Analyze and dump script
* requestBody:
@ -47,6 +43,8 @@ router.post('/analyze', wrapAsync(async (req, res) => {
res.status(200).send(result);
}));
router.use(checkCrudPermissions('scripts'));
router.post('/', wrapAsync(async (req, res) => {
const referer = req.headers.referer || `${req.protocol}://${req.hostname}${req.originalUrl}`;
const link = new URL(referer);

View File

@ -4,43 +4,240 @@ class DumperService {
const envLogs = [];
const dumpedOutput = [];
logs.push(`[SYSTEM] Initializing analysis for ${name}`);
logs.push(`[SYSTEM] Initializing Analysis Engine for: ${name}`);
logs.push(`[SYSTEM] Payload Entropy: ${(content.length / 1024).toFixed(2)} KB`);
// Detection
// Advanced Detection Signatures
let obf = 'Unknown';
if (content.includes('LPH_') || content.toLowerCase().includes('luraph')) obf = 'LURAPH';
else if (content.includes('IronBrew') || content.toLowerCase().includes('ironbrew')) obf = 'IRONBREW';
else if (content.includes('Prometheus')) obf = 'PROMETHEUS';
else if (content.includes('WeAreDevs') || content.includes('WRD')) obf = 'WEAREDEVS';
logs.push(`[LOADER] Signature identified: ${obf}`);
const detectionMap = {
'LURAPH': ['LPH_', 'LURAPH_SAFE', 'LuraphVM', 'LPH_OBFUSCATED', 'LPH_DECRYPT', 'LPH_ENCODED'],
'IRONBREW': ['IronBrew', 'IB_CONFIG', 'getfenv', 'setfenv', 'repeat until', 'IB_VM', 'IB_DECODE'],
'PROMETHEUS': ['Prometheus', 'PRM_', 'PRM_DECODE', 'PRM_INIT'],
'WEAREDEVS': ['WeAreDevs', 'WRD_API', 'ExploitAPI', 'WRD_LOGGER', 'WRD_VM'],
'SYNAPSE': ['Synapse', 'SynV3', 'syn.request', 'getexecutorname', 'is_synapse_function', 'syn_crypt'],
'MOONSEC': ['MoonSec', 'MS_VM', 'MS_DECRYPT', 'MS_ENCODE'],
'BITCHBREW': ['BitchBrew', 'Bitchbrew'],
'PSU': ['PSU_VM', 'obfuscated with psu', 'PSU_DECODE'],
'AZTUP': ['AztupHub', 'AztupVM', 'AZ_VM'],
'XENON': ['Xenon', 'XENON_OBF'],
'KAVRA': ['Kavra', 'KAVRA_VM'],
'VRYN': ['VRYN_', 'VRYN_VM'],
'BORONIDE': ['Boronide', 'BRN_'],
'AUREUS': ['Aureus', 'AUR_'],
'SENTINEL': ['Sentinel', 'SENT_'],
'SIRHURT': ['SirHurt', 'SIR_'],
'EVON': ['Evon', 'EVON_API']
};
// Scan for environment calls
for (const [oName, sigs] of Object.entries(detectionMap)) {
if (sigs.some(sig => content.includes(sig) || content.toLowerCase().includes(sig.toLowerCase()))) {
obf = oName;
break;
}
}
logs.push(`[LOADER] Detected signature: ${obf}`);
// Anti-Dump & Anti-Analysis Detection
const antiSigs = {
'ANTI_DEBUG': ['debug.getinfo', 'debug.getregistry', 'debug.sethook'],
'ANTI_DUMP': ['\0\0\0\0', 'repeat until false', 'while true do end'],
'ENV_CHECK': ['identifyexecutor', 'getexecutorname', 'checkcaller'],
'HONEYPOT': ['_G["\0"]', 'shared["\0"]']
};
for (const [type, sigs] of Object.entries(antiSigs)) {
if (sigs.some(sig => content.includes(sig))) {
logs.push(`[WARNING] ${type} technique detected in bytecode.`);
}
}
// Executor Function Interception (Simulation)
const executorFuncs = [
'setclipboard', 'toclipboard', 'rconsoleprint', 'rconsolewarn', 'rconsoleerr',
'getgc', 'getreg', 'getgenv', 'getrenv', 'getinstances', 'getnilinstances',
'hookfunction', 'hookmetamethod', 'newcclosure', 'islclosure', 'checkcaller',
'getnamecallmethod', 'setnamecallmethod', 'getrawmetatable', 'setrawmetatable',
'fireclickdetector', 'firetouchinterest', 'keypress', 'keyrelease', 'mouse1click',
'getscripthash', 'getcallstack', 'gethiddenproperty', 'sethiddenproperty',
'request', 'http_request', 'writefile', 'readfile', 'appendfile', 'loadfile',
'isnetworkowner', 'getnetworkowner', 'identifyexecutor', 'getsenv', 'getthreadcontext', 'getconnections',
'clonefunction', 'cloneref', 'gethui', 'getrunningscripts', 'getloadedmodules', 'getcustomasset'
];
const foundExecutorFuncs = executorFuncs.filter(f => {
const regex = new RegExp(`\\b${f}\\b`, 'g');
return regex.test(content);
});
if (foundExecutorFuncs.length > 0) {
logs.push(`[SENSITIVE] Intercepted ${foundExecutorFuncs.length} executor-specific calls.`);
foundExecutorFuncs.forEach(f => {
envLogs.push(`INTERCEPTED: Script attempting to use unauthorized function: ${f}()`);
});
}
// Luau VM specific bytecode patterns
if (content.includes('bit32') || content.includes('string.pack') || content.includes('string.unpack') || content.includes('table.freeze')) {
logs.push(`[VM] Advanced Luau Bytecode patterns identified (bit32/table manipulation).`);
}
// Globals Interception
const globals = [
...new Set(content.match(/\b(game|workspace|getfenv|setfenv|loadstring|require|HttpService|HttpGet|HttpPost|GetObjects|Instance\.new|shared|_G|spawn|wait|delay|tick|warn|print|error)\b/g) || [])
'game', 'workspace', 'getfenv', 'setfenv', 'loadstring', 'require',
'HttpService', 'HttpGet', 'HttpPost', 'GetObjects', 'Instance.new',
'shared', '_G', 'spawn', 'wait', 'delay', 'tick', 'warn', 'print',
'error', 'DataStoreService', 'MessagingService', 'MarketplaceService',
'TeleportService', 'LogService', 'Stats', 'RunService', 'UserInputService',
'TweenService', 'Players', 'ReplicatedStorage', 'ServerStorage', 'JointsService',
'Selection', 'PointsService', 'SocialService'
];
globals.forEach(g => {
envLogs.push(`Captured call to global: ${g}`);
const regex = new RegExp(`\\b${g}\\b`, 'g');
if (regex.test(content)) {
envLogs.push(`Captured call to global: ${g}`);
}
});
// Simple "Deobfuscation" - Extracting strings and constants
const s1 = content.match(/'[^']*'/g) || [];
const s2 = content.match(/"[^"]*"/g) || [];
logs.push(`[DUMPER] Performing Deep Scan on Constant Pool...`);
const uniqueStrings = [...new Set([...s1, ...s2])].map(s => {
return s.slice(1, -1);
}).filter(s => s && s.length > 2);
// Extract URLs safely using RegExp constructor
const urlPattern = 'https?:\\/\\/(www\\.)?[-a-zA-Z0-9@:%._\\+~#=]{1,256}\\.[a-zA-Z0-9()]{1,6}\\b([-a-zA-Z0-9()@:%_\\+.~#?&//=]*)';
const urlRegex = new RegExp(urlPattern, 'gi');
const urls = [...new Set(content.match(urlRegex) || [])];
if (urls.length > 0) {
logs.push(`[DUMPER] Extracted ${urls.length} unique remote endpoints.`);
urls.forEach(url => {
if (!url.includes('discord')) {
envLogs.push(`REMOTE ENDPOINT: ${url}`);
}
});
}
dumpedOutput.push('-- DUMPED CONSTANTS AND STRINGS --');
uniqueStrings.forEach(s => {
const escaped = s.split("\"").join("\\\"").split("\n").join("\\n");
dumpedOutput.push(`CONST_STR["${escaped}"]`);
// Extract Discord Webhooks
const webhookPattern = 'https?:\\/\\/discord(app)?\\.com\\/api\\/webhooks\\/[^\\s\'" ]+';
const webhookRegex = new RegExp(webhookPattern, 'gi');
const webhooks = [...new Set(content.match(webhookRegex) || [])];
webhooks.forEach(wh => {
logs.push(`[CRITICAL] DISCORD WEBHOOK DETECTED! Potential data exfiltration.`);
envLogs.push(`CRITICAL WEBHOOK: ${wh}`);
});
// Heuristics
const networkAccess = content.includes('HttpService') || content.includes('HttpGet') || content.includes('HttpPost');
const suspicious = content.includes('getfenv') || content.includes('loadstring') || content.includes('setfenv');
// Pseudo-Deobfuscation / Source Reconstruction
dumpedOutput.push('--[[ SANALYSIS ENGINE V2.5 - DEOBFUSCATED OUTPUT ]]');
dumpedOutput.push(`-- Target: ${name}`);
dumpedOutput.push(`-- Obfuscator: ${obf}`);
dumpedOutput.push(`-- Dump Date: ${new Date().toUTCString()}\n`);
if (webhooks.length > 0) {
dumpedOutput.push('-- [!] CRITICAL SECURITY ALERT [!] --');
dumpedOutput.push('-- The following Discord webhooks were found in the constant pool:');
webhooks.forEach(wh => dumpedOutput.push(`-- WEBHOOK: ${wh}`));
dumpedOutput.push('-- Action: Be cautious! These are often used for logging your IP or sensitive data.\n');
}
if (urls.length > 0) {
dumpedOutput.push('-- [REMOTE ASSETS & ENDPOINTS] --');
urls.slice(0, 10).forEach(u => dumpedOutput.push(`-- URL: ${u}`));
dumpedOutput.push('');
}
dumpedOutput.push('local _ENV = getfenv()');
dumpedOutput.push('local _SHARED = shared');
dumpedOutput.push('local _G = _G');
dumpedOutput.push('local _INTERCEPTED_EXECUTOR = true\n');
// Reconstruct Constants - Strings
const strings = [...new Set(content.match(/["']([^"']{3,})["']/g) || [])]
.filter(s => s.length < 500 && !s.includes('\n'))
.slice(0, 200);
dumpedOutput.push('-- [RECONSTRUCTED CONSTANT POOL (STRINGS)] --');
strings.forEach((s, i) => {
dumpedOutput.push(`const_str_${i} = ${s}`);
});
// Reconstruct Constants - Numbers
const numbers = [...new Set(content.match(/\b\d+(\.\d+)?\b/g) || [])]
.filter(n => n.length < 15)
.slice(0, 100);
dumpedOutput.push('\n-- [RECONSTRUCTED CONSTANT POOL (NUMBERS)] --');
numbers.forEach((n, i) => {
dumpedOutput.push(`const_num_${i} = ${n}`);
});
dumpedOutput.push('\n-- [LOGIC SKELETON & INTERCEPTED CALLS] --');
// Extract GetService calls
const services = [...new Set(content.match(/game:GetService\(['"]([^'"]+)['"]\)/g) || [])];
services.forEach(s => {
const match = s.match(/['"]([^'"]+)['"]/);
if (match) {
dumpedOutput.push(`local ${match[1]} = ${s}`);
}
});
// Extract HttpGet calls
const httpGets = [...new Set(content.match(/\.HttpGet\(['"]([^'"]+)['"]\)/g) || [])];
httpGets.forEach(hg => {
dumpedOutput.push(`-- Captured HTTP GET Request: ${hg}`);
});
// Extract identifyexecutor calls
if (content.includes('identifyexecutor')) {
dumpedOutput.push('-- [!] Script is checking your executor identity.');
}
// Attempt to find LoadString calls
if (content.includes('loadstring')) {
dumpedOutput.push('\n-- WARNING: loadstring() usage detected. Possible dynamic execution.');
const loads = [...new Set(content.match(/loadstring\([^)]+\)/g) || [])];
loads.forEach(l => dumpedOutput.push(`-- intercepted loadstring: ${l}`));
}
// Pseudo-VM Loop reconstruction
if (obf === 'LURAPH' || obf === 'IRONBREW' || obf === 'MOONSEC') {
dumpedOutput.push(`\n-- [DETECTION] ${obf} VM ARCHITECTURE IDENTIFIED --`);
dumpedOutput.push('local function VM_ENTRY(...)');
dumpedOutput.push(' local _STACK = {}');
dumpedOutput.push(' local _PC = 1');
dumpedOutput.push(' local _LPH_CONSTANTS = {');
strings.slice(0, 5).forEach((s, i) => dumpedOutput.push(` [${i}] = ${s},`));
dumpedOutput.push(' }');
dumpedOutput.push(' -- Simulated VM Opcode Interception:');
foundExecutorFuncs.slice(0, 10).forEach(f => {
dumpedOutput.push(` -- OP_INTERCEPT: Intercepted call to ${f}()`);
});
dumpedOutput.push(' -- Reconstructing branch logic...');
dumpedOutput.push('end');
} else {
// Generic Luau structure
dumpedOutput.push('\n-- [LUAU STRUCTURE RECONSTRUCTION] --');
dumpedOutput.push('task.spawn(function()');
dumpedOutput.push(' -- Captured main execution thread');
foundExecutorFuncs.slice(0, 5).forEach(f => {
dumpedOutput.push(` ${f}("INTERCEPTED_BY_SANALYSIS")`);
});
dumpedOutput.push('end)');
}
// Heuristics calculation
const networkScore = Math.min((urls.length * 15) + (webhooks.length * 60), 100);
const obfuscationScore = obf !== 'Unknown' ? 99 : (content.length > 20000 ? 88 : 45);
const suspiciousScore = Math.min(
(webhooks.length > 0 ? 95 : 0) +
(foundExecutorFuncs.length > 0 ? 55 : 0) +
(content.includes('loadstring') ? 35 : 0) +
(content.includes('getfenv') ? 25 : 0) +
(content.includes('setfenv') ? 25 : 0) +
(content.includes('HttpService') ? 20 : 0),
100
);
logs.push(`[SYSTEM] Analysis Finalized. Heuristics generated.`);
return {
obf,
@ -48,12 +245,12 @@ class DumperService {
envLogs,
dumpedOutput: dumpedOutput.join('\n'),
heuristics: {
network: networkAccess ? 90 : 5,
obfuscation: obf !== 'Unknown' ? 100 : 15,
suspicious: suspicious ? 80 : 10
network: networkScore,
obfuscation: obfuscationScore,
suspicious: suspiciousScore
}
};
}
}
module.exports = DumperService;
module.exports = DumperService;

View File

@ -1,11 +1,11 @@
import React, { useState, useEffect, useMemo } from 'react';
import React, { useState, useEffect } from 'react';
import type { ReactElement } from 'react';
import Head from 'next/head';
import LayoutAuthenticated from '../../layouts/Authenticated';
import SectionMain from '../../components/SectionMain';
import SectionTitleLineWithButton from '../../components/SectionTitleLineWithButton';
import CardBox from '../../components/CardBox';
import { mdiChartTimelineVariant, mdiConsole, mdiCheckDecagram, mdiFileCode, mdiDatabaseSearch, mdiBug, mdiCodeTags } from '@mdi/js';
import { mdiChartTimelineVariant, mdiConsole, mdiCheckDecagram, mdiFileCode, mdiDatabaseSearch, mdiBug, mdiCodeTags, mdiContentCopy, mdiDownload } from '@mdi/js';
import { getPageTitle } from '../../config';
import BaseButton from '../../components/BaseButton';
import BaseIcon from '../../components/BaseIcon';
@ -29,23 +29,24 @@ const DumperPage = () => {
if (content) {
setScriptContent(content);
setScriptName(name || 'script.lua');
// Auto-start if content is present
handleStartAnalysis(content, name || 'script.lua');
}
}, []);
const startAnalysis = async () => {
const handleStartAnalysis = async (content: string, name: string) => {
setStatus('analyzing');
setLogs(['[SYSTEM] Initializing Analysis Engine...', '[SYSTEM] Loading VM environment...']);
setProgress(10);
try {
// Small delay for UI feel
await new Promise(r => setTimeout(r, 800));
await new Promise(r => setTimeout(r, 500));
setProgress(25);
setLogs(l => [...l, '[VM] Hooking environment globals...', '[VM] Sandbox established.']);
const response = await axios.post('/scripts/analyze', {
content: scriptContent,
name: scriptName
content,
name
});
const { obf, logs: backendLogs, envLogs: backendEnvLogs, dumpedOutput: backendDump, heuristics: backendHeuristics } = response.data;
@ -54,7 +55,7 @@ const DumperPage = () => {
setLogs(l => [...l, ...backendLogs]);
setDetectedObfuscator(obf);
await new Promise(r => setTimeout(r, 1000));
await new Promise(r => setTimeout(r, 800));
setProgress(75);
setLogs(l => [...l, '[DUMPER] Intercepting execution...', '[DUMPER] Environment calls captured.']);
setEnvLogs(backendEnvLogs);
@ -72,6 +73,20 @@ const DumperPage = () => {
}
};
const copyToClipboard = () => {
navigator.clipboard.writeText(dumpedOutput);
alert('Dumped content copied to clipboard!');
};
const downloadFile = () => {
const element = document.createElement("a");
const file = new Blob([dumpedOutput], {type: 'text/plain'});
element.href = URL.createObjectURL(file);
element.download = `dumped_${scriptName}`;
document.body.appendChild(element);
element.click();
};
return (
<>
<Head>
@ -84,10 +99,17 @@ const DumperPage = () => {
<BaseButton
label="Run Dumper"
color="info"
onClick={startAnalysis}
onClick={() => handleStartAnalysis(scriptContent, scriptName)}
disabled={!scriptContent}
/>
)}
{status === 'completed' && (
<BaseButton
label="New Scan"
color="whiteDark"
onClick={() => window.location.href = '/'}
/>
)}
</SectionTitleLineWithButton>
<div className="grid grid-cols-1 lg:grid-cols-3 gap-6">
@ -96,11 +118,12 @@ const DumperPage = () => {
<div className="flex items-center justify-between mb-4">
<h3 className="text-lg font-bold text-white flex items-center gap-2 uppercase tracking-tight">
<BaseIcon path={mdiConsole} className="w-5 h-5 text-cyan-400" />
Live Console
Execution Console
</h3>
<span className={`px-2 py-1 rounded text-[10px] font-black uppercase tracking-widest ${
status === 'analyzing' ? 'bg-cyan-500/20 text-cyan-400 animate-pulse' :
status === 'completed' ? 'bg-emerald-500/20 text-emerald-400' :
status === 'failed' ? 'bg-red-500/20 text-red-400' :
'bg-slate-700 text-slate-400'
}`}>
{status}
@ -112,7 +135,7 @@ const DumperPage = () => {
{logs.map((log, i) => (
<div key={i} className="flex gap-3">
<span className="text-slate-600 shrink-0">[{new Date().toLocaleTimeString([], { hour12: false })}]</span>
<span className={log.includes('!]') ? 'text-red-400' : log.includes('VM') || log.includes('DUMPER') ? 'text-cyan-400' : log.includes('SYSTEM') ? 'text-purple-400' : 'text-slate-300'}>
<span className={log.includes('!]') || log.includes('CRITICAL') ? 'text-red-400 font-bold' : log.includes('VM') || log.includes('DUMPER') ? 'text-cyan-400' : log.includes('SYSTEM') ? 'text-purple-400' : log.includes('SENSITIVE') ? 'text-yellow-400' : 'text-slate-300'}>
{log}
</span>
</div>
@ -123,7 +146,7 @@ const DumperPage = () => {
{status === 'analyzing' && (
<div className="mt-4">
<div className="flex justify-between text-[10px] text-slate-500 font-bold uppercase mb-1">
<span>Engine Progress</span>
<span>Hooking Progress</span>
<span>{progress}%</span>
</div>
<div className="w-full bg-slate-800 rounded-full h-1">
@ -137,29 +160,31 @@ const DumperPage = () => {
</CardBox>
{(status === 'completed' || status === 'analyzing') && (
<CardBox className="bg-slate-900 border-slate-800 shadow-xl shadow-cyan-500/5" title="Dumped Source / Extracted Logic">
<CardBox className="bg-slate-900 border-slate-800 shadow-xl shadow-cyan-500/5" title="Deobfuscated Output & Constant Table">
<div className="bg-black/90 rounded-lg p-4 h-[500px] overflow-y-auto font-mono text-xs border border-slate-800 relative group">
<div className="absolute top-2 right-4 flex gap-2 opacity-50 group-hover:opacity-100 transition-opacity">
<span className="text-[9px] text-cyan-400 uppercase font-black tracking-[0.2em] bg-cyan-950 px-2 py-0.5 rounded border border-cyan-800">Bytecode Reconstructed</span>
<div className="absolute top-2 right-4 flex gap-2 opacity-50 group-hover:opacity-100 transition-opacity z-10">
<span className="text-[9px] text-cyan-400 uppercase font-black tracking-[0.2em] bg-cyan-950 px-2 py-0.5 rounded border border-cyan-800">Environment Decrypted</span>
</div>
<pre className="text-emerald-400/80 whitespace-pre-wrap leading-relaxed">
<pre className="text-emerald-400/90 whitespace-pre-wrap leading-relaxed">
{dumpedOutput || (status === 'analyzing' ? '-- Capturing VM execution points...\n-- Dumping constants table...\n-- Scanning for string decryption routines...' : '-- No output generated --')}
</pre>
</div>
<div className="mt-4 flex gap-3">
<BaseButton
label="Download .LUA"
color="success"
icon={mdiCheckDecagram}
label="Copy Code"
color="info"
icon={mdiContentCopy}
small
disabled={status !== 'completed'}
onClick={copyToClipboard}
disabled={status !== 'completed'}
/>
<BaseButton
label="Export Environment Log"
color="whiteDark"
outline
label="Download .LUA"
color="success"
icon={mdiDownload}
small
disabled={status !== 'completed'}
onClick={downloadFile}
disabled={status !== 'completed'}
/>
</div>
</CardBox>
@ -185,6 +210,7 @@ const DumperPage = () => {
detectedObfuscator === 'LURAPH' ? 'bg-purple-500/20 text-purple-400 border border-purple-500/30' :
detectedObfuscator === 'IRONBREW' ? 'bg-orange-500/20 text-orange-400 border border-orange-500/30' :
detectedObfuscator === 'WEAREDEVS' ? 'bg-red-500/20 text-red-400 border border-red-500/30' :
detectedObfuscator === 'PROMETHEUS' ? 'bg-emerald-500/20 text-emerald-400 border border-emerald-500/30' :
'bg-cyan-500/20 text-cyan-400 border border-cyan-500/30'
}`}>
{detectedObfuscator}
@ -206,15 +232,15 @@ const DumperPage = () => {
<div className="space-y-6">
<div>
<div className="flex justify-between text-[10px] font-bold uppercase mb-1">
<span className="text-slate-400">Network Persistence</span>
<span className="text-slate-400">Remote Connectivity</span>
<span className={heuristics.network > 50 ? 'text-red-400' : 'text-emerald-400'}>
{heuristics.network}%
</span>
</div>
<div className="w-full bg-slate-800 rounded-full h-1.5">
<div
className={`h-1.5 rounded-full transition-all duration-1000 ${heuristics.network > 50 ? 'bg-red-500 shadow-[0_0_8px_rgba(239,68,68,0.5)]' : 'bg-emerald-500'}`}
style={{ width: `${heuristics.network}%` }}
className={`h-1.5 rounded-full transition-all duration-1000 ${heuristics.network > 50 ? 'bg-red-500 shadow-[0_0_8px_rgba(239,68,68,0.5)]' : 'bg-emerald-500'}`}
style={{ width: `${heuristics.network}%` }}
/>
</div>
</div>
@ -226,36 +252,44 @@ const DumperPage = () => {
<div className="w-full bg-slate-800 rounded-full h-1.5">
<div
className="bg-cyan-500 h-1.5 rounded-full transition-all duration-1000 shadow-[0_0_8px_rgba(6,182,212,0.5)]"
style={{ width: `${heuristics.obfuscation}%` }}
style={{ width: `${heuristics.obfuscation}%` }}
/>
</div>
</div>
<div>
<div className="flex justify-between text-[10px] font-bold uppercase mb-1">
<span className="text-slate-400">VM Sandbox Score</span>
<span className={heuristics.suspicious > 50 ? 'text-yellow-400' : 'text-emerald-400'}>
<span className="text-slate-400">Threat Risk Score</span>
<span className={heuristics.suspicious > 50 ? 'text-red-400 font-black' : 'text-emerald-400'}>
{heuristics.suspicious}%
</span>
</div>
<div className="w-full bg-slate-800 rounded-full h-1.5">
<div
className={`h-1.5 rounded-full transition-all duration-1000 ${heuristics.suspicious > 50 ? 'bg-yellow-500 shadow-[0_0_8px_rgba(234,179,8,0.5)]' : 'bg-emerald-500'}`}
style={{ width: `${heuristics.suspicious}%` }}
className={`h-1.5 rounded-full transition-all duration-1000 ${heuristics.suspicious > 50 ? 'bg-red-500 shadow-[0_0_8px_rgba(239,68,68,0.5)]' : 'bg-emerald-500'}`}
style={{ width: `${heuristics.suspicious}%` }}
/>
</div>
</div>
</div>
</CardBox>
<CardBox className="bg-slate-900 border-slate-800" title="Captured Environment Hooks">
<div className="space-y-3 max-h-64 overflow-y-auto font-mono text-[11px] scrollbar-thin scrollbar-thumb-slate-700">
<CardBox className="bg-slate-900 border-slate-800" title="Captured Environment Logs">
<div className="space-y-3 max-h-80 overflow-y-auto font-mono text-[11px] scrollbar-thin scrollbar-thumb-slate-700">
{envLogs.length > 0 ? envLogs.map((log, i) => (
<div key={i} className="flex items-start gap-3 text-slate-400 border-l-2 border-cyan-500/50 pl-3 py-0.5">
<BaseIcon path={mdiBug} size={12} className="text-cyan-400 shrink-0 mt-0.5" />
<div key={i} className={`flex items-start gap-3 border-l-2 pl-3 py-1 transition-colors ${
log.includes('WEBHOOK') || log.includes('REMOTE') ? 'bg-red-500/5 border-red-500/50 text-red-200' :
log.includes('INTERCEPTED') ? 'bg-yellow-500/5 border-yellow-500/50 text-yellow-200' :
'bg-cyan-500/5 border-cyan-500/50 text-slate-300'
}`}>
<BaseIcon path={mdiBug} size={12} className={`shrink-0 mt-0.5 ${
log.includes('WEBHOOK') || log.includes('REMOTE') ? 'text-red-400' :
log.includes('INTERCEPTED') ? 'text-yellow-400' :
'text-cyan-400'
}`} />
<span className="break-all">{log}</span>
</div>
)) : (
<p className="text-slate-600 italic text-[10px] text-center py-4 uppercase tracking-widest">No environment hooks triggered</p>
<p className="text-slate-600 italic text-[10px] text-center py-4 uppercase tracking-widest">Waiting for VM telemetry...</p>
)}
</div>
</CardBox>
@ -270,4 +304,4 @@ DumperPage.getLayout = function getLayout(page: ReactElement) {
return <LayoutAuthenticated>{page}</LayoutAuthenticated>;
};
export default DumperPage;
export default DumperPage;