قم بإزالة تشويش جافا سكريبت وأعد بناء السلاسل. قم بتبسيط المنطق المرهق حيثما أمكن ذلك مع الالتزام بقيود النطاق.
جربه عبر الإنترنت @ Restringer.tech.
للحصول على التعليقات والاقتراحات، لا تتردد في فتح مشكلة أو ابحث عني على Twitter - @ctrl__esc
npm install -g restringer
يتطلب العقدة 16 أو الأحدث.
git clone [email protected]:PerimeterX/restringer.git
cd restringer
npm install
يستخدم ملف Restringer.js أساليب إزالة التشويش العامة التي تعيد بناء السلاسل المبهمة واستعادتها وتبسيط المنطق الزائد الذي يهدف فقط إلى إثقال كاهله. يستخدم REstringer كاشف التشويش لتحديد أنواع معينة من التشويش التي تحتاج إلى تطبيق طرق محددة لإزالة التشويش من أجل التحايل على آليات مكافحة تصحيح الأخطاء أو مصائد التعليمات البرمجية الأخرى التي تمنع إزالة التشويش من البرنامج النصي.
Usage: restringer input_filename [-h] [-c] [-q | -v] [-m M] [-o [output_filename]]
positional arguments:
input_filename The obfuscated JS file
optional arguments:
-h, --help Show this help message and exit.
-c, --clean Remove dead nodes from script after deobfuscation is complete (unsafe).
-q, --quiet Suppress output to stdout. Output result only to stdout if the -o option is not set.
Does not go with the -v option.
-m, --max-iterations M Run at most M iterations
-v, --verbose Show more debug messages while deobfuscating. Does not go with the -q option.
-o, --output [output_filename] Write deobfuscated script to output_filename.
<input_filename>-deob.js is used if no filename is provided.
أمثلة:
restringer [target-file.js]
restringer [target-file.js] -o output.js
restringer [target-file.js] -v
restringer [target-file.js] -q
import { REstringer } from 'restringer' ;
const restringer = new REstringer ( '"RE" + "stringer"' ) ;
if ( restringer . deobfuscate ( ) ) {
console . log ( restringer . script ) ;
} else {
console . log ( 'Nothing was deobfuscated :/' ) ;
}
// Output: 'REstringer';
REstringer معياري للغاية. إنه يكشف عن الوحدات التي تسمح بإنشاء أدوات إزالة التشويش المخصصة التي يمكنها حل مشكلات محددة.
سيكون الهيكل الأساسي لمثل هذا مزيل التشويش عبارة عن مجموعة من وحدات إزالة التشويش (سواء كانت آمنة أو غير آمنة)، يتم تشغيلها عبر وظيفة الأداة المساعدة applicationIteratively الخاصة بـ flAST.
تقوم الوحدات غير الآمنة بتشغيل التعليمات البرمجية من خلال eval
(باستخدام المعزول-vm لتكون في الجانب الآمن) بينما لا تقوم الوحدات الآمنة بذلك.
import { applyIteratively } from 'flast' ;
import { safe , unsafe } from 'restringer' ;
const { normalizeComputed } = safe ;
const { resolveDefiniteBinaryExpressions , resolveLocalCalls } = unsafe ;
let script = 'obfuscated JS here' ;
const deobModules = [
resolveDefiniteBinaryExpressions ,
resolveLocalCalls ,
normalizeComputed ,
] ;
script = applyIteratively ( script , deobModules ) ;
console . log ( script ) ; // Deobfuscated script
باستخدام وسيطة دالة candidateFilter
الإضافية، من الممكن تضييق نطاق العقد المستهدفة:
import { unsafe } from 'restringer' ;
const { resolveLocalCalls } = unsafe ;
import { applyIteratively } from 'flast' ;
let script = 'obfuscated JS here' ;
// It's better to define a function with a meaningful name that can show up in the log
function resolveLocalCallsInGlobalScope ( arb ) {
return resolveLocalCalls ( arb , n => n . parentNode ?. type === 'Program' ) ;
}
script = applyIteratively ( script , [ resolveLocalCallsInGlobalScope ] ) ;
console . log ( script ) ; // Deobfuscated script
يمكنك أيضًا تخصيص أي طريقة لإزالة التشويش مع الاستمرار في استخدام REstringer دون تشغيل الحلقة بنفسك:
import fs from 'node:fs' ;
import { REstringer } from 'restringer' ;
const inputFilename = process . argv [ 2 ] ;
const code = fs . readFileSync ( inputFilename , 'utf-8' ) ;
const res = new REstringer ( code ) ;
// res.logger.setLogLevelDebug();
res . detectObfuscationType = false ; // Skip obfuscation type detection, including any pre and post processors
const targetFunc = res . unsafeMethods . find ( m => m . name === 'resolveLocalCalls' ) ;
let changes = 0 ; // Resolve only the first 5 calls
res . safeMethods [ res . unsafeMethods . indexOf ( targetFunc ) ] = function customResolveLocalCalls ( n ) { return targetFunc ( n , ( ) => changes ++ < 5 ) }
res . deobfuscate ( ) ;
if ( res . script !== code ) {
console . log ( '[+] Deob successful' ) ;
fs . writeFileSync ( ` ${ inputFilename } -deob.js` , res . script , 'utf-8' ) ;
} else console . log ( '[-] Nothing deobfuscated :/' ) ;
import { applyIteratively , logger } from 'flast' ;
// Optional loading from file
// import fs from 'node:fs';
// const inputFilename = process.argv[2] || 'target.js';
// const code = fs.readFileSync(inputFilename, 'utf-8');
const code = `(function() {
function createMessage() {return 'Hello' + ' ' + 'there!';}
function print(msg) {console.log(msg);}
print(createMessage());
})();` ;
logger . setLogLevelDebug ( ) ;
/**
* Replace specific strings with other strings
* @param {Arborist} arb
* @return {Arborist}
*/
function replaceSpecificLiterals ( arb ) {
const replacements = {
'Hello' : 'General' ,
'there!' : 'Kenobi!' ,
} ;
// Iterate over only the relevant nodes by targeting specific types using the typeMap property on the root node
const relevantNodes = [
... ( arb . ast [ 0 ] . typeMap . Literal || [ ] ) ,
// ...(arb.ast.typeMap.TemplateLiteral || []), // unnecessary for this example, but this is how to add more types
] ;
for ( const n of relevantNodes ) {
if ( replacements [ n . value ] ) {
// dynamically define a replacement node by creating an object with a type and value properties
// markNode(n) would delete the node, while markNode(n, {...}) would replace the node with the supplied node.
arb . markNode ( n , { type : 'Literal' , value : replacements [ n . value ] } ) ;
}
}
return arb ;
}
let script = code ;
script = applyIteratively ( script , [
replaceSpecificLiterals ,
] ) ;
if ( code !== script ) {
console . log ( script ) ;
// fs.writeFileSync(inputFilename + '-deob.js', script, 'utf-8');
} else console . log ( `No changes` ) ;