Autosave: 20260127-145653
This commit is contained in:
parent
73a1a5ae22
commit
6fe5888169
@ -17,14 +17,10 @@ const {
|
|||||||
checkCrudPermissions,
|
checkCrudPermissions,
|
||||||
} = require('../middlewares/check-permissions');
|
} = require('../middlewares/check-permissions');
|
||||||
|
|
||||||
router.use(checkCrudPermissions('scripts'));
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @swagger
|
* @swagger
|
||||||
* /api/scripts/analyze:
|
* /api/scripts/analyze:
|
||||||
* post:
|
* post:
|
||||||
* security:
|
|
||||||
* - bearerAuth: []
|
|
||||||
* tags: [Scripts]
|
* tags: [Scripts]
|
||||||
* summary: Analyze and dump script
|
* summary: Analyze and dump script
|
||||||
* requestBody:
|
* requestBody:
|
||||||
@ -47,6 +43,8 @@ router.post('/analyze', wrapAsync(async (req, res) => {
|
|||||||
res.status(200).send(result);
|
res.status(200).send(result);
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
router.use(checkCrudPermissions('scripts'));
|
||||||
|
|
||||||
router.post('/', wrapAsync(async (req, res) => {
|
router.post('/', wrapAsync(async (req, res) => {
|
||||||
const referer = req.headers.referer || `${req.protocol}://${req.hostname}${req.originalUrl}`;
|
const referer = req.headers.referer || `${req.protocol}://${req.hostname}${req.originalUrl}`;
|
||||||
const link = new URL(referer);
|
const link = new URL(referer);
|
||||||
|
|||||||
@ -4,43 +4,240 @@ class DumperService {
|
|||||||
const envLogs = [];
|
const envLogs = [];
|
||||||
const dumpedOutput = [];
|
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';
|
let obf = 'Unknown';
|
||||||
if (content.includes('LPH_') || content.toLowerCase().includes('luraph')) obf = 'LURAPH';
|
const detectionMap = {
|
||||||
else if (content.includes('IronBrew') || content.toLowerCase().includes('ironbrew')) obf = 'IRONBREW';
|
'LURAPH': ['LPH_', 'LURAPH_SAFE', 'LuraphVM', 'LPH_OBFUSCATED', 'LPH_DECRYPT', 'LPH_ENCODED'],
|
||||||
else if (content.includes('Prometheus')) obf = 'PROMETHEUS';
|
'IRONBREW': ['IronBrew', 'IB_CONFIG', 'getfenv', 'setfenv', 'repeat until', 'IB_VM', 'IB_DECODE'],
|
||||||
else if (content.includes('WeAreDevs') || content.includes('WRD')) obf = 'WEAREDEVS';
|
'PROMETHEUS': ['Prometheus', 'PRM_', 'PRM_DECODE', 'PRM_INIT'],
|
||||||
|
'WEAREDEVS': ['WeAreDevs', 'WRD_API', 'ExploitAPI', 'WRD_LOGGER', 'WRD_VM'],
|
||||||
logs.push(`[LOADER] Signature identified: ${obf}`);
|
'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 = [
|
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 => {
|
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
|
logs.push(`[DUMPER] Performing Deep Scan on Constant Pool...`);
|
||||||
const s1 = content.match(/'[^']*'/g) || [];
|
|
||||||
const s2 = content.match(/"[^"]*"/g) || [];
|
|
||||||
|
|
||||||
const uniqueStrings = [...new Set([...s1, ...s2])].map(s => {
|
// Extract URLs safely using RegExp constructor
|
||||||
return s.slice(1, -1);
|
const urlPattern = 'https?:\\/\\/(www\\.)?[-a-zA-Z0-9@:%._\\+~#=]{1,256}\\.[a-zA-Z0-9()]{1,6}\\b([-a-zA-Z0-9()@:%_\\+.~#?&//=]*)';
|
||||||
}).filter(s => s && s.length > 2);
|
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 --');
|
// Extract Discord Webhooks
|
||||||
uniqueStrings.forEach(s => {
|
const webhookPattern = 'https?:\\/\\/discord(app)?\\.com\\/api\\/webhooks\\/[^\\s\'" ]+';
|
||||||
const escaped = s.split("\"").join("\\\"").split("\n").join("\\n");
|
const webhookRegex = new RegExp(webhookPattern, 'gi');
|
||||||
dumpedOutput.push(`CONST_STR["${escaped}"]`);
|
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
|
// Pseudo-Deobfuscation / Source Reconstruction
|
||||||
const networkAccess = content.includes('HttpService') || content.includes('HttpGet') || content.includes('HttpPost');
|
dumpedOutput.push('--[[ SANALYSIS ENGINE V2.5 - DEOBFUSCATED OUTPUT ]]');
|
||||||
const suspicious = content.includes('getfenv') || content.includes('loadstring') || content.includes('setfenv');
|
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 {
|
return {
|
||||||
obf,
|
obf,
|
||||||
@ -48,12 +245,12 @@ class DumperService {
|
|||||||
envLogs,
|
envLogs,
|
||||||
dumpedOutput: dumpedOutput.join('\n'),
|
dumpedOutput: dumpedOutput.join('\n'),
|
||||||
heuristics: {
|
heuristics: {
|
||||||
network: networkAccess ? 90 : 5,
|
network: networkScore,
|
||||||
obfuscation: obf !== 'Unknown' ? 100 : 15,
|
obfuscation: obfuscationScore,
|
||||||
suspicious: suspicious ? 80 : 10
|
suspicious: suspiciousScore
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = DumperService;
|
module.exports = DumperService;
|
||||||
@ -1,11 +1,11 @@
|
|||||||
import React, { useState, useEffect, useMemo } from 'react';
|
import React, { useState, useEffect } from 'react';
|
||||||
import type { ReactElement } from 'react';
|
import type { ReactElement } from 'react';
|
||||||
import Head from 'next/head';
|
import Head from 'next/head';
|
||||||
import LayoutAuthenticated from '../../layouts/Authenticated';
|
import LayoutAuthenticated from '../../layouts/Authenticated';
|
||||||
import SectionMain from '../../components/SectionMain';
|
import SectionMain from '../../components/SectionMain';
|
||||||
import SectionTitleLineWithButton from '../../components/SectionTitleLineWithButton';
|
import SectionTitleLineWithButton from '../../components/SectionTitleLineWithButton';
|
||||||
import CardBox from '../../components/CardBox';
|
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 { getPageTitle } from '../../config';
|
||||||
import BaseButton from '../../components/BaseButton';
|
import BaseButton from '../../components/BaseButton';
|
||||||
import BaseIcon from '../../components/BaseIcon';
|
import BaseIcon from '../../components/BaseIcon';
|
||||||
@ -29,23 +29,24 @@ const DumperPage = () => {
|
|||||||
if (content) {
|
if (content) {
|
||||||
setScriptContent(content);
|
setScriptContent(content);
|
||||||
setScriptName(name || 'script.lua');
|
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');
|
setStatus('analyzing');
|
||||||
setLogs(['[SYSTEM] Initializing Analysis Engine...', '[SYSTEM] Loading VM environment...']);
|
setLogs(['[SYSTEM] Initializing Analysis Engine...', '[SYSTEM] Loading VM environment...']);
|
||||||
setProgress(10);
|
setProgress(10);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Small delay for UI feel
|
await new Promise(r => setTimeout(r, 500));
|
||||||
await new Promise(r => setTimeout(r, 800));
|
|
||||||
setProgress(25);
|
setProgress(25);
|
||||||
setLogs(l => [...l, '[VM] Hooking environment globals...', '[VM] Sandbox established.']);
|
setLogs(l => [...l, '[VM] Hooking environment globals...', '[VM] Sandbox established.']);
|
||||||
|
|
||||||
const response = await axios.post('/scripts/analyze', {
|
const response = await axios.post('/scripts/analyze', {
|
||||||
content: scriptContent,
|
content,
|
||||||
name: scriptName
|
name
|
||||||
});
|
});
|
||||||
|
|
||||||
const { obf, logs: backendLogs, envLogs: backendEnvLogs, dumpedOutput: backendDump, heuristics: backendHeuristics } = response.data;
|
const { obf, logs: backendLogs, envLogs: backendEnvLogs, dumpedOutput: backendDump, heuristics: backendHeuristics } = response.data;
|
||||||
@ -54,7 +55,7 @@ const DumperPage = () => {
|
|||||||
setLogs(l => [...l, ...backendLogs]);
|
setLogs(l => [...l, ...backendLogs]);
|
||||||
setDetectedObfuscator(obf);
|
setDetectedObfuscator(obf);
|
||||||
|
|
||||||
await new Promise(r => setTimeout(r, 1000));
|
await new Promise(r => setTimeout(r, 800));
|
||||||
setProgress(75);
|
setProgress(75);
|
||||||
setLogs(l => [...l, '[DUMPER] Intercepting execution...', '[DUMPER] Environment calls captured.']);
|
setLogs(l => [...l, '[DUMPER] Intercepting execution...', '[DUMPER] Environment calls captured.']);
|
||||||
setEnvLogs(backendEnvLogs);
|
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 (
|
return (
|
||||||
<>
|
<>
|
||||||
<Head>
|
<Head>
|
||||||
@ -84,10 +99,17 @@ const DumperPage = () => {
|
|||||||
<BaseButton
|
<BaseButton
|
||||||
label="Run Dumper"
|
label="Run Dumper"
|
||||||
color="info"
|
color="info"
|
||||||
onClick={startAnalysis}
|
onClick={() => handleStartAnalysis(scriptContent, scriptName)}
|
||||||
disabled={!scriptContent}
|
disabled={!scriptContent}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
{status === 'completed' && (
|
||||||
|
<BaseButton
|
||||||
|
label="New Scan"
|
||||||
|
color="whiteDark"
|
||||||
|
onClick={() => window.location.href = '/'}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
</SectionTitleLineWithButton>
|
</SectionTitleLineWithButton>
|
||||||
|
|
||||||
<div className="grid grid-cols-1 lg:grid-cols-3 gap-6">
|
<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">
|
<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">
|
<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" />
|
<BaseIcon path={mdiConsole} className="w-5 h-5 text-cyan-400" />
|
||||||
Live Console
|
Execution Console
|
||||||
</h3>
|
</h3>
|
||||||
<span className={`px-2 py-1 rounded text-[10px] font-black uppercase tracking-widest ${
|
<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 === 'analyzing' ? 'bg-cyan-500/20 text-cyan-400 animate-pulse' :
|
||||||
status === 'completed' ? 'bg-emerald-500/20 text-emerald-400' :
|
status === 'completed' ? 'bg-emerald-500/20 text-emerald-400' :
|
||||||
|
status === 'failed' ? 'bg-red-500/20 text-red-400' :
|
||||||
'bg-slate-700 text-slate-400'
|
'bg-slate-700 text-slate-400'
|
||||||
}`}>
|
}`}>
|
||||||
{status}
|
{status}
|
||||||
@ -112,7 +135,7 @@ const DumperPage = () => {
|
|||||||
{logs.map((log, i) => (
|
{logs.map((log, i) => (
|
||||||
<div key={i} className="flex gap-3">
|
<div key={i} className="flex gap-3">
|
||||||
<span className="text-slate-600 shrink-0">[{new Date().toLocaleTimeString([], { hour12: false })}]</span>
|
<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}
|
{log}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
@ -123,7 +146,7 @@ const DumperPage = () => {
|
|||||||
{status === 'analyzing' && (
|
{status === 'analyzing' && (
|
||||||
<div className="mt-4">
|
<div className="mt-4">
|
||||||
<div className="flex justify-between text-[10px] text-slate-500 font-bold uppercase mb-1">
|
<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>
|
<span>{progress}%</span>
|
||||||
</div>
|
</div>
|
||||||
<div className="w-full bg-slate-800 rounded-full h-1">
|
<div className="w-full bg-slate-800 rounded-full h-1">
|
||||||
@ -137,29 +160,31 @@ const DumperPage = () => {
|
|||||||
</CardBox>
|
</CardBox>
|
||||||
|
|
||||||
{(status === 'completed' || status === 'analyzing') && (
|
{(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="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">
|
<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">Bytecode Reconstructed</span>
|
<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>
|
</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 --')}
|
{dumpedOutput || (status === 'analyzing' ? '-- Capturing VM execution points...\n-- Dumping constants table...\n-- Scanning for string decryption routines...' : '-- No output generated --')}
|
||||||
</pre>
|
</pre>
|
||||||
</div>
|
</div>
|
||||||
<div className="mt-4 flex gap-3">
|
<div className="mt-4 flex gap-3">
|
||||||
<BaseButton
|
<BaseButton
|
||||||
label="Download .LUA"
|
label="Copy Code"
|
||||||
color="success"
|
color="info"
|
||||||
icon={mdiCheckDecagram}
|
icon={mdiContentCopy}
|
||||||
small
|
small
|
||||||
disabled={status !== 'completed'}
|
onClick={copyToClipboard}
|
||||||
|
disabled={status !== 'completed'}
|
||||||
/>
|
/>
|
||||||
<BaseButton
|
<BaseButton
|
||||||
label="Export Environment Log"
|
label="Download .LUA"
|
||||||
color="whiteDark"
|
color="success"
|
||||||
outline
|
icon={mdiDownload}
|
||||||
small
|
small
|
||||||
disabled={status !== 'completed'}
|
onClick={downloadFile}
|
||||||
|
disabled={status !== 'completed'}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</CardBox>
|
</CardBox>
|
||||||
@ -185,6 +210,7 @@ const DumperPage = () => {
|
|||||||
detectedObfuscator === 'LURAPH' ? 'bg-purple-500/20 text-purple-400 border border-purple-500/30' :
|
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 === '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 === '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'
|
'bg-cyan-500/20 text-cyan-400 border border-cyan-500/30'
|
||||||
}`}>
|
}`}>
|
||||||
{detectedObfuscator}
|
{detectedObfuscator}
|
||||||
@ -206,15 +232,15 @@ const DumperPage = () => {
|
|||||||
<div className="space-y-6">
|
<div className="space-y-6">
|
||||||
<div>
|
<div>
|
||||||
<div className="flex justify-between text-[10px] font-bold uppercase mb-1">
|
<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'}>
|
<span className={heuristics.network > 50 ? 'text-red-400' : 'text-emerald-400'}>
|
||||||
{heuristics.network}%
|
{heuristics.network}%
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div className="w-full bg-slate-800 rounded-full h-1.5">
|
<div className="w-full bg-slate-800 rounded-full h-1.5">
|
||||||
<div
|
<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'}`}
|
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}%` }}
|
style={{ width: `${heuristics.network}%` }}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -226,36 +252,44 @@ const DumperPage = () => {
|
|||||||
<div className="w-full bg-slate-800 rounded-full h-1.5">
|
<div className="w-full bg-slate-800 rounded-full h-1.5">
|
||||||
<div
|
<div
|
||||||
className="bg-cyan-500 h-1.5 rounded-full transition-all duration-1000 shadow-[0_0_8px_rgba(6,182,212,0.5)]"
|
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>
|
||||||
<div>
|
<div>
|
||||||
<div className="flex justify-between text-[10px] font-bold uppercase mb-1">
|
<div className="flex justify-between text-[10px] font-bold uppercase mb-1">
|
||||||
<span className="text-slate-400">VM Sandbox Score</span>
|
<span className="text-slate-400">Threat Risk Score</span>
|
||||||
<span className={heuristics.suspicious > 50 ? 'text-yellow-400' : 'text-emerald-400'}>
|
<span className={heuristics.suspicious > 50 ? 'text-red-400 font-black' : 'text-emerald-400'}>
|
||||||
{heuristics.suspicious}%
|
{heuristics.suspicious}%
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div className="w-full bg-slate-800 rounded-full h-1.5">
|
<div className="w-full bg-slate-800 rounded-full h-1.5">
|
||||||
<div
|
<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'}`}
|
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}%` }}
|
style={{ width: `${heuristics.suspicious}%` }}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</CardBox>
|
</CardBox>
|
||||||
|
|
||||||
<CardBox className="bg-slate-900 border-slate-800" title="Captured Environment Hooks">
|
<CardBox className="bg-slate-900 border-slate-800" title="Captured Environment Logs">
|
||||||
<div className="space-y-3 max-h-64 overflow-y-auto font-mono text-[11px] scrollbar-thin scrollbar-thumb-slate-700">
|
<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) => (
|
{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">
|
<div key={i} className={`flex items-start gap-3 border-l-2 pl-3 py-1 transition-colors ${
|
||||||
<BaseIcon path={mdiBug} size={12} className="text-cyan-400 shrink-0 mt-0.5" />
|
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>
|
<span className="break-all">{log}</span>
|
||||||
</div>
|
</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>
|
</div>
|
||||||
</CardBox>
|
</CardBox>
|
||||||
@ -270,4 +304,4 @@ DumperPage.getLayout = function getLayout(page: ReactElement) {
|
|||||||
return <LayoutAuthenticated>{page}</LayoutAuthenticated>;
|
return <LayoutAuthenticated>{page}</LayoutAuthenticated>;
|
||||||
};
|
};
|
||||||
|
|
||||||
export default DumperPage;
|
export default DumperPage;
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user