مرجع الخيارات
المحتويات
compact
config
controlFlowFlattening
controlFlowFlatteningThreshold
deadCodeInjection
deadCodeInjectionThreshold
debugProtection
debugProtectionInterval
disableConsoleOutput
domainLock
نطاقات ونطاقات فرعية متعددة
domainLockRedirectUrl
exclude
forceTransformStrings
identifierNamesCache
واجهة Node.js
CLI
identifierNamesGenerator
identifiersDictionary
identifiersPrefix
randomIdentifiersPrefix
ignoreImports
inputFileName
log
numbersToExpressions
optionsPreset
parseHtml
renameGlobals
renameProperties
renamePropertiesMode
reservedNames
reservedStrings
seed
selfDefending
simplify
sourceMap
sourceMapBaseUrl
sourceMapFileName
sourceMapMode
sourceMapSourcesMode
splitStrings
splitStringsChunkLength
stringArray
stringArrayCallsTransform
stringArrayCallsTransformThreshold
stringArrayEncoding
stringArrayIndexesType
stringArrayIndexShift
stringArrayRotate
stringArrayShuffle
stringArrayWrappersCount
stringArrayWrappersChainedCalls
stringArrayWrappersParametersMaxCount
stringArrayWrappersType
stringArrayThreshold
strictMode
target
transformObjectKeys
warnings
vmObfuscation
vmTargetFunctions
vmExcludeFunctions
vmTargetFunctionsMode
vmForceCompileDynamicCode
vmWrapTopLevelInitializers
vmDynamicOpcodes
vmBytecodeEncoding
vmBytecodeArrayEncoding
vmBytecodeArrayEncodingKey
vmBytecodeArrayEncodingKeyGetter
vmAsyncExecutor
vmJumpsEncoding
vmMacroOps
vmDebugProtection
vmSelfDefending
vmDefenseHook
vmDefenseReaction
vmStatefulOpcodes
vmCallContextOpcodes
vmStackEncoding
vmCompactDispatcher
vmStringArrayBytecodeOnly
vmDomainLock
نطاقات ونطاقات فرعية متعددة
vmDomainLockRedirectUrl
Preset Options
تشويش عالٍ، أداء منخفض
تشويش متوسط، أداء مثالي
تشويش منخفض، أداء عالٍ
الإعداد المسبق الافتراضي، أداء عالٍ
تشويش VM فائق العلو (أقصى أمان)
VM المضاد لنماذج LLM (حماية من وكلاء الذكاء الاصطناعي)
تشويش VM العالي (أعلى أمان)
تشويش VM المتوسط (أمان متوازن)
تشويش VM المنخفض (أمان أساسي، أداء أفضل)
VM الافتراضي (VM + حماية مصفوفة النصوص)
compact
Type: boolean Default: true
يجمع الكود الناتج في سطر واحد.
config
Type: string Default: ``
اسم ملف الإعدادات بصيغة JS/JSON الذي يحتوي على خيارات المشوِّش. تُتجاوَز هذه الخيارات بالخيارات المُمرَّرة مباشرةً إلى CLI
controlFlowFlattening
Type: boolean Default: false
⚠️ يؤثّر هذا الخيار بشدة في الأداء، إذ قد يبطّئ سرعة التشغيل حتى 1.5 ضعف. استخدم controlFlowFlatteningThreshold لتحديد نسبة العُقد التي سيطالها تسطيح تدفق التحكم.
يفعّل تسطيح تدفق التحكم في الكود. وتسطيح تدفق التحكم هو تحويل بنيوي للكود المصدري يعيق فهم البرنامج.
مثال:
// input
(function(){
function foo () {
return function () {
var sum = 1 + 2;
console.log(1);
console.log(2);
console.log(3);
console.log(4);
console.log(5);
console.log(6);
}
}
foo()();
})();
// output
(function () {
function _0x3bfc5c() {
return function () {
var _0x3260a5 = {
'WtABe': '4|0|6|5|3|2|1',
'GokKo': function _0xf87260(_0x427a8e, _0x43354c) {
return _0x427a8e + _0x43354c;
}
};
var _0x1ad4d6 = _0x3260a5['WtABe']['split']('|'), _0x1a7b12 = 0x0;
while (!![]) {
switch (_0x1ad4d6[_0x1a7b12++]) {
case '0':
console['log'](0x1);
continue;
case '1':
console['log'](0x6);
continue;
case '2':
console['log'](0x5);
continue;
case '3':
console['log'](0x4);
continue;
case '4':
var _0x1f2f2f = _0x3260a5['GokKo'](0x1, 0x2);
continue;
case '5':
console['log'](0x3);
continue;
case '6':
console['log'](0x2);
continue;
}
break;
}
};
}
_0x3bfc5c()();
}());
controlFlowFlatteningThreshold
Type: number Default: 0.75 Min: 0 Max: 1
احتمال تطبيق تحويل controlFlowFlattening على أي عقدة بعينها.
هذا الإعداد مفيد بوجه خاص مع أحجام الكود الكبيرة، لأن الكميات الكبيرة من تحويلات تدفق التحكم قد تبطّئ كودك وتزيد حجمه.
القيمة controlFlowFlatteningThreshold: 0 تكافئ controlFlowFlattening: false.
deadCodeInjection
Type: boolean Default: false
⚠️ يزيد حجم الكود المشوَّش زيادة كبيرة (حتى 200%)، فلا تستخدمه إلا إذا كان حجم الكود المشوَّش لا يهم. استخدم deadCodeInjectionThreshold لتحديد نسبة العُقد التي سيطالها حقن الكود الميت.
⚠️ يفعّل هذا الخيار قسرًا خيار stringArray.
⚠️ يُعطَّل هذا الخيار بصمت عند تفعيل vmObfuscation.
مع هذا الخيار، تُضاف كتل عشوائية من الكود الميت إلى الكود المشوَّش.
مثال:
// input
(function(){
if (true) {
var foo = function () {
console.log('abc');
};
var bar = function () {
console.log('def');
};
var baz = function () {
console.log('ghi');
};
var bark = function () {
console.log('jkl');
};
var hawk = function () {
console.log('mno');
};
foo();
bar();
baz();
bark();
hawk();
}
})();
// output
var _0x37b8 = [
'YBCtz',
'GlrkA',
'urPbb',
'abc',
'NMIhC',
'yZgAj',
'zrAId',
'EtyJA',
'log',
'mno',
'jkl',
'def',
'Quzya',
'IWbBa',
'ghi'
];
function _0x43a7(_0x12cf56, _0x587376) {
_0x43a7 = function (_0x2f87a8, _0x47eac2) {
_0x2f87a8 = _0x2f87a8 - (0x16a7 * 0x1 + 0x5 * 0x151 + -0x1c92);
var _0x341e03 = _0x37b8[_0x2f87a8];
return _0x341e03;
};
return _0x43a7(_0x12cf56, _0x587376);
}
(function () {
if (!![]) {
var _0xbbe28f = function () {
var _0x2fc85f = _0x43a7;
if (_0x2fc85f(0xaf) === _0x2fc85f(0xae)) {
_0x1dd94f[_0x2fc85f(0xb2)](_0x2fc85f(0xb5));
} else {
console[_0x2fc85f(0xb2)](_0x2fc85f(0xad));
}
};
var _0x5e46bc = function () {
var _0x15b472 = _0x43a7;
if (_0x15b472(0xb6) !== _0x15b472(0xaa)) {
console[_0x15b472(0xb2)](_0x15b472(0xb5));
} else {
_0x47eac2[_0x15b472(0xb2)](_0x15b472(0xad));
}
};
var _0x3669e8 = function () {
var _0x47a442 = _0x43a7;
if (_0x47a442(0xb7) !== _0x47a442(0xb0)) {
console[_0x47a442(0xb2)](_0x47a442(0xb8));
} else {
_0x24e0bf[_0x47a442(0xb2)](_0x47a442(0xb3));
}
};
var _0x28b05a = function () {
var _0x497902 = _0x43a7;
if (_0x497902(0xb1) === _0x497902(0xb1)) {
console[_0x497902(0xb2)](_0x497902(0xb4));
} else {
_0x59c9c6[_0x497902(0xb2)](_0x497902(0xb4));
}
};
var _0x402a54 = function () {
var _0x1906b7 = _0x43a7;
if (_0x1906b7(0xab) === _0x1906b7(0xac)) {
_0xb89cd0[_0x1906b7(0xb2)](_0x1906b7(0xb8));
} else {
console[_0x1906b7(0xb2)](_0x1906b7(0xb3));
}
};
_0xbbe28f();
_0x5e46bc();
_0x3669e8();
_0x28b05a();
_0x402a54();
}
}());
deadCodeInjectionThreshold
Type: number Default: 0.4 Min: 0 Max: 1
يتيح تحديد نسبة العُقد التي سيطالها deadCodeInjection.
debugProtection
Type: boolean Default: false
⚠️ قد يجمّد متصفحك إذا فتحت أدوات المطور.
⚠️ يُعطَّل هذا الخيار بصمت عند تفعيل vmObfuscation. استخدم vmDebugProtection بدلًا منه.
يجعل هذا الخيار استخدام وظيفة debugger في أدوات المطور شبه مستحيل (سواء في المتصفحات المبنية على WebKit أو في Mozilla Firefox).
debugProtectionInterval
Type: number Default: 0
⚠️ قد يجمّد متصفحك! استخدمه على مسؤوليتك الخاصة.
⚠️ يُعطَّل هذا الخيار بصمت عند تفعيل vmObfuscation. استخدم vmDebugProtection بدلًا منه.
عند ضبطه، يُستخدَم فاصل زمني بالميلي ثانية لفرض وضع التنقيح على علامة تبويب Console، مما يصعّب استخدام ميزات أدوات المطور الأخرى. يعمل إذا كان debugProtection مفعَّلًا. القيمة المُوصى بها بين 2000 و4000 ميلي ثانية.
disableConsoleOutput
Type: boolean Default: false
⚠️ يعطّل هذا الخيار استدعاءات console عالميًا لكل السكربتات
يعطّل استخدام console.log وconsole.info وconsole.error وconsole.warn وconsole.debug وconsole.exception وconsole.trace باستبدالها بدوال فارغة. وهذا يصعّب استخدام المنقّح.
domainLock
Type: string[] Default: []
⚠️ لا يعمل هذا الخيار مع target: 'node' أو target: 'service-worker' أو target: 'bytenode'
يتيح تشغيل الكود المصدري المشوَّش على نطاقات و/أو نطاقات فرعية بعينها فقط. وهذا يصعّب كثيرًا على أي شخص أن ينسخ كودك المصدري ويشغّله في مكان آخر.
إذا لم يُشغَّل الكود المصدري على النطاقات المحددة بهذا الخيار، فسيُعاد توجيه المتصفح إلى عنوان URL المُمرَّر إلى خيار domainLockRedirectUrl.
نطاقات ونطاقات فرعية متعددة
يمكن قفل كودك على أكثر من نطاق أو نطاق فرعي. فمثلًا، لقفله بحيث لا يعمل الكود إلا على www.example.com أضف www.example.com. ولجعله يعمل على النطاق الجذري بما في ذلك أي نطاقات فرعية (example.com وsub.example.com)، استخدم .example.com.
domainLockRedirectUrl
Type: string Default: about:blank
⚠️ لا يعمل هذا الخيار مع target: 'node' أو target: 'service-worker' أو target: 'bytenode'
يتيح إعادة توجيه المتصفح إلى عنوان URL مُمرَّر إذا لم يُشغَّل الكود المصدري على النطاقات المحددة بواسطة domainLock
exclude
Type: string[] Default: []
أسماء ملفات أو أنماط glob تشير إلى الملفات المُستثناة من التشويش.
forceTransformStrings
Type: string[] Default: []
يفعّل التحويل القسري للنصوص الحرفية المطابِقة لأنماط RegExp المُمرَّرة.
⚠️ يؤثّر هذا الخيار فقط في النصوص التي لا ينبغي أن يحوّلها stringArrayThreshold (أو ربما عتبات أخرى مستقبلًا)
للخيار أولوية على خيار reservedStrings لكن لا أولوية له على conditional comments.
مثال:
{
forceTransformStrings: [
'some-important-value',
'some-string_\d'
]
}
identifierNamesCache
Type: Object | null Default: null
الهدف الأساسي من هذا الخيار هو إمكانية استخدام أسماء المعرِّفات نفسها أثناء تشويش عدة مصادر/ملفات.
يُدعَم حاليًا نوعان من المعرِّفات:
- المعرِّفات العامة:
- تُكتب جميع المعرِّفات العامة إلى الذاكرة المؤقتة؛
- تُستبدل جميع المعرِّفات العامة غير المصرَّح بها المطابِقة بالقيم المأخوذة من الذاكرة المؤقتة.
- معرِّفات الخصائص، فقط عند تفعيل خيار
renameProperties:- تُكتب جميع معرِّفات الخصائص إلى الذاكرة المؤقتة؛
- تُستبدل جميع معرِّفات الخصائص المطابِقة بالقيم المأخوذة من الذاكرة المؤقتة.
واجهة Node.js
إذا مُرِّرت القيمة null، تُعطَّل الذاكرة المؤقتة كليًا.
إذا مُرِّر كائن فارغ ({})، يُفعَّل كتابة أسماء المعرِّفات إلى كائن الذاكرة المؤقتة (من النوع TIdentifierNamesCache). ويمكن الوصول إلى كائن الذاكرة المؤقتة هذا عبر استدعاء التابع getIdentifierNamesCache لكائن ObfuscationResult.
يمكن بعد ذلك استخدام كائن الذاكرة المؤقتة الناتج كقيمة لخيار identifierNamesGenerator لاستعمال هذه الأسماء أثناء تشويش جميع أسماء المعرِّفات المطابِقة في المصادر التالية.
مثال:
const source1ObfuscationResult = JavaScriptObfuscator.obfuscate(
`
function foo(arg) {
console.log(arg)
}
function bar() {
var bark = 2;
}
`,
{
compact: false,
identifierNamesCache: {},
renameGlobals: true
}
)
console.log(source1ObfuscationResult.getIdentifierNamesCache());
/*
{
globalIdentifiers: {
foo: '_0x5de86d',
bar: '_0x2a943b'
}
}
*/
const source2ObfuscationResult = JavaScriptObfuscator.obfuscate(
`
// Expecting that these global functions are defined in another obfuscated file
foo(1);
bar();
// Expecting that this global function is defined in third-party package
baz();
`,
{
compact: false,
identifierNamesCache: source1ObfuscationResult.getIdentifierNamesCache(),
renameGlobals: true
}
)
console.log(source2ObfuscationResult.getObfuscatedCode());
/*
_0x5de86d(0x1);
_0x2a943b();
baz();
*/
CLI
تملك واجهة CLI خيارًا مختلفًا هو --identifier-names-cache-path يتيح تحديد مسار إلى ملف .json موجود يُستخدَم لقراءة الذاكرة المؤقتة لأسماء المعرِّفات وكتابتها.
إذا مُرِّر مسار إلى ملف فارغ، تُكتب الذاكرة المؤقتة لأسماء المعرِّفات إلى ذلك الملف.
يمكن استخدام هذا الملف الذي يحتوي على ذاكرة مؤقتة موجودة مجددًا كقيمة لخيار --identifier-names-cache-path لاستعمال هذه الأسماء أثناء تشويش جميع أسماء المعرِّفات المطابِقة في الملفات التالية.
identifierNamesGenerator
Type: string Default: hexadecimal
يضبط مولِّد أسماء المعرِّفات.
القيم المتاحة:
dictionary: أسماء معرِّفات من قائمةidentifiersDictionaryhexadecimal: أسماء معرِّفات مثل_0xabc123mangled: أسماء معرِّفات قصيرة مثلaوbوcmangled-shuffled: مثلmangledلكن بأبجدية مخلوطة
identifiersDictionary
Type: string[] Default: []
يضبط قاموس المعرِّفات لخيار identifierNamesGenerator: dictionary. سيُستخدَم كل معرِّف من القاموس في بضع صيغ باختلاف حالة الأحرف في كل محرف. ولذلك ينبغي أن يعتمد عدد المعرِّفات في القاموس على كمية المعرِّفات في الكود المصدري الأصلي.
identifiersPrefix
Type: string Default: ''
يضبط بادئة لجميع المعرِّفات العامة.
استخدم هذا الخيار عندما تريد تشويش عدة ملفات. يساعد هذا الخيار على تجنّب التعارضات بين المعرِّفات العامة لهذه الملفات. وينبغي أن تكون البادئة مختلفة لكل ملف.
randomIdentifiersPrefix
Type: boolean Default: false
يُلحق بادئة عشوائية مبنية على بذرة (6 محارف أبجدية رقمية) بجميع المعرِّفات العامة. استخدم هذا الخيار لتجنّب التصادمات بين الحزم المشوَّشة على حدة والمُحمَّلة في النطاق العام نفسه — فهو يغني عن الحاجة إلى اختيار identifiersPrefix فريد لكل حزمة يدويًا.
- تُشتق القيمة العشوائية من خيار
seedومن بصمة تجزئة الكود المصدري، لذا تُنتج عمليات البناء القابلة للتكرار بالبذرة نفسها البادئة نفسها. - عند دمجه مع
identifiersPrefix، تُلحق المحارف العشوائية بالبادئة التي قدّمها المستخدم (مثلًاmyApp+ العشوائيaBc123←myAppaBc123). - عند دمجه مع
vmObfuscation، تحلّ القيمة العشوائية محل البادئة الافتراضيةvm— فالعشوائية تضمن التفرّد أصلًا.
ignoreImports
Type: boolean Default: false
يمنع تشويش عمليات الاستيراد عبر require. قد يكون مفيدًا في بعض الحالات عندما تتطلب بيئة التشغيل لسبب ما أن تكون عمليات الاستيراد هذه بنصوص ثابتة فقط.
inputFileName
Type: string Default: ''
يتيح تحديد اسم ملف المُدخل الذي يحتوي على الكود المصدري. يُستخدَم هذا الاسم داخليًا لتوليد خريطة المصدر.
مطلوب عند استخدام واجهة NodeJS وامتلاك خيار sourceMapSourcesMode القيمة sources.
log
Type: boolean Default: false
يفعّل تسجيل المعلومات في وحدة التحكم.
numbersToExpressions
Type: boolean Default: false
يفعّل تحويل الأرقام إلى تعبيرات
مثال:
// input
const foo = 1234;
// output
const foo=-0xd93+-0x10b4+0x41*0x67+0x84e*0x3+-0xff8;
optionsPreset
Type: string Default: default
يتيح ضبط إعداد الخيارات المسبق.
القيم المتاحة:
vm-default؛vm-low-obfuscation؛vm-medium-obfuscation؛vm-high-obfuscation؛vm-ultra-high-obfuscation؛vm-anti-llm؛default؛low-obfuscation؛medium-obfuscation؛high-obfuscation.
ستُدمَج جميع الخيارات الإضافية مع إعداد الخيارات المسبق المُحدَّد.
parseHtml
Type: boolean Default: false
يفعّل تشويش JavaScript داخل وسوم <script> في HTML.
عند التفعيل، سيقوم المشوِّش بما يلي:
- الكشف التلقائي عمّا إذا كان المُدخل HTML (بالتحقق من وجود وسوم
<!DOCTYPEأو<html>أو<head>أو<body>أو<script>) - استخراج JavaScript من وسوم
<script>المُعلَّمة بالسمةdata-javascript-obfuscator - تشويش كل سكربت مُعلَّم على حدة مع الحفاظ على بنية HTML
- إعادة حقن الكود المشوَّش في مواضعه الأصلية
مهم: لا يُشوَّش سوى السكربتات التي تحمل السمة data-javascript-obfuscator. ويُشوَّش كل سكربت مُعلَّم على حدة وباستقلال. وهذا يعني:
- يجب أن يكون الكود داخل وسوم السكربت المُعلَّمة معزولًا - يجب ألّا يشير إلى متغيرات أو دوال أو أصناف معرَّفة في وسوم سكربت مُعلَّمة أخرى
- لا يزال بإمكان السكربتات غير المُعلَّمة الوصول إلى المتغيرات العامة التي تعرّفها السكربتات المُعلَّمة (عبر تصريحات
varأو إسناداتglobalThisالصريحة) - يمنحك هذا تحكمًا صريحًا في السكربتات التي تريد حمايتها
يُشوَّش (يجب أن يحمل السمة data-javascript-obfuscator):
<script data-javascript-obfuscator>- السكربتات العادية<script type="text/javascript" data-javascript-obfuscator>- السكربتات المُحدَّد نوعها صراحةً- السكربتات ذات أي سمات إضافية (
idأوclassأوdata-*أخرى، إلخ.)
يُتخطّى (يُترَك دون تغيير):
- السكربتات التي لا تحمل السمة
data-javascript-obfuscator <script type="module">- وحدات ES (حتى مع السمة)<script src="...">- السكربتات الخارجية (حتى مع السمة)- وسوم السكربت الفارغة
ملاحظة: لا تُولَّد خرائط المصدر عند تفعيل parseHtml، لأنها لن تُطابِق ناتج HTML بشكل صحيح.
مثال:
// input
const html = `<!DOCTYPE html>
<html>
<body>
<!-- This script will NOT be obfuscated -->
<script>
var helper = 'utility';
</script>
<!-- This script WILL be obfuscated -->
<script data-javascript-obfuscator>
var greeting = 'Hello World';
console.log(greeting);
</script>
</body>
</html>`;
JavaScriptObfuscator.obfuscate(html, {
parseHtml: true,
stringArray: true
});
// output: HTML with only the marked script obfuscated
renameGlobals
Type: boolean Default: false
⚠️ قد يعطّل هذا الخيار عمل كودك. لا تفعّله إلا إذا كنت تعرف ما يفعله!
يفعّل تشويش أسماء المتغيرات والدوال العامة مع تصريحها.
عندما يكون هذا الخيار معطَّلًا ويصرّح كود المُدخل عن دوال أو أصناف في النطاق العام (أي أن الكود غير مغلَّف داخل IIFE)، تُبقى أسماؤها كما هي في الكود المشوَّش — فقد تشير إليها سكربتات أخرى بالاسم. وتحت vmObfuscation يُبلَّغ عن تحذير VMGlobalFunctionNamesNotRenamed يسرد هذه الأسماء، إذ إن جسم الدالة مخفي كبايت كود لكن الاسم القابل للقراءة على المستوى الأعلى لا يزال يكشف ما يفعله الكود (لنموذج LLM مثلًا). ولتجنّب هذا الكشف، غلّف الكود داخل IIFE أو فعّل هذا الخيار.
renameProperties
Type: boolean Default: false
⚠️ قد يعطّل هذا الخيار عمل كودك. لا تفعّله إلا إذا كنت تعرف ما يفعله!
يفعّل إعادة تسمية أسماء الخصائص. وسيُتجاهَل جميع خصائص DOM المدمجة والخصائص في أصناف JavaScript الأساسية.
للتبديل بين الوضعين safe وunsafe لهذا الخيار استخدم خيار renamePropertiesMode.
لضبط صيغة أسماء الخصائص المُعاد تسميتها استخدم خيار identifierNamesGenerator.
للتحكم في الخصائص التي سيُعاد تسميتها استخدم خيار reservedNames.
مثال:
// input
(function () {
const foo = {
prop1: 1,
prop2: 2,
calc: function () {
return this.prop1 + this.prop2;
}
};
console.log(foo.calc());
})();
// output
(function () {
const _0x46529b = {
'_0x10cec7': 0x1,
'_0xc1c0ca': 0x2,
'_0x4b961d': function () {
return this['_0x10cec7'] + this['_0xc1c0ca'];
}
};
console['log'](_0x46529b['_0x4b961d']());
}());
renamePropertiesMode
Type: string Default: safe
⚠️ حتى في الوضع safe، قد يعطّل خيار renameProperties عمل كودك.
يحدّد وضع خيار renameProperties:
safe- السلوك الافتراضي بعد الإصدار2.11.0. يحاول إعادة تسمية الخصائص بطريقة أكثر أمانًا لمنع أخطاء التشغيل. مع هذا الوضع، تُستثنى بعض الخصائص من إعادة التسمية.unsafe- السلوك الافتراضي قبل الإصدار2.11.0. يعيد تسمية الخصائص بطريقة غير آمنة دون أي قيود.
إذا كان أحد الملفات يستخدم خصائص من ملف آخر، فاستخدم خيار identifierNamesCache للحفاظ على أسماء الخصائص نفسها بين هذه الملفات.
reservedNames
Type: string[] Default: []
يعطّل تشويش وتوليد المعرِّفات المطابِقة لأنماط RegExp المُمرَّرة.
مثال:
{
reservedNames: [
'^someVariable',
'functionParameter_\d'
]
}
reservedStrings
Type: string[] Default: []
يعطّل تحويل النصوص الحرفية المطابِقة لأنماط RegExp المُمرَّرة. وتبقى النصوص المطابِقة ظاهرة في الناتج المشوَّش.
عند استخدام تشويش VM، تُخزَّن النصوص المحجوزة في مصفوفة منفصلة غير مشفَّرة لإبقائها ظاهرة. وهذا مفيد للنصوص التي يجب أن تبقى قابلة للقراءة، مثل نقاط نهاية API للمراقبة أو معرِّفات المكتبات.
مثال:
{
reservedStrings: [
'react-native',
'\.\/src\/test',
'some-string_\d'
]
}
seed
Type: string|number Default: 0
يضبط هذا الخيار بذرة مولِّد الأرقام العشوائية. وهذا مفيد لإنشاء نتائج قابلة للتكرار.
إذا كانت البذرة 0، فسيعمل مولِّد الأرقام العشوائية بلا بذرة.
selfDefending
Type: boolean Default: false
⚠️ لا تغيّر الكود المشوَّش بأي شكل بعد التشويش بهذا الخيار، لأن أي تغيير مثل ضغط الكود قد يفعّل الدفاع الذاتي فيتوقف الكود عن العمل!
⚠️ يضبط هذا الخيار قسرًا قيمة compact إلى true
⚠️ يُعطَّل هذا الخيار بصمت عند تفعيل vmObfuscation. استخدم vmSelfDefending بدلًا منه.
يجعل هذا الخيار الكود الناتج صامدًا أمام إعادة التنسيق وإعادة تسمية المتغيرات. فإذا حاول أحد استخدام مُجمِّل JavaScript على الكود المشوَّش، فسيتوقف الكود عن العمل، مما يصعّب فهمه وتعديله.
simplify
Type: boolean Default: true
يفعّل تشويشًا إضافيًا للكود عبر التبسيط.
⚠️ في الإصدارات المستقبلية سيُنقَل تشويش النصوص الحرفية من نوع boolean (true => !![]) ليكون ضمن هذا الخيار.
مثال:
// input
if (condition1) {
const foo = 1;
const bar = 2;
console.log(foo);
return bar;
} else if (condition2) {
console.log(1);
console.log(2);
console.log(3);
return 4;
} else {
return 5;
}
// output
if (condition1) {
const foo = 0x1, bar = 0x2;
return console['log'](foo), bar;
} else
return condition2 ? (console['log'](0x1), console['log'](0x2), console['log'](0x3), 0x4) : 0x5;
sourceMap
Type: boolean Default: false
يفعّل توليد خريطة المصدر للكود المشوَّش.
قد تكون خرائط المصدر مفيدة لمساعدتك على تنقيح كود JavaScript المصدري المشوَّش. فإذا أردت أو احتجت إلى التنقيح في بيئة الإنتاج، يمكنك رفع ملف خريطة المصدر المنفصل إلى موقع سرّي ثم توجيه متصفحك إليه.
sourceMapBaseUrl
Type: string Default: ``
يضبط عنوان URL الأساسي لعنوان استيراد خريطة المصدر عند sourceMapMode: 'separate'.
مثال CLI:
javascript-obfuscator input.js --output out.js --source-map true --source-map-base-url 'http://localhost:9000'
النتيجة:
//# sourceMappingURL=http://localhost:9000/out.js.map
sourceMapFileName
Type: string Default: ``
يضبط اسم ملف خريطة المصدر الناتجة عند sourceMapMode: 'separate'.
مثال CLI:
javascript-obfuscator input.js --output out.js --source-map true --source-map-base-url 'http://localhost:9000' --source-map-file-name example
النتيجة:
//# sourceMappingURL=http://localhost:9000/example.js.map
sourceMapMode
Type: string Default: separate
يحدّد وضع توليد خريطة المصدر:
inline- يضيف خريطة المصدر في نهاية كل ملف .js؛separate- يولّد ملف '.map' مقابلًا يحتوي على خريطة المصدر. وفي حال تشغيل المشوِّش عبر CLI، يضيف رابطًا إلى ملف خريطة المصدر في نهاية ملف الكود المشوَّش//# sourceMappingUrl=file.js.map.
sourceMapSourcesMode
Type: string Default: sources-content
يتيح التحكم في الحقلين sources وsourcesContent لخريطة المصدر:
sources-content- يضيف حقلsourcesوهميًا، ويضيف حقلsourcesContentمع الكود المصدري الأصلي؛sources- يضيف حقلsourcesمع وصف مصدر صالح، ولا يضيف حقلsourcesContent. وعند استخدام واجهة NodeJS يلزم تحديد خيارinputFileNameالذي سيُستخدَم كقيمة لحقلsources.
splitStrings
Type: boolean Default: false
يقسّم النصوص الحرفية إلى أجزاء بطول قيمة خيار splitStringsChunkLength.
مثال:
// input
(function(){
var test = 'abcdefg';
})();
// output
(function(){
var _0x5a21 = 'ab' + 'cd' + 'ef' + 'g';
})();
splitStringsChunkLength
Type: number Default: 10
يضبط طول أجزاء خيار splitStrings.
stringArray
Type: boolean Default: true
يزيل النصوص الحرفية ويضعها في مصفوفة خاصة. فمثلًا، النص "Hello World" في var m = "Hello World"; سيُستبدَل بشيء مثل var m = _0x12c456[0x1];
stringArrayCallsTransform
Type: boolean Default: false
⚠️ يجب تفعيل خيار stringArray
يفعّل تحويل الاستدعاءات إلى stringArray. قد تُستخرَج جميع وسائط هذه الاستدعاءات إلى كائن مختلف اعتمادًا على قيمة stringArrayCallsTransformThreshold.
وهذا يزيد صعوبة العثور تلقائيًا على الاستدعاءات إلى مصفوفة النصوص.
مثال:
function foo() {
var k = {
c: 0x2f2,
d: '0x396',
e: '0x397',
f: '0x39a',
g: '0x39d',
h: 0x398,
l: 0x394,
m: '0x39b',
n: '0x39f',
o: 0x395,
p: 0x395,
q: 0x399,
r: '0x399'
};
var c = i(k.d, k.e);
var d = i(k.f, k.g);
var e = i(k.h, k.l);
var f = i(k.m, k.n);
function i(c, d) {
return b(c - k.c, d);
}
var g = i(k.o, k.p);
var h = i(k.q, k.r);
}
function j(c, d) {
var l = { c: 0x14b };
return b(c - -l.c, d);
}
console[j(-'0xa6', -'0xa6')](foo());
function b(c, d) {
var e = a();
b = function (f, g) {
f = f - 0xa3;
var h = e[f];
return h;
};
return b(c, d);
}
function a() {
var m = [
'string5',
'string1',
'log',
'string3',
'string6',
'string2',
'string4'
];
a = function () {
return m;
};
return a();
}
stringArrayCallsTransformThreshold
Type: number Default: 0.5
⚠️ يجب تفعيل خياري stringArray وstringArrayCallsTransformThreshold
يمكنك استخدام هذا الإعداد لضبط الاحتمال (من 0 إلى 1) بأن تُحوَّل الاستدعاءات إلى مصفوفة النصوص.
stringArrayEncoding
Type: string[] Default: []
⚠️ يجب تفعيل خيار stringArray
قد يبطّئ هذا الخيار سكربتك.
يرمّز جميع النصوص الحرفية في stringArray باستخدام base64 أو rc4 ويُدرج كودًا خاصًا يُستخدَم لفك ترميزها مجددًا أثناء التشغيل.
سيُرمَّز كل قيمة من stringArray بالترميز المُنتقى عشوائيًا من القائمة المُمرَّرة. وهذا يتيح استخدام عدة ترميزات.
القيم المتاحة:
'none'(boolean): لا يرمّز قيمةstringArray'base64'(string): يرمّز قيمةstringArrayباستخدامbase64'rc4'(string): يرمّز قيمةstringArrayباستخدامrc4. أبطأ منbase64بنحو 30-50%، لكنه يصعّب الحصول على القيم الأولية.
فمثلًا، مع قيم الخيار التالية لن يُرمَّز بعض قيم stringArray، وسيُرمَّز بعضها الآخر بترميز base64 وrc4:
stringArrayEncoding: [
'none',
'base64',
'rc4'
]
stringArrayIndexesType
Type: string[] Default: ['hexadecimal-number']
⚠️ يجب تفعيل خيار stringArray
يتيح التحكم في نوع فهارس استدعاء مصفوفة النصوص.
سيُحوَّل كل فهرس استدعاء لـ stringArray بالنوع المُنتقى عشوائيًا من القائمة المُمرَّرة. وهذا يتيح استخدام عدة أنواع.
القيم المتاحة:
'hexadecimal-number'(default): يحوّل فهارس استدعاء مصفوفة النصوص كأرقام ست عشرية'hexadecimal-numeric-string': يحوّل فهارس استدعاء مصفوفة النصوص كنص عددي ست عشري
قبل الإصدار 2.9.0 كان javascript-obfuscator يحوّل جميع فهارس استدعاء مصفوفة النصوص بالنوع hexadecimal-numeric-string. وهذا يصعّب بعض إزالة التشويش اليدوية قليلًا، لكنه يتيح كشف هذه الاستدعاءات بسهولة بواسطة أدوات إزالة التشويش التلقائية.
يهدف النوع الجديد hexadecimal-number إلى تصعيب الكشف التلقائي عن أنماط استدعاء مصفوفة النصوص في الكود.
سيُضاف مزيد من الأنواع مستقبلًا.
stringArrayIndexShift
Type: boolean Default: true
⚠️ يجب تفعيل خيار stringArray
يفعّل إزاحة فهرس إضافية لجميع استدعاءات مصفوفة النصوص
stringArrayRotate
Type: boolean Default: true
⚠️ يجب تفعيل stringArray
يزيح مصفوفة stringArray بمقدار ثابت وعشوائي (يُولَّد عند تشويش الكود) من المواضع. وهذا يصعّب مطابقة ترتيب النصوص المُزالة بمواضعها الأصلية.
stringArrayShuffle
Type: boolean Default: true
⚠️ يجب تفعيل stringArray
يخلط عناصر مصفوفة stringArray عشوائيًا.
stringArrayWrappersCount
Type: number Default: 1
⚠️ يجب تفعيل خيار stringArray
يضبط عدد المغلِّفات لـ string array داخل كل نطاق جذري أو نطاق دالة.
والعدد الفعلي للمغلِّفات داخل كل نطاق محدود بعدد عُقد literal ضمن هذا النطاق.
مثال:
// Input
const foo = 'foo';
const bar = 'bar';
function test () {
const baz = 'baz';
const bark = 'bark';
const hawk = 'hawk';
}
const eagle = 'eagle';
// Output, stringArrayWrappersCount: 5
const _0x3f6c = [
'bark',
'bar',
'foo',
'eagle',
'hawk',
'baz'
];
const _0x48f96e = _0x2e13;
const _0x4dfed8 = _0x2e13;
const _0x55e970 = _0x2e13;
function _0x2e13(_0x33c4f5, _0x3f6c62) {
_0x2e13 = function (_0x2e1388, _0x60b1e) {
_0x2e1388 = _0x2e1388 - 0xe2;
let _0x53d475 = _0x3f6c[_0x2e1388];
return _0x53d475;
};
return _0x2e13(_0x33c4f5, _0x3f6c62);
}
const foo = _0x48f96e(0xe4);
const bar = _0x4dfed8(0xe3);
function test() {
const _0x1c262f = _0x2e13;
const _0x54d7a4 = _0x2e13;
const _0x5142fe = _0x2e13;
const _0x1392b0 = _0x1c262f(0xe7);
const _0x201a58 = _0x1c262f(0xe2);
const _0xd3a7fb = _0x1c262f(0xe6);
}
const eagle = _0x48f96e(0xe5);
stringArrayWrappersChainedCalls
Type: boolean Default: true
⚠️ يجب تفعيل خياري stringArray وstringArrayWrappersCount
يفعّل الاستدعاءات المتسلسلة بين مغلِّفات string array.
مثال:
// Input
const foo = 'foo';
const bar = 'bar';
function test () {
const baz = 'baz';
const bark = 'bark';
function test1() {
const hawk = 'hawk';
const eagle = 'eagle';
}
}
// Output, stringArrayWrappersCount: 5, stringArrayWrappersChainedCalls: true
const _0x40c2 = [
'bar',
'bark',
'hawk',
'eagle',
'foo',
'baz'
];
const _0x31c087 = _0x3280;
const _0x31759a = _0x3280;
function _0x3280(_0x1f52ee, _0x40c2a2) {
_0x3280 = function (_0x3280a4, _0xf07b02) {
_0x3280a4 = _0x3280a4 - 0x1c4;
let _0x57a182 = _0x40c2[_0x3280a4];
return _0x57a182;
};
return _0x3280(_0x1f52ee, _0x40c2a2);
}
const foo = _0x31c087(0x1c8);
const bar = _0x31c087(0x1c4);
function test() {
const _0x848719 = _0x31759a;
const _0x2693bf = _0x31c087;
const _0x2c08e8 = _0x848719(0x1c9);
const _0x359365 = _0x2693bf(0x1c5);
function _0x175e90() {
const _0x310023 = _0x848719;
const _0x2302ef = _0x2693bf;
const _0x237437 = _0x310023(0x1c6);
const _0x56145c = _0x310023(0x1c7);
}
}
stringArrayWrappersParametersMaxCount
Type: number Default: 2
⚠️ يجب تفعيل خيار stringArray
⚠️ يؤثّر هذا الخيار حاليًا فقط في المغلِّفات المُضافة بقيمة خيار stringArrayWrappersType المساوية function
يتيح التحكم في العدد الأقصى لمعاملات مغلِّفات مصفوفة النصوص.
القيمة الافتراضية والدنيا هي 2. القيمة المُوصى بها بين 2 و5.
stringArrayWrappersType
Type: string Default: variable
⚠️ يجب تفعيل خياري stringArray وstringArrayWrappersCount
يتيح اختيار نوع المغلِّفات التي يضيفها خيار stringArrayWrappersCount.
القيم المتاحة:
'variable': يضيف مغلِّفات متغيرات في أعلى كل نطاق. أداء سريع.'function': يضيف مغلِّفات دوال في مواضع عشوائية داخل كل نطاق. أداء أبطأ منvariableلكنه يوفّر تشويشًا أكثر صرامة.
يُوصى بشدة باستخدام مغلِّفات function لتشويش أعلى عندما لا يكون لخسارة الأداء تأثير كبير على التطبيق المشوَّش.
مثال على قيمة الخيار 'function':
// input
const foo = 'foo';
function test () {
const bar = 'bar';
console.log(foo, bar);
}
test();
// output
const a = [
'log',
'bar',
'foo'
];
const foo = d(0x567, 0x568);
function b(c, d) {
b = function (e, f) {
e = e - 0x185;
let g = a[e];
return g;
};
return b(c, d);
}
function test() {
const c = e(0x51c, 0x51b);
function e (c, g) {
return b(c - 0x396, g);
}
console[f(0x51b, 0x51d)](foo, c);
function f (c, g) {
return b(c - 0x396, g);
}
}
function d (c, g) {
return b(g - 0x3e1, c);
}
test();
stringArrayThreshold
Type: number Default: 0.8 Min: 0 Max: 1
⚠️ يجب تفعيل خيار stringArray
يمكنك استخدام هذا الإعداد لضبط الاحتمال (من 0 إلى 1) بأن يُدرَج نص حرفي في stringArray.
هذا الإعداد مفيد بوجه خاص مع أحجام الكود الكبيرة لأنه يستدعي string array مرارًا وقد يبطّئ كودك.
القيمة stringArrayThreshold: 0 تكافئ stringArray: false.
strictMode
Type: boolean | null Default: null
يتيح تحديد كيف ينبغي للمشوِّش أن يعامل الكود فيما يخص الوضع الصارم في JavaScript.
القيم المتاحة:
null(افتراضي) - كشف الوضع الصارم تلقائيًا من الكود. إذا كان الكود يحتوي على توجيه'use strict'صريح، أو بنية وحدة ES، أو توابع أصناف، فيُعامَل على أنه وضع صارم. وإلا يُفترَض الوضع المتساهل.true- فرض معاملة الوضع الصارم لكل الكود، حتى دون توجيه'use strict'صريح. استخدم هذا عندما يعمل كودك في سياق وضع صارم (مثلًا في وحدات ES أو أدوات التحزيم أو أطر العمل الحديثة).false- لا يُعامَل على أنه صارم إلا مؤشرات الوضع الصارم الصريحة ('use strict'، وحدات ES، توابع الأصناف). ولا يزال توريث نطاق الأب مطبَّقًا وفق مواصفة JS.
target
Type: string Default: browser
يتيح ضبط البيئة الهدف للكود المشوَّش.
القيم المتاحة:
browser(افتراضي) — بيئة صفحة ويب قياسية. الكود الناتج مطابق لـnode، لكن لا يُسمح باستخدام بعض الخيارات الخاصة بالمتصفح مع الهدفnodebrowser-no-eval— مثلbrowser، لكن الناتج لا يستخدمeval(). استخدمه عندما تفرض الصفحة الهدف سياسة أمان محتوى تمنعeval/unsafe-eval.node— بيئة Node.js. تُعطَّل الخيارات الخاصة بالمتصفح (فهي تتطلبwindow/documentوستكون بلا أثر أو ستطلق استثناءً في Node). ولا تُصدَر لهذا الهدف بعض دفاعاتvmSelfDefendingالتي تعتمد على واجهات برمجية خاصة بالمتصفح — كشف المتصفح مقطوع الرأس، والتعافي عبر عالَم نظيف قائم على iframe، وفحوصات مضادة للمفتِّش/DOM.service-worker— سياق Service Worker. لاwindow، ولاdocument، ومتغيّرselfعام مختلف.userscript— صندوق حماية مدير سكربتات المستخدم (مثل Tampermonkey). تُعدَّل دفاعاتvmSelfDefendingتبعًا لذلك.bytenode— كود Node.js سيُترجَم بواسطة مُحمِّل bytenode (بايت كود V8 المُخزَّن.jsc) بعد التشويش. لا يستدعي المشوِّش نفسهbytenode؛ بل يُصدر JavaScript مشوَّشًا بـ VM بُنيت بيئة تشغيله لتصمد أمام خطوة ترجمة bytenode، وتُعدَّل دفاعاتvmSelfDefendingتبعًا لذلك. شغّلbytenodeبنفسك على الناتج المشوَّش لإنتاج ملف.jscالنهائي.
transformObjectKeys
Type: boolean Default: false
يفعّل تحويل مفاتيح الكائنات.
مثال:
// input
(function(){
var object = {
foo: 'test1',
bar: {
baz: 'test2'
}
};
})();
// output
var _0x4735 = [
'foo',
'baz',
'bar',
'test1',
'test2'
];
function _0x390c(_0x33d6b6, _0x4735f4) {
_0x390c = function (_0x390c37, _0x1eed85) {
_0x390c37 = _0x390c37 - 0x198;
var _0x2275f8 = _0x4735[_0x390c37];
return _0x2275f8;
};
return _0x390c(_0x33d6b6, _0x4735f4);
}
(function () {
var _0x17d1b7 = _0x390c;
var _0xc9b6bb = {};
_0xc9b6bb[_0x17d1b7(0x199)] = _0x17d1b7(0x19c);
var _0x3d959a = {};
_0x3d959a[_0x17d1b7(0x198)] = _0x17d1b7(0x19b);
_0x3d959a[_0x17d1b7(0x19a)] = _0xc9b6bb;
var _0x41fd86 = _0x3d959a;
}());
warnings
Type: string | object Default: all
يتحكم في تحذيرات التشويش غير القاتلة التي تُصدَر عبر التابع ObfuscationResult.getWarnings().
القيم المتاحة:
'all'(افتراضي) — يُصدَر كل تحذير.'none'— تُكتَم كل التحذيرات.- كائن يربط أنواع التحذيرات بقيم منطقية — النوع المربوط بـ
falseيُكتَم؛ وكل نوع غير موجود (أو مربوط بـtrue) يبقى مفعَّلًا. فمثلًا،{ "VMGlobalFunctionNamesNotRenamed": false }يبقي كل تحذير عدا ذاك.
أنواع التحذيرات:
VMGlobalFunctionNamesNotRenamed— تحتvmObfuscation، بقيت أسماء تصريحات الدوال على المستوى الأعلى، وتصريحات الأصناف، والمتغيرات المُسنَد إليها تعبير دالة/سهمية/صنف كما هي (خيارrenameGlobalsمعطَّل والكود غير مغلَّف داخل IIFE)، فتبقى قابلة للقراءة في الناتج رغم إخفاء الأجسام كبايت كود. ولا يُبلَّغ عن الأسماء المُصدَّرة.VMTopLevelInitializerNotVirtualized— بقيت مُهيّئات المتغيرات على المستوى الأعلى بصيغة JavaScript عادية تحت تشويش VM لأنvmWrapTopLevelInitializersمعطَّل أو تعذّر عليه محاكاتها افتراضيًا.DynamicCodeRenameRisk— يبني الكود دالة من نص أثناء التشغيل (عبرevalالمباشر، أو بانيFunction، أوfn.toString()المحقون في<script>/Worker)، وقد يشير ذلك إلى معرِّفات أعاد المشوِّش تسميتها.VMDynamicCodeSkipped— تُخطّي دالة من ترميز بايت كود VM لأنها تحتوي علىevalمباشر /new Functionديناميكي /Function(انظرvmForceCompileDynamicCode).VMSyncFunctionSkippedInAsyncMode— مع تفعيلvmAsyncExecutor، تبيّن أن دالة علّمتها صراحةً في وضعcommentمتزامنة فتُخطّيت (لا يُحاكى افتراضيًا في ذلك الوضع سوى الدوال غير المتزامنة).VMAsyncGeneratorSkippedInAsyncMode— مع تفعيلvmAsyncExecutorوجالِب مفتاح غير متزامن نشط، تعذّرت محاكاة مولِّد غير متزامن مُعلَّم افتراضيًا (يجب أن يُعيد مُكرِّره بشكل متزامن).BrowserTargetWithNodeStyleCode— يبدو أن الكود يستهدف Node.js (مثلrequire('fs')أو__dirnameأوprocess.argv) بينما خيارtargetمضبوط على بيئة شبيهة بالمتصفح.
vmObfuscation
Type: boolean Default: false
يفعّل تشويش البايت كود القائم على VM. عند التفعيل، تُترجَم دوال JavaScript إلى بايت كود مخصص يعمل على آلة افتراضية مضمَّنة. وهذا يوفّر أعلى مستوى من الحماية إذ يُحوَّل منطق الكود الأصلي بالكامل.
مثال:
كودك القابل للقراءة مثل return qty * price يصبح قائمة من الأرقام مثل [0x15,0x03,0x17,...] لا يستطيع تنفيذها سوى مفسِّر VM المضمَّن. ولم يعد المنطق الأصلي ظاهرًا بصيغة JavaScript.
vmTargetFunctions
Type: string[] Default: []
حدّد بدقّة أيّ دوال على المستوى الجذري ينبغي أن تحصل على حماية VM بالاسم.
مثال:
{
vmObfuscation: true,
vmTargetFunctions: ['someFunctionName']
}
النتيجة: هذه الدوال الثلاث فقط تحصل على حماية VM. وكل ما عداها يبقى JavaScript عاديًا (لكنه مشوَّش مع ذلك). مثالي لحماية فحوصات التراخيص الحساسة أو منطق المصادقة مع إبقاء بقية كودك رشيقًا.
vmExcludeFunctions
Type: string[] Default: []
حدّد الدوال على المستوى الجذري التي ينبغي ألّا تحصل أبدًا على حماية VM. له الأسبقية على الإعدادات الأخرى.
مثال:
{
vmObfuscation: true,
vmExcludeFunctions: ['someFunctionName']
}
متى تستخدمه: يمكن استثناء الدوال الحرجة للأداء على المستوى الجذري (حلقات الرسوم المتحركة، ومعالجة البيانات الفورية) لتجنّب حِمل VM مع الاستمرار في حماية كل شيء آخر.
vmTargetFunctionsMode
Type: string Default: root
يتحكم في كيفية اختيار الدوال/التوابع لتشويش VM.
مثال - وضع Comment:
// Source code
function regularFunction() {
return 'not virtualized';
}
/* javascript-obfuscator:vm */
function sensitiveFunction() {
return 'this will be VM-protected';
}
function outer() {
/* javascript-obfuscator:vm */
function nestedSensitive() {
return 'nested but still VM-protected';
}
return nestedSensitive();
}
// Obfuscator options
{
vmObfuscation: true,
vmTargetFunctionsMode: 'comment'
}
متى تستخدمه: عندما تحتاج إلى تحكم دقيق في الدوال التي تحصل تحديدًا على حماية VM، خصوصًا الدوال المتداخلة التي تحتوي على منطق حساس. فخلافًا لـ vmTargetFunctions الذي لا يعمل إلا مع الدوال المُسمّاة على المستوى الجذري، يتيح لك وضع comment حماية أي دالة في أي مكان من كودك.
vmForceCompileDynamicCode
Type: boolean Default: false
يتحكم فيما يفعله تشويش VM مع دالة تحتوي على استدعاء eval مباشر، أو new Function(...)، أو Function(...).
افتراضيًا، تُخطّى مثل هذه الدالة (وكل دالة معرَّفة داخلها) من ترميز بايت كود VM ويُبلَّغ عن تحذير VMDynamicCodeSkipped في result.getWarnings(). وذلك لأن المصدر المبني أثناء التشغيل قد يشير إلى معرِّفات من سلسلة النطاقات المحيطة — معرِّفات أعاد المشوِّش تسميتها.
عند ضبطه على true، تُرمَّز الدالة إلى بايت كود على أي حال ولا يُصدَر تحذير VMDynamicCodeSkipped بعد ذلك.
ويستمر إطلاق تحذير DynamicCodeRenameRisk المنفصل بصرف النظر عن هذا الخيار، لأن خطر إعادة التسمية الذي يصفه مستقل عن تخطّي VM — فتفعيل هذا الخيار لا يجعل النمط الأساسي أكثر أمانًا.
// Source code
function loadConfig(src) {
return eval(src);
}
loadConfig('1 + 2');
// Options
{
vmObfuscation: true,
vmForceCompileDynamicCode: true
}
مع إيقاف الخيار (الافتراضي)، تُترَك loadConfig بصيغة JavaScript عادية. ومع تفعيله، تُترجَم loadConfig إلى بايت كود VM مثل أي دالة أخرى. استخدم هذا عندما تكون قد راجعت موضع الاستدعاء وتعرف أن الكود المبني أثناء التشغيل لا يعتمد على معرِّفات مُعاد تسميتها في الإغلاق.
vmWrapTopLevelInitializers
Type: boolean Default: false
يغلّف بعض مُهيّئات المتغيرات على المستوى الأعلى داخل IIFE (تعبيرات دوال مُستدعاة فورًا) حتى يمكن تشويشها بـ VM.
ما يفعله: دون هذا الخيار، تبقى الثوابت والمتغيرات على المستوى الأعلى ظاهرة في الناتج:
// Input
const MY_STRING = "my-string";
// Output (without vmWrapTopLevelInitializers)
const MY_STRING = "my-string"; // String is visible!
مع تفعيل هذا الخيار، يُغلَّف المُهيّئ داخل IIFE يُشوَّش بـ VM:
// Input
const MY_STRING = "my-string";
// Output (with vmWrapTopLevelInitializers: true)
const MY_STRING = (() => { return /* VM bytecode call */ })(); // String hidden in bytecode
ملاحظة: لا يعمل هذا الخيار إلا عندما يكون vmTargetFunctionsMode بقيمة 'root' (الافتراضي).
vmDynamicOpcodes
Type: boolean Default: false
يجعل مفسِّر VM أصغر وفريدًا لكل عملية بناء.
ما يفعله:
- يصفّي التعليمات غير المستخدمة - إذا كان كودك لا يستخدم الأصناف، تُزال التعليمات المتعلقة بالأصناف كليًا
- يعشوِئ البنية - يُخلَط ترتيب معالِجات التعليمات في كل عملية بناء
والنتيجة - ناتج أصغر وكل عملية بناء تبدو مختلفة.
vmBytecodeEncoding
Type: boolean Default: false
يرمّز كل تعليمة بايت كود. تُفكّ ترميز التعليمات واحدة تلو الأخرى أثناء التنفيذ.
vmBytecodeArrayEncoding
Type: boolean Default: false
يرمّز مصفوفة البايت كود بأكملها ككتلة واحدة. تُفكّ ترميز المصفوفة مرة واحدة عند بدء التشغيل قبل بدء التنفيذ. استخدمه مع vmBytecodeEncoding للحصول على طبقتي حماية.
vmBytecodeArrayEncodingKey
Type: string Default: ''
مفتاح تشفير مخصص لترميز مصفوفة البايت كود. عند ضبطه، يُستخدَم هذا المفتاح بدلًا من المفتاح الافتراضي المشتق من البيئة. يجب توفير المفتاح أثناء التشغيل عبر vmBytecodeArrayEncodingKeyGetter.
يُخرج هذا الخيار مفتاح التشفير خارجيًا - فهو غير مضمَّن في الكود المشوَّش نفسه. ومع أن المفتاح لا يزال متاحًا أثناء التشغيل (وبالتالي ليس سرّيًا حقًا)، فإن هذا الفصل يمنع أدوات التحليل الساكن من العثور على المفتاح بفحص الكود وحده.
مهم: يجب أن يكون المفتاح متاحًا بشكل متزامن عند تحميل الكود المشوَّش. استخدم تخزينًا متزامنًا مثل الكوكيز، أو localStorage، أو sessionStorage، أو المتغيرات العامة، أو عناصر DOM (مثل وسوم meta المحقونة من الخادم). ولا يمكن استخدام الطرق غير المتزامنة مثل fetch() مباشرةً في تعبير جالِب المفتاح.
vmBytecodeArrayEncodingKeyGetter
Type: string Default: ''
تعبير JavaScript متزامن يُعيد مفتاح التشفير أثناء التشغيل. يُقيَّم هذا التعبير عند تحميل الكود المشوَّش، ويجب أن يُعيد المفتاح نفسه الذي قُدِّم في vmBytecodeArrayEncodingKey. ولحل المفتاح بشكل غير متزامن (عبر Promise)، فعّل vmAsyncExecutor.
ملاحظة: الجالِب الذي يُعيد Promise يتطلب vmAsyncExecutor. ولا يمكن التحقق من ذلك وقت البناء، لذا فإن جالِبًا يُعيد Promise مع vmAsyncExecutor معطَّل يفشل أثناء التشغيل — إذ يتلقى فاكّ الترميز الـ Promise بدلًا من المفتاح.
لن يعمل الكود المشوَّش إلا عندما يُعيد جالِب المفتاح المفتاح نفسه تمامًا الذي استُخدِم أثناء التشويش. فإذا لم يتطابق المفتاحان، سيفشل فك التشفير وسيُنتج الكود بيانات فاسدة أو أخطاء. وإذا أعاد جالِب المفتاح undefined أو null أو نصًا فارغًا، فسيطلق الكود خطأً: "VM decryption key not available".
مهم: أبقِ المفتاح خارج الملف/السكربت نفسه الذي يحوي الكود المشوَّش — فتضمينه هناك يتيح استعادته حتى بفحص ساكن محض للحزمة. خزّنه في مصدر منفصل بدلًا من ذلك: كوكيز يضبطها الخادم، أو localStorage يملؤه سكربت آخر، أو وسم meta في HTML محقون من الخادم، أو متغير عام يضبطه سكربت مختلف، أو (مع vmAsyncExecutor) يُجلَب من خادمك الخلفي أثناء التشغيل.
عندما يُجلَب المفتاح من خادمك الخلفي (عبر vmAsyncExecutor)، أضف فحوصات قائمة على الجلسة أو الأصل على نقطة النهاية تلك: أعِد المفتاح الصحيح للمستخدمين الحقيقيين (جلسة صالحة، Origin/Referer متوقعان) ومفتاحًا فاسدًا للطلبات المشبوهة (مثل أصل localhost/غير متوقع، أو غياب الجلسة). فيعمل المستخدمون الحقيقيون بشكل طبيعي؛ أما نسخة تعمل خارج بيئتك فتحصل على مفتاح يفكّ إلى لا شيء. والمنطق الدقيق يعتمد على موقعك.
أمثلة:
// From cookie
vmBytecodeArrayEncodingKeyGetter: "document.cookie.match(/vmKey=([^;]+)/)?.[1]"
// From localStorage
vmBytecodeArrayEncodingKeyGetter: "localStorage.getItem('vmKey')"
// From global variable
vmBytecodeArrayEncodingKeyGetter: "window.__VM_KEY__"
// From meta tag (server-injected)
vmBytecodeArrayEncodingKeyGetter: "document.querySelector('meta[name=\"vm-key\"]').content"
// From nested object
vmBytecodeArrayEncodingKeyGetter: "window.config.encryption.key"
// From backend, async (requires vmAsyncExecutor)
vmBytecodeArrayEncodingKeyGetter: 'fetch("/vm-key").then((res) => res.text())'
مثال استخدام:
// Build time
JavaScriptObfuscator.obfuscate(code, {
vmObfuscation: true,
vmBytecodeArrayEncoding: true,
vmBytecodeArrayEncodingKey: 'mySecretKey123',
vmBytecodeArrayEncodingKeyGetter: 'window.__VM_KEY__'
});
// Runtime - key must be set before obfuscated code runs
window.__VM_KEY__ = 'mySecretKey123';
vmAsyncExecutor
Type: boolean Default: false
يفعّل منفِّذ VM غير المتزامن، الذي يتيح لـ vmBytecodeArrayEncodingKeyGetter أن يُعيد Promise (جالِب مفتاح غير متزامن) — بحيث يمكن جلب مفتاح فك التشفير أثناء التشغيل (طلب شبكة، IndexedDB، إلخ.) بدلًا من وجوب توفّره بشكل متزامن عند تحميل الكود.
يُوصى به بشدة للأكواد غير المتزامنة بالكامل. في هذا الوضع لا يُحاكى افتراضيًا سوى الدوال async — فلا يمكن جعل دالة متزامنة غير متزامنة دون تحويل قيمة إعادتها إلى Promise وكسر مستدعيها — لذا فإن الكود غير المتزامن كليًا يحصل على أوسع تغطية. وهو يعمل أيضًا عندما يكون الجذر متزامنًا (مثل IIFE متزامن / مغلِّف UMD): إذ تُحمى الدوال async الأبعد داخلها، وتُترَك الأجزاء المتزامنة كما هي.
ما الذي يُحوَّل: كل دالة async الأبعد، أينما ظهرت (بما في ذلك المتداخلة داخل مغلِّفات متزامنة). الدالة غير المتزامنة الأبعد في كل سلسلة هي الوحدة المحمية — فكل ما بداخلها، متزامنًا وغير متزامن، يُترجَم ضمنها. أما الدوال المتزامنة والمولِّدات العادية فتُترَك دون تشويش.
function foo() { // sync — left as-is
function bar() {} // sync — left as-is
async function baz() { // transformed
// any code here, including calls to other async or sync functions
}
async function bark() { // transformed
// any code here, including calls to other async or sync functions
}
}
التخطّيات والتحذيرات. تُترَك المولِّدات غير المتزامنة أيضًا دون تشويش عندما يكون جالِب مفتاح غير متزامن نشطًا (يجب أن يُعيد المولِّد غير المتزامن مُكرِّره بشكل متزامن ولا يمكنه انتظار المفتاح). في الوضع الافتراضي vmTargetFunctionsMode: 'root' تكون التخطّيات صامتة (الاختيار تلقائي)؛ وفي وضع comment يُصدَر تحذير عبر ObfuscationResult.getWarnings() كلما تعذّرت محاكاة دالة علّمتها صراحةً — إمّا لأنها تبيّنت متزامنة، أو لأنها مولِّد غير متزامن تحت جالِب مفتاح غير متزامن.
ويتطلب جالِب المفتاح غير المتزامن إضافةً vmBytecodeArrayEncoding مع vmBytecodeArrayEncodingKeyGetter.
مثال استخدام:
JavaScriptObfuscator.obfuscate(code, {
vmObfuscation: true,
vmAsyncExecutor: true,
vmBytecodeArrayEncoding: true,
vmBytecodeArrayEncodingKey: 'mySecretKey123',
// the key getter may now return a Promise
vmBytecodeArrayEncodingKeyGetter: 'fetch("/vm-key").then((res) => res.text())'
});
vmJumpsEncoding
Type: boolean Default: false
يرمّز أهداف القفزات في البايت كود. تُحسَب إزاحات القفز أثناء التشغيل، مما يخفي بنية تدفق التحكم (if/else، الحلقات، إلخ.) عن التحليل الساكن.
vmMacroOps
Type: boolean Default: false
يدمج تسلسلات التعليمات الشائعة في أكواد عمليات "ماكرو" مفردة. فمثلًا، قد يصبح LOAD + ADD + STORE تعليمة MACRO_ADD_TO_VAR واحدة. وهذا يكسر التعرّف على الأنماط وقد يحسّن الأداء.
vmDebugProtection
Type: boolean Default: false
يضيف دفاعات متعددة الطبقات مضادة للتنقيح والتحليل ونماذج LLM إلى بيئة تشغيل VM. يعمل على أفضل نحو مع الأهداف browser/browser-no-eval.
vmSelfDefending
Type: boolean Default: false
يضيف حماية متعددة الطبقات لكشف العبث، ومنع الاعتراض، ومقاومة الهندسة العكسية إلى بيئة تشغيل VM.
⚠️ يفعّل هذا الخيار قسرًا vmBytecodeArrayEncoding.
⚠️ كشف البيئات الحساسة. يربط هذا الخيار الكود المشوَّش ببيئة التشغيل الهدف ويستخدم بصمة متصفح متقدمة لكشف أدوات الأتمتة. والكود المحمي بهذا الخيار سيتعطّل عمدًا عند تشغيله في:
- المتصفحات مقطوعة الرأس (Chrome/Chromium مقطوع الرأس، PhantomJS)
- أدوات أتمتة المتصفح (Puppeteer، Playwright، Cypress، Selenium/ChromeDriver، Nightmare)
- Node.js (عندما يكون
targetمضبوطًا علىbrowser) - jsdom أو محاكاة DOM المشابهة على جانب الخادم
- البيئات التي اعتُرِض فيها على أدوات المتصفح المدمجة الأصلية أو استُبدلت
والكود سيعمل بشكل صحيح في المتصفحات العادية (Chrome، Firefox، Safari، Edge)، بما في ذلك عند تحميله داخل iframe، وإضافات المتصفح (سكربتات المحتوى)، وWeb Workers. إذا احتجت إلى تشغيل اختبارات آلية على كود محمي، فعطّل vmSelfDefending لعمليات بناء الاختبار — فهذا الخيار مصمَّم لمنع التحليل الآلي ولا يمكن استخدامه بأمان مع أي إطار أتمتة.
يُوصى بشدة باستخدامه مع vmDebugProtection وvmBytecodeArrayEncodingKey وvmBytecodeArrayEncodingKeyGetter.
vmDefenseHook
Type: { name: string, aliases?: object } Default: ''
يأخذ vmDefenseHook كائنًا بمفتاحين: name (مطلوب) و**aliases** (اختياري).
name هو دالة عامة تعرّفها صفحتك المُضيفة يستدعيها دفاع VM (vmDebugProtection / vmSelfDefending) بكائن إشارة عندما يكتشف إشارة عدائية — منقّح أو مفتِّش، أو متصفح مقطوع الرأس / أتمتة، أو عملية وكيل برمجة بالذكاء الاصطناعي، أو نطاق غير مسموح، وهكذا. استخدمها للإبلاغ عن الحدث إلى خادمك الخلفي (مثل navigator.sendBeacon). والإشارة (hook) هي مصرف قياس عن بُعد محض: تُتجاهَل قيمة إعادتها، وإشارة غائبة أو تطلق استثناءً هي عملية لا شيء صامتة لا يمكنها أبدًا تعطيل دفاع. ولتغيير ما يفعله الدفاع عند الكشف، استخدم vmDefenseReaction.
aliases يعيد تسمية حقول كائن الإشارة ذاك اختياريًا — مشروح تحت إعادة تسمية حقول الإشارة أدناه.
كائن الإشارة. تتلقى الإشارة signal واحدة:
source— الكاشف المحدد الذي أُطلِق (انظر الجدول).category— المجموعة التي يُبلَّغ ضمنها:automation(متصفحات غير بشرية)، أوdebugger(منقّح/مفتِّش نشط)، أوsandbox(مُضيف مُجهَّز/مزيَّف)، أوdomain(خرق قفل النطاق)، أوtamper(تعديل الأدوات المدمجة أثناء التشغيل)، أوintegrity(تغيّر كود VM نفسه).score/threshold— مدى قوة إطلاق الكاشف والقيمة التي كان عليه بلوغها؛ لا تُطلَق الإشارة إلا عندما يكونscore >= threshold. معظم الفحوصات كل شيء أو لا شيء (إشارة حاسمة واحدة)؛ أماheadlessفيجمع عدة إشارات لشكل المتصفح، لذا يكونscoreلديه أعلى منthresholdعادةً.
تسجيل الإشارة. عرّفها كمتغير عام عادي قبل تحميل الحزمة المشوَّشة — فبيئة تشغيل VM ودفاعاتها تعمل قبل برنامجك (المحمي)، لذا تُطلَق كثير من عمليات الكشف أثناء بدء التشغيل:
// in your page, before the obfuscated script:
window.__vmDetection = function (signal) { navigator.sendBeacon('/vm-defense', JSON.stringify(signal)); };
// obfuscation option:
vmDefenseHook: { name: '__vmDetection' }
الإشارة المعرَّفة داخل المصدر المشوَّش تُسجَّل متأخرة جدًا بحيث لا تلتقط عمليات الكشف وقت بدء التشغيل، وإذا رُمِّزت بـ VM فلا يمكن الوصول إليها حتى يعمل برنامجك. وهي آمنة على أي حال (إشارة غائبة تنفّذ لا شيء، وحارس منع إعادة الدخول يمنع أي انفلات)، لكن للتغطية الكاملة سجّلها مقدَّمًا. ولحماية منطق إبلاغك رغم ذلك، أبقِ الإشارة المسجَّلة عازلًا من سطر واحد ((window.__vmDet = window.__vmDet || []).push(signal)) واقرأ/أرسِل ذلك العازل من كودك المشوَّش.
إعادة تسمية حقول الإشارة (aliases). القيم الافتراضية لـ source/category أسماء وصفية، فيستطيع أي شخص يُجهِّز رد النداء (أو يقرأ الناتج) أن يتعرّف على الحماية وعلى الكاشف الذي أُطلِق. aliases يعيد تسمية حقول الإشارة إلى رموز مبهمة من اختيارك، تُطبَّق داخل VM قبل إصدار الإشارة، بحيث لا تظهر تلك الأسماء أبدًا في الناتج ولا تصل إلى رد النداء. ويعرف تطبيقك التعيين الخاص به ويمرّر الرموز إلى خادمك الخلفي.
الأسماء البديلة لكل حقل، مع إبقاء إعادة تسمية المفاتيح والقيم منفصلة: يأخذ كل حقل key (اسم الخاصية الذي يتلقاه رد النداء)؛ كما يأخذ الحقلان النصيان source وcategory خريطة values، بينما score/threshold رقمان ويأخذان key فقط. الأسماء التي يمكنك تعيينها (وأي شيء آخر يُرفَض وقت البناء):
- مفاتيح الحقول —
source،category،score،threshold - قيم
source—headless،agent،node،debugger،timing،sandbox،domain،nativeHook،integrity - قيم
category—automation،debugger،sandbox،domain،tamper،integrity
vmDefenseHook: {
name: '__vmDetection',
aliases: {
source: { key: 'a8Qm', values: { headless: 'xP4m9Q' } },
category: { key: 'p3Tx', values: { automation: 'bQ7s1M' } },
score: { key: 's1' },
threshold: { key: 't1' }
}
// the callback now receives e.g. { a8Qm: 'xP4m9Q', p3Tx: 'bQ7s1M', s1: <score>, t1: <threshold> }
}
هذا تجنّبٌ للبصمة، لا سرّية — إذ لا يزال بالإمكان استنتاج التعيين بالاختبار المتكرر — فمنفعته الوحيدة هي عدم كشف أسماء ثابتة تفسّر نفسها. والمدخلات غير المضبوطة تبقى بأسمائها الافتراضية.
يُقبَل نص مجرد (vmDefenseHook: '__vmDetection') كاختصار لـ { name: '__vmDetection' } لكنه مهجور — فضّل صيغة الكائن.
vmDefenseReaction
Type: object Default: { automation: 'break', debugger: 'decoy', sandbox: 'decoy', domain: 'break', tamper: 'break', integrity: 'break' }
يضبط كيفية تفاعل كل فئة كشف. وهو لا يفعّل أي شيء — فالدفاعات نفسها تُشغَّل بواسطة vmSelfDefending وvmDebugProtection وvmDomainLock؛ ولا يختار هذا الخيار سوى كيفية تفاعل دفاع مفعَّل. الفئة هي وحدة التحكم — فكل كاشف في فئة يُنفِّذ تفاعل تلك الفئة.
تجمع كل فئة الكواشف التي تراقب نوعًا واحدًا من الحالات العدائية. ولا تتفاعل الفئة إلا عندما يكون الخيار الذي يُصدِر كواشفها مفعَّلًا:
تُطابَق كل فئة واحدًا أو أكثر من vmSelfDefending وvmDebugProtection وvmDomainLock؛ ولا توجد فئة خارج تلك الخيارات الثلاثة، وتفاعل مضبوط لفئة خيارها معطَّل ببساطة بلا أثر.
المفاتيح هي أسماء الفئات الست هذه، أو default (احتياطي للفئات غير المحددة). والقيم هي:
break— يتوقف فورًاdecoy— يستمر في العمل على حالة مسمومة، منتجًا نتائج خاطئة بصمتnone— لا يفعل شيئًا محليًا (قياس عن بُعد فقط)
الافتراضيات لكل فئة مبيَّنة أعلاه؛ والفئة التي لا تضبطها (أو تضبطها على قيمتها الافتراضية) تستخدم ذلك الافتراضي. default يصل إلى كل فئة، بما في ذلك الفئات الصحيحة بحكم البناء (integrity وtamper)، لذا فإن { default: 'none' } عملية بناء غير كاسرة حقًا، للقياس عن بُعد فقط:
vmDefenseReaction: { default: 'none' } // never break — pair with vmDefenseHook
vmDefenseReaction: { automation: 'none', domain: 'break' } // tolerate automation FPs, still break on a bad domain
vmStatefulOpcodes
Type: boolean Default: false
يجعل معاني أكواد العمليات تعتمد على الموضع في البايت كود. لكل موضع تعيين مختلف من كود العملية إلى المعالِج مشتق من بذرة، بحيث يؤدي رقم كود العملية نفسه عمليات مختلفة في مواضع مختلفة.
vmCallContextOpcodes
Type: boolean Default: false
يجعل الدالة المحمية تعتمد على المكان الذي تُستدعى منه، بحيث لا يمكن انتزاعها من الكود وتشغيلها أو تحليلها بمفردها — فهي لا تتصرف بشكل صحيح إلا عند استدعائها عبر مواضع استدعائها الحقيقية في البرنامج. يؤثّر هذا الخيار في أداء التشغيل.
يُدعَم حاليًا فقط التركيبات التالية:
- تصريحات الدوال (
function f() {})؛ - تعبيرات الدوال والدوال السهمية المُسنَدة إلى متغير (
const f = () => {})؛ - التوابع الخاصة للنسخ (
this.#m()).
في كل حالة، يجب أن يُوصَل إلى الدالة دائمًا عبر استدعاء مباشر (f()، this.#m()). فإذا خُزِّنت في متغير آخر، أو مُرِّرت كوسيط، أو استُخدمت بأي طريقة أخرى كقيمة، فتُترَك دون حماية. الدوال غير المتزامنة مدعومة؛ أما المولِّدات فلا.
هذا الخيار تجريبي وقد يعطّل عمل كودك، فاختبر الناتج جيدًا قبل استخدامه.
vmStackEncoding
Type: boolean Default: false
يشفّر القيم على مكدس VM أثناء التنفيذ. تُرمَّز القيم عند دفعها وتُفكّ ترميزها عند سحبها، بحيث يُظهر فحص الذاكرة بيانات مشفَّرة بدلًا من القيم الفعلية.
يؤثّر هذا الخيار في الأداء تأثيرًا كبيرًا.
vmCompactDispatcher
Type: boolean Default: false
يستخدم منفِّذ VM واحدًا بدلًا من منفِّذين مزدوجين (متزامن + مولِّد). يقلّل حجم الكود المشوَّش لكنه يضيف حِملًا على الأداء بنحو 20% في الكود كثير التعاود.
false(افتراضي): منفِّذان مزدوجان — أداء مثالي، ناتج أكبرtrue: منفِّذ واحد — ناتج أصغر، أبطأ قليلًا
vmStringArrayBytecodeOnly
Type: boolean Default: false
عند التفعيل، ستستخرج مصفوفة النصوص النصوص من بيانات البايت كود فقط — ولا تُحوَّل أي نصوص أخرى في الكود. وهذا يفعّل stringArray قسرًا حتى لو لم يُضبَط صراحةً.
لماذا تستخدمه: استخراج كل نصوص بيئة تشغيل VM إلى مصفوفة نصوص بطيء. يستهدف هذا الخيار محتوى البايت كود فقط لاستخراج مصفوفة النصوص، مما يحسّن الأداء مع الاستمرار في حماية ثوابت البايت كود.
- عند
vmBytecodeArrayEncoding: false— تُستخرَج النصوص داخل مجمّعات ثوابت البايت كود (مصفوفاتc) - عند
vmBytecodeArrayEncoding: true— تُستخرَج نصوص البايت كود المُرمَّزة بـ base64 على المستوى الأعلى - لا يزال
stringArrayThresholdيتحكم في نسبة نصوص البايت كود تلك التي تُستخرَج
vmDomainLock
Type: string[] Default: []
⚠️ لا يعمل هذا الخيار مع target: 'node' أو target: 'service-worker' أو target: 'bytenode'
يقصر الكود المشوَّش على نطاقات و/أو نطاقات فرعية بعينها، وهو أصعب بكثير في تحديد موضعه وإزالته من domainLock.
إذا لم يُشغَّل الكود المصدري على النطاقات المحددة بهذا الخيار، فسيُعاد توجيه المتصفح إلى عنوان URL المُمرَّر إلى vmDomainLockRedirectUrl، وستُعيد الاستدعاءات المحمية اللاحقة نتائج غير صحيحة حتى لو كُبِت إعادة التوجيه.
نطاقات ونطاقات فرعية متعددة
يمكن قفل كودك على أكثر من نطاق أو نطاق فرعي. فمثلًا، لقفله بحيث لا يعمل الكود إلا على www.example.com أضف www.example.com. ولجعله يعمل على النطاق الجذري بما في ذلك أي نطاقات فرعية (example.com وsub.example.com)، استخدم .example.com.
vmDomainLockRedirectUrl
Type: string Default: about:blank
⚠️ لا يعمل هذا الخيار مع target: 'node' أو target: 'service-worker' أو target: 'bytenode'
يتيح إعادة توجيه المتصفح إلى عنوان URL مُمرَّر إذا لم يُشغَّل الكود المصدري على النطاقات المحددة بواسطة vmDomainLock.
Preset Options
تشويش عالٍ، أداء منخفض
سيكون الأداء أبطأ بكثير مما هو عليه دون تشويش
{
compact: true,
controlFlowFlattening: true,
controlFlowFlatteningThreshold: 1,
deadCodeInjection: true,
deadCodeInjectionThreshold: 1,
debugProtection: true,
debugProtectionInterval: 4000,
disableConsoleOutput: true,
identifierNamesGenerator: 'hexadecimal',
log: false,
numbersToExpressions: true,
renameGlobals: false,
selfDefending: true,
simplify: true,
splitStrings: true,
splitStringsChunkLength: 5,
strictMode: null,
stringArray: true,
stringArrayCallsTransform: true,
stringArrayEncoding: ['rc4'],
stringArrayIndexShift: true,
stringArrayRotate: true,
stringArrayShuffle: true,
stringArrayWrappersCount: 5,
stringArrayWrappersChainedCalls: true,
stringArrayWrappersParametersMaxCount: 5,
stringArrayWrappersType: 'function',
stringArrayThreshold: 1,
transformObjectKeys: true
}
تشويش متوسط، أداء مثالي
سيكون الأداء أبطأ مما هو عليه دون تشويش
{
compact: true,
controlFlowFlattening: true,
controlFlowFlatteningThreshold: 0.75,
deadCodeInjection: true,
deadCodeInjectionThreshold: 0.4,
debugProtection: false,
debugProtectionInterval: 0,
disableConsoleOutput: true,
identifierNamesGenerator: 'hexadecimal',
log: false,
numbersToExpressions: true,
renameGlobals: false,
selfDefending: true,
simplify: true,
splitStrings: true,
splitStringsChunkLength: 10,
strictMode: null,
stringArray: true,
stringArrayCallsTransform: true,
stringArrayCallsTransformThreshold: 0.75,
stringArrayEncoding: ['base64'],
stringArrayIndexShift: true,
stringArrayRotate: true,
stringArrayShuffle: true,
stringArrayWrappersCount: 2,
stringArrayWrappersChainedCalls: true,
stringArrayWrappersParametersMaxCount: 4,
stringArrayWrappersType: 'function',
stringArrayThreshold: 0.75,
transformObjectKeys: true
}
تشويش منخفض، أداء عالٍ
سيكون الأداء عند مستوى طبيعي نسبيًا
{
compact: true,
controlFlowFlattening: false,
deadCodeInjection: false,
debugProtection: false,
debugProtectionInterval: 0,
disableConsoleOutput: true,
identifierNamesGenerator: 'hexadecimal',
log: false,
numbersToExpressions: false,
renameGlobals: false,
selfDefending: true,
simplify: true,
splitStrings: false,
strictMode: null,
stringArray: true,
stringArrayCallsTransform: false,
stringArrayEncoding: [],
stringArrayIndexShift: true,
stringArrayRotate: true,
stringArrayShuffle: true,
stringArrayWrappersCount: 1,
stringArrayWrappersChainedCalls: true,
stringArrayWrappersParametersMaxCount: 2,
stringArrayWrappersType: 'variable',
stringArrayThreshold: 0.75
}
الإعداد المسبق الافتراضي، أداء عالٍ
{
compact: true,
controlFlowFlattening: false,
deadCodeInjection: false,
debugProtection: false,
debugProtectionInterval: 0,
disableConsoleOutput: false,
identifierNamesGenerator: 'hexadecimal',
log: false,
numbersToExpressions: false,
renameGlobals: false,
selfDefending: false,
simplify: true,
splitStrings: false,
strictMode: null,
stringArray: true,
stringArrayCallsTransform: false,
stringArrayCallsTransformThreshold: 0.5,
stringArrayEncoding: [],
stringArrayIndexShift: true,
stringArrayRotate: true,
stringArrayShuffle: true,
stringArrayWrappersCount: 1,
stringArrayWrappersChainedCalls: true,
stringArrayWrappersParametersMaxCount: 2,
stringArrayWrappersType: 'variable',
stringArrayThreshold: 0.75
}
تشويش VM فائق العلو (أقصى أمان)
يفعّل هذا الإعداد المسبق تشويش البايت كود القائم على VM مع كل ميزات التصليب بما في ذلك الإرسال غير المباشر. يوفّر أقوى حماية لكن بحجم ناتج أكبر وتنفيذ أبطأ بكثير.
{
optionsPreset: 'vm-ultra-high-obfuscation'
}
أو اضبط الخيارات بشكل فردي:
{
compact: true,
simplify: true,
identifierNamesGenerator: 'mangled-shuffled',
vmObfuscation: true,
vmForceCompileDynamicCode: false,
vmWrapTopLevelInitializers: true,
vmDynamicOpcodes: true,
vmBytecodeEncoding: true,
vmBytecodeArrayEncoding: true,
vmBytecodeArrayEncodingKey: '',
vmBytecodeArrayEncodingKeyGetter: '',
vmAsyncExecutor: false,
vmJumpsEncoding: true,
vmMacroOps: true,
vmDebugProtection: true,
vmSelfDefending: true,
vmDefenseHook: '',
vmDefenseReaction: {
automation: 'break',
debugger: 'decoy',
sandbox: 'decoy',
domain: 'break',
tamper: 'break',
integrity: 'break'
},
vmStatefulOpcodes: true,
vmCallContextOpcodes: false,
vmStackEncoding: true,
vmCompactDispatcher: true,
controlFlowFlattening: true,
controlFlowFlatteningThreshold: 0.5,
deadCodeInjection: true,
deadCodeInjectionThreshold: 0.5,
debugProtection: true,
debugProtectionInterval: 4000,
disableConsoleOutput: true,
identifierNamesGenerator: 'hexadecimal',
log: false,
numbersToExpressions: true,
renameGlobals: false,
selfDefending: true,
simplify: true,
splitStrings: true,
splitStringsChunkLength: 5,
strictMode: null,
stringArray: true,
stringArrayCallsTransform: true,
stringArrayEncoding: ['rc4'],
stringArrayIndexShift: true,
stringArrayRotate: true,
stringArrayShuffle: true,
stringArrayWrappersCount: 5,
stringArrayWrappersChainedCalls: true,
stringArrayWrappersParametersMaxCount: 5,
stringArrayWrappersType: 'function',
stringArrayThreshold: 0.5,
transformObjectKeys: true
}
VM المضاد لنماذج LLM (حماية من وكلاء الذكاء الاصطناعي)
صُمِّم هذا الإعداد المسبق خصيصًا لمنع وكلاء الذكاء الاصطناعي ونماذج LLM من إجراء هندسة عكسية على الكود المُرمَّز ببايت كود VM. يستند إلى vm-default مع تفعيل الدفاع الذاتي وحماية التنقيح. أخف من vm-high-obfuscation لكنه مصلَّب خصيصًا ضد التحليل الآلي.
{
optionsPreset: 'vm-anti-llm'
}
يشمل:
- تشويش بايت كود VM مع مصفوفة النصوص (من
vm-default) vmSelfDefending— كشف الاعتراض، وتجزئة السلامة، وبصمة المصدر، والتحقق عبر عالَم iframe نظيف، واشتقاق مفتاح شيفرة ARXvmDebugProtection— فحوصات مضادة للتنقيح في حلقة إرسال VMdebugProtection: false— لا حماية تنقيح قديمة (حماية تنقيح VM أفضل)
تشويش VM العالي (أعلى أمان)
يفعّل هذا الإعداد المسبق تشويش البايت كود القائم على VM مع معظم ميزات التصليب. يوفّر حماية قوية بأداء أفضل من الإعداد المسبق فائق العلو.
{
optionsPreset: 'vm-high-obfuscation'
}
أو اضبط الخيارات بشكل فردي:
{
compact: true,
simplify: true,
identifierNamesGenerator: 'mangled-shuffled',
vmObfuscation: true,
vmForceCompileDynamicCode: false,
vmWrapTopLevelInitializers: true,
vmDynamicOpcodes: true,
vmBytecodeEncoding: true,
vmBytecodeArrayEncoding: true,
vmBytecodeArrayEncodingKey: '',
vmBytecodeArrayEncodingKeyGetter: '',
vmAsyncExecutor: false,
vmJumpsEncoding: true,
vmMacroOps: true,
vmDebugProtection: true,
vmSelfDefending: true,
vmDefenseHook: '',
vmDefenseReaction: {
automation: 'break',
debugger: 'decoy',
sandbox: 'decoy',
domain: 'break',
tamper: 'break',
integrity: 'break'
},
vmStatefulOpcodes: true,
vmCallContextOpcodes: false,
vmStackEncoding: true,
vmCompactDispatcher: false
}
تشويش VM المتوسط (أمان متوازن)
يفعّل هذا الإعداد المسبق تشويش البايت كود القائم على VM مع مجموعة متوازنة من ميزات التصليب. حل وسط جيد بين الأمان والأداء.
{
optionsPreset: 'vm-medium-obfuscation'
}
أو اضبط الخيارات بشكل فردي:
{
compact: true,
simplify: true,
identifierNamesGenerator: 'mangled-shuffled',
vmObfuscation: true,
vmForceCompileDynamicCode: false,
vmWrapTopLevelInitializers: true,
vmDynamicOpcodes: true,
vmBytecodeEncoding: true,
vmBytecodeArrayEncoding: false,
vmBytecodeArrayEncodingKey: '',
vmBytecodeArrayEncodingKeyGetter: '',
vmAsyncExecutor: false,
vmJumpsEncoding: true,
vmMacroOps: true,
vmDebugProtection: true,
vmSelfDefending: false,
vmDefenseHook: '',
vmDefenseReaction: {
automation: 'break',
debugger: 'decoy',
sandbox: 'decoy',
domain: 'break',
tamper: 'break',
integrity: 'break'
},
vmStatefulOpcodes: false,
vmCallContextOpcodes: false,
vmStackEncoding: false,
vmCompactDispatcher: false
}
تشويش VM المنخفض (أمان أساسي، أداء أفضل)
يفعّل هذا الإعداد المسبق تشويش بايت كود VM الأساسي دون ميزات تصليب إضافية. توازن جيد بين الأمان وحجم الناتج.
{
optionsPreset: 'vm-low-obfuscation'
}
أو اضبط الخيارات بشكل فردي:
{
compact: true,
simplify: true,
identifierNamesGenerator: 'mangled-shuffled',
vmObfuscation: true,
vmForceCompileDynamicCode: false,
vmWrapTopLevelInitializers: true,
vmDynamicOpcodes: false,
vmBytecodeEncoding: false,
vmBytecodeArrayEncoding: false,
vmBytecodeArrayEncodingKey: '',
vmBytecodeArrayEncodingKeyGetter: '',
vmAsyncExecutor: false,
vmJumpsEncoding: false,
vmMacroOps: false,
vmDebugProtection: false,
vmSelfDefending: false,
vmDefenseHook: '',
vmDefenseReaction: {
automation: 'break',
debugger: 'decoy',
sandbox: 'decoy',
domain: 'break',
tamper: 'break',
integrity: 'break'
},
vmStatefulOpcodes: false,
vmCallContextOpcodes: false,
vmStackEncoding: false,
vmCompactDispatcher: false
}
VM الافتراضي (VM + حماية مصفوفة النصوص)
يجمع هذا الإعداد المسبق بين تشويش البايت كود الأساسي القائم على VM وحماية مصفوفة النصوص. نقطة بداية جيدة لتشويش VM مع حماية النصوص.
{
optionsPreset: 'vm-default'
}
أو اضبط الخيارات بشكل فردي:
{
compact: true,
simplify: true,
identifierNamesGenerator: 'mangled-shuffled',
vmObfuscation: true,
vmForceCompileDynamicCode: false,
vmWrapTopLevelInitializers: true,
vmDynamicOpcodes: true,
vmBytecodeEncoding: false,
vmBytecodeArrayEncoding: true,
vmStringArrayBytecodeOnly: true,
vmAsyncExecutor: false,
vmJumpsEncoding: false,
vmMacroOps: false,
vmDebugProtection: false,
vmSelfDefending: false,
vmDefenseHook: '',
vmDefenseReaction: {
automation: 'break',
debugger: 'decoy',
sandbox: 'decoy',
domain: 'break',
tamper: 'break',
integrity: 'break'
},
vmStatefulOpcodes: false,
vmCallContextOpcodes: false,
vmStackEncoding: false,
vmCompactDispatcher: false,
stringArray: true,
stringArrayRotate: true,
stringArrayShuffle: true,
stringArrayThreshold: 1,
stringArrayIndexShift: true,
stringArrayIndexesType: ['hexadecimal-number'],
stringArrayCallsTransform: true,
stringArrayCallsTransformThreshold: 1,
stringArrayWrappersCount: 3,
stringArrayWrappersType: 'function',
stringArrayWrappersParametersMaxCount: 5,
stringArrayWrappersChainedCalls: true,
stringArrayEncoding: ['base64'],
splitStrings: true,
splitStringsChunkLength: 6
}
compact
Type: boolean Default: true
يجمع الكود الناتج في سطر واحد.
config
Type: string Default: ``
اسم ملف الإعدادات بصيغة JS/JSON الذي يحتوي على خيارات المشوِّش. تُتجاوَز هذه الخيارات بالخيارات المُمرَّرة مباشرةً إلى CLI
controlFlowFlattening
Type: boolean Default: false
⚠️ يؤثّر هذا الخيار بشدة في الأداء، إذ قد يبطّئ سرعة التشغيل حتى 1.5 ضعف. استخدم controlFlowFlatteningThreshold لتحديد نسبة العُقد التي سيطالها تسطيح تدفق التحكم.
يفعّل تسطيح تدفق التحكم في الكود. وتسطيح تدفق التحكم هو تحويل بنيوي للكود المصدري يعيق فهم البرنامج.
مثال:
// input
(function(){
function foo () {
return function () {
var sum = 1 + 2;
console.log(1);
console.log(2);
console.log(3);
console.log(4);
console.log(5);
console.log(6);
}
}
foo()();
})();
// output
(function () {
function _0x3bfc5c() {
return function () {
var _0x3260a5 = {
'WtABe': '4|0|6|5|3|2|1',
'GokKo': function _0xf87260(_0x427a8e, _0x43354c) {
return _0x427a8e + _0x43354c;
}
};
var _0x1ad4d6 = _0x3260a5['WtABe']['split']('|'), _0x1a7b12 = 0x0;
while (!![]) {
switch (_0x1ad4d6[_0x1a7b12++]) {
case '0':
console['log'](0x1);
continue;
case '1':
console['log'](0x6);
continue;
case '2':
console['log'](0x5);
continue;
case '3':
console['log'](0x4);
continue;
case '4':
var _0x1f2f2f = _0x3260a5['GokKo'](0x1, 0x2);
continue;
case '5':
console['log'](0x3);
continue;
case '6':
console['log'](0x2);
continue;
}
break;
}
};
}
_0x3bfc5c()();
}());
controlFlowFlatteningThreshold
Type: number Default: 0.75 Min: 0 Max: 1
احتمال تطبيق تحويل controlFlowFlattening على أي عقدة بعينها.
هذا الإعداد مفيد بوجه خاص مع أحجام الكود الكبيرة، لأن الكميات الكبيرة من تحويلات تدفق التحكم قد تبطّئ كودك وتزيد حجمه.
القيمة controlFlowFlatteningThreshold: 0 تكافئ controlFlowFlattening: false.
deadCodeInjection
Type: boolean Default: false
⚠️ يزيد حجم الكود المشوَّش زيادة كبيرة (حتى 200%)، فلا تستخدمه إلا إذا كان حجم الكود المشوَّش لا يهم. استخدم deadCodeInjectionThreshold لتحديد نسبة العُقد التي سيطالها حقن الكود الميت.
⚠️ يفعّل هذا الخيار قسرًا خيار stringArray.
⚠️ يُعطَّل هذا الخيار بصمت عند تفعيل vmObfuscation.
مع هذا الخيار، تُضاف كتل عشوائية من الكود الميت إلى الكود المشوَّش.
مثال:
// input
(function(){
if (true) {
var foo = function () {
console.log('abc');
};
var bar = function () {
console.log('def');
};
var baz = function () {
console.log('ghi');
};
var bark = function () {
console.log('jkl');
};
var hawk = function () {
console.log('mno');
};
foo();
bar();
baz();
bark();
hawk();
}
})();
// output
var _0x37b8 = [
'YBCtz',
'GlrkA',
'urPbb',
'abc',
'NMIhC',
'yZgAj',
'zrAId',
'EtyJA',
'log',
'mno',
'jkl',
'def',
'Quzya',
'IWbBa',
'ghi'
];
function _0x43a7(_0x12cf56, _0x587376) {
_0x43a7 = function (_0x2f87a8, _0x47eac2) {
_0x2f87a8 = _0x2f87a8 - (0x16a7 * 0x1 + 0x5 * 0x151 + -0x1c92);
var _0x341e03 = _0x37b8[_0x2f87a8];
return _0x341e03;
};
return _0x43a7(_0x12cf56, _0x587376);
}
(function () {
if (!![]) {
var _0xbbe28f = function () {
var _0x2fc85f = _0x43a7;
if (_0x2fc85f(0xaf) === _0x2fc85f(0xae)) {
_0x1dd94f[_0x2fc85f(0xb2)](_0x2fc85f(0xb5));
} else {
console[_0x2fc85f(0xb2)](_0x2fc85f(0xad));
}
};
var _0x5e46bc = function () {
var _0x15b472 = _0x43a7;
if (_0x15b472(0xb6) !== _0x15b472(0xaa)) {
console[_0x15b472(0xb2)](_0x15b472(0xb5));
} else {
_0x47eac2[_0x15b472(0xb2)](_0x15b472(0xad));
}
};
var _0x3669e8 = function () {
var _0x47a442 = _0x43a7;
if (_0x47a442(0xb7) !== _0x47a442(0xb0)) {
console[_0x47a442(0xb2)](_0x47a442(0xb8));
} else {
_0x24e0bf[_0x47a442(0xb2)](_0x47a442(0xb3));
}
};
var _0x28b05a = function () {
var _0x497902 = _0x43a7;
if (_0x497902(0xb1) === _0x497902(0xb1)) {
console[_0x497902(0xb2)](_0x497902(0xb4));
} else {
_0x59c9c6[_0x497902(0xb2)](_0x497902(0xb4));
}
};
var _0x402a54 = function () {
var _0x1906b7 = _0x43a7;
if (_0x1906b7(0xab) === _0x1906b7(0xac)) {
_0xb89cd0[_0x1906b7(0xb2)](_0x1906b7(0xb8));
} else {
console[_0x1906b7(0xb2)](_0x1906b7(0xb3));
}
};
_0xbbe28f();
_0x5e46bc();
_0x3669e8();
_0x28b05a();
_0x402a54();
}
}());
deadCodeInjectionThreshold
Type: number Default: 0.4 Min: 0 Max: 1
يتيح تحديد نسبة العُقد التي سيطالها deadCodeInjection.
debugProtection
Type: boolean Default: false
⚠️ قد يجمّد متصفحك إذا فتحت أدوات المطور.
⚠️ يُعطَّل هذا الخيار بصمت عند تفعيل vmObfuscation. استخدم vmDebugProtection بدلًا منه.
يجعل هذا الخيار استخدام وظيفة debugger في أدوات المطور شبه مستحيل (سواء في المتصفحات المبنية على WebKit أو في Mozilla Firefox).
debugProtectionInterval
Type: number Default: 0
⚠️ قد يجمّد متصفحك! استخدمه على مسؤوليتك الخاصة.
⚠️ يُعطَّل هذا الخيار بصمت عند تفعيل vmObfuscation. استخدم vmDebugProtection بدلًا منه.
عند ضبطه، يُستخدَم فاصل زمني بالميلي ثانية لفرض وضع التنقيح على علامة تبويب Console، مما يصعّب استخدام ميزات أدوات المطور الأخرى. يعمل إذا كان debugProtection مفعَّلًا. القيمة المُوصى بها بين 2000 و4000 ميلي ثانية.
disableConsoleOutput
Type: boolean Default: false
⚠️ يعطّل هذا الخيار استدعاءات console عالميًا لكل السكربتات
يعطّل استخدام console.log وconsole.info وconsole.error وconsole.warn وconsole.debug وconsole.exception وconsole.trace باستبدالها بدوال فارغة. وهذا يصعّب استخدام المنقّح.
domainLock
Type: string[] Default: []
⚠️ لا يعمل هذا الخيار مع target: 'node' أو target: 'service-worker' أو target: 'bytenode'
يتيح تشغيل الكود المصدري المشوَّش على نطاقات و/أو نطاقات فرعية بعينها فقط. وهذا يصعّب كثيرًا على أي شخص أن ينسخ كودك المصدري ويشغّله في مكان آخر.
إذا لم يُشغَّل الكود المصدري على النطاقات المحددة بهذا الخيار، فسيُعاد توجيه المتصفح إلى عنوان URL المُمرَّر إلى خيار domainLockRedirectUrl.
نطاقات ونطاقات فرعية متعددة
يمكن قفل كودك على أكثر من نطاق أو نطاق فرعي. فمثلًا، لقفله بحيث لا يعمل الكود إلا على www.example.com أضف www.example.com. ولجعله يعمل على النطاق الجذري بما في ذلك أي نطاقات فرعية (example.com وsub.example.com)، استخدم .example.com.
domainLockRedirectUrl
Type: string Default: about:blank
⚠️ لا يعمل هذا الخيار مع target: 'node' أو target: 'service-worker' أو target: 'bytenode'
يتيح إعادة توجيه المتصفح إلى عنوان URL مُمرَّر إذا لم يُشغَّل الكود المصدري على النطاقات المحددة بواسطة domainLock
exclude
Type: string[] Default: []
أسماء ملفات أو أنماط glob تشير إلى الملفات المُستثناة من التشويش.
forceTransformStrings
Type: string[] Default: []
يفعّل التحويل القسري للنصوص الحرفية المطابِقة لأنماط RegExp المُمرَّرة.
⚠️ يؤثّر هذا الخيار فقط في النصوص التي لا ينبغي أن يحوّلها stringArrayThreshold (أو ربما عتبات أخرى مستقبلًا)
للخيار أولوية على خيار reservedStrings لكن لا أولوية له على conditional comments.
مثال:
{
forceTransformStrings: [
'some-important-value',
'some-string_\d'
]
}
identifierNamesCache
Type: Object | null Default: null
الهدف الأساسي من هذا الخيار هو إمكانية استخدام أسماء المعرِّفات نفسها أثناء تشويش عدة مصادر/ملفات.
يُدعَم حاليًا نوعان من المعرِّفات:
- المعرِّفات العامة:
- تُكتب جميع المعرِّفات العامة إلى الذاكرة المؤقتة؛
- تُستبدل جميع المعرِّفات العامة غير المصرَّح بها المطابِقة بالقيم المأخوذة من الذاكرة المؤقتة.
- معرِّفات الخصائص، فقط عند تفعيل خيار
renameProperties:- تُكتب جميع معرِّفات الخصائص إلى الذاكرة المؤقتة؛
- تُستبدل جميع معرِّفات الخصائص المطابِقة بالقيم المأخوذة من الذاكرة المؤقتة.
واجهة Node.js
إذا مُرِّرت القيمة null، تُعطَّل الذاكرة المؤقتة كليًا.
إذا مُرِّر كائن فارغ ({})، يُفعَّل كتابة أسماء المعرِّفات إلى كائن الذاكرة المؤقتة (من النوع TIdentifierNamesCache). ويمكن الوصول إلى كائن الذاكرة المؤقتة هذا عبر استدعاء التابع getIdentifierNamesCache لكائن ObfuscationResult.
يمكن بعد ذلك استخدام كائن الذاكرة المؤقتة الناتج كقيمة لخيار identifierNamesGenerator لاستعمال هذه الأسماء أثناء تشويش جميع أسماء المعرِّفات المطابِقة في المصادر التالية.
مثال:
const source1ObfuscationResult = JavaScriptObfuscator.obfuscate(
`
function foo(arg) {
console.log(arg)
}
function bar() {
var bark = 2;
}
`,
{
compact: false,
identifierNamesCache: {},
renameGlobals: true
}
)
console.log(source1ObfuscationResult.getIdentifierNamesCache());
/*
{
globalIdentifiers: {
foo: '_0x5de86d',
bar: '_0x2a943b'
}
}
*/
const source2ObfuscationResult = JavaScriptObfuscator.obfuscate(
`
// Expecting that these global functions are defined in another obfuscated file
foo(1);
bar();
// Expecting that this global function is defined in third-party package
baz();
`,
{
compact: false,
identifierNamesCache: source1ObfuscationResult.getIdentifierNamesCache(),
renameGlobals: true
}
)
console.log(source2ObfuscationResult.getObfuscatedCode());
/*
_0x5de86d(0x1);
_0x2a943b();
baz();
*/
CLI
تملك واجهة CLI خيارًا مختلفًا هو --identifier-names-cache-path يتيح تحديد مسار إلى ملف .json موجود يُستخدَم لقراءة الذاكرة المؤقتة لأسماء المعرِّفات وكتابتها.
إذا مُرِّر مسار إلى ملف فارغ، تُكتب الذاكرة المؤقتة لأسماء المعرِّفات إلى ذلك الملف.
يمكن استخدام هذا الملف الذي يحتوي على ذاكرة مؤقتة موجودة مجددًا كقيمة لخيار --identifier-names-cache-path لاستعمال هذه الأسماء أثناء تشويش جميع أسماء المعرِّفات المطابِقة في الملفات التالية.
identifierNamesGenerator
Type: string Default: hexadecimal
يضبط مولِّد أسماء المعرِّفات.
القيم المتاحة:
dictionary: أسماء معرِّفات من قائمةidentifiersDictionaryhexadecimal: أسماء معرِّفات مثل_0xabc123mangled: أسماء معرِّفات قصيرة مثلaوbوcmangled-shuffled: مثلmangledلكن بأبجدية مخلوطة
identifiersDictionary
Type: string[] Default: []
يضبط قاموس المعرِّفات لخيار identifierNamesGenerator: dictionary. سيُستخدَم كل معرِّف من القاموس في بضع صيغ باختلاف حالة الأحرف في كل محرف. ولذلك ينبغي أن يعتمد عدد المعرِّفات في القاموس على كمية المعرِّفات في الكود المصدري الأصلي.
identifiersPrefix
Type: string Default: ''
يضبط بادئة لجميع المعرِّفات العامة.
استخدم هذا الخيار عندما تريد تشويش عدة ملفات. يساعد هذا الخيار على تجنّب التعارضات بين المعرِّفات العامة لهذه الملفات. وينبغي أن تكون البادئة مختلفة لكل ملف.
randomIdentifiersPrefix
Type: boolean Default: false
يُلحق بادئة عشوائية مبنية على بذرة (6 محارف أبجدية رقمية) بجميع المعرِّفات العامة. استخدم هذا الخيار لتجنّب التصادمات بين الحزم المشوَّشة على حدة والمُحمَّلة في النطاق العام نفسه — فهو يغني عن الحاجة إلى اختيار identifiersPrefix فريد لكل حزمة يدويًا.
- تُشتق القيمة العشوائية من خيار
seedومن بصمة تجزئة الكود المصدري، لذا تُنتج عمليات البناء القابلة للتكرار بالبذرة نفسها البادئة نفسها. - عند دمجه مع
identifiersPrefix، تُلحق المحارف العشوائية بالبادئة التي قدّمها المستخدم (مثلًاmyApp+ العشوائيaBc123←myAppaBc123). - عند دمجه مع
vmObfuscation، تحلّ القيمة العشوائية محل البادئة الافتراضيةvm— فالعشوائية تضمن التفرّد أصلًا.
ignoreImports
Type: boolean Default: false
يمنع تشويش عمليات الاستيراد عبر require. قد يكون مفيدًا في بعض الحالات عندما تتطلب بيئة التشغيل لسبب ما أن تكون عمليات الاستيراد هذه بنصوص ثابتة فقط.
inputFileName
Type: string Default: ''
يتيح تحديد اسم ملف المُدخل الذي يحتوي على الكود المصدري. يُستخدَم هذا الاسم داخليًا لتوليد خريطة المصدر.
مطلوب عند استخدام واجهة NodeJS وامتلاك خيار sourceMapSourcesMode القيمة sources.
log
Type: boolean Default: false
يفعّل تسجيل المعلومات في وحدة التحكم.
numbersToExpressions
Type: boolean Default: false
يفعّل تحويل الأرقام إلى تعبيرات
مثال:
// input
const foo = 1234;
// output
const foo=-0xd93+-0x10b4+0x41*0x67+0x84e*0x3+-0xff8;
optionsPreset
Type: string Default: default
يتيح ضبط إعداد الخيارات المسبق.
القيم المتاحة:
vm-default؛vm-low-obfuscation؛vm-medium-obfuscation؛vm-high-obfuscation؛vm-ultra-high-obfuscation؛vm-anti-llm؛default؛low-obfuscation؛medium-obfuscation؛high-obfuscation.
ستُدمَج جميع الخيارات الإضافية مع إعداد الخيارات المسبق المُحدَّد.
parseHtml
Type: boolean Default: false
يفعّل تشويش JavaScript داخل وسوم <script> في HTML.
عند التفعيل، سيقوم المشوِّش بما يلي:
- الكشف التلقائي عمّا إذا كان المُدخل HTML (بالتحقق من وجود وسوم
<!DOCTYPEأو<html>أو<head>أو<body>أو<script>) - استخراج JavaScript من وسوم
<script>المُعلَّمة بالسمةdata-javascript-obfuscator - تشويش كل سكربت مُعلَّم على حدة مع الحفاظ على بنية HTML
- إعادة حقن الكود المشوَّش في مواضعه الأصلية
مهم: لا يُشوَّش سوى السكربتات التي تحمل السمة data-javascript-obfuscator. ويُشوَّش كل سكربت مُعلَّم على حدة وباستقلال. وهذا يعني:
- يجب أن يكون الكود داخل وسوم السكربت المُعلَّمة معزولًا - يجب ألّا يشير إلى متغيرات أو دوال أو أصناف معرَّفة في وسوم سكربت مُعلَّمة أخرى
- لا يزال بإمكان السكربتات غير المُعلَّمة الوصول إلى المتغيرات العامة التي تعرّفها السكربتات المُعلَّمة (عبر تصريحات
varأو إسناداتglobalThisالصريحة) - يمنحك هذا تحكمًا صريحًا في السكربتات التي تريد حمايتها
يُشوَّش (يجب أن يحمل السمة data-javascript-obfuscator):
<script data-javascript-obfuscator>- السكربتات العادية<script type="text/javascript" data-javascript-obfuscator>- السكربتات المُحدَّد نوعها صراحةً- السكربتات ذات أي سمات إضافية (
idأوclassأوdata-*أخرى، إلخ.)
يُتخطّى (يُترَك دون تغيير):
- السكربتات التي لا تحمل السمة
data-javascript-obfuscator <script type="module">- وحدات ES (حتى مع السمة)<script src="...">- السكربتات الخارجية (حتى مع السمة)- وسوم السكربت الفارغة
ملاحظة: لا تُولَّد خرائط المصدر عند تفعيل parseHtml، لأنها لن تُطابِق ناتج HTML بشكل صحيح.
مثال:
// input
const html = `<!DOCTYPE html>
<html>
<body>
<!-- This script will NOT be obfuscated -->
<script>
var helper = 'utility';
</script>
<!-- This script WILL be obfuscated -->
<script data-javascript-obfuscator>
var greeting = 'Hello World';
console.log(greeting);
</script>
</body>
</html>`;
JavaScriptObfuscator.obfuscate(html, {
parseHtml: true,
stringArray: true
});
// output: HTML with only the marked script obfuscated
renameGlobals
Type: boolean Default: false
⚠️ قد يعطّل هذا الخيار عمل كودك. لا تفعّله إلا إذا كنت تعرف ما يفعله!
يفعّل تشويش أسماء المتغيرات والدوال العامة مع تصريحها.
عندما يكون هذا الخيار معطَّلًا ويصرّح كود المُدخل عن دوال أو أصناف في النطاق العام (أي أن الكود غير مغلَّف داخل IIFE)، تُبقى أسماؤها كما هي في الكود المشوَّش — فقد تشير إليها سكربتات أخرى بالاسم. وتحت vmObfuscation يُبلَّغ عن تحذير VMGlobalFunctionNamesNotRenamed يسرد هذه الأسماء، إذ إن جسم الدالة مخفي كبايت كود لكن الاسم القابل للقراءة على المستوى الأعلى لا يزال يكشف ما يفعله الكود (لنموذج LLM مثلًا). ولتجنّب هذا الكشف، غلّف الكود داخل IIFE أو فعّل هذا الخيار.
renameProperties
Type: boolean Default: false
⚠️ قد يعطّل هذا الخيار عمل كودك. لا تفعّله إلا إذا كنت تعرف ما يفعله!
يفعّل إعادة تسمية أسماء الخصائص. وسيُتجاهَل جميع خصائص DOM المدمجة والخصائص في أصناف JavaScript الأساسية.
للتبديل بين الوضعين safe وunsafe لهذا الخيار استخدم خيار renamePropertiesMode.
لضبط صيغة أسماء الخصائص المُعاد تسميتها استخدم خيار identifierNamesGenerator.
للتحكم في الخصائص التي سيُعاد تسميتها استخدم خيار reservedNames.
مثال:
// input
(function () {
const foo = {
prop1: 1,
prop2: 2,
calc: function () {
return this.prop1 + this.prop2;
}
};
console.log(foo.calc());
})();
// output
(function () {
const _0x46529b = {
'_0x10cec7': 0x1,
'_0xc1c0ca': 0x2,
'_0x4b961d': function () {
return this['_0x10cec7'] + this['_0xc1c0ca'];
}
};
console['log'](_0x46529b['_0x4b961d']());
}());
renamePropertiesMode
Type: string Default: safe
⚠️ حتى في الوضع safe، قد يعطّل خيار renameProperties عمل كودك.
يحدّد وضع خيار renameProperties:
safe- السلوك الافتراضي بعد الإصدار2.11.0. يحاول إعادة تسمية الخصائص بطريقة أكثر أمانًا لمنع أخطاء التشغيل. مع هذا الوضع، تُستثنى بعض الخصائص من إعادة التسمية.unsafe- السلوك الافتراضي قبل الإصدار2.11.0. يعيد تسمية الخصائص بطريقة غير آمنة دون أي قيود.
إذا كان أحد الملفات يستخدم خصائص من ملف آخر، فاستخدم خيار identifierNamesCache للحفاظ على أسماء الخصائص نفسها بين هذه الملفات.
reservedNames
Type: string[] Default: []
يعطّل تشويش وتوليد المعرِّفات المطابِقة لأنماط RegExp المُمرَّرة.
مثال:
{
reservedNames: [
'^someVariable',
'functionParameter_\d'
]
}
reservedStrings
Type: string[] Default: []
يعطّل تحويل النصوص الحرفية المطابِقة لأنماط RegExp المُمرَّرة. وتبقى النصوص المطابِقة ظاهرة في الناتج المشوَّش.
عند استخدام تشويش VM، تُخزَّن النصوص المحجوزة في مصفوفة منفصلة غير مشفَّرة لإبقائها ظاهرة. وهذا مفيد للنصوص التي يجب أن تبقى قابلة للقراءة، مثل نقاط نهاية API للمراقبة أو معرِّفات المكتبات.
مثال:
{
reservedStrings: [
'react-native',
'\.\/src\/test',
'some-string_\d'
]
}
seed
Type: string|number Default: 0
يضبط هذا الخيار بذرة مولِّد الأرقام العشوائية. وهذا مفيد لإنشاء نتائج قابلة للتكرار.
إذا كانت البذرة 0، فسيعمل مولِّد الأرقام العشوائية بلا بذرة.
selfDefending
Type: boolean Default: false
⚠️ لا تغيّر الكود المشوَّش بأي شكل بعد التشويش بهذا الخيار، لأن أي تغيير مثل ضغط الكود قد يفعّل الدفاع الذاتي فيتوقف الكود عن العمل!
⚠️ يضبط هذا الخيار قسرًا قيمة compact إلى true
⚠️ يُعطَّل هذا الخيار بصمت عند تفعيل vmObfuscation. استخدم vmSelfDefending بدلًا منه.
يجعل هذا الخيار الكود الناتج صامدًا أمام إعادة التنسيق وإعادة تسمية المتغيرات. فإذا حاول أحد استخدام مُجمِّل JavaScript على الكود المشوَّش، فسيتوقف الكود عن العمل، مما يصعّب فهمه وتعديله.
simplify
Type: boolean Default: true
يفعّل تشويشًا إضافيًا للكود عبر التبسيط.
⚠️ في الإصدارات المستقبلية سيُنقَل تشويش النصوص الحرفية من نوع boolean (true => !![]) ليكون ضمن هذا الخيار.
مثال:
// input
if (condition1) {
const foo = 1;
const bar = 2;
console.log(foo);
return bar;
} else if (condition2) {
console.log(1);
console.log(2);
console.log(3);
return 4;
} else {
return 5;
}
// output
if (condition1) {
const foo = 0x1, bar = 0x2;
return console['log'](foo), bar;
} else
return condition2 ? (console['log'](0x1), console['log'](0x2), console['log'](0x3), 0x4) : 0x5;
sourceMap
Type: boolean Default: false
يفعّل توليد خريطة المصدر للكود المشوَّش.
قد تكون خرائط المصدر مفيدة لمساعدتك على تنقيح كود JavaScript المصدري المشوَّش. فإذا أردت أو احتجت إلى التنقيح في بيئة الإنتاج، يمكنك رفع ملف خريطة المصدر المنفصل إلى موقع سرّي ثم توجيه متصفحك إليه.
sourceMapBaseUrl
Type: string Default: ``
يضبط عنوان URL الأساسي لعنوان استيراد خريطة المصدر عند sourceMapMode: 'separate'.
مثال CLI:
javascript-obfuscator input.js --output out.js --source-map true --source-map-base-url 'http://localhost:9000'
النتيجة:
//# sourceMappingURL=http://localhost:9000/out.js.map
sourceMapFileName
Type: string Default: ``
يضبط اسم ملف خريطة المصدر الناتجة عند sourceMapMode: 'separate'.
مثال CLI:
javascript-obfuscator input.js --output out.js --source-map true --source-map-base-url 'http://localhost:9000' --source-map-file-name example
النتيجة:
//# sourceMappingURL=http://localhost:9000/example.js.map
sourceMapMode
Type: string Default: separate
يحدّد وضع توليد خريطة المصدر:
inline- يضيف خريطة المصدر في نهاية كل ملف .js؛separate- يولّد ملف '.map' مقابلًا يحتوي على خريطة المصدر. وفي حال تشغيل المشوِّش عبر CLI، يضيف رابطًا إلى ملف خريطة المصدر في نهاية ملف الكود المشوَّش//# sourceMappingUrl=file.js.map.
sourceMapSourcesMode
Type: string Default: sources-content
يتيح التحكم في الحقلين sources وsourcesContent لخريطة المصدر:
sources-content- يضيف حقلsourcesوهميًا، ويضيف حقلsourcesContentمع الكود المصدري الأصلي؛sources- يضيف حقلsourcesمع وصف مصدر صالح، ولا يضيف حقلsourcesContent. وعند استخدام واجهة NodeJS يلزم تحديد خيارinputFileNameالذي سيُستخدَم كقيمة لحقلsources.
splitStrings
Type: boolean Default: false
يقسّم النصوص الحرفية إلى أجزاء بطول قيمة خيار splitStringsChunkLength.
مثال:
// input
(function(){
var test = 'abcdefg';
})();
// output
(function(){
var _0x5a21 = 'ab' + 'cd' + 'ef' + 'g';
})();
splitStringsChunkLength
Type: number Default: 10
يضبط طول أجزاء خيار splitStrings.
stringArray
Type: boolean Default: true
يزيل النصوص الحرفية ويضعها في مصفوفة خاصة. فمثلًا، النص "Hello World" في var m = "Hello World"; سيُستبدَل بشيء مثل var m = _0x12c456[0x1];
stringArrayCallsTransform
Type: boolean Default: false
⚠️ يجب تفعيل خيار stringArray
يفعّل تحويل الاستدعاءات إلى stringArray. قد تُستخرَج جميع وسائط هذه الاستدعاءات إلى كائن مختلف اعتمادًا على قيمة stringArrayCallsTransformThreshold.
وهذا يزيد صعوبة العثور تلقائيًا على الاستدعاءات إلى مصفوفة النصوص.
مثال:
function foo() {
var k = {
c: 0x2f2,
d: '0x396',
e: '0x397',
f: '0x39a',
g: '0x39d',
h: 0x398,
l: 0x394,
m: '0x39b',
n: '0x39f',
o: 0x395,
p: 0x395,
q: 0x399,
r: '0x399'
};
var c = i(k.d, k.e);
var d = i(k.f, k.g);
var e = i(k.h, k.l);
var f = i(k.m, k.n);
function i(c, d) {
return b(c - k.c, d);
}
var g = i(k.o, k.p);
var h = i(k.q, k.r);
}
function j(c, d) {
var l = { c: 0x14b };
return b(c - -l.c, d);
}
console[j(-'0xa6', -'0xa6')](foo());
function b(c, d) {
var e = a();
b = function (f, g) {
f = f - 0xa3;
var h = e[f];
return h;
};
return b(c, d);
}
function a() {
var m = [
'string5',
'string1',
'log',
'string3',
'string6',
'string2',
'string4'
];
a = function () {
return m;
};
return a();
}
stringArrayCallsTransformThreshold
Type: number Default: 0.5
⚠️ يجب تفعيل خياري stringArray وstringArrayCallsTransformThreshold
يمكنك استخدام هذا الإعداد لضبط الاحتمال (من 0 إلى 1) بأن تُحوَّل الاستدعاءات إلى مصفوفة النصوص.
stringArrayEncoding
Type: string[] Default: []
⚠️ يجب تفعيل خيار stringArray
قد يبطّئ هذا الخيار سكربتك.
يرمّز جميع النصوص الحرفية في stringArray باستخدام base64 أو rc4 ويُدرج كودًا خاصًا يُستخدَم لفك ترميزها مجددًا أثناء التشغيل.
سيُرمَّز كل قيمة من stringArray بالترميز المُنتقى عشوائيًا من القائمة المُمرَّرة. وهذا يتيح استخدام عدة ترميزات.
القيم المتاحة:
'none'(boolean): لا يرمّز قيمةstringArray'base64'(string): يرمّز قيمةstringArrayباستخدامbase64'rc4'(string): يرمّز قيمةstringArrayباستخدامrc4. أبطأ منbase64بنحو 30-50%، لكنه يصعّب الحصول على القيم الأولية.
فمثلًا، مع قيم الخيار التالية لن يُرمَّز بعض قيم stringArray، وسيُرمَّز بعضها الآخر بترميز base64 وrc4:
stringArrayEncoding: [
'none',
'base64',
'rc4'
]
stringArrayIndexesType
Type: string[] Default: ['hexadecimal-number']
⚠️ يجب تفعيل خيار stringArray
يتيح التحكم في نوع فهارس استدعاء مصفوفة النصوص.
سيُحوَّل كل فهرس استدعاء لـ stringArray بالنوع المُنتقى عشوائيًا من القائمة المُمرَّرة. وهذا يتيح استخدام عدة أنواع.
القيم المتاحة:
'hexadecimal-number'(default): يحوّل فهارس استدعاء مصفوفة النصوص كأرقام ست عشرية'hexadecimal-numeric-string': يحوّل فهارس استدعاء مصفوفة النصوص كنص عددي ست عشري
قبل الإصدار 2.9.0 كان javascript-obfuscator يحوّل جميع فهارس استدعاء مصفوفة النصوص بالنوع hexadecimal-numeric-string. وهذا يصعّب بعض إزالة التشويش اليدوية قليلًا، لكنه يتيح كشف هذه الاستدعاءات بسهولة بواسطة أدوات إزالة التشويش التلقائية.
يهدف النوع الجديد hexadecimal-number إلى تصعيب الكشف التلقائي عن أنماط استدعاء مصفوفة النصوص في الكود.
سيُضاف مزيد من الأنواع مستقبلًا.
stringArrayIndexShift
Type: boolean Default: true
⚠️ يجب تفعيل خيار stringArray
يفعّل إزاحة فهرس إضافية لجميع استدعاءات مصفوفة النصوص
stringArrayRotate
Type: boolean Default: true
⚠️ يجب تفعيل stringArray
يزيح مصفوفة stringArray بمقدار ثابت وعشوائي (يُولَّد عند تشويش الكود) من المواضع. وهذا يصعّب مطابقة ترتيب النصوص المُزالة بمواضعها الأصلية.
stringArrayShuffle
Type: boolean Default: true
⚠️ يجب تفعيل stringArray
يخلط عناصر مصفوفة stringArray عشوائيًا.
stringArrayWrappersCount
Type: number Default: 1
⚠️ يجب تفعيل خيار stringArray
يضبط عدد المغلِّفات لـ string array داخل كل نطاق جذري أو نطاق دالة.
والعدد الفعلي للمغلِّفات داخل كل نطاق محدود بعدد عُقد literal ضمن هذا النطاق.
مثال:
// Input
const foo = 'foo';
const bar = 'bar';
function test () {
const baz = 'baz';
const bark = 'bark';
const hawk = 'hawk';
}
const eagle = 'eagle';
// Output, stringArrayWrappersCount: 5
const _0x3f6c = [
'bark',
'bar',
'foo',
'eagle',
'hawk',
'baz'
];
const _0x48f96e = _0x2e13;
const _0x4dfed8 = _0x2e13;
const _0x55e970 = _0x2e13;
function _0x2e13(_0x33c4f5, _0x3f6c62) {
_0x2e13 = function (_0x2e1388, _0x60b1e) {
_0x2e1388 = _0x2e1388 - 0xe2;
let _0x53d475 = _0x3f6c[_0x2e1388];
return _0x53d475;
};
return _0x2e13(_0x33c4f5, _0x3f6c62);
}
const foo = _0x48f96e(0xe4);
const bar = _0x4dfed8(0xe3);
function test() {
const _0x1c262f = _0x2e13;
const _0x54d7a4 = _0x2e13;
const _0x5142fe = _0x2e13;
const _0x1392b0 = _0x1c262f(0xe7);
const _0x201a58 = _0x1c262f(0xe2);
const _0xd3a7fb = _0x1c262f(0xe6);
}
const eagle = _0x48f96e(0xe5);
stringArrayWrappersChainedCalls
Type: boolean Default: true
⚠️ يجب تفعيل خياري stringArray وstringArrayWrappersCount
يفعّل الاستدعاءات المتسلسلة بين مغلِّفات string array.
مثال:
// Input
const foo = 'foo';
const bar = 'bar';
function test () {
const baz = 'baz';
const bark = 'bark';
function test1() {
const hawk = 'hawk';
const eagle = 'eagle';
}
}
// Output, stringArrayWrappersCount: 5, stringArrayWrappersChainedCalls: true
const _0x40c2 = [
'bar',
'bark',
'hawk',
'eagle',
'foo',
'baz'
];
const _0x31c087 = _0x3280;
const _0x31759a = _0x3280;
function _0x3280(_0x1f52ee, _0x40c2a2) {
_0x3280 = function (_0x3280a4, _0xf07b02) {
_0x3280a4 = _0x3280a4 - 0x1c4;
let _0x57a182 = _0x40c2[_0x3280a4];
return _0x57a182;
};
return _0x3280(_0x1f52ee, _0x40c2a2);
}
const foo = _0x31c087(0x1c8);
const bar = _0x31c087(0x1c4);
function test() {
const _0x848719 = _0x31759a;
const _0x2693bf = _0x31c087;
const _0x2c08e8 = _0x848719(0x1c9);
const _0x359365 = _0x2693bf(0x1c5);
function _0x175e90() {
const _0x310023 = _0x848719;
const _0x2302ef = _0x2693bf;
const _0x237437 = _0x310023(0x1c6);
const _0x56145c = _0x310023(0x1c7);
}
}
stringArrayWrappersParametersMaxCount
Type: number Default: 2
⚠️ يجب تفعيل خيار stringArray
⚠️ يؤثّر هذا الخيار حاليًا فقط في المغلِّفات المُضافة بقيمة خيار stringArrayWrappersType المساوية function
يتيح التحكم في العدد الأقصى لمعاملات مغلِّفات مصفوفة النصوص.
القيمة الافتراضية والدنيا هي 2. القيمة المُوصى بها بين 2 و5.
stringArrayWrappersType
Type: string Default: variable
⚠️ يجب تفعيل خياري stringArray وstringArrayWrappersCount
يتيح اختيار نوع المغلِّفات التي يضيفها خيار stringArrayWrappersCount.
القيم المتاحة:
'variable': يضيف مغلِّفات متغيرات في أعلى كل نطاق. أداء سريع.'function': يضيف مغلِّفات دوال في مواضع عشوائية داخل كل نطاق. أداء أبطأ منvariableلكنه يوفّر تشويشًا أكثر صرامة.
يُوصى بشدة باستخدام مغلِّفات function لتشويش أعلى عندما لا يكون لخسارة الأداء تأثير كبير على التطبيق المشوَّش.
مثال على قيمة الخيار 'function':
// input
const foo = 'foo';
function test () {
const bar = 'bar';
console.log(foo, bar);
}
test();
// output
const a = [
'log',
'bar',
'foo'
];
const foo = d(0x567, 0x568);
function b(c, d) {
b = function (e, f) {
e = e - 0x185;
let g = a[e];
return g;
};
return b(c, d);
}
function test() {
const c = e(0x51c, 0x51b);
function e (c, g) {
return b(c - 0x396, g);
}
console[f(0x51b, 0x51d)](foo, c);
function f (c, g) {
return b(c - 0x396, g);
}
}
function d (c, g) {
return b(g - 0x3e1, c);
}
test();
stringArrayThreshold
Type: number Default: 0.8 Min: 0 Max: 1
⚠️ يجب تفعيل خيار stringArray
يمكنك استخدام هذا الإعداد لضبط الاحتمال (من 0 إلى 1) بأن يُدرَج نص حرفي في stringArray.
هذا الإعداد مفيد بوجه خاص مع أحجام الكود الكبيرة لأنه يستدعي string array مرارًا وقد يبطّئ كودك.
القيمة stringArrayThreshold: 0 تكافئ stringArray: false.
strictMode
Type: boolean | null Default: null
يتيح تحديد كيف ينبغي للمشوِّش أن يعامل الكود فيما يخص الوضع الصارم في JavaScript.
القيم المتاحة:
null(افتراضي) - كشف الوضع الصارم تلقائيًا من الكود. إذا كان الكود يحتوي على توجيه'use strict'صريح، أو بنية وحدة ES، أو توابع أصناف، فيُعامَل على أنه وضع صارم. وإلا يُفترَض الوضع المتساهل.true- فرض معاملة الوضع الصارم لكل الكود، حتى دون توجيه'use strict'صريح. استخدم هذا عندما يعمل كودك في سياق وضع صارم (مثلًا في وحدات ES أو أدوات التحزيم أو أطر العمل الحديثة).false- لا يُعامَل على أنه صارم إلا مؤشرات الوضع الصارم الصريحة ('use strict'، وحدات ES، توابع الأصناف). ولا يزال توريث نطاق الأب مطبَّقًا وفق مواصفة JS.
target
Type: string Default: browser
يتيح ضبط البيئة الهدف للكود المشوَّش.
القيم المتاحة:
browser(افتراضي) — بيئة صفحة ويب قياسية. الكود الناتج مطابق لـnode، لكن لا يُسمح باستخدام بعض الخيارات الخاصة بالمتصفح مع الهدفnodebrowser-no-eval— مثلbrowser، لكن الناتج لا يستخدمeval(). استخدمه عندما تفرض الصفحة الهدف سياسة أمان محتوى تمنعeval/unsafe-eval.node— بيئة Node.js. تُعطَّل الخيارات الخاصة بالمتصفح (فهي تتطلبwindow/documentوستكون بلا أثر أو ستطلق استثناءً في Node). ولا تُصدَر لهذا الهدف بعض دفاعاتvmSelfDefendingالتي تعتمد على واجهات برمجية خاصة بالمتصفح — كشف المتصفح مقطوع الرأس، والتعافي عبر عالَم نظيف قائم على iframe، وفحوصات مضادة للمفتِّش/DOM.service-worker— سياق Service Worker. لاwindow، ولاdocument، ومتغيّرselfعام مختلف.userscript— صندوق حماية مدير سكربتات المستخدم (مثل Tampermonkey). تُعدَّل دفاعاتvmSelfDefendingتبعًا لذلك.bytenode— كود Node.js سيُترجَم بواسطة مُحمِّل bytenode (بايت كود V8 المُخزَّن.jsc) بعد التشويش. لا يستدعي المشوِّش نفسهbytenode؛ بل يُصدر JavaScript مشوَّشًا بـ VM بُنيت بيئة تشغيله لتصمد أمام خطوة ترجمة bytenode، وتُعدَّل دفاعاتvmSelfDefendingتبعًا لذلك. شغّلbytenodeبنفسك على الناتج المشوَّش لإنتاج ملف.jscالنهائي.
transformObjectKeys
Type: boolean Default: false
يفعّل تحويل مفاتيح الكائنات.
مثال:
// input
(function(){
var object = {
foo: 'test1',
bar: {
baz: 'test2'
}
};
})();
// output
var _0x4735 = [
'foo',
'baz',
'bar',
'test1',
'test2'
];
function _0x390c(_0x33d6b6, _0x4735f4) {
_0x390c = function (_0x390c37, _0x1eed85) {
_0x390c37 = _0x390c37 - 0x198;
var _0x2275f8 = _0x4735[_0x390c37];
return _0x2275f8;
};
return _0x390c(_0x33d6b6, _0x4735f4);
}
(function () {
var _0x17d1b7 = _0x390c;
var _0xc9b6bb = {};
_0xc9b6bb[_0x17d1b7(0x199)] = _0x17d1b7(0x19c);
var _0x3d959a = {};
_0x3d959a[_0x17d1b7(0x198)] = _0x17d1b7(0x19b);
_0x3d959a[_0x17d1b7(0x19a)] = _0xc9b6bb;
var _0x41fd86 = _0x3d959a;
}());
warnings
Type: string | object Default: all
يتحكم في تحذيرات التشويش غير القاتلة التي تُصدَر عبر التابع ObfuscationResult.getWarnings().
القيم المتاحة:
'all'(افتراضي) — يُصدَر كل تحذير.'none'— تُكتَم كل التحذيرات.- كائن يربط أنواع التحذيرات بقيم منطقية — النوع المربوط بـ
falseيُكتَم؛ وكل نوع غير موجود (أو مربوط بـtrue) يبقى مفعَّلًا. فمثلًا،{ "VMGlobalFunctionNamesNotRenamed": false }يبقي كل تحذير عدا ذاك.
أنواع التحذيرات:
VMGlobalFunctionNamesNotRenamed— تحتvmObfuscation، بقيت أسماء تصريحات الدوال على المستوى الأعلى، وتصريحات الأصناف، والمتغيرات المُسنَد إليها تعبير دالة/سهمية/صنف كما هي (خيارrenameGlobalsمعطَّل والكود غير مغلَّف داخل IIFE)، فتبقى قابلة للقراءة في الناتج رغم إخفاء الأجسام كبايت كود. ولا يُبلَّغ عن الأسماء المُصدَّرة.VMTopLevelInitializerNotVirtualized— بقيت مُهيّئات المتغيرات على المستوى الأعلى بصيغة JavaScript عادية تحت تشويش VM لأنvmWrapTopLevelInitializersمعطَّل أو تعذّر عليه محاكاتها افتراضيًا.DynamicCodeRenameRisk— يبني الكود دالة من نص أثناء التشغيل (عبرevalالمباشر، أو بانيFunction، أوfn.toString()المحقون في<script>/Worker)، وقد يشير ذلك إلى معرِّفات أعاد المشوِّش تسميتها.VMDynamicCodeSkipped— تُخطّي دالة من ترميز بايت كود VM لأنها تحتوي علىevalمباشر /new Functionديناميكي /Function(انظرvmForceCompileDynamicCode).VMSyncFunctionSkippedInAsyncMode— مع تفعيلvmAsyncExecutor، تبيّن أن دالة علّمتها صراحةً في وضعcommentمتزامنة فتُخطّيت (لا يُحاكى افتراضيًا في ذلك الوضع سوى الدوال غير المتزامنة).VMAsyncGeneratorSkippedInAsyncMode— مع تفعيلvmAsyncExecutorوجالِب مفتاح غير متزامن نشط، تعذّرت محاكاة مولِّد غير متزامن مُعلَّم افتراضيًا (يجب أن يُعيد مُكرِّره بشكل متزامن).BrowserTargetWithNodeStyleCode— يبدو أن الكود يستهدف Node.js (مثلrequire('fs')أو__dirnameأوprocess.argv) بينما خيارtargetمضبوط على بيئة شبيهة بالمتصفح.
vmObfuscation
Type: boolean Default: false
يفعّل تشويش البايت كود القائم على VM. عند التفعيل، تُترجَم دوال JavaScript إلى بايت كود مخصص يعمل على آلة افتراضية مضمَّنة. وهذا يوفّر أعلى مستوى من الحماية إذ يُحوَّل منطق الكود الأصلي بالكامل.
مثال:
كودك القابل للقراءة مثل return qty * price يصبح قائمة من الأرقام مثل [0x15,0x03,0x17,...] لا يستطيع تنفيذها سوى مفسِّر VM المضمَّن. ولم يعد المنطق الأصلي ظاهرًا بصيغة JavaScript.
vmTargetFunctions
Type: string[] Default: []
حدّد بدقّة أيّ دوال على المستوى الجذري ينبغي أن تحصل على حماية VM بالاسم.
مثال:
{
vmObfuscation: true,
vmTargetFunctions: ['someFunctionName']
}
النتيجة: هذه الدوال الثلاث فقط تحصل على حماية VM. وكل ما عداها يبقى JavaScript عاديًا (لكنه مشوَّش مع ذلك). مثالي لحماية فحوصات التراخيص الحساسة أو منطق المصادقة مع إبقاء بقية كودك رشيقًا.
vmExcludeFunctions
Type: string[] Default: []
حدّد الدوال على المستوى الجذري التي ينبغي ألّا تحصل أبدًا على حماية VM. له الأسبقية على الإعدادات الأخرى.
مثال:
{
vmObfuscation: true,
vmExcludeFunctions: ['someFunctionName']
}
متى تستخدمه: يمكن استثناء الدوال الحرجة للأداء على المستوى الجذري (حلقات الرسوم المتحركة، ومعالجة البيانات الفورية) لتجنّب حِمل VM مع الاستمرار في حماية كل شيء آخر.
vmTargetFunctionsMode
Type: string Default: root
يتحكم في كيفية اختيار الدوال/التوابع لتشويش VM.
مثال - وضع Comment:
// Source code
function regularFunction() {
return 'not virtualized';
}
/* javascript-obfuscator:vm */
function sensitiveFunction() {
return 'this will be VM-protected';
}
function outer() {
/* javascript-obfuscator:vm */
function nestedSensitive() {
return 'nested but still VM-protected';
}
return nestedSensitive();
}
// Obfuscator options
{
vmObfuscation: true,
vmTargetFunctionsMode: 'comment'
}
متى تستخدمه: عندما تحتاج إلى تحكم دقيق في الدوال التي تحصل تحديدًا على حماية VM، خصوصًا الدوال المتداخلة التي تحتوي على منطق حساس. فخلافًا لـ vmTargetFunctions الذي لا يعمل إلا مع الدوال المُسمّاة على المستوى الجذري، يتيح لك وضع comment حماية أي دالة في أي مكان من كودك.
vmForceCompileDynamicCode
Type: boolean Default: false
يتحكم فيما يفعله تشويش VM مع دالة تحتوي على استدعاء eval مباشر، أو new Function(...)، أو Function(...).
افتراضيًا، تُخطّى مثل هذه الدالة (وكل دالة معرَّفة داخلها) من ترميز بايت كود VM ويُبلَّغ عن تحذير VMDynamicCodeSkipped في result.getWarnings(). وذلك لأن المصدر المبني أثناء التشغيل قد يشير إلى معرِّفات من سلسلة النطاقات المحيطة — معرِّفات أعاد المشوِّش تسميتها.
عند ضبطه على true، تُرمَّز الدالة إلى بايت كود على أي حال ولا يُصدَر تحذير VMDynamicCodeSkipped بعد ذلك.
ويستمر إطلاق تحذير DynamicCodeRenameRisk المنفصل بصرف النظر عن هذا الخيار، لأن خطر إعادة التسمية الذي يصفه مستقل عن تخطّي VM — فتفعيل هذا الخيار لا يجعل النمط الأساسي أكثر أمانًا.
// Source code
function loadConfig(src) {
return eval(src);
}
loadConfig('1 + 2');
// Options
{
vmObfuscation: true,
vmForceCompileDynamicCode: true
}
مع إيقاف الخيار (الافتراضي)، تُترَك loadConfig بصيغة JavaScript عادية. ومع تفعيله، تُترجَم loadConfig إلى بايت كود VM مثل أي دالة أخرى. استخدم هذا عندما تكون قد راجعت موضع الاستدعاء وتعرف أن الكود المبني أثناء التشغيل لا يعتمد على معرِّفات مُعاد تسميتها في الإغلاق.
vmWrapTopLevelInitializers
Type: boolean Default: false
يغلّف بعض مُهيّئات المتغيرات على المستوى الأعلى داخل IIFE (تعبيرات دوال مُستدعاة فورًا) حتى يمكن تشويشها بـ VM.
ما يفعله: دون هذا الخيار، تبقى الثوابت والمتغيرات على المستوى الأعلى ظاهرة في الناتج:
// Input
const MY_STRING = "my-string";
// Output (without vmWrapTopLevelInitializers)
const MY_STRING = "my-string"; // String is visible!
مع تفعيل هذا الخيار، يُغلَّف المُهيّئ داخل IIFE يُشوَّش بـ VM:
// Input
const MY_STRING = "my-string";
// Output (with vmWrapTopLevelInitializers: true)
const MY_STRING = (() => { return /* VM bytecode call */ })(); // String hidden in bytecode
ملاحظة: لا يعمل هذا الخيار إلا عندما يكون vmTargetFunctionsMode بقيمة 'root' (الافتراضي).
vmDynamicOpcodes
Type: boolean Default: false
يجعل مفسِّر VM أصغر وفريدًا لكل عملية بناء.
ما يفعله:
- يصفّي التعليمات غير المستخدمة - إذا كان كودك لا يستخدم الأصناف، تُزال التعليمات المتعلقة بالأصناف كليًا
- يعشوِئ البنية - يُخلَط ترتيب معالِجات التعليمات في كل عملية بناء
والنتيجة - ناتج أصغر وكل عملية بناء تبدو مختلفة.
vmBytecodeEncoding
Type: boolean Default: false
يرمّز كل تعليمة بايت كود. تُفكّ ترميز التعليمات واحدة تلو الأخرى أثناء التنفيذ.
vmBytecodeArrayEncoding
Type: boolean Default: false
يرمّز مصفوفة البايت كود بأكملها ككتلة واحدة. تُفكّ ترميز المصفوفة مرة واحدة عند بدء التشغيل قبل بدء التنفيذ. استخدمه مع vmBytecodeEncoding للحصول على طبقتي حماية.
vmBytecodeArrayEncodingKey
Type: string Default: ''
مفتاح تشفير مخصص لترميز مصفوفة البايت كود. عند ضبطه، يُستخدَم هذا المفتاح بدلًا من المفتاح الافتراضي المشتق من البيئة. يجب توفير المفتاح أثناء التشغيل عبر vmBytecodeArrayEncodingKeyGetter.
يُخرج هذا الخيار مفتاح التشفير خارجيًا - فهو غير مضمَّن في الكود المشوَّش نفسه. ومع أن المفتاح لا يزال متاحًا أثناء التشغيل (وبالتالي ليس سرّيًا حقًا)، فإن هذا الفصل يمنع أدوات التحليل الساكن من العثور على المفتاح بفحص الكود وحده.
مهم: يجب أن يكون المفتاح متاحًا بشكل متزامن عند تحميل الكود المشوَّش. استخدم تخزينًا متزامنًا مثل الكوكيز، أو localStorage، أو sessionStorage، أو المتغيرات العامة، أو عناصر DOM (مثل وسوم meta المحقونة من الخادم). ولا يمكن استخدام الطرق غير المتزامنة مثل fetch() مباشرةً في تعبير جالِب المفتاح.
vmBytecodeArrayEncodingKeyGetter
Type: string Default: ''
تعبير JavaScript متزامن يُعيد مفتاح التشفير أثناء التشغيل. يُقيَّم هذا التعبير عند تحميل الكود المشوَّش، ويجب أن يُعيد المفتاح نفسه الذي قُدِّم في vmBytecodeArrayEncodingKey. ولحل المفتاح بشكل غير متزامن (عبر Promise)، فعّل vmAsyncExecutor.
ملاحظة: الجالِب الذي يُعيد Promise يتطلب vmAsyncExecutor. ولا يمكن التحقق من ذلك وقت البناء، لذا فإن جالِبًا يُعيد Promise مع vmAsyncExecutor معطَّل يفشل أثناء التشغيل — إذ يتلقى فاكّ الترميز الـ Promise بدلًا من المفتاح.
لن يعمل الكود المشوَّش إلا عندما يُعيد جالِب المفتاح المفتاح نفسه تمامًا الذي استُخدِم أثناء التشويش. فإذا لم يتطابق المفتاحان، سيفشل فك التشفير وسيُنتج الكود بيانات فاسدة أو أخطاء. وإذا أعاد جالِب المفتاح undefined أو null أو نصًا فارغًا، فسيطلق الكود خطأً: "VM decryption key not available".
مهم: أبقِ المفتاح خارج الملف/السكربت نفسه الذي يحوي الكود المشوَّش — فتضمينه هناك يتيح استعادته حتى بفحص ساكن محض للحزمة. خزّنه في مصدر منفصل بدلًا من ذلك: كوكيز يضبطها الخادم، أو localStorage يملؤه سكربت آخر، أو وسم meta في HTML محقون من الخادم، أو متغير عام يضبطه سكربت مختلف، أو (مع vmAsyncExecutor) يُجلَب من خادمك الخلفي أثناء التشغيل.
عندما يُجلَب المفتاح من خادمك الخلفي (عبر vmAsyncExecutor)، أضف فحوصات قائمة على الجلسة أو الأصل على نقطة النهاية تلك: أعِد المفتاح الصحيح للمستخدمين الحقيقيين (جلسة صالحة، Origin/Referer متوقعان) ومفتاحًا فاسدًا للطلبات المشبوهة (مثل أصل localhost/غير متوقع، أو غياب الجلسة). فيعمل المستخدمون الحقيقيون بشكل طبيعي؛ أما نسخة تعمل خارج بيئتك فتحصل على مفتاح يفكّ إلى لا شيء. والمنطق الدقيق يعتمد على موقعك.
أمثلة:
// From cookie
vmBytecodeArrayEncodingKeyGetter: "document.cookie.match(/vmKey=([^;]+)/)?.[1]"
// From localStorage
vmBytecodeArrayEncodingKeyGetter: "localStorage.getItem('vmKey')"
// From global variable
vmBytecodeArrayEncodingKeyGetter: "window.__VM_KEY__"
// From meta tag (server-injected)
vmBytecodeArrayEncodingKeyGetter: "document.querySelector('meta[name=\"vm-key\"]').content"
// From nested object
vmBytecodeArrayEncodingKeyGetter: "window.config.encryption.key"
// From backend, async (requires vmAsyncExecutor)
vmBytecodeArrayEncodingKeyGetter: 'fetch("/vm-key").then((res) => res.text())'
مثال استخدام:
// Build time
JavaScriptObfuscator.obfuscate(code, {
vmObfuscation: true,
vmBytecodeArrayEncoding: true,
vmBytecodeArrayEncodingKey: 'mySecretKey123',
vmBytecodeArrayEncodingKeyGetter: 'window.__VM_KEY__'
});
// Runtime - key must be set before obfuscated code runs
window.__VM_KEY__ = 'mySecretKey123';
vmAsyncExecutor
Type: boolean Default: false
يفعّل منفِّذ VM غير المتزامن، الذي يتيح لـ vmBytecodeArrayEncodingKeyGetter أن يُعيد Promise (جالِب مفتاح غير متزامن) — بحيث يمكن جلب مفتاح فك التشفير أثناء التشغيل (طلب شبكة، IndexedDB، إلخ.) بدلًا من وجوب توفّره بشكل متزامن عند تحميل الكود.
يُوصى به بشدة للأكواد غير المتزامنة بالكامل. في هذا الوضع لا يُحاكى افتراضيًا سوى الدوال async — فلا يمكن جعل دالة متزامنة غير متزامنة دون تحويل قيمة إعادتها إلى Promise وكسر مستدعيها — لذا فإن الكود غير المتزامن كليًا يحصل على أوسع تغطية. وهو يعمل أيضًا عندما يكون الجذر متزامنًا (مثل IIFE متزامن / مغلِّف UMD): إذ تُحمى الدوال async الأبعد داخلها، وتُترَك الأجزاء المتزامنة كما هي.
ما الذي يُحوَّل: كل دالة async الأبعد، أينما ظهرت (بما في ذلك المتداخلة داخل مغلِّفات متزامنة). الدالة غير المتزامنة الأبعد في كل سلسلة هي الوحدة المحمية — فكل ما بداخلها، متزامنًا وغير متزامن، يُترجَم ضمنها. أما الدوال المتزامنة والمولِّدات العادية فتُترَك دون تشويش.
function foo() { // sync — left as-is
function bar() {} // sync — left as-is
async function baz() { // transformed
// any code here, including calls to other async or sync functions
}
async function bark() { // transformed
// any code here, including calls to other async or sync functions
}
}
التخطّيات والتحذيرات. تُترَك المولِّدات غير المتزامنة أيضًا دون تشويش عندما يكون جالِب مفتاح غير متزامن نشطًا (يجب أن يُعيد المولِّد غير المتزامن مُكرِّره بشكل متزامن ولا يمكنه انتظار المفتاح). في الوضع الافتراضي vmTargetFunctionsMode: 'root' تكون التخطّيات صامتة (الاختيار تلقائي)؛ وفي وضع comment يُصدَر تحذير عبر ObfuscationResult.getWarnings() كلما تعذّرت محاكاة دالة علّمتها صراحةً — إمّا لأنها تبيّنت متزامنة، أو لأنها مولِّد غير متزامن تحت جالِب مفتاح غير متزامن.
ويتطلب جالِب المفتاح غير المتزامن إضافةً vmBytecodeArrayEncoding مع vmBytecodeArrayEncodingKeyGetter.
مثال استخدام:
JavaScriptObfuscator.obfuscate(code, {
vmObfuscation: true,
vmAsyncExecutor: true,
vmBytecodeArrayEncoding: true,
vmBytecodeArrayEncodingKey: 'mySecretKey123',
// the key getter may now return a Promise
vmBytecodeArrayEncodingKeyGetter: 'fetch("/vm-key").then((res) => res.text())'
});
vmJumpsEncoding
Type: boolean Default: false
يرمّز أهداف القفزات في البايت كود. تُحسَب إزاحات القفز أثناء التشغيل، مما يخفي بنية تدفق التحكم (if/else، الحلقات، إلخ.) عن التحليل الساكن.
vmMacroOps
Type: boolean Default: false
يدمج تسلسلات التعليمات الشائعة في أكواد عمليات "ماكرو" مفردة. فمثلًا، قد يصبح LOAD + ADD + STORE تعليمة MACRO_ADD_TO_VAR واحدة. وهذا يكسر التعرّف على الأنماط وقد يحسّن الأداء.
vmDebugProtection
Type: boolean Default: false
يضيف دفاعات متعددة الطبقات مضادة للتنقيح والتحليل ونماذج LLM إلى بيئة تشغيل VM. يعمل على أفضل نحو مع الأهداف browser/browser-no-eval.
vmSelfDefending
Type: boolean Default: false
يضيف حماية متعددة الطبقات لكشف العبث، ومنع الاعتراض، ومقاومة الهندسة العكسية إلى بيئة تشغيل VM.
⚠️ يفعّل هذا الخيار قسرًا vmBytecodeArrayEncoding.
⚠️ كشف البيئات الحساسة. يربط هذا الخيار الكود المشوَّش ببيئة التشغيل الهدف ويستخدم بصمة متصفح متقدمة لكشف أدوات الأتمتة. والكود المحمي بهذا الخيار سيتعطّل عمدًا عند تشغيله في:
- المتصفحات مقطوعة الرأس (Chrome/Chromium مقطوع الرأس، PhantomJS)
- أدوات أتمتة المتصفح (Puppeteer، Playwright، Cypress، Selenium/ChromeDriver، Nightmare)
- Node.js (عندما يكون
targetمضبوطًا علىbrowser) - jsdom أو محاكاة DOM المشابهة على جانب الخادم
- البيئات التي اعتُرِض فيها على أدوات المتصفح المدمجة الأصلية أو استُبدلت
والكود سيعمل بشكل صحيح في المتصفحات العادية (Chrome، Firefox، Safari، Edge)، بما في ذلك عند تحميله داخل iframe، وإضافات المتصفح (سكربتات المحتوى)، وWeb Workers. إذا احتجت إلى تشغيل اختبارات آلية على كود محمي، فعطّل vmSelfDefending لعمليات بناء الاختبار — فهذا الخيار مصمَّم لمنع التحليل الآلي ولا يمكن استخدامه بأمان مع أي إطار أتمتة.
يُوصى بشدة باستخدامه مع vmDebugProtection وvmBytecodeArrayEncodingKey وvmBytecodeArrayEncodingKeyGetter.
vmDefenseHook
Type: { name: string, aliases?: object } Default: ''
يأخذ vmDefenseHook كائنًا بمفتاحين: name (مطلوب) و**aliases** (اختياري).
name هو دالة عامة تعرّفها صفحتك المُضيفة يستدعيها دفاع VM (vmDebugProtection / vmSelfDefending) بكائن إشارة عندما يكتشف إشارة عدائية — منقّح أو مفتِّش، أو متصفح مقطوع الرأس / أتمتة، أو عملية وكيل برمجة بالذكاء الاصطناعي، أو نطاق غير مسموح، وهكذا. استخدمها للإبلاغ عن الحدث إلى خادمك الخلفي (مثل navigator.sendBeacon). والإشارة (hook) هي مصرف قياس عن بُعد محض: تُتجاهَل قيمة إعادتها، وإشارة غائبة أو تطلق استثناءً هي عملية لا شيء صامتة لا يمكنها أبدًا تعطيل دفاع. ولتغيير ما يفعله الدفاع عند الكشف، استخدم vmDefenseReaction.
aliases يعيد تسمية حقول كائن الإشارة ذاك اختياريًا — مشروح تحت إعادة تسمية حقول الإشارة أدناه.
كائن الإشارة. تتلقى الإشارة signal واحدة:
source— الكاشف المحدد الذي أُطلِق (انظر الجدول).category— المجموعة التي يُبلَّغ ضمنها:automation(متصفحات غير بشرية)، أوdebugger(منقّح/مفتِّش نشط)، أوsandbox(مُضيف مُجهَّز/مزيَّف)، أوdomain(خرق قفل النطاق)، أوtamper(تعديل الأدوات المدمجة أثناء التشغيل)، أوintegrity(تغيّر كود VM نفسه).score/threshold— مدى قوة إطلاق الكاشف والقيمة التي كان عليه بلوغها؛ لا تُطلَق الإشارة إلا عندما يكونscore >= threshold. معظم الفحوصات كل شيء أو لا شيء (إشارة حاسمة واحدة)؛ أماheadlessفيجمع عدة إشارات لشكل المتصفح، لذا يكونscoreلديه أعلى منthresholdعادةً.
تسجيل الإشارة. عرّفها كمتغير عام عادي قبل تحميل الحزمة المشوَّشة — فبيئة تشغيل VM ودفاعاتها تعمل قبل برنامجك (المحمي)، لذا تُطلَق كثير من عمليات الكشف أثناء بدء التشغيل:
// in your page, before the obfuscated script:
window.__vmDetection = function (signal) { navigator.sendBeacon('/vm-defense', JSON.stringify(signal)); };
// obfuscation option:
vmDefenseHook: { name: '__vmDetection' }
الإشارة المعرَّفة داخل المصدر المشوَّش تُسجَّل متأخرة جدًا بحيث لا تلتقط عمليات الكشف وقت بدء التشغيل، وإذا رُمِّزت بـ VM فلا يمكن الوصول إليها حتى يعمل برنامجك. وهي آمنة على أي حال (إشارة غائبة تنفّذ لا شيء، وحارس منع إعادة الدخول يمنع أي انفلات)، لكن للتغطية الكاملة سجّلها مقدَّمًا. ولحماية منطق إبلاغك رغم ذلك، أبقِ الإشارة المسجَّلة عازلًا من سطر واحد ((window.__vmDet = window.__vmDet || []).push(signal)) واقرأ/أرسِل ذلك العازل من كودك المشوَّش.
إعادة تسمية حقول الإشارة (aliases). القيم الافتراضية لـ source/category أسماء وصفية، فيستطيع أي شخص يُجهِّز رد النداء (أو يقرأ الناتج) أن يتعرّف على الحماية وعلى الكاشف الذي أُطلِق. aliases يعيد تسمية حقول الإشارة إلى رموز مبهمة من اختيارك، تُطبَّق داخل VM قبل إصدار الإشارة، بحيث لا تظهر تلك الأسماء أبدًا في الناتج ولا تصل إلى رد النداء. ويعرف تطبيقك التعيين الخاص به ويمرّر الرموز إلى خادمك الخلفي.
الأسماء البديلة لكل حقل، مع إبقاء إعادة تسمية المفاتيح والقيم منفصلة: يأخذ كل حقل key (اسم الخاصية الذي يتلقاه رد النداء)؛ كما يأخذ الحقلان النصيان source وcategory خريطة values، بينما score/threshold رقمان ويأخذان key فقط. الأسماء التي يمكنك تعيينها (وأي شيء آخر يُرفَض وقت البناء):
- مفاتيح الحقول —
source،category،score،threshold - قيم
source—headless،agent،node،debugger،timing،sandbox،domain،nativeHook،integrity - قيم
category—automation،debugger،sandbox،domain،tamper،integrity
vmDefenseHook: {
name: '__vmDetection',
aliases: {
source: { key: 'a8Qm', values: { headless: 'xP4m9Q' } },
category: { key: 'p3Tx', values: { automation: 'bQ7s1M' } },
score: { key: 's1' },
threshold: { key: 't1' }
}
// the callback now receives e.g. { a8Qm: 'xP4m9Q', p3Tx: 'bQ7s1M', s1: <score>, t1: <threshold> }
}
هذا تجنّبٌ للبصمة، لا سرّية — إذ لا يزال بالإمكان استنتاج التعيين بالاختبار المتكرر — فمنفعته الوحيدة هي عدم كشف أسماء ثابتة تفسّر نفسها. والمدخلات غير المضبوطة تبقى بأسمائها الافتراضية.
يُقبَل نص مجرد (vmDefenseHook: '__vmDetection') كاختصار لـ { name: '__vmDetection' } لكنه مهجور — فضّل صيغة الكائن.
vmDefenseReaction
Type: object Default: { automation: 'break', debugger: 'decoy', sandbox: 'decoy', domain: 'break', tamper: 'break', integrity: 'break' }
يضبط كيفية تفاعل كل فئة كشف. وهو لا يفعّل أي شيء — فالدفاعات نفسها تُشغَّل بواسطة vmSelfDefending وvmDebugProtection وvmDomainLock؛ ولا يختار هذا الخيار سوى كيفية تفاعل دفاع مفعَّل. الفئة هي وحدة التحكم — فكل كاشف في فئة يُنفِّذ تفاعل تلك الفئة.
تجمع كل فئة الكواشف التي تراقب نوعًا واحدًا من الحالات العدائية. ولا تتفاعل الفئة إلا عندما يكون الخيار الذي يُصدِر كواشفها مفعَّلًا:
تُطابَق كل فئة واحدًا أو أكثر من vmSelfDefending وvmDebugProtection وvmDomainLock؛ ولا توجد فئة خارج تلك الخيارات الثلاثة، وتفاعل مضبوط لفئة خيارها معطَّل ببساطة بلا أثر.
المفاتيح هي أسماء الفئات الست هذه، أو default (احتياطي للفئات غير المحددة). والقيم هي:
break— يتوقف فورًاdecoy— يستمر في العمل على حالة مسمومة، منتجًا نتائج خاطئة بصمتnone— لا يفعل شيئًا محليًا (قياس عن بُعد فقط)
الافتراضيات لكل فئة مبيَّنة أعلاه؛ والفئة التي لا تضبطها (أو تضبطها على قيمتها الافتراضية) تستخدم ذلك الافتراضي. default يصل إلى كل فئة، بما في ذلك الفئات الصحيحة بحكم البناء (integrity وtamper)، لذا فإن { default: 'none' } عملية بناء غير كاسرة حقًا، للقياس عن بُعد فقط:
vmDefenseReaction: { default: 'none' } // never break — pair with vmDefenseHook
vmDefenseReaction: { automation: 'none', domain: 'break' } // tolerate automation FPs, still break on a bad domain
vmStatefulOpcodes
Type: boolean Default: false
يجعل معاني أكواد العمليات تعتمد على الموضع في البايت كود. لكل موضع تعيين مختلف من كود العملية إلى المعالِج مشتق من بذرة، بحيث يؤدي رقم كود العملية نفسه عمليات مختلفة في مواضع مختلفة.
vmCallContextOpcodes
Type: boolean Default: false
يجعل الدالة المحمية تعتمد على المكان الذي تُستدعى منه، بحيث لا يمكن انتزاعها من الكود وتشغيلها أو تحليلها بمفردها — فهي لا تتصرف بشكل صحيح إلا عند استدعائها عبر مواضع استدعائها الحقيقية في البرنامج. يؤثّر هذا الخيار في أداء التشغيل.
يُدعَم حاليًا فقط التركيبات التالية:
- تصريحات الدوال (
function f() {})؛ - تعبيرات الدوال والدوال السهمية المُسنَدة إلى متغير (
const f = () => {})؛ - التوابع الخاصة للنسخ (
this.#m()).
في كل حالة، يجب أن يُوصَل إلى الدالة دائمًا عبر استدعاء مباشر (f()، this.#m()). فإذا خُزِّنت في متغير آخر، أو مُرِّرت كوسيط، أو استُخدمت بأي طريقة أخرى كقيمة، فتُترَك دون حماية. الدوال غير المتزامنة مدعومة؛ أما المولِّدات فلا.
هذا الخيار تجريبي وقد يعطّل عمل كودك، فاختبر الناتج جيدًا قبل استخدامه.
vmStackEncoding
Type: boolean Default: false
يشفّر القيم على مكدس VM أثناء التنفيذ. تُرمَّز القيم عند دفعها وتُفكّ ترميزها عند سحبها، بحيث يُظهر فحص الذاكرة بيانات مشفَّرة بدلًا من القيم الفعلية.
يؤثّر هذا الخيار في الأداء تأثيرًا كبيرًا.
vmCompactDispatcher
Type: boolean Default: false
يستخدم منفِّذ VM واحدًا بدلًا من منفِّذين مزدوجين (متزامن + مولِّد). يقلّل حجم الكود المشوَّش لكنه يضيف حِملًا على الأداء بنحو 20% في الكود كثير التعاود.
false(افتراضي): منفِّذان مزدوجان — أداء مثالي، ناتج أكبرtrue: منفِّذ واحد — ناتج أصغر، أبطأ قليلًا
vmStringArrayBytecodeOnly
Type: boolean Default: false
عند التفعيل، ستستخرج مصفوفة النصوص النصوص من بيانات البايت كود فقط — ولا تُحوَّل أي نصوص أخرى في الكود. وهذا يفعّل stringArray قسرًا حتى لو لم يُضبَط صراحةً.
لماذا تستخدمه: استخراج كل نصوص بيئة تشغيل VM إلى مصفوفة نصوص بطيء. يستهدف هذا الخيار محتوى البايت كود فقط لاستخراج مصفوفة النصوص، مما يحسّن الأداء مع الاستمرار في حماية ثوابت البايت كود.
- عند
vmBytecodeArrayEncoding: false— تُستخرَج النصوص داخل مجمّعات ثوابت البايت كود (مصفوفاتc) - عند
vmBytecodeArrayEncoding: true— تُستخرَج نصوص البايت كود المُرمَّزة بـ base64 على المستوى الأعلى - لا يزال
stringArrayThresholdيتحكم في نسبة نصوص البايت كود تلك التي تُستخرَج
vmDomainLock
Type: string[] Default: []
⚠️ لا يعمل هذا الخيار مع target: 'node' أو target: 'service-worker' أو target: 'bytenode'
يقصر الكود المشوَّش على نطاقات و/أو نطاقات فرعية بعينها، وهو أصعب بكثير في تحديد موضعه وإزالته من domainLock.
إذا لم يُشغَّل الكود المصدري على النطاقات المحددة بهذا الخيار، فسيُعاد توجيه المتصفح إلى عنوان URL المُمرَّر إلى vmDomainLockRedirectUrl، وستُعيد الاستدعاءات المحمية اللاحقة نتائج غير صحيحة حتى لو كُبِت إعادة التوجيه.
نطاقات ونطاقات فرعية متعددة
يمكن قفل كودك على أكثر من نطاق أو نطاق فرعي. فمثلًا، لقفله بحيث لا يعمل الكود إلا على www.example.com أضف www.example.com. ولجعله يعمل على النطاق الجذري بما في ذلك أي نطاقات فرعية (example.com وsub.example.com)، استخدم .example.com.
vmDomainLockRedirectUrl
Type: string Default: about:blank
⚠️ لا يعمل هذا الخيار مع target: 'node' أو target: 'service-worker' أو target: 'bytenode'
يتيح إعادة توجيه المتصفح إلى عنوان URL مُمرَّر إذا لم يُشغَّل الكود المصدري على النطاقات المحددة بواسطة vmDomainLock.
Preset Options
تشويش عالٍ، أداء منخفض
سيكون الأداء أبطأ بكثير مما هو عليه دون تشويش
{
compact: true,
controlFlowFlattening: true,
controlFlowFlatteningThreshold: 1,
deadCodeInjection: true,
deadCodeInjectionThreshold: 1,
debugProtection: true,
debugProtectionInterval: 4000,
disableConsoleOutput: true,
identifierNamesGenerator: 'hexadecimal',
log: false,
numbersToExpressions: true,
renameGlobals: false,
selfDefending: true,
simplify: true,
splitStrings: true,
splitStringsChunkLength: 5,
strictMode: null,
stringArray: true,
stringArrayCallsTransform: true,
stringArrayEncoding: ['rc4'],
stringArrayIndexShift: true,
stringArrayRotate: true,
stringArrayShuffle: true,
stringArrayWrappersCount: 5,
stringArrayWrappersChainedCalls: true,
stringArrayWrappersParametersMaxCount: 5,
stringArrayWrappersType: 'function',
stringArrayThreshold: 1,
transformObjectKeys: true
}
تشويش متوسط، أداء مثالي
سيكون الأداء أبطأ مما هو عليه دون تشويش
{
compact: true,
controlFlowFlattening: true,
controlFlowFlatteningThreshold: 0.75,
deadCodeInjection: true,
deadCodeInjectionThreshold: 0.4,
debugProtection: false,
debugProtectionInterval: 0,
disableConsoleOutput: true,
identifierNamesGenerator: 'hexadecimal',
log: false,
numbersToExpressions: true,
renameGlobals: false,
selfDefending: true,
simplify: true,
splitStrings: true,
splitStringsChunkLength: 10,
strictMode: null,
stringArray: true,
stringArrayCallsTransform: true,
stringArrayCallsTransformThreshold: 0.75,
stringArrayEncoding: ['base64'],
stringArrayIndexShift: true,
stringArrayRotate: true,
stringArrayShuffle: true,
stringArrayWrappersCount: 2,
stringArrayWrappersChainedCalls: true,
stringArrayWrappersParametersMaxCount: 4,
stringArrayWrappersType: 'function',
stringArrayThreshold: 0.75,
transformObjectKeys: true
}
تشويش منخفض، أداء عالٍ
سيكون الأداء عند مستوى طبيعي نسبيًا
{
compact: true,
controlFlowFlattening: false,
deadCodeInjection: false,
debugProtection: false,
debugProtectionInterval: 0,
disableConsoleOutput: true,
identifierNamesGenerator: 'hexadecimal',
log: false,
numbersToExpressions: false,
renameGlobals: false,
selfDefending: true,
simplify: true,
splitStrings: false,
strictMode: null,
stringArray: true,
stringArrayCallsTransform: false,
stringArrayEncoding: [],
stringArrayIndexShift: true,
stringArrayRotate: true,
stringArrayShuffle: true,
stringArrayWrappersCount: 1,
stringArrayWrappersChainedCalls: true,
stringArrayWrappersParametersMaxCount: 2,
stringArrayWrappersType: 'variable',
stringArrayThreshold: 0.75
}
الإعداد المسبق الافتراضي، أداء عالٍ
{
compact: true,
controlFlowFlattening: false,
deadCodeInjection: false,
debugProtection: false,
debugProtectionInterval: 0,
disableConsoleOutput: false,
identifierNamesGenerator: 'hexadecimal',
log: false,
numbersToExpressions: false,
renameGlobals: false,
selfDefending: false,
simplify: true,
splitStrings: false,
strictMode: null,
stringArray: true,
stringArrayCallsTransform: false,
stringArrayCallsTransformThreshold: 0.5,
stringArrayEncoding: [],
stringArrayIndexShift: true,
stringArrayRotate: true,
stringArrayShuffle: true,
stringArrayWrappersCount: 1,
stringArrayWrappersChainedCalls: true,
stringArrayWrappersParametersMaxCount: 2,
stringArrayWrappersType: 'variable',
stringArrayThreshold: 0.75
}
تشويش VM فائق العلو (أقصى أمان)
يفعّل هذا الإعداد المسبق تشويش البايت كود القائم على VM مع كل ميزات التصليب بما في ذلك الإرسال غير المباشر. يوفّر أقوى حماية لكن بحجم ناتج أكبر وتنفيذ أبطأ بكثير.
{
optionsPreset: 'vm-ultra-high-obfuscation'
}
أو اضبط الخيارات بشكل فردي:
{
compact: true,
simplify: true,
identifierNamesGenerator: 'mangled-shuffled',
vmObfuscation: true,
vmForceCompileDynamicCode: false,
vmWrapTopLevelInitializers: true,
vmDynamicOpcodes: true,
vmBytecodeEncoding: true,
vmBytecodeArrayEncoding: true,
vmBytecodeArrayEncodingKey: '',
vmBytecodeArrayEncodingKeyGetter: '',
vmAsyncExecutor: false,
vmJumpsEncoding: true,
vmMacroOps: true,
vmDebugProtection: true,
vmSelfDefending: true,
vmDefenseHook: '',
vmDefenseReaction: {
automation: 'break',
debugger: 'decoy',
sandbox: 'decoy',
domain: 'break',
tamper: 'break',
integrity: 'break'
},
vmStatefulOpcodes: true,
vmCallContextOpcodes: false,
vmStackEncoding: true,
vmCompactDispatcher: true,
controlFlowFlattening: true,
controlFlowFlatteningThreshold: 0.5,
deadCodeInjection: true,
deadCodeInjectionThreshold: 0.5,
debugProtection: true,
debugProtectionInterval: 4000,
disableConsoleOutput: true,
identifierNamesGenerator: 'hexadecimal',
log: false,
numbersToExpressions: true,
renameGlobals: false,
selfDefending: true,
simplify: true,
splitStrings: true,
splitStringsChunkLength: 5,
strictMode: null,
stringArray: true,
stringArrayCallsTransform: true,
stringArrayEncoding: ['rc4'],
stringArrayIndexShift: true,
stringArrayRotate: true,
stringArrayShuffle: true,
stringArrayWrappersCount: 5,
stringArrayWrappersChainedCalls: true,
stringArrayWrappersParametersMaxCount: 5,
stringArrayWrappersType: 'function',
stringArrayThreshold: 0.5,
transformObjectKeys: true
}
VM المضاد لنماذج LLM (حماية من وكلاء الذكاء الاصطناعي)
صُمِّم هذا الإعداد المسبق خصيصًا لمنع وكلاء الذكاء الاصطناعي ونماذج LLM من إجراء هندسة عكسية على الكود المُرمَّز ببايت كود VM. يستند إلى vm-default مع تفعيل الدفاع الذاتي وحماية التنقيح. أخف من vm-high-obfuscation لكنه مصلَّب خصيصًا ضد التحليل الآلي.
{
optionsPreset: 'vm-anti-llm'
}
يشمل:
- تشويش بايت كود VM مع مصفوفة النصوص (من
vm-default) vmSelfDefending— كشف الاعتراض، وتجزئة السلامة، وبصمة المصدر، والتحقق عبر عالَم iframe نظيف، واشتقاق مفتاح شيفرة ARXvmDebugProtection— فحوصات مضادة للتنقيح في حلقة إرسال VMdebugProtection: false— لا حماية تنقيح قديمة (حماية تنقيح VM أفضل)
تشويش VM العالي (أعلى أمان)
يفعّل هذا الإعداد المسبق تشويش البايت كود القائم على VM مع معظم ميزات التصليب. يوفّر حماية قوية بأداء أفضل من الإعداد المسبق فائق العلو.
{
optionsPreset: 'vm-high-obfuscation'
}
أو اضبط الخيارات بشكل فردي:
{
compact: true,
simplify: true,
identifierNamesGenerator: 'mangled-shuffled',
vmObfuscation: true,
vmForceCompileDynamicCode: false,
vmWrapTopLevelInitializers: true,
vmDynamicOpcodes: true,
vmBytecodeEncoding: true,
vmBytecodeArrayEncoding: true,
vmBytecodeArrayEncodingKey: '',
vmBytecodeArrayEncodingKeyGetter: '',
vmAsyncExecutor: false,
vmJumpsEncoding: true,
vmMacroOps: true,
vmDebugProtection: true,
vmSelfDefending: true,
vmDefenseHook: '',
vmDefenseReaction: {
automation: 'break',
debugger: 'decoy',
sandbox: 'decoy',
domain: 'break',
tamper: 'break',
integrity: 'break'
},
vmStatefulOpcodes: true,
vmCallContextOpcodes: false,
vmStackEncoding: true,
vmCompactDispatcher: false
}
تشويش VM المتوسط (أمان متوازن)
يفعّل هذا الإعداد المسبق تشويش البايت كود القائم على VM مع مجموعة متوازنة من ميزات التصليب. حل وسط جيد بين الأمان والأداء.
{
optionsPreset: 'vm-medium-obfuscation'
}
أو اضبط الخيارات بشكل فردي:
{
compact: true,
simplify: true,
identifierNamesGenerator: 'mangled-shuffled',
vmObfuscation: true,
vmForceCompileDynamicCode: false,
vmWrapTopLevelInitializers: true,
vmDynamicOpcodes: true,
vmBytecodeEncoding: true,
vmBytecodeArrayEncoding: false,
vmBytecodeArrayEncodingKey: '',
vmBytecodeArrayEncodingKeyGetter: '',
vmAsyncExecutor: false,
vmJumpsEncoding: true,
vmMacroOps: true,
vmDebugProtection: true,
vmSelfDefending: false,
vmDefenseHook: '',
vmDefenseReaction: {
automation: 'break',
debugger: 'decoy',
sandbox: 'decoy',
domain: 'break',
tamper: 'break',
integrity: 'break'
},
vmStatefulOpcodes: false,
vmCallContextOpcodes: false,
vmStackEncoding: false,
vmCompactDispatcher: false
}
تشويش VM المنخفض (أمان أساسي، أداء أفضل)
يفعّل هذا الإعداد المسبق تشويش بايت كود VM الأساسي دون ميزات تصليب إضافية. توازن جيد بين الأمان وحجم الناتج.
{
optionsPreset: 'vm-low-obfuscation'
}
أو اضبط الخيارات بشكل فردي:
{
compact: true,
simplify: true,
identifierNamesGenerator: 'mangled-shuffled',
vmObfuscation: true,
vmForceCompileDynamicCode: false,
vmWrapTopLevelInitializers: true,
vmDynamicOpcodes: false,
vmBytecodeEncoding: false,
vmBytecodeArrayEncoding: false,
vmBytecodeArrayEncodingKey: '',
vmBytecodeArrayEncodingKeyGetter: '',
vmAsyncExecutor: false,
vmJumpsEncoding: false,
vmMacroOps: false,
vmDebugProtection: false,
vmSelfDefending: false,
vmDefenseHook: '',
vmDefenseReaction: {
automation: 'break',
debugger: 'decoy',
sandbox: 'decoy',
domain: 'break',
tamper: 'break',
integrity: 'break'
},
vmStatefulOpcodes: false,
vmCallContextOpcodes: false,
vmStackEncoding: false,
vmCompactDispatcher: false
}
VM الافتراضي (VM + حماية مصفوفة النصوص)
يجمع هذا الإعداد المسبق بين تشويش البايت كود الأساسي القائم على VM وحماية مصفوفة النصوص. نقطة بداية جيدة لتشويش VM مع حماية النصوص.
{
optionsPreset: 'vm-default'
}
أو اضبط الخيارات بشكل فردي:
{
compact: true,
simplify: true,
identifierNamesGenerator: 'mangled-shuffled',
vmObfuscation: true,
vmForceCompileDynamicCode: false,
vmWrapTopLevelInitializers: true,
vmDynamicOpcodes: true,
vmBytecodeEncoding: false,
vmBytecodeArrayEncoding: true,
vmStringArrayBytecodeOnly: true,
vmAsyncExecutor: false,
vmJumpsEncoding: false,
vmMacroOps: false,
vmDebugProtection: false,
vmSelfDefending: false,
vmDefenseHook: '',
vmDefenseReaction: {
automation: 'break',
debugger: 'decoy',
sandbox: 'decoy',
domain: 'break',
tamper: 'break',
integrity: 'break'
},
vmStatefulOpcodes: false,
vmCallContextOpcodes: false,
vmStackEncoding: false,
vmCompactDispatcher: false,
stringArray: true,
stringArrayRotate: true,
stringArrayShuffle: true,
stringArrayThreshold: 1,
stringArrayIndexShift: true,
stringArrayIndexesType: ['hexadecimal-number'],
stringArrayCallsTransform: true,
stringArrayCallsTransformThreshold: 1,
stringArrayWrappersCount: 3,
stringArrayWrappersType: 'function',
stringArrayWrappersParametersMaxCount: 5,
stringArrayWrappersChainedCalls: true,
stringArrayEncoding: ['base64'],
splitStrings: true,
splitStringsChunkLength: 6
}
