// Detect It Easy: detection rule file // Author: DosX // E-Mail: collab@kay-software.ru // GitHub: https://github.com/DosX-dev // Telegram: @DosX_dev function detect() { main(); } function main() { if (Binary.isHeuristicScan()) { switch (Binary.getFileSuffix().toLowerCase()) { case "js": // JavaScript case "jse": // JScript Encoded case "jsc": // JavaScript Compiled case "sg": // Detect It Easy module var options = String(); if (!Binary.isPlainText()) { options = "bytecode"; } else { if (Binary.getSize() > 3000) { var scriptContent = Binary.getString(0x00, Binary.getSize()); // Split the code into segments that are outside of string literals. // Handle escaping (\", \\', \`) — escaped quotes are not treated as string delimiters. // Also include expressions inside template literals `${...}` as code (they will be scanned). var segments = [], currentSegment = String(), insideString = false, stringDelimiter = String(), isEscaped = false; for (var i = 0; i < scriptContent.length; i++) { var currChar = scriptContent[i]; if (insideString) { if (isEscaped) { isEscaped = false; continue; } if (currChar === '\\') { isEscaped = true; continue; } // For template literals: when encountering `${` include nested expression into current segment if (stringDelimiter === '`' && currChar === '$' && i + 1 < scriptContent.length && scriptContent[i + 1] === '{') { // skip '{' and start accumulating the expression content i++; // now scriptContent[i] === '{' var braceDepth = 1; // Inside the expression, handle escaping as well while (i + 1 < scriptContent.length && braceDepth > 0) { i++; var innerChar = scriptContent[i]; if (innerChar === '\\') { // capture escaped char and the next one currentSegment += innerChar; if (i + 1 < scriptContent.length) { i++; currentSegment += scriptContent[i]; } continue; } if (innerChar === '{') { braceDepth++; currentSegment += innerChar; continue; } if (innerChar === '}') { braceDepth--; if (braceDepth === 0) break; currentSegment += innerChar; continue; } currentSegment += innerChar; } continue; } if (currChar === stringDelimiter) { insideString = false; stringDelimiter = String(); } // do not copy characters that are inside strings } else { // not inside a string if (currChar === '"' || currChar === "'" || currChar === '`') { // start of string — finish current segment if (currentSegment.length > 0) { segments.push(currentSegment); currentSegment = String(); } insideString = true; stringDelimiter = currChar; } else { currentSegment += currChar; } } } if (currentSegment.length > 0) segments.push(currentSegment); for (var segIndex = 0; segIndex < segments.length; segIndex++) { var tokenToProcess = segments[segIndex]; if (!/( |\t)/.test(tokenToProcess) && ( /(((var|let|const)[\t ]|\())\b[a-zA-Z](?:,[a-zA-Z]){3,}\b/.test(tokenToProcess) || /[a-zA-Z][!=]?=?=![01][;,})]/.test(tokenToProcess) )) { options = "minified/compiled"; break; } } } } _setResult("~language", "JavaScript", String(), Binary.isVerbose() ? options : String()); break; } } }