Dokumentacja opcji
Spis treści
compact
config
controlFlowFlattening
controlFlowFlatteningThreshold
deadCodeInjection
deadCodeInjectionThreshold
debugProtection
debugProtectionInterval
disableConsoleOutput
domainLock
Wiele domen i subdomen
domainLockRedirectUrl
exclude
forceTransformStrings
identifierNamesCache
Node.js API
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
Wiele domen i subdomen
vmDomainLockRedirectUrl
Preset Options
Wysoka obfuskacja, niska wydajność
Średnia obfuskacja, optymalna wydajność
Niska obfuskacja, wysoka wydajność
Preset domyślny, wysoka wydajność
VM Ultra High – bardzo wysoka obfuskacja (maksymalne bezpieczeństwo)
VM Anti-LLM (ochrona przed agentami AI)
VM High – wysoka obfuskacja (najwyższe bezpieczeństwo)
VM Medium – średnia obfuskacja (zrównoważone bezpieczeństwo)
VM Low – niska obfuskacja (podstawowe bezpieczeństwo, lepsza wydajność)
VM Default (VM + ochrona tablicą ciągów)
compact
Type: boolean Default: true
Kompaktowy kod wynikowy w jednej linii.
config
Type: string Default: ``
Nazwa pliku konfiguracyjnego JS/JSON zawierającego opcje obfuskatora. Zostaną one nadpisane przez opcje przekazane bezpośrednio do CLI
controlFlowFlattening
Type: boolean Default: false
⚠️ Ta opcja znacząco wpływa na wydajność – szybkość działania może spaść nawet 1,5-krotnie. Za pomocą opcji controlFlowFlatteningThreshold można ustawić procent węzłów, których dotyczy spłaszczanie przepływu sterowania.
Włącza spłaszczanie przepływu sterowania w kodzie. Spłaszczanie przepływu sterowania to transformacja struktury kodu źródłowego, która utrudnia zrozumienie programu.
Przykład:
// 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
Prawdopodobieństwo, że transformacja controlFlowFlattening zostanie zastosowana do danego węzła.
To ustawienie jest szczególnie przydatne przy dużym rozmiarze kodu, ponieważ duża liczba transformacji przepływu sterowania może spowolnić kod i zwiększyć jego rozmiar.
controlFlowFlatteningThreshold: 0 jest równoznaczne z controlFlowFlattening: false.
deadCodeInjection
Type: boolean Default: false
⚠️ Drastycznie zwiększa rozmiar zobfuskowanego kodu (nawet o 200%) – należy stosować tylko wtedy, gdy rozmiar zobfuskowanego kodu nie ma znaczenia. Za pomocą opcji deadCodeInjectionThreshold można ustawić procent węzłów, których dotyczy wstrzykiwanie martwego kodu.
⚠️ Ta opcja wymusza włączenie opcji stringArray.
⚠️ Ta opcja jest po cichu wyłączana, gdy włączona jest opcja vmObfuscation.
Przy tej opcji do zobfuskowanego kodu dodawane są losowe bloki martwego kodu.
Przykład:
// 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
Pozwala ustawić procent węzłów, których dotyczy deadCodeInjection.
debugProtection
Type: boolean Default: false
⚠️ Może zawiesić przeglądarkę po otwarciu narzędzi deweloperskich.
⚠️ Ta opcja jest po cichu wyłączana, gdy włączona jest opcja vmObfuscation. Należy wtedy użyć opcji vmDebugProtection.
Ta opcja sprawia, że korzystanie z funkcji debugger w narzędziach deweloperskich staje się niemal niemożliwe (zarówno w przeglądarkach opartych na WebKit, jak i w Mozilla Firefox).
debugProtectionInterval
Type: number Default: 0
⚠️ Może zawiesić przeglądarkę! Stosowanie na własne ryzyko.
⚠️ Ta opcja jest po cichu wyłączana, gdy włączona jest opcja vmObfuscation. Należy wtedy użyć opcji vmDebugProtection.
Jeśli ta opcja jest ustawiona, wykorzystywany jest interwał w milisekundach wymuszający tryb debugowania w karcie Console, co utrudnia korzystanie z pozostałych funkcji narzędzi deweloperskich. Działa, gdy włączona jest opcja debugProtection. Zalecana wartość mieści się w przedziale od 2000 do 4000 milisekund.
disableConsoleOutput
Type: boolean Default: false
⚠️ Ta opcja globalnie wyłącza wywołania console dla wszystkich skryptów
Wyłącza możliwość korzystania z console.log, console.info, console.error, console.warn, console.debug, console.exception i console.trace, zastępując je pustymi funkcjami. Utrudnia to korzystanie z debuggera.
domainLock
Type: string[] Default: []
⚠️ Ta opcja nie działa z target: 'node', target: 'service-worker' ani target: 'bytenode'
Pozwala uruchamiać zobfuskowany kod źródłowy wyłącznie w określonych domenach i/lub subdomenach. Bardzo utrudnia to skopiowanie kodu źródłowego i uruchomienie go w innym miejscu.
Jeśli kod źródłowy nie jest uruchamiany w domenach wskazanych w tej opcji, przeglądarka zostanie przekierowana pod adres URL przekazany w opcji domainLockRedirectUrl.
Wiele domen i subdomen
Kod można zablokować do więcej niż jednej domeny lub subdomeny. Na przykład, aby zablokować go tak, by działał wyłącznie w www.example.com, należy dodać www.example.com. Aby działał w domenie głównej wraz ze wszystkimi subdomenami (example.com, sub.example.com), należy użyć .example.com.
domainLockRedirectUrl
Type: string Default: about:blank
⚠️ Ta opcja nie działa z target: 'node', target: 'service-worker' ani target: 'bytenode'
Pozwala przekierować przeglądarkę pod przekazany adres URL, jeśli kod źródłowy nie jest uruchamiany w domenach wskazanych w opcji domainLock
exclude
Type: string[] Default: []
Nazwy plików lub wzorce glob wskazujące pliki wykluczone z obfuskacji.
forceTransformStrings
Type: string[] Default: []
Włącza wymuszoną transformację literałów tekstowych pasujących do przekazanych wzorców RegExp.
⚠️ Ta opcja dotyczy wyłącznie ciągów, które nie powinny zostać przekształcone zgodnie z opcją stringArrayThreshold (lub, być może, innymi progami w przyszłości)
Opcja ma priorytet nad opcją reservedStrings, ale nie ma priorytetu nad conditional comments.
Przykład:
{
forceTransformStrings: [
'some-important-value',
'some-string_\d'
]
}
identifierNamesCache
Type: Object | null Default: null
Głównym celem tej opcji jest możliwość używania tych samych nazw identyfikatorów podczas obfuskacji wielu źródeł/plików.
Obecnie obsługiwane są dwa rodzaje identyfikatorów:
- Identyfikatory globalne:
- wszystkie identyfikatory globalne zostaną zapisane w pamięci podręcznej;
- wszystkie dopasowane niezadeklarowane identyfikatory globalne zostaną zastąpione wartościami z pamięci podręcznej.
- Identyfikatory właściwości, tylko gdy włączona jest opcja
renameProperties:- wszystkie identyfikatory właściwości zostaną zapisane w pamięci podręcznej;
- wszystkie dopasowane identyfikatory właściwości zostaną zastąpione wartościami z pamięci podręcznej.
Node.js API
Przekazanie wartości null całkowicie wyłącza pamięć podręczną.
Przekazanie pustego obiektu ({}) włącza zapisywanie nazw identyfikatorów do obiektu pamięci podręcznej (typ TIdentifierNamesCache). Dostęp do tego obiektu uzyskuje się przez wywołanie metody getIdentifierNamesCache obiektu ObfuscationResult.
Powstały obiekt pamięci podręcznej można następnie przekazać jako wartość opcji identifierNamesGenerator, aby użyć tych nazw podczas obfuskacji wszystkich dopasowanych nazw identyfikatorów w kolejnych źródłach.
Przykład:
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 udostępnia inną opcję – --identifier-names-cache-path – która pozwala wskazać ścieżkę do istniejącego pliku .json używanego do odczytu i zapisu pamięci podręcznej nazw identyfikatorów.
Jeśli zostanie przekazana ścieżka do pustego pliku, pamięć podręczna nazw identyfikatorów zostanie zapisana do tego pliku.
Ten plik z istniejącą pamięcią podręczną można ponownie wykorzystać jako wartość opcji --identifier-names-cache-path, aby użyć tych nazw podczas obfuskacji wszystkich dopasowanych nazw identyfikatorów w kolejnych plikach.
identifierNamesGenerator
Type: string Default: hexadecimal
Ustawia generator nazw identyfikatorów.
Dostępne wartości:
dictionary: nazwy identyfikatorów z listyidentifiersDictionaryhexadecimal: nazwy identyfikatorów w rodzaju_0xabc123mangled: krótkie nazwy identyfikatorów, takie jaka,b,cmangled-shuffled: to samo comangled, ale z przetasowanym alfabetem
identifiersDictionary
Type: string[] Default: []
Ustawia słownik identyfikatorów dla opcji identifierNamesGenerator: dictionary. Każdy identyfikator ze słownika zostanie użyty w kilku wariantach różniących się wielkością poszczególnych znaków. Liczba identyfikatorów w słowniku powinna zatem zależeć od liczby identyfikatorów w oryginalnym kodzie źródłowym.
identifiersPrefix
Type: string Default: ''
Ustawia prefiks dla wszystkich identyfikatorów globalnych.
Tej opcji należy używać przy obfuskacji wielu plików. Pomaga ona uniknąć konfliktów między identyfikatorami globalnymi tych plików. Prefiks powinien być inny dla każdego pliku.
randomIdentifiersPrefix
Type: boolean Default: false
Dodaje do wszystkich identyfikatorów globalnych losowy prefiks (6 znaków alfanumerycznych) generowany na podstawie ziarna. Tej opcji należy używać, aby uniknąć kolizji między osobno zobfuskowanymi bundle’ami ładowanymi do tego samego zasięgu globalnego — dzięki niej nie trzeba ręcznie dobierać unikalnej wartości identifiersPrefix dla każdego bundle’a.
- Wartość losowa jest wyprowadzana z opcji
seedoraz skrótu kodu źródłowego, więc powtarzalne kompilacje z tym samym ziarnem dają ten sam prefiks. - W połączeniu z
identifiersPrefixlosowe znaki są dopisywane na końcu prefiksu podanego przez użytkownika (np.myApp+ losoweaBc123→myAppaBc123). - W połączeniu z
vmObfuscationwartość losowa zastępuje domyślny prefiksvm— losowość i tak gwarantuje unikalność.
ignoreImports
Type: boolean Default: false
Zapobiega obfuskacji importów require. Może się przydać w sytuacjach, gdy środowisko uruchomieniowe z jakiegoś powodu wymaga, aby te importy zawierały wyłącznie statyczne ciągi znaków.
inputFileName
Type: string Default: ''
Pozwala ustawić nazwę pliku wejściowego z kodem źródłowym. Nazwa ta będzie używana wewnętrznie podczas generowania mapy źródeł.
Wymagana przy korzystaniu z API NodeJS, gdy opcja sourceMapSourcesMode ma wartość sources.
log
Type: boolean Default: false
Włącza wypisywanie informacji do konsoli.
numbersToExpressions
Type: boolean Default: false
Włącza zamianę liczb na wyrażenia
Przykład:
// input
const foo = 1234;
// output
const foo=-0xd93+-0x10b4+0x41*0x67+0x84e*0x3+-0xff8;
optionsPreset
Type: string Default: default
Pozwala ustawić preset opcji.
Dostępne wartości:
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.
Wszystkie dodatkowe opcje zostaną scalone z wybranym presetem opcji.
parseHtml
Type: boolean Default: false
Włącza obfuskację kodu JavaScript wewnątrz znaczników <script> w plikach HTML.
Po włączeniu obfuskator:
- Automatycznie wykrywa, czy wejście jest kodem HTML (sprawdzając znaczniki
<!DOCTYPE,<html>,<head>,<body>lub<script>) - Wyodrębnia kod JavaScript ze znaczników
<script>oznaczonych atrybutemdata-javascript-obfuscator - Obfuskuje każdy oznaczony skrypt osobno, zachowując strukturę HTML
- Wstawia zobfuskowany kod z powrotem w pierwotne miejsca
Ważne: obfuskowane są wyłącznie skrypty z atrybutem data-javascript-obfuscator. Każdy oznaczony skrypt jest obfuskowany osobno i niezależnie. Oznacza to, że:
- Kod wewnątrz oznaczonych znaczników skryptu musi być odizolowany – nie może odwoływać się do zmiennych, funkcji ani klas zdefiniowanych w innych oznaczonych znacznikach skryptu
- Nieoznaczone skrypty nadal mają dostęp do zmiennych globalnych zdefiniowanych przez oznaczone skrypty (przez deklaracje
varlub jawne przypisania doglobalThis) - Daje to jawną kontrolę nad tym, które skrypty są chronione
Obfuskowane (muszą mieć atrybut data-javascript-obfuscator):
<script data-javascript-obfuscator>– zwykłe skrypty<script type="text/javascript" data-javascript-obfuscator>– skrypty z jawnie podanym typem- Skrypty z dowolnymi dodatkowymi atrybutami (
id,class, innedata-*itd.)
Pomijane (pozostają bez zmian):
- Skrypty bez atrybutu
data-javascript-obfuscator <script type="module">– moduły ES (nawet z tym atrybutem)<script src="...">– skrypty zewnętrzne (nawet z tym atrybutem)- Puste znaczniki skryptu
Uwaga: przy włączonej opcji parseHtml mapy źródeł nie są generowane, ponieważ nie odwzorowywałyby poprawnie wyniku w formacie HTML.
Przykład:
// 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
⚠️ ta opcja może zepsuć kod. Należy ją włączać tylko wtedy, gdy wiadomo, do czego służy!
Włącza obfuskację nazw zmiennych i funkcji globalnych wraz z deklaracją.
Gdy ta opcja jest wyłączona, a kod wejściowy deklaruje funkcje lub klasy w zasięgu globalnym (tzn. nie jest opakowany w IIFE), ich nazwy pozostają w zobfuskowanym wyniku bez zmian — inne skrypty mogą odwoływać się do nich po nazwie. Przy włączonej opcji vmObfuscation zgłaszane jest ostrzeżenie VMGlobalFunctionNamesNotRenamed z listą tych nazw, ponieważ ciało funkcji jest ukryte w postaci kodu bajtowego, ale czytelna nazwa najwyższego poziomu nadal zdradza, co robi kod (np. modelowi LLM). Aby uniknąć tego ujawnienia, należy opakować kod w IIFE albo włączyć tę opcję.
renameProperties
Type: boolean Default: false
⚠️ ta opcja MOŻE zepsuć kod. Należy ją włączać tylko wtedy, gdy wiadomo, do czego służy!
Włącza zmianę nazw właściwości. Wszystkie wbudowane właściwości DOM oraz właściwości podstawowych klas JavaScriptu zostaną pominięte.
Do przełączania między trybem safe i unsafe tej opcji służy opcja renamePropertiesMode.
Format zmienionych nazw właściwości ustawia się opcją identifierNamesGenerator.
Tym, którym właściwościom zostaną zmienione nazwy, steruje opcja reservedNames.
Przykład:
// 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
⚠️ Nawet w trybie safe opcja renameProperties MOŻE zepsuć kod.
Określa tryb opcji renameProperties:
safe– domyślne zachowanie po wydaniu2.11.0. Próbuje zmieniać nazwy właściwości w bezpieczniejszy sposób, aby zapobiec błędom w czasie wykonania. W tym trybie część właściwości zostanie wykluczona ze zmiany nazw.unsafe– domyślne zachowanie przed wydaniem2.11.0. Zmienia nazwy właściwości w niebezpieczny sposób, bez żadnych ograniczeń.
Jeśli jeden plik korzysta z właściwości pochodzących z innego pliku, należy użyć opcji identifierNamesCache, aby zachować te same nazwy właściwości w obu plikach.
reservedNames
Type: string[] Default: []
Wyłącza obfuskację i generowanie identyfikatorów pasujących do przekazanych wzorców RegExp.
Przykład:
{
reservedNames: [
'^someVariable',
'functionParameter_\d'
]
}
reservedStrings
Type: string[] Default: []
Wyłącza transformację literałów tekstowych pasujących do przekazanych wzorców RegExp. Dopasowane ciągi pozostaną widoczne w zobfuskowanym wyniku.
Przy obfuskacji VM zarezerwowane ciągi są przechowywane w osobnej, niezaszyfrowanej tablicy, aby pozostały widoczne. Jest to przydatne dla ciągów, które muszą pozostać czytelne, takich jak adresy endpointów API używanych do monitorowania czy identyfikatory bibliotek.
Przykład:
{
reservedStrings: [
'react-native',
'\.\/src\/test',
'some-string_\d'
]
}
seed
Type: string|number Default: 0
Ta opcja ustawia ziarno (seed) generatora liczb losowych. Przydaje się do uzyskiwania powtarzalnych wyników.
Jeśli ziarno wynosi 0, generator liczb losowych działa bez ziarna.
selfDefending
Type: boolean Default: false
⚠️ Po obfuskacji z tą opcją nie wolno w żaden sposób modyfikować zobfuskowanego kodu, ponieważ każda zmiana, na przykład minifikacja, może uruchomić mechanizm samoobrony i kod przestanie działać!
⚠️ Ta opcja wymusza ustawienie wartości compact na true
⚠️ Ta opcja jest po cichu wyłączana, gdy włączona jest opcja vmObfuscation. Należy wtedy użyć opcji vmSelfDefending.
Ta opcja sprawia, że kod wynikowy jest odporny na formatowanie i zmianę nazw zmiennych. Jeśli ktoś spróbuje użyć na zobfuskowanym kodzie narzędzia upiększającego JavaScript, kod przestanie działać, co utrudnia jego zrozumienie i modyfikację.
simplify
Type: boolean Default: true
Włącza dodatkową obfuskację kodu poprzez upraszczanie.
⚠️ w przyszłych wydaniach obfuskacja literałów boolean (true => !![]) zostanie przeniesiona pod tę opcję.
Przykład:
// 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
Włącza generowanie mapy źródeł dla zobfuskowanego kodu.
Mapy źródeł ułatwiają debugowanie zobfuskowanego kodu źródłowego JavaScript. Jeśli konieczne jest debugowanie na produkcji, osobny plik mapy źródeł można umieścić w niejawnej lokalizacji, a następnie wskazać ją przeglądarce.
sourceMapBaseUrl
Type: string Default: ``
Ustawia bazowy adres URL dla adresu importu mapy źródeł przy sourceMapMode: 'separate'.
Przykład CLI:
javascript-obfuscator input.js --output out.js --source-map true --source-map-base-url 'http://localhost:9000'
Wynik:
//# sourceMappingURL=http://localhost:9000/out.js.map
sourceMapFileName
Type: string Default: ``
Ustawia nazwę pliku wynikowej mapy źródeł przy sourceMapMode: 'separate'.
Przykład CLI:
javascript-obfuscator input.js --output out.js --source-map true --source-map-base-url 'http://localhost:9000' --source-map-file-name example
Wynik:
//# sourceMappingURL=http://localhost:9000/example.js.map
sourceMapMode
Type: string Default: separate
Określa tryb generowania mapy źródeł:
inline– dodaje mapę źródeł na końcu każdego pliku .js;separate– generuje odpowiadający plik '.map' z mapą źródeł. W przypadku uruchamiania obfuskatora przez CLI dodaje na końcu pliku z zobfuskowanym kodem odnośnik do pliku mapy źródeł//# sourceMappingUrl=file.js.map.
sourceMapSourcesMode
Type: string Default: sources-content
Pozwala sterować polami sources i sourcesContent mapy źródeł:
sources-content– dodaje atrapę polasourcesoraz polesourcesContentz oryginalnym kodem źródłowym;sources– dodaje polesourcesz poprawnym opisem źródeł i nie dodaje polasourcesContent. Przy korzystaniu z API NodeJS wymagane jest zdefiniowanie opcjiinputFileName, której wartość zostanie użyta jako wartość polasources.
splitStrings
Type: boolean Default: false
Dzieli literały tekstowe na fragmenty o długości określonej wartością opcji splitStringsChunkLength.
Przykład:
// input
(function(){
var test = 'abcdefg';
})();
// output
(function(){
var _0x5a21 = 'ab' + 'cd' + 'ef' + 'g';
})();
splitStringsChunkLength
Type: number Default: 10
Ustawia długość fragmentu dla opcji splitStrings.
stringArray
Type: boolean Default: true
Usuwa literały tekstowe i umieszcza je w specjalnej tablicy. Na przykład ciąg "Hello World" w var m = "Hello World"; zostanie zastąpiony czymś w rodzaju var m = _0x12c456[0x1];
stringArrayCallsTransform
Type: boolean Default: false
⚠️ Opcja stringArray musi być włączona
Włącza transformację wywołań do stringArray. Wszystkie argumenty tych wywołań mogą zostać wyodrębnione do osobnego obiektu, w zależności od wartości opcji stringArrayCallsTransformThreshold.
Dzięki temu automatyczne wyszukiwanie wywołań tablicy ciągów staje się jeszcze trudniejsze.
Przykład:
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
⚠️ Opcje stringArray i stringArrayCallsTransformThreshold muszą być włączone
Za pomocą tego ustawienia można dostosować prawdopodobieństwo (od 0 do 1) przekształcenia wywołań tablicy ciągów.
stringArrayEncoding
Type: string[] Default: []
⚠️ Opcja stringArray musi być włączona
Ta opcja może spowolnić skrypt.
Koduje wszystkie literały tekstowe z stringArray przy użyciu base64 lub rc4 i wstawia specjalny kod, który dekoduje je z powrotem w czasie wykonania.
Każda wartość stringArray zostanie zakodowana losowo wybranym kodowaniem z przekazanej listy. Umożliwia to jednoczesne stosowanie wielu kodowań.
Dostępne wartości:
'none'(boolean): nie koduje wartościstringArray'base64'(string): koduje wartośćstringArrayprzy użyciubase64'rc4'(string): koduje wartośćstringArrayprzy użyciurc4. Około 30–50% wolniejsze niżbase64, ale trudniej odtworzyć pierwotne wartości.
Na przykład przy poniższych wartościach opcji część wartości stringArray nie zostanie zakodowana, a pozostałe zostaną zakodowane kodowaniem base64 oraz rc4:
stringArrayEncoding: [
'none',
'base64',
'rc4'
]
stringArrayIndexesType
Type: string[] Default: ['hexadecimal-number']
⚠️ Opcja stringArray musi być włączona
Pozwala sterować typem indeksów wywołań tablicy ciągów.
Każdy indeks wywołania stringArray zostanie przekształcony zgodnie z losowo wybranym typem z przekazanej listy. Umożliwia to jednoczesne stosowanie wielu typów.
Dostępne wartości:
'hexadecimal-number'(default): przekształca indeksy wywołań tablicy ciągów w liczby szesnastkowe'hexadecimal-numeric-string': przekształca indeksy wywołań tablicy ciągów w szesnastkowe ciągi liczbowe
Przed wydaniem 2.9.0 javascript-obfuscator przekształcał wszystkie indeksy wywołań tablicy ciągów zgodnie z typem hexadecimal-numeric-string. Utrudnia to nieco ręczną deobfuskację, ale pozwala automatycznym deobfuskatorom łatwo wykrywać takie wywołania.
Nowy typ hexadecimal-number ma na celu utrudnienie automatycznego wykrywania wzorców wywołań tablicy ciągów w kodzie.
W przyszłości zostaną dodane kolejne typy.
stringArrayIndexShift
Type: boolean Default: true
⚠️ Opcja stringArray musi być włączona
Włącza dodatkowe przesunięcie indeksu dla wszystkich wywołań tablicy ciągów
stringArrayRotate
Type: boolean Default: true
⚠️ Opcja stringArray musi być włączona
Przesuwa tablicę stringArray o stałą, losowo wyznaczoną (podczas obfuskacji kodu) liczbę pozycji. Utrudnia to dopasowanie kolejności usuniętych ciągów do ich pierwotnych miejsc.
stringArrayShuffle
Type: boolean Default: true
⚠️ Opcja stringArray musi być włączona
Losowo tasuje elementy tablicy stringArray.
stringArrayWrappersCount
Type: number Default: 1
⚠️ Opcja stringArray musi być włączona
Ustawia liczbę wrapperów dla string array wewnątrz zasięgu głównego oraz każdego zasięgu funkcji.
Faktyczna liczba wrapperów w danym zasięgu jest ograniczona liczbą węzłów literal w tym zasięgu.
Przykład:
// 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
⚠️ Opcje stringArray i stringArrayWrappersCount muszą być włączone
Włącza łańcuchowe wywołania między wrapperami string array.
Przykład:
// 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
⚠️ Opcja stringArray musi być włączona
⚠️ Obecnie ta opcja dotyczy wyłącznie wrapperów dodawanych przy wartości function opcji stringArrayWrappersType
Pozwala sterować maksymalną liczbą parametrów wrapperów tablicy ciągów.
Wartość domyślna i minimalna to 2. Zalecana wartość mieści się w przedziale od 2 do 5.
stringArrayWrappersType
Type: string Default: variable
⚠️ Opcje stringArray i stringArrayWrappersCount muszą być włączone
Pozwala wybrać typ wrapperów dodawanych przez opcję stringArrayWrappersCount.
Dostępne wartości:
'variable': dodaje wrappery w postaci zmiennych na początku każdego zasięgu. Wysoka wydajność.'function': dodaje wrappery w postaci funkcji w losowych miejscach wewnątrz każdego zasięgu. Wydajność niższa niż przyvariable, ale obfuskacja jest ostrzejsza.
Zdecydowanie zaleca się stosowanie wrapperów function dla silniejszej obfuskacji, o ile spadek wydajności nie ma dużego wpływu na zobfuskowaną aplikację.
Przykład dla wartości opcji '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
⚠️ Opcja stringArray musi być włączona
Za pomocą tego ustawienia można dostosować prawdopodobieństwo (od 0 do 1), że literał tekstowy zostanie umieszczony w stringArray.
To ustawienie jest szczególnie przydatne przy dużym rozmiarze kodu, ponieważ powoduje ono wielokrotne wywołania string array i może spowolnić kod.
stringArrayThreshold: 0 jest równoznaczne z stringArray: false.
strictMode
Type: boolean | null Default: null
Pozwala określić, jak obfuskator ma traktować kod w kontekście trybu ścisłego (strict mode) JavaScriptu.
Dostępne wartości:
null(domyślnie) – automatycznie wykrywa tryb ścisły na podstawie kodu. Jeśli kod zawiera jawną dyrektywę'use strict', składnię modułów ES lub metody klas, jest traktowany jako kod w trybie ścisłym. W przeciwnym razie zakładany jest tryb swobodny (sloppy mode).true– wymusza traktowanie całego kodu jako kodu w trybie ścisłym, nawet bez jawnej dyrektywy'use strict'. Należy stosować, gdy kod będzie uruchamiany w kontekście trybu ścisłego (np. w modułach ES, bundlerach lub nowoczesnych frameworkach).false– jako kod w trybie ścisłym traktowane są wyłącznie fragmenty z jawnymi wskaźnikami trybu ścisłego ('use strict', moduły ES, metody klas). Dziedziczenie z zasięgu nadrzędnego nadal obowiązuje zgodnie ze specyfikacją JS.
target
Type: string Default: browser
Pozwala ustawić środowisko docelowe zobfuskowanego kodu.
Dostępne wartości:
browser(domyślnie) — standardowe środowisko strony internetowej. Kod wynikowy jest identyczny jak dlanode, ale niektórych opcji przeznaczonych dla przeglądarki nie można używać ze środowiskiemnodebrowser-no-eval— tak samo jakbrowser, ale kod wynikowy nie używaeval(). Należy stosować, gdy strona docelowa ma politykę Content Security Policy zabraniającąeval/unsafe-eval.node— środowisko Node.js. Opcje przeznaczone dla przeglądarki są wyłączone (wymagająwindow/document, a w Node nie robiłyby nic lub zgłaszałyby błąd). Część mechanizmów obronnychvmSelfDefendingopartych na API dostępnych wyłącznie w przeglądarce — wykrywanie przeglądarki headless, odtwarzanie czystego realmu przy użyciu iframe, kontrole antyinspektorowe i sprawdzanie DOM — nie jest generowana dla tego środowiska.service-worker— kontekst Service Workera. Brakwindow, brakdocument, inny obiekt globalnyself.userscript— piaskownica menedżera userscriptów (np. Tampermonkey). Mechanizmy obronnevmSelfDefendingsą odpowiednio dostosowywane.bytenode— kod Node.js, który po obfuskacji zostanie skompilowany loaderem bytenode (kod bajtowy V8 z pamięci podręcznej,.jsc). Sam obfuskator nie uruchamiabytenode; generuje kod JavaScript po obfuskacji VM, którego środowisko uruchomieniowe jest zbudowane tak, aby przetrwało etap kompilacji przez bytenode, a mechanizmy obronnevmSelfDefendingsą odpowiednio dostosowywane. Aby otrzymać końcowy plik.jsc, należy samodzielnie uruchomićbytenodena zobfuskowanym kodzie wynikowym.
transformObjectKeys
Type: boolean Default: false
Włącza transformację kluczy obiektów.
Przykład:
// 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
Określa, które nieblokujące ostrzeżenia obfuskacji są zwracane przez metodę ObfuscationResult.getWarnings().
Dostępne wartości:
'all'(domyślnie) — zwracane są wszystkie ostrzeżenia.'none'— wszystkie ostrzeżenia są pomijane.- obiekt mapujący typy ostrzeżeń na wartości logiczne — typ przypisany do
falsejest pomijany; każdy typ nieobecny w mapie (lub przypisany dotrue) pozostaje włączony. Na przykład{ "VMGlobalFunctionNamesNotRenamed": false }zachowuje wszystkie ostrzeżenia z wyjątkiem tego jednego.
Typy ostrzeżeń:
VMGlobalFunctionNamesNotRenamed— przy włączonej opcjivmObfuscationnazwy deklaracji funkcji i klas najwyższego poziomu oraz zmiennych, którym przypisano wyrażenie funkcyjne, funkcję strzałkową lub wyrażenie klasowe, pozostały bez zmian (opcjarenameGlobalsjest wyłączona, a kod nie jest opakowany w IIFE), więc pozostają czytelne w wyniku, mimo że ciała funkcji są ukryte w postaci kodu bajtowego. Nazwy eksportowane nie są zgłaszane.VMTopLevelInitializerNotVirtualized— inicjalizatory zmiennych najwyższego poziomu pozostały przy obfuskacji VM zwykłym kodem JavaScript, ponieważ opcjavmWrapTopLevelInitializersjest wyłączona lub nie zdołała ich zwirtualizować.DynamicCodeRenameRisk— kod tworzy funkcję z ciągu znaków w czasie wykonania (bezpośrednieval, konstruktorFunctionlubfn.toString()wstrzyknięty do znacznika<script>/Workera), przez co może odwoływać się do identyfikatorów, których nazwy zmienił obfuskator.VMDynamicCodeSkipped— funkcja została pominięta przy generowaniu kodu bajtowego VM, ponieważ zawiera bezpośrednieval, dynamicznenew FunctionalboFunction(zob.vmForceCompileDynamicCode).VMSyncFunctionSkippedInAsyncMode— przy włączonej opcjivmAsyncExecutorfunkcja jawnie oznaczona w trybiecommentokazała się synchroniczna i została pominięta (w tym trybie wirtualizowane są wyłącznie funkcje asynchroniczne).VMAsyncGeneratorSkippedInAsyncMode— przy włączonej opcjivmAsyncExecutori aktywnym asynchronicznym getterze klucza nie udało się zwirtualizować oznaczonego generatora asynchronicznego (musi on zwracać swój iterator synchronicznie).BrowserTargetWithNodeStyleCode— kod wygląda na przeznaczony dla Node.js (np.require('fs'),__dirname,process.argv), podczas gdy opcjatargetjest ustawiona na środowisko przeglądarkowe.
vmObfuscation
Type: boolean Default: false
Włącza obfuskację opartą na kodzie bajtowym VM. Po jej włączeniu funkcje JavaScript są kompilowane do niestandardowego kodu bajtowego wykonywanego przez osadzoną maszynę wirtualną. Zapewnia to najwyższy poziom ochrony, ponieważ pierwotna logika kodu zostaje całkowicie przekształcona.
Przykład:
Czytelny kod w rodzaju return qty * price zamienia się w listę liczb, na przykład [0x15,0x03,0x17,...], którą potrafi wykonać wyłącznie osadzony interpreter VM. Pierwotna logika nie jest już widoczna jako kod JavaScript.
vmTargetFunctions
Type: string[] Default: []
Pozwala wskazać po nazwie dokładnie te funkcje najwyższego poziomu, które mają zostać objęte ochroną VM.
Przykład:
{
vmObfuscation: true,
vmTargetFunctions: ['someFunctionName']
}
Wynik: ochroną VM zostaną objęte wyłącznie te trzy funkcje. Cała reszta pozostanie zwykłym (choć nadal zobfuskowanym) kodem JavaScript. Idealne rozwiązanie do ochrony wrażliwej weryfikacji licencji lub logiki uwierzytelniania przy zachowaniu lekkości pozostałej części kodu.
vmExcludeFunctions
Type: string[] Default: []
Pozwala wskazać funkcje najwyższego poziomu, które nigdy nie mają być objęte ochroną VM. Ma pierwszeństwo przed pozostałymi ustawieniami.
Przykład:
{
vmObfuscation: true,
vmExcludeFunctions: ['someFunctionName']
}
Kiedy stosować: funkcje najwyższego poziomu krytyczne dla wydajności (pętle animacji, przetwarzanie danych w czasie rzeczywistym) można wykluczyć, aby uniknąć narzutu VM, chroniąc jednocześnie całą resztę.
vmTargetFunctionsMode
Type: string Default: root
Określa sposób wyboru funkcji i metod do obfuskacji VM.
Przykład – tryb 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'
}
Kiedy stosować: gdy potrzebna jest chirurgiczna kontrola nad tym, które dokładnie funkcje zostaną objęte ochroną VM, zwłaszcza funkcje zagnieżdżone zawierające wrażliwą logikę. W przeciwieństwie do vmTargetFunctions, które działa wyłącznie dla nazwanych funkcji najwyższego poziomu, tryb comment pozwala chronić dowolną funkcję w dowolnym miejscu kodu.
vmForceCompileDynamicCode
Type: boolean Default: false
Określa, co obfuskacja VM robi z funkcją zawierającą bezpośrednie wywołanie eval, new Function(...) lub Function(...).
Domyślnie taka funkcja (oraz każda funkcja zdefiniowana w jej wnętrzu) jest pomijana przy generowaniu kodu bajtowego VM, a w result.getWarnings() zgłaszane jest ostrzeżenie VMDynamicCodeSkipped. Dzieje się tak dlatego, że kod źródłowy budowany w czasie wykonania może odwoływać się do identyfikatorów z otaczającego łańcucha zasięgów — identyfikatorów, których nazwy zmienił obfuskator.
Po ustawieniu wartości true funkcja mimo wszystko zostaje przekształcona w kod bajtowy, a ostrzeżenie VMDynamicCodeSkipped nie jest już zgłaszane.
Osobne ostrzeżenie DynamicCodeRenameRisk jest zgłaszane niezależnie od tej opcji, ponieważ opisywane przez nie ryzyko związane ze zmianą nazw nie ma związku z pomijaniem funkcji przez VM — włączenie tej opcji w żaden sposób nie czyni tego wzorca bezpieczniejszym.
// Source code
function loadConfig(src) {
return eval(src);
}
loadConfig('1 + 2');
// Options
{
vmObfuscation: true,
vmForceCompileDynamicCode: true
}
Przy wyłączonej opcji (domyślnie) loadConfig pozostaje zwykłym kodem JavaScript. Przy włączonej opcji loadConfig jest kompilowana do kodu bajtowego VM jak każda inna funkcja. Należy z tego korzystać po sprawdzeniu miejsca wywołania i upewnieniu się, że kod budowany w czasie wykonania nie zależy od identyfikatorów z domknięcia, których nazwy zostały zmienione.
vmWrapTopLevelInitializers
Type: boolean Default: false
Opakowuje część inicjalizatorów zmiennych najwyższego poziomu w IIFE (natychmiast wywoływane wyrażenia funkcyjne), dzięki czemu mogą zostać poddane obfuskacji VM.
Co robi: Bez tej opcji stałe i zmienne najwyższego poziomu pozostają widoczne w wyniku:
// Input
const MY_STRING = "my-string";
// Output (without vmWrapTopLevelInitializers)
const MY_STRING = "my-string"; // String is visible!
Po włączeniu tej opcji inicjalizator zostaje opakowany w IIFE, które podlega obfuskacji VM:
// Input
const MY_STRING = "my-string";
// Output (with vmWrapTopLevelInitializers: true)
const MY_STRING = (() => { return /* VM bytecode call */ })(); // String hidden in bytecode
Uwaga: ta opcja działa wyłącznie wtedy, gdy vmTargetFunctionsMode ma wartość 'root' (domyślną).
Ostrzeżenia: za każdym razem, gdy przy obfuskacji VM inicjalizator najwyższego poziomu pozostanie zwykłym kodem JavaScript, zgłaszane jest ostrzeżenie VMTopLevelInitializerNotVirtualized z listą nazw zmiennych, których to dotyczy. Obejmuje ono: wyłączenie tej opcji, inicjalizatory, które opcja musiała pominąć (każdy wraz z powodem — np. inicjalizator odwołuje się do sąsiedniego deklaratora albo zawiera await najwyższego poziomu), oraz tryb vmAsyncExecutor, w którym synchronicznych wrapperów w ogóle nie da się zwirtualizować.
vmDynamicOpcodes
Type: boolean Default: false
Sprawia, że interpreter VM jest mniejszy i unikalny dla każdej kompilacji.
Co robi:
- Odfiltrowuje nieużywane instrukcje – jeśli kod nie korzysta z klas, instrukcje związane z klasami są całkowicie usuwane
- Losuje strukturę – kolejność procedur obsługi instrukcji jest tasowana przy każdej kompilacji
W efekcie wynik jest mniejszy, a każda kompilacja wygląda inaczej.
vmBytecodeEncoding
Type: boolean Default: false
Koduje każdą instrukcję kodu bajtowego. Instrukcje są dekodowane pojedynczo w trakcie wykonywania.
vmBytecodeArrayEncoding
Type: boolean Default: false
Koduje całą tablicę kodu bajtowego jako pojedynczy blok. Tablica jest dekodowana jednorazowo przy starcie, zanim rozpocznie się wykonywanie. Warto stosować razem z vmBytecodeEncoding, aby uzyskać dwie warstwy ochrony.
vmBytecodeArrayEncodingKey
Type: string Default: ''
Własny klucz szyfrujący dla kodowania tablicy kodu bajtowego. Po ustawieniu używany jest ten klucz zamiast domyślnego klucza wyprowadzanego ze środowiska. Klucz musi zostać dostarczony w czasie wykonania przez vmBytecodeArrayEncodingKeyGetter.
Ta opcja wynosi klucz szyfrujący na zewnątrz — nie jest on osadzony w samym zobfuskowanym kodzie. Klucz jest wprawdzie nadal dostępny w czasie wykonania (a więc nie jest naprawdę tajny), ale takie rozdzielenie uniemożliwia narzędziom do analizy statycznej znalezienie go na podstawie samego kodu.
Ważne: klucz musi być dostępny synchronicznie w momencie ładowania zobfuskowanego kodu. Należy korzystać z synchronicznych źródeł danych, takich jak ciasteczka, localStorage, sessionStorage, zmienne globalne lub elementy DOM (np. znaczniki meta wstrzykiwane przez serwer). Metod asynchronicznych, takich jak fetch(), nie można użyć bezpośrednio w wyrażeniu gettera klucza.
vmBytecodeArrayEncodingKeyGetter
Type: string Default: ''
Synchroniczne wyrażenie JavaScript, które zwraca klucz szyfrujący w czasie wykonania. Wyrażenie to jest obliczane w momencie załadowania zobfuskowanego kodu i musi zwrócić dokładnie ten sam klucz, który podano w vmBytecodeArrayEncodingKey. Aby uzyskiwać klucz asynchronicznie (jako Promise), należy włączyć opcję vmAsyncExecutor.
Uwaga: getter zwracający obiekt Promise wymaga opcji vmAsyncExecutor. Nie da się tego sprawdzić na etapie kompilacji, więc getter zwracający Promise przy wyłączonej opcji vmAsyncExecutor zawiedzie w czasie wykonania — dekoder otrzyma obiekt Promise zamiast klucza.
Zobfuskowany kod zadziała wyłącznie wtedy, gdy getter klucza zwróci dokładnie ten sam klucz, którego użyto podczas obfuskacji. Jeśli klucze się nie zgadzają, odszyfrowanie się nie powiedzie, a kod będzie generował śmieci lub błędy. Jeśli getter klucza zwróci undefined, null albo pusty ciąg, kod zgłosi błąd: „VM decryption key not available”.
Ważne: klucz należy trzymać poza tym samym plikiem/skryptem co zobfuskowany kod — umieszczenie go tam pozwala odzyskać go nawet czysto statycznym przeskanowaniem bundle’a. Zamiast tego należy przechowywać go w osobnym źródle: w ciasteczkach ustawianych przez serwer, w localStorage wypełnianym przez inny skrypt, w znaczniku meta HTML wstrzykiwanym przez serwer, w zmiennej globalnej ustawianej przez inny skrypt lub (przy włączonej opcji vmAsyncExecutor) pobierać go w czasie wykonania z własnego backendu.
Gdy klucz jest pobierany z backendu (przez vmAsyncExecutor), warto dodać na tym endpoincie kontrole oparte na sesji lub źródle żądania: prawdziwym użytkownikom (ważna sesja, oczekiwane nagłówki Origin/Referer) należy zwracać poprawny klucz, a podejrzanym żądaniom (np. z localhost lub nieoczekiwanego źródła, bez sesji) — klucz-śmieć. Prawdziwi użytkownicy pracują normalnie, natomiast kopia uruchomiona poza Twoim środowiskiem otrzymuje klucz, który niczego nie odszyfruje. Konkretna logika zależy od danej witryny.
Przykłady:
// 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())'
Przykład użycia:
// 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
Włącza asynchroniczny executor VM, dzięki któremu vmBytecodeArrayEncodingKeyGetter może zwracać obiekt Promise (asynchroniczny getter klucza) — klucz deszyfrujący może więc być pobierany w czasie wykonania (żądanie sieciowe, IndexedDB itp.), zamiast być dostępny synchronicznie w momencie ładowania kodu.
Zdecydowanie zalecane dla w pełni asynchronicznych baz kodu. W tym trybie wirtualizowane są wyłącznie funkcje async — funkcji synchronicznej nie da się uczynić asynchroniczną bez zamiany jej wartości zwracanej w Promise i zepsucia kodu wywołującego — więc kod asynchroniczny w całości uzyskuje największe pokrycie. Tryb działa również wtedy, gdy poziom główny jest synchroniczny (np. synchroniczne IIFE lub wrapper UMD): chronione są najbardziej zewnętrzne funkcje async znajdujące się w środku, a części synchroniczne pozostają bez zmian.
Co podlega transformacji: każda najbardziej zewnętrzna funkcja async, gdziekolwiek się pojawia (również zagnieżdżona w synchronicznych wrapperach). Najbardziej zewnętrzna funkcja async w każdym łańcuchu jest chronioną jednostką — wszystko w jej wnętrzu, zarówno synchroniczne, jak i asynchroniczne, zostaje skompilowane razem z nią. Funkcje synchroniczne i zwykłe generatory pozostają bez obfuskacji.
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
}
}
Pominięcia i ostrzeżenia. Generatory asynchroniczne również pozostają bez obfuskacji, gdy aktywny jest asynchroniczny getter klucza (generator asynchroniczny musi zwrócić swój iterator synchronicznie i nie może czekać na klucz). W domyślnym trybie vmTargetFunctionsMode: 'root' pominięcia są ciche (wybór jest automatyczny); w trybie comment za każdym razem, gdy jawnie oznaczonej funkcji nie da się zwirtualizować — okazała się synchroniczna albo jest generatorem asynchronicznym przy asynchronicznym getterze klucza — zgłaszane jest ostrzeżenie przez ObfuscationResult.getWarnings().
Asynchroniczny getter klucza wymaga dodatkowo opcji vmBytecodeArrayEncoding wraz z vmBytecodeArrayEncodingKeyGetter.
Przykład użycia:
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
Koduje cele skoków w kodzie bajtowym. Przesunięcia skoków są obliczane w czasie wykonania, co ukrywa strukturę przepływu sterowania (if/else, pętle itd.) przed analizą statyczną.
vmMacroOps
Type: boolean Default: false
Łączy typowe sekwencje instrukcji w pojedyncze opkody „makro”. Na przykład LOAD + ADD + STORE może stać się jedną instrukcją MACRO_ADD_TO_VAR. Utrudnia to rozpoznawanie wzorców i może poprawić wydajność.
vmDebugProtection
Type: boolean Default: false
Dodaje do środowiska uruchomieniowego VM wielowarstwowe zabezpieczenia przed debugowaniem, analizą oraz działaniem modeli LLM. Działa najlepiej ze środowiskami browser/browser-no-eval.
vmSelfDefending
Type: boolean Default: false
Dodaje do środowiska uruchomieniowego VM wielowarstwową ochronę: wykrywanie manipulacji, ochronę przed hookowaniem oraz przed inżynierią wsteczną.
⚠️ Ta opcja wymusza włączenie opcji vmBytecodeArrayEncoding.
⚠️ Wykrywanie wrażliwego środowiska. Ta opcja wiąże zobfuskowany kod z docelowym środowiskiem uruchomieniowym i wykorzystuje zaawansowany fingerprinting przeglądarki do wykrywania narzędzi automatyzujących. Kod chroniony tą opcją celowo przestanie działać, gdy zostanie uruchomiony w:
- Przeglądarkach headless (headless Chrome/Chromium, PhantomJS)
- Narzędziach do automatyzacji przeglądarek (Puppeteer, Playwright, Cypress, Selenium/ChromeDriver, Nightmare)
- Node.js (gdy
targetjest ustawiony nabrowser) - jsdom lub podobnych serwerowych emulacjach DOM
- Środowiskach, w których natywne wbudowane funkcje przeglądarki zostały podhaczone (hooked) lub podmienione
Kod będzie działał poprawnie w zwykłych przeglądarkach (Chrome, Firefox, Safari, Edge), w tym po załadowaniu wewnątrz elementów iframe, w rozszerzeniach przeglądarki (content scripts) oraz w Web Workerach. Jeśli konieczne jest uruchamianie automatycznych testów na chronionym kodzie, w kompilacjach testowych należy wyłączyć vmSelfDefending — ta opcja została zaprojektowana tak, aby uniemożliwiać automatyczną analizę, i nie może być bezpiecznie używana z żadnym frameworkiem automatyzującym.
Zdecydowanie zaleca się stosowanie jej wraz z vmDebugProtection, vmBytecodeArrayEncodingKey oraz vmBytecodeArrayEncodingKeyGetter.
vmDefenseHook
Type: { name: string, aliases?: object } Default: ''
vmDefenseHook przyjmuje obiekt z dwoma kluczami: name (wymagany) i aliases (opcjonalny).
name to globalna funkcja definiowana przez Twoją stronę hostującą, którą mechanizm obronny VM (vmDebugProtection / vmSelfDefending) wywołuje z obiektem sygnału po wykryciu wrogiego sygnału — debuggera lub inspektora, przeglądarki headless / automatyzującej, procesu agenta AI programującego kod, niedozwolonej domeny itp. Służy do raportowania zdarzenia do własnego backendu (np. przez navigator.sendBeacon). Hook jest czystym odbiornikiem telemetrii: jego wartość zwracana jest ignorowana, a brakujący lub zgłaszający wyjątek hook to cichy brak działania, który nigdy nie może wyłączyć mechanizmu obronnego. Aby zmienić to, co mechanizm obronny robi po wykryciu, należy użyć opcji vmDefenseReaction.
aliases opcjonalnie zmienia nazwy pól tego obiektu sygnału — opisano to poniżej w części Zmiana nazw pól sygnału.
Obiekt sygnału. Hook otrzymuje jeden signal:
source— konkretny detektor, który zadziałał (zob. tabelę).category— grupa, w ramach której raportuje:automation(przeglądarki nieobsługiwane przez człowieka),debugger(aktywny debugger/inspektor),sandbox(instrumentowany/fałszywy host),domain(naruszenie blokady domeny),tamper(wbudowane funkcje podmienione w czasie wykonania) lubintegrity(zmieniono kod samej VM).score/threshold— jak silnie zadziałał detektor oraz wartość, którą musiał osiągnąć; hook zadziała dopiero wtedy, gdyscore >= threshold. Większość kontroli działa na zasadzie „wszystko albo nic” (pojedynczy rozstrzygający sygnał);headlesssumuje kilka sygnałów dotyczących kształtu przeglądarki, więc jegoscorejest zwykle wyższy niżthreshold.
Rejestrowanie hooka. Należy zdefiniować go jako zwykłą zmienną globalną przed załadowaniem zobfuskowanego bundle’a — środowisko uruchomieniowe VM i jego mechanizmy obronne działają przed Twoim (chronionym) programem, więc wiele detekcji zachodzi już podczas startu:
// in your page, before the obfuscated script:
window.__vmDetection = function (signal) { navigator.sendBeacon('/vm-defense', JSON.stringify(signal)); };
// obfuscation option:
vmDefenseHook: { name: '__vmDetection' }
Hook zdefiniowany wewnątrz zobfuskowanego kodu źródłowego jest rejestrowany zbyt późno, aby wychwycić detekcje zachodzące podczas startu, a jeśli zostanie skompilowany do VM, nie da się do niego dotrzeć, dopóki nie uruchomi się Twój program. Jest on bezpieczny w obu przypadkach (brakujący hook nie robi nic, a zabezpieczenie przed ponownym wejściem zapobiega niekontrolowanemu działaniu), ale dla pełnego pokrycia należy rejestrować go z wyprzedzeniem. Aby mimo to chronić własną logikę raportowania, rejestrowany hook warto ograniczyć do jednolinijkowego bufora ((window.__vmDet = window.__vmDet || []).push(signal)) i odczytywać/wysyłać ten bufor z poziomu zobfuskowanego kodu.
Zmiana nazw pól sygnału (aliases). Domyślne wartości source/category to opisowe nazwy, więc każdy, kto instrumentuje callback (lub czyta wynik), może rozpoznać zabezpieczenie i wskazać, który detektor zadziałał. aliases zmienia nazwy pól sygnału na wybrane przez Ciebie nieprzejrzyste tokeny, stosowane wewnątrz VM przed wyemitowaniem sygnału, dzięki czemu te nazwy nigdy nie pojawiają się w wyniku ani nie docierają do callbacku. Twoja aplikacja zna własne odwzorowanie i przekazuje tokeny do backendu.
Aliasy działają per pole, rozdzielając zmianę nazw kluczy i wartości: każde pole przyjmuje key (nazwę właściwości otrzymywaną przez callback); tekstowe pola nazw source i category przyjmują też mapę values, natomiast score/threshold są liczbami i przyjmują wyłącznie key. Nazwy, które można odwzorować (wszystko inne jest odrzucane na etapie kompilacji):
- klucze pól —
source,category,score,threshold - wartości
source—headless,agent,node,debugger,timing,sandbox,domain,nativeHook,integrity - wartości
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> }
}
To zabezpieczenie przed fingerprintingiem, a nie utajnianie — odwzorowanie wciąż da się wywnioskować przez wielokrotne testowanie — więc jego jedyną korzyścią jest nieujawnianie stałych, samoopisujących się nazw. Nieustawione wpisy zachowują swoje domyślne nazwy.
Zwykły ciąg znaków (vmDefenseHook: '__vmDetection') jest akceptowany jako skrót dla { name: '__vmDetection' }, ale jest przestarzały — należy preferować postać obiektową.
vmDefenseReaction
Type: object Default: { automation: 'break', debugger: 'decoy', sandbox: 'decoy', domain: 'break', tamper: 'break', integrity: 'break' }
Konfiguruje sposób reakcji każdej kategorii detekcji. Nie włącza niczego — same mechanizmy obronne uruchamiają opcje vmSelfDefending, vmDebugProtection oraz vmDomainLock; ta opcja wybiera jedynie, jak włączony mechanizm obronny reaguje. Jednostką kontroli jest kategoria — każdy detektor w kategorii wprowadza reakcję przypisaną tej kategorii.
Każda kategoria grupuje detektory czuwające nad jednym rodzajem wrogiego warunku. Kategoria reaguje tylko wtedy, gdy włączona jest opcja emitująca jej detektory:
Każda kategoria odwzorowuje się na co najmniej jedną z opcji vmSelfDefending, vmDebugProtection i vmDomainLock; nie istnieje kategoria poza tymi trzema opcjami, a reakcja ustawiona dla kategorii, której opcja jest wyłączona, po prostu nie ma żadnego efektu.
Kluczami są te sześć nazw kategorii lub default (rozwiązanie awaryjne dla nieokreślonych kategorii). Wartości to:
break— natychmiast przerwij działaniedecoy— kontynuuj działanie na zatrutym stanie, po cichu generując błędne wynikinone— nie rób nic lokalnie (tylko telemetria)
Domyślne wartości poszczególnych kategorii pokazano powyżej; kategoria, której nie ustawisz (lub ustawisz na jej wartość domyślną), korzysta z tej wartości domyślnej. default obejmuje każdą kategorię, w tym te poprawne z założenia (integrity, tamper), więc { default: 'none' } to naprawdę nieprzerywająca kompilacja wyłącznie z telemetrią:
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
Sprawia, że znaczenie opkodów zależy od pozycji w kodzie bajtowym. Każda pozycja ma inne odwzorowanie opkodu na procedurę obsługi, wyprowadzane z ziarna, więc ten sam numer opkodu wykonuje różne operacje na różnych pozycjach.
vmCallContextOpcodes
Type: boolean Default: false
Sprawia, że chroniona funkcja zależy od miejsca, z którego jest wywoływana, dzięki czemu nie da się jej wyodrębnić z kodu i uruchomić ani przeanalizować samodzielnie — działa poprawnie wyłącznie wtedy, gdy jest wywoływana przez swoje rzeczywiste miejsca wywołań w programie. Ta opcja wpływa na wydajność w czasie wykonania.
Obecnie obsługiwane są wyłącznie następujące konstrukcje:
- deklaracje funkcji (
function f() {}); - wyrażenia funkcyjne i funkcje strzałkowe przypisane do zmiennej (
const f = () => {}); - prywatne metody instancji (
this.#m()).
W każdym przypadku funkcja musi być zawsze osiągana przez bezpośrednie wywołanie (f(), this.#m()). Jeśli zostanie zapisana w innej zmiennej, przekazana jako argument lub w inny sposób użyta jako wartość, pozostanie niechroniona. Funkcje asynchroniczne są obsługiwane; generatory — nie.
Ta opcja jest eksperymentalna i może zepsuć kod, dlatego przed użyciem należy dokładnie przetestować wynik.
vmStackEncoding
Type: boolean Default: false
Szyfruje wartości na stosie VM w trakcie wykonywania. Wartości są kodowane przy odkładaniu na stos i dekodowane przy zdejmowaniu, więc inspekcja pamięci pokazuje zaszyfrowane dane zamiast rzeczywistych wartości.
Ta opcja mocno wpływa na wydajność.
vmCompactDispatcher
Type: boolean Default: false
Używa pojedynczego executora VM zamiast dwóch (synchronicznego + generatorowego). Zmniejsza rozmiar zobfuskowanego kodu, ale dodaje około 20% narzutu wydajnościowego przy kodzie intensywnie korzystającym z rekurencji.
false(domyślnie): dwa executory — optymalna wydajność, większy wyniktrue: pojedynczy executor — mniejszy wynik, nieco wolniej
vmStringArrayBytecodeOnly
Type: boolean Default: false
Po włączeniu tablica ciągów wyłącznie wyodrębnia ciągi z danych kodu bajtowego — żadne inne ciągi w kodzie nie są przekształcane. Wymusza to włączenie stringArray, nawet jeśli nie ustawiono jej jawnie.
Dlaczego warto: wyodrębnianie wszystkich ciągów środowiska uruchomieniowego VM do tablicy ciągów jest powolne. Ta opcja obejmuje wyodrębnianiem do tablicy ciągów wyłącznie zawartość kodu bajtowego, poprawiając wydajność i chroniąc jednocześnie stałe kodu bajtowego.
- Gdy
vmBytecodeArrayEncoding: false— wyodrębniane są ciągi z pul stałych kodu bajtowego (tablicec) - Gdy
vmBytecodeArrayEncoding: true— wyodrębniane są zakodowane w base64 ciągi kodu bajtowego najwyższego poziomu stringArrayThresholdnadal steruje tym, jaki procent tych ciągów kodu bajtowego jest wyodrębniany
vmDomainLock
Type: string[] Default: []
⚠️ Ta opcja nie działa z target: 'node', target: 'service-worker' ani target: 'bytenode'
Ogranicza działanie zobfuskowanego kodu do określonych domen i/lub subdomen i jest znacznie trudniejsza do zlokalizowania i usunięcia niż domainLock.
Jeśli kod źródłowy nie jest uruchamiany w domenach wskazanych w tej opcji, przeglądarka zostanie przekierowana pod adres URL przekazany w opcji vmDomainLockRedirectUrl, a kolejne chronione wywołania będą zwracać nieprawidłowe wyniki, nawet jeśli przekierowanie zostanie zablokowane.
Wiele domen i subdomen
Kod można zablokować do więcej niż jednej domeny lub subdomeny. Na przykład, aby zablokować go tak, by działał wyłącznie w www.example.com, należy dodać www.example.com. Aby działał w domenie głównej wraz ze wszystkimi subdomenami (example.com, sub.example.com), należy użyć .example.com.
vmDomainLockRedirectUrl
Type: string Default: about:blank
⚠️ Ta opcja nie działa z target: 'node', target: 'service-worker' ani target: 'bytenode'
Pozwala przekierować przeglądarkę pod przekazany adres URL, jeśli kod źródłowy nie jest uruchamiany w domenach wskazanych w opcji vmDomainLock.
Preset Options
Wysoka obfuskacja, niska wydajność
Wydajność będzie znacznie niższa niż bez obfuskacji
{
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
}
Średnia obfuskacja, optymalna wydajność
Wydajność będzie niższa niż bez obfuskacji
{
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
}
Niska obfuskacja, wysoka wydajność
Wydajność pozostanie na względnie normalnym poziomie
{
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
}
Preset domyślny, wysoka wydajność
{
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 Ultra High – bardzo wysoka obfuskacja (maksymalne bezpieczeństwo)
Ten preset włącza obfuskację opartą na kodzie bajtowym VM ze wszystkimi funkcjami wzmacniającymi ochronę, w tym z pośrednim dyspozytorem (indirect dispatch). Zapewnia najsilniejszą ochronę, ale kosztem większego rozmiaru wyniku i znacznie wolniejszego wykonywania.
{
optionsPreset: 'vm-ultra-high-obfuscation'
}
Lub skonfiguruj poszczególne opcje osobno:
{
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 Anti-LLM (ochrona przed agentami AI)
Ten preset został zaprojektowany specjalnie tak, aby uniemożliwiać agentom AI i modelom LLM inżynierię wsteczną kodu bajtowego VM. Oparty na vm-default z włączoną samoobroną i ochroną przed debugowaniem. Lżejszy niż vm-high-obfuscation, ale specjalnie utwardzony przeciwko automatycznej analizie.
{
optionsPreset: 'vm-anti-llm'
}
Obejmuje:
- Obfuskację kodu bajtowego VM z tablicą ciągów (z
vm-default) vmSelfDefending— wykrywanie hooków, hash integralności, fingerprint kodu źródłowego, weryfikację czystego realmu przez iframe, wyprowadzanie klucza szyfrem ARXvmDebugProtection— kontrole antydebugujące w pętli dyspozytora VMdebugProtection: false— brak przestarzałej ochrony przed debugowaniem (ochrona przed debugowaniem VM jest lepsza)
VM High – wysoka obfuskacja (najwyższe bezpieczeństwo)
Ten preset włącza obfuskację opartą na kodzie bajtowym VM z większością funkcji wzmacniających ochronę. Zapewnia silną ochronę przy lepszej wydajności niż preset ultra-high.
{
optionsPreset: 'vm-high-obfuscation'
}
Lub skonfiguruj poszczególne opcje osobno:
{
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 Medium – średnia obfuskacja (zrównoważone bezpieczeństwo)
Ten preset włącza obfuskację opartą na kodzie bajtowym VM ze zrównoważonym zestawem funkcji wzmacniających ochronę. Dobry kompromis między bezpieczeństwem a wydajnością.
{
optionsPreset: 'vm-medium-obfuscation'
}
Lub skonfiguruj poszczególne opcje osobno:
{
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 Low – niska obfuskacja (podstawowe bezpieczeństwo, lepsza wydajność)
Ten preset włącza podstawową obfuskację opartą na kodzie bajtowym VM bez dodatkowych funkcji wzmacniających ochronę. Dobra równowaga między bezpieczeństwem a rozmiarem wyniku.
{
optionsPreset: 'vm-low-obfuscation'
}
Lub skonfiguruj poszczególne opcje osobno:
{
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 Default (VM + ochrona tablicą ciągów)
Ten preset łączy podstawową obfuskację opartą na kodzie bajtowym VM z ochroną tablicą ciągów. Dobry punkt wyjścia do obfuskacji VM z ochroną ciągów.
{
optionsPreset: 'vm-default'
}
Lub skonfiguruj poszczególne opcje osobno:
{
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
Kompaktowy kod wynikowy w jednej linii.
config
Type: string Default: ``
Nazwa pliku konfiguracyjnego JS/JSON zawierającego opcje obfuskatora. Zostaną one nadpisane przez opcje przekazane bezpośrednio do CLI
controlFlowFlattening
Type: boolean Default: false
⚠️ Ta opcja znacząco wpływa na wydajność – szybkość działania może spaść nawet 1,5-krotnie. Za pomocą opcji controlFlowFlatteningThreshold można ustawić procent węzłów, których dotyczy spłaszczanie przepływu sterowania.
Włącza spłaszczanie przepływu sterowania w kodzie. Spłaszczanie przepływu sterowania to transformacja struktury kodu źródłowego, która utrudnia zrozumienie programu.
Przykład:
// 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
Prawdopodobieństwo, że transformacja controlFlowFlattening zostanie zastosowana do danego węzła.
To ustawienie jest szczególnie przydatne przy dużym rozmiarze kodu, ponieważ duża liczba transformacji przepływu sterowania może spowolnić kod i zwiększyć jego rozmiar.
controlFlowFlatteningThreshold: 0 jest równoznaczne z controlFlowFlattening: false.
deadCodeInjection
Type: boolean Default: false
⚠️ Drastycznie zwiększa rozmiar zobfuskowanego kodu (nawet o 200%) – należy stosować tylko wtedy, gdy rozmiar zobfuskowanego kodu nie ma znaczenia. Za pomocą opcji deadCodeInjectionThreshold można ustawić procent węzłów, których dotyczy wstrzykiwanie martwego kodu.
⚠️ Ta opcja wymusza włączenie opcji stringArray.
⚠️ Ta opcja jest po cichu wyłączana, gdy włączona jest opcja vmObfuscation.
Przy tej opcji do zobfuskowanego kodu dodawane są losowe bloki martwego kodu.
Przykład:
// 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
Pozwala ustawić procent węzłów, których dotyczy deadCodeInjection.
debugProtection
Type: boolean Default: false
⚠️ Może zawiesić przeglądarkę po otwarciu narzędzi deweloperskich.
⚠️ Ta opcja jest po cichu wyłączana, gdy włączona jest opcja vmObfuscation. Należy wtedy użyć opcji vmDebugProtection.
Ta opcja sprawia, że korzystanie z funkcji debugger w narzędziach deweloperskich staje się niemal niemożliwe (zarówno w przeglądarkach opartych na WebKit, jak i w Mozilla Firefox).
debugProtectionInterval
Type: number Default: 0
⚠️ Może zawiesić przeglądarkę! Stosowanie na własne ryzyko.
⚠️ Ta opcja jest po cichu wyłączana, gdy włączona jest opcja vmObfuscation. Należy wtedy użyć opcji vmDebugProtection.
Jeśli ta opcja jest ustawiona, wykorzystywany jest interwał w milisekundach wymuszający tryb debugowania w karcie Console, co utrudnia korzystanie z pozostałych funkcji narzędzi deweloperskich. Działa, gdy włączona jest opcja debugProtection. Zalecana wartość mieści się w przedziale od 2000 do 4000 milisekund.
disableConsoleOutput
Type: boolean Default: false
⚠️ Ta opcja globalnie wyłącza wywołania console dla wszystkich skryptów
Wyłącza możliwość korzystania z console.log, console.info, console.error, console.warn, console.debug, console.exception i console.trace, zastępując je pustymi funkcjami. Utrudnia to korzystanie z debuggera.
domainLock
Type: string[] Default: []
⚠️ Ta opcja nie działa z target: 'node', target: 'service-worker' ani target: 'bytenode'
Pozwala uruchamiać zobfuskowany kod źródłowy wyłącznie w określonych domenach i/lub subdomenach. Bardzo utrudnia to skopiowanie kodu źródłowego i uruchomienie go w innym miejscu.
Jeśli kod źródłowy nie jest uruchamiany w domenach wskazanych w tej opcji, przeglądarka zostanie przekierowana pod adres URL przekazany w opcji domainLockRedirectUrl.
Wiele domen i subdomen
Kod można zablokować do więcej niż jednej domeny lub subdomeny. Na przykład, aby zablokować go tak, by działał wyłącznie w www.example.com, należy dodać www.example.com. Aby działał w domenie głównej wraz ze wszystkimi subdomenami (example.com, sub.example.com), należy użyć .example.com.
domainLockRedirectUrl
Type: string Default: about:blank
⚠️ Ta opcja nie działa z target: 'node', target: 'service-worker' ani target: 'bytenode'
Pozwala przekierować przeglądarkę pod przekazany adres URL, jeśli kod źródłowy nie jest uruchamiany w domenach wskazanych w opcji domainLock
exclude
Type: string[] Default: []
Nazwy plików lub wzorce glob wskazujące pliki wykluczone z obfuskacji.
forceTransformStrings
Type: string[] Default: []
Włącza wymuszoną transformację literałów tekstowych pasujących do przekazanych wzorców RegExp.
⚠️ Ta opcja dotyczy wyłącznie ciągów, które nie powinny zostać przekształcone zgodnie z opcją stringArrayThreshold (lub, być może, innymi progami w przyszłości)
Opcja ma priorytet nad opcją reservedStrings, ale nie ma priorytetu nad conditional comments.
Przykład:
{
forceTransformStrings: [
'some-important-value',
'some-string_\d'
]
}
identifierNamesCache
Type: Object | null Default: null
Głównym celem tej opcji jest możliwość używania tych samych nazw identyfikatorów podczas obfuskacji wielu źródeł/plików.
Obecnie obsługiwane są dwa rodzaje identyfikatorów:
- Identyfikatory globalne:
- wszystkie identyfikatory globalne zostaną zapisane w pamięci podręcznej;
- wszystkie dopasowane niezadeklarowane identyfikatory globalne zostaną zastąpione wartościami z pamięci podręcznej.
- Identyfikatory właściwości, tylko gdy włączona jest opcja
renameProperties:- wszystkie identyfikatory właściwości zostaną zapisane w pamięci podręcznej;
- wszystkie dopasowane identyfikatory właściwości zostaną zastąpione wartościami z pamięci podręcznej.
Node.js API
Przekazanie wartości null całkowicie wyłącza pamięć podręczną.
Przekazanie pustego obiektu ({}) włącza zapisywanie nazw identyfikatorów do obiektu pamięci podręcznej (typ TIdentifierNamesCache). Dostęp do tego obiektu uzyskuje się przez wywołanie metody getIdentifierNamesCache obiektu ObfuscationResult.
Powstały obiekt pamięci podręcznej można następnie przekazać jako wartość opcji identifierNamesGenerator, aby użyć tych nazw podczas obfuskacji wszystkich dopasowanych nazw identyfikatorów w kolejnych źródłach.
Przykład:
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 udostępnia inną opcję – --identifier-names-cache-path – która pozwala wskazać ścieżkę do istniejącego pliku .json używanego do odczytu i zapisu pamięci podręcznej nazw identyfikatorów.
Jeśli zostanie przekazana ścieżka do pustego pliku, pamięć podręczna nazw identyfikatorów zostanie zapisana do tego pliku.
Ten plik z istniejącą pamięcią podręczną można ponownie wykorzystać jako wartość opcji --identifier-names-cache-path, aby użyć tych nazw podczas obfuskacji wszystkich dopasowanych nazw identyfikatorów w kolejnych plikach.
identifierNamesGenerator
Type: string Default: hexadecimal
Ustawia generator nazw identyfikatorów.
Dostępne wartości:
dictionary: nazwy identyfikatorów z listyidentifiersDictionaryhexadecimal: nazwy identyfikatorów w rodzaju_0xabc123mangled: krótkie nazwy identyfikatorów, takie jaka,b,cmangled-shuffled: to samo comangled, ale z przetasowanym alfabetem
identifiersDictionary
Type: string[] Default: []
Ustawia słownik identyfikatorów dla opcji identifierNamesGenerator: dictionary. Każdy identyfikator ze słownika zostanie użyty w kilku wariantach różniących się wielkością poszczególnych znaków. Liczba identyfikatorów w słowniku powinna zatem zależeć od liczby identyfikatorów w oryginalnym kodzie źródłowym.
identifiersPrefix
Type: string Default: ''
Ustawia prefiks dla wszystkich identyfikatorów globalnych.
Tej opcji należy używać przy obfuskacji wielu plików. Pomaga ona uniknąć konfliktów między identyfikatorami globalnymi tych plików. Prefiks powinien być inny dla każdego pliku.
randomIdentifiersPrefix
Type: boolean Default: false
Dodaje do wszystkich identyfikatorów globalnych losowy prefiks (6 znaków alfanumerycznych) generowany na podstawie ziarna. Tej opcji należy używać, aby uniknąć kolizji między osobno zobfuskowanymi bundle’ami ładowanymi do tego samego zasięgu globalnego — dzięki niej nie trzeba ręcznie dobierać unikalnej wartości identifiersPrefix dla każdego bundle’a.
- Wartość losowa jest wyprowadzana z opcji
seedoraz skrótu kodu źródłowego, więc powtarzalne kompilacje z tym samym ziarnem dają ten sam prefiks. - W połączeniu z
identifiersPrefixlosowe znaki są dopisywane na końcu prefiksu podanego przez użytkownika (np.myApp+ losoweaBc123→myAppaBc123). - W połączeniu z
vmObfuscationwartość losowa zastępuje domyślny prefiksvm— losowość i tak gwarantuje unikalność.
ignoreImports
Type: boolean Default: false
Zapobiega obfuskacji importów require. Może się przydać w sytuacjach, gdy środowisko uruchomieniowe z jakiegoś powodu wymaga, aby te importy zawierały wyłącznie statyczne ciągi znaków.
inputFileName
Type: string Default: ''
Pozwala ustawić nazwę pliku wejściowego z kodem źródłowym. Nazwa ta będzie używana wewnętrznie podczas generowania mapy źródeł.
Wymagana przy korzystaniu z API NodeJS, gdy opcja sourceMapSourcesMode ma wartość sources.
log
Type: boolean Default: false
Włącza wypisywanie informacji do konsoli.
numbersToExpressions
Type: boolean Default: false
Włącza zamianę liczb na wyrażenia
Przykład:
// input
const foo = 1234;
// output
const foo=-0xd93+-0x10b4+0x41*0x67+0x84e*0x3+-0xff8;
optionsPreset
Type: string Default: default
Pozwala ustawić preset opcji.
Dostępne wartości:
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.
Wszystkie dodatkowe opcje zostaną scalone z wybranym presetem opcji.
parseHtml
Type: boolean Default: false
Włącza obfuskację kodu JavaScript wewnątrz znaczników <script> w plikach HTML.
Po włączeniu obfuskator:
- Automatycznie wykrywa, czy wejście jest kodem HTML (sprawdzając znaczniki
<!DOCTYPE,<html>,<head>,<body>lub<script>) - Wyodrębnia kod JavaScript ze znaczników
<script>oznaczonych atrybutemdata-javascript-obfuscator - Obfuskuje każdy oznaczony skrypt osobno, zachowując strukturę HTML
- Wstawia zobfuskowany kod z powrotem w pierwotne miejsca
Ważne: obfuskowane są wyłącznie skrypty z atrybutem data-javascript-obfuscator. Każdy oznaczony skrypt jest obfuskowany osobno i niezależnie. Oznacza to, że:
- Kod wewnątrz oznaczonych znaczników skryptu musi być odizolowany – nie może odwoływać się do zmiennych, funkcji ani klas zdefiniowanych w innych oznaczonych znacznikach skryptu
- Nieoznaczone skrypty nadal mają dostęp do zmiennych globalnych zdefiniowanych przez oznaczone skrypty (przez deklaracje
varlub jawne przypisania doglobalThis) - Daje to jawną kontrolę nad tym, które skrypty są chronione
Obfuskowane (muszą mieć atrybut data-javascript-obfuscator):
<script data-javascript-obfuscator>– zwykłe skrypty<script type="text/javascript" data-javascript-obfuscator>– skrypty z jawnie podanym typem- Skrypty z dowolnymi dodatkowymi atrybutami (
id,class, innedata-*itd.)
Pomijane (pozostają bez zmian):
- Skrypty bez atrybutu
data-javascript-obfuscator <script type="module">– moduły ES (nawet z tym atrybutem)<script src="...">– skrypty zewnętrzne (nawet z tym atrybutem)- Puste znaczniki skryptu
Uwaga: przy włączonej opcji parseHtml mapy źródeł nie są generowane, ponieważ nie odwzorowywałyby poprawnie wyniku w formacie HTML.
Przykład:
// 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
⚠️ ta opcja może zepsuć kod. Należy ją włączać tylko wtedy, gdy wiadomo, do czego służy!
Włącza obfuskację nazw zmiennych i funkcji globalnych wraz z deklaracją.
Gdy ta opcja jest wyłączona, a kod wejściowy deklaruje funkcje lub klasy w zasięgu globalnym (tzn. nie jest opakowany w IIFE), ich nazwy pozostają w zobfuskowanym wyniku bez zmian — inne skrypty mogą odwoływać się do nich po nazwie. Przy włączonej opcji vmObfuscation zgłaszane jest ostrzeżenie VMGlobalFunctionNamesNotRenamed z listą tych nazw, ponieważ ciało funkcji jest ukryte w postaci kodu bajtowego, ale czytelna nazwa najwyższego poziomu nadal zdradza, co robi kod (np. modelowi LLM). Aby uniknąć tego ujawnienia, należy opakować kod w IIFE albo włączyć tę opcję.
renameProperties
Type: boolean Default: false
⚠️ ta opcja MOŻE zepsuć kod. Należy ją włączać tylko wtedy, gdy wiadomo, do czego służy!
Włącza zmianę nazw właściwości. Wszystkie wbudowane właściwości DOM oraz właściwości podstawowych klas JavaScriptu zostaną pominięte.
Do przełączania między trybem safe i unsafe tej opcji służy opcja renamePropertiesMode.
Format zmienionych nazw właściwości ustawia się opcją identifierNamesGenerator.
Tym, którym właściwościom zostaną zmienione nazwy, steruje opcja reservedNames.
Przykład:
// 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
⚠️ Nawet w trybie safe opcja renameProperties MOŻE zepsuć kod.
Określa tryb opcji renameProperties:
safe– domyślne zachowanie po wydaniu2.11.0. Próbuje zmieniać nazwy właściwości w bezpieczniejszy sposób, aby zapobiec błędom w czasie wykonania. W tym trybie część właściwości zostanie wykluczona ze zmiany nazw.unsafe– domyślne zachowanie przed wydaniem2.11.0. Zmienia nazwy właściwości w niebezpieczny sposób, bez żadnych ograniczeń.
Jeśli jeden plik korzysta z właściwości pochodzących z innego pliku, należy użyć opcji identifierNamesCache, aby zachować te same nazwy właściwości w obu plikach.
reservedNames
Type: string[] Default: []
Wyłącza obfuskację i generowanie identyfikatorów pasujących do przekazanych wzorców RegExp.
Przykład:
{
reservedNames: [
'^someVariable',
'functionParameter_\d'
]
}
reservedStrings
Type: string[] Default: []
Wyłącza transformację literałów tekstowych pasujących do przekazanych wzorców RegExp. Dopasowane ciągi pozostaną widoczne w zobfuskowanym wyniku.
Przy obfuskacji VM zarezerwowane ciągi są przechowywane w osobnej, niezaszyfrowanej tablicy, aby pozostały widoczne. Jest to przydatne dla ciągów, które muszą pozostać czytelne, takich jak adresy endpointów API używanych do monitorowania czy identyfikatory bibliotek.
Przykład:
{
reservedStrings: [
'react-native',
'\.\/src\/test',
'some-string_\d'
]
}
seed
Type: string|number Default: 0
Ta opcja ustawia ziarno (seed) generatora liczb losowych. Przydaje się do uzyskiwania powtarzalnych wyników.
Jeśli ziarno wynosi 0, generator liczb losowych działa bez ziarna.
selfDefending
Type: boolean Default: false
⚠️ Po obfuskacji z tą opcją nie wolno w żaden sposób modyfikować zobfuskowanego kodu, ponieważ każda zmiana, na przykład minifikacja, może uruchomić mechanizm samoobrony i kod przestanie działać!
⚠️ Ta opcja wymusza ustawienie wartości compact na true
⚠️ Ta opcja jest po cichu wyłączana, gdy włączona jest opcja vmObfuscation. Należy wtedy użyć opcji vmSelfDefending.
Ta opcja sprawia, że kod wynikowy jest odporny na formatowanie i zmianę nazw zmiennych. Jeśli ktoś spróbuje użyć na zobfuskowanym kodzie narzędzia upiększającego JavaScript, kod przestanie działać, co utrudnia jego zrozumienie i modyfikację.
simplify
Type: boolean Default: true
Włącza dodatkową obfuskację kodu poprzez upraszczanie.
⚠️ w przyszłych wydaniach obfuskacja literałów boolean (true => !![]) zostanie przeniesiona pod tę opcję.
Przykład:
// 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
Włącza generowanie mapy źródeł dla zobfuskowanego kodu.
Mapy źródeł ułatwiają debugowanie zobfuskowanego kodu źródłowego JavaScript. Jeśli konieczne jest debugowanie na produkcji, osobny plik mapy źródeł można umieścić w niejawnej lokalizacji, a następnie wskazać ją przeglądarce.
sourceMapBaseUrl
Type: string Default: ``
Ustawia bazowy adres URL dla adresu importu mapy źródeł przy sourceMapMode: 'separate'.
Przykład CLI:
javascript-obfuscator input.js --output out.js --source-map true --source-map-base-url 'http://localhost:9000'
Wynik:
//# sourceMappingURL=http://localhost:9000/out.js.map
sourceMapFileName
Type: string Default: ``
Ustawia nazwę pliku wynikowej mapy źródeł przy sourceMapMode: 'separate'.
Przykład CLI:
javascript-obfuscator input.js --output out.js --source-map true --source-map-base-url 'http://localhost:9000' --source-map-file-name example
Wynik:
//# sourceMappingURL=http://localhost:9000/example.js.map
sourceMapMode
Type: string Default: separate
Określa tryb generowania mapy źródeł:
inline– dodaje mapę źródeł na końcu każdego pliku .js;separate– generuje odpowiadający plik '.map' z mapą źródeł. W przypadku uruchamiania obfuskatora przez CLI dodaje na końcu pliku z zobfuskowanym kodem odnośnik do pliku mapy źródeł//# sourceMappingUrl=file.js.map.
sourceMapSourcesMode
Type: string Default: sources-content
Pozwala sterować polami sources i sourcesContent mapy źródeł:
sources-content– dodaje atrapę polasourcesoraz polesourcesContentz oryginalnym kodem źródłowym;sources– dodaje polesourcesz poprawnym opisem źródeł i nie dodaje polasourcesContent. Przy korzystaniu z API NodeJS wymagane jest zdefiniowanie opcjiinputFileName, której wartość zostanie użyta jako wartość polasources.
splitStrings
Type: boolean Default: false
Dzieli literały tekstowe na fragmenty o długości określonej wartością opcji splitStringsChunkLength.
Przykład:
// input
(function(){
var test = 'abcdefg';
})();
// output
(function(){
var _0x5a21 = 'ab' + 'cd' + 'ef' + 'g';
})();
splitStringsChunkLength
Type: number Default: 10
Ustawia długość fragmentu dla opcji splitStrings.
stringArray
Type: boolean Default: true
Usuwa literały tekstowe i umieszcza je w specjalnej tablicy. Na przykład ciąg "Hello World" w var m = "Hello World"; zostanie zastąpiony czymś w rodzaju var m = _0x12c456[0x1];
stringArrayCallsTransform
Type: boolean Default: false
⚠️ Opcja stringArray musi być włączona
Włącza transformację wywołań do stringArray. Wszystkie argumenty tych wywołań mogą zostać wyodrębnione do osobnego obiektu, w zależności od wartości opcji stringArrayCallsTransformThreshold.
Dzięki temu automatyczne wyszukiwanie wywołań tablicy ciągów staje się jeszcze trudniejsze.
Przykład:
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
⚠️ Opcje stringArray i stringArrayCallsTransformThreshold muszą być włączone
Za pomocą tego ustawienia można dostosować prawdopodobieństwo (od 0 do 1) przekształcenia wywołań tablicy ciągów.
stringArrayEncoding
Type: string[] Default: []
⚠️ Opcja stringArray musi być włączona
Ta opcja może spowolnić skrypt.
Koduje wszystkie literały tekstowe z stringArray przy użyciu base64 lub rc4 i wstawia specjalny kod, który dekoduje je z powrotem w czasie wykonania.
Każda wartość stringArray zostanie zakodowana losowo wybranym kodowaniem z przekazanej listy. Umożliwia to jednoczesne stosowanie wielu kodowań.
Dostępne wartości:
'none'(boolean): nie koduje wartościstringArray'base64'(string): koduje wartośćstringArrayprzy użyciubase64'rc4'(string): koduje wartośćstringArrayprzy użyciurc4. Około 30–50% wolniejsze niżbase64, ale trudniej odtworzyć pierwotne wartości.
Na przykład przy poniższych wartościach opcji część wartości stringArray nie zostanie zakodowana, a pozostałe zostaną zakodowane kodowaniem base64 oraz rc4:
stringArrayEncoding: [
'none',
'base64',
'rc4'
]
stringArrayIndexesType
Type: string[] Default: ['hexadecimal-number']
⚠️ Opcja stringArray musi być włączona
Pozwala sterować typem indeksów wywołań tablicy ciągów.
Każdy indeks wywołania stringArray zostanie przekształcony zgodnie z losowo wybranym typem z przekazanej listy. Umożliwia to jednoczesne stosowanie wielu typów.
Dostępne wartości:
'hexadecimal-number'(default): przekształca indeksy wywołań tablicy ciągów w liczby szesnastkowe'hexadecimal-numeric-string': przekształca indeksy wywołań tablicy ciągów w szesnastkowe ciągi liczbowe
Przed wydaniem 2.9.0 javascript-obfuscator przekształcał wszystkie indeksy wywołań tablicy ciągów zgodnie z typem hexadecimal-numeric-string. Utrudnia to nieco ręczną deobfuskację, ale pozwala automatycznym deobfuskatorom łatwo wykrywać takie wywołania.
Nowy typ hexadecimal-number ma na celu utrudnienie automatycznego wykrywania wzorców wywołań tablicy ciągów w kodzie.
W przyszłości zostaną dodane kolejne typy.
stringArrayIndexShift
Type: boolean Default: true
⚠️ Opcja stringArray musi być włączona
Włącza dodatkowe przesunięcie indeksu dla wszystkich wywołań tablicy ciągów
stringArrayRotate
Type: boolean Default: true
⚠️ Opcja stringArray musi być włączona
Przesuwa tablicę stringArray o stałą, losowo wyznaczoną (podczas obfuskacji kodu) liczbę pozycji. Utrudnia to dopasowanie kolejności usuniętych ciągów do ich pierwotnych miejsc.
stringArrayShuffle
Type: boolean Default: true
⚠️ Opcja stringArray musi być włączona
Losowo tasuje elementy tablicy stringArray.
stringArrayWrappersCount
Type: number Default: 1
⚠️ Opcja stringArray musi być włączona
Ustawia liczbę wrapperów dla string array wewnątrz zasięgu głównego oraz każdego zasięgu funkcji.
Faktyczna liczba wrapperów w danym zasięgu jest ograniczona liczbą węzłów literal w tym zasięgu.
Przykład:
// 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
⚠️ Opcje stringArray i stringArrayWrappersCount muszą być włączone
Włącza łańcuchowe wywołania między wrapperami string array.
Przykład:
// 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
⚠️ Opcja stringArray musi być włączona
⚠️ Obecnie ta opcja dotyczy wyłącznie wrapperów dodawanych przy wartości function opcji stringArrayWrappersType
Pozwala sterować maksymalną liczbą parametrów wrapperów tablicy ciągów.
Wartość domyślna i minimalna to 2. Zalecana wartość mieści się w przedziale od 2 do 5.
stringArrayWrappersType
Type: string Default: variable
⚠️ Opcje stringArray i stringArrayWrappersCount muszą być włączone
Pozwala wybrać typ wrapperów dodawanych przez opcję stringArrayWrappersCount.
Dostępne wartości:
'variable': dodaje wrappery w postaci zmiennych na początku każdego zasięgu. Wysoka wydajność.'function': dodaje wrappery w postaci funkcji w losowych miejscach wewnątrz każdego zasięgu. Wydajność niższa niż przyvariable, ale obfuskacja jest ostrzejsza.
Zdecydowanie zaleca się stosowanie wrapperów function dla silniejszej obfuskacji, o ile spadek wydajności nie ma dużego wpływu na zobfuskowaną aplikację.
Przykład dla wartości opcji '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
⚠️ Opcja stringArray musi być włączona
Za pomocą tego ustawienia można dostosować prawdopodobieństwo (od 0 do 1), że literał tekstowy zostanie umieszczony w stringArray.
To ustawienie jest szczególnie przydatne przy dużym rozmiarze kodu, ponieważ powoduje ono wielokrotne wywołania string array i może spowolnić kod.
stringArrayThreshold: 0 jest równoznaczne z stringArray: false.
strictMode
Type: boolean | null Default: null
Pozwala określić, jak obfuskator ma traktować kod w kontekście trybu ścisłego (strict mode) JavaScriptu.
Dostępne wartości:
null(domyślnie) – automatycznie wykrywa tryb ścisły na podstawie kodu. Jeśli kod zawiera jawną dyrektywę'use strict', składnię modułów ES lub metody klas, jest traktowany jako kod w trybie ścisłym. W przeciwnym razie zakładany jest tryb swobodny (sloppy mode).true– wymusza traktowanie całego kodu jako kodu w trybie ścisłym, nawet bez jawnej dyrektywy'use strict'. Należy stosować, gdy kod będzie uruchamiany w kontekście trybu ścisłego (np. w modułach ES, bundlerach lub nowoczesnych frameworkach).false– jako kod w trybie ścisłym traktowane są wyłącznie fragmenty z jawnymi wskaźnikami trybu ścisłego ('use strict', moduły ES, metody klas). Dziedziczenie z zasięgu nadrzędnego nadal obowiązuje zgodnie ze specyfikacją JS.
target
Type: string Default: browser
Pozwala ustawić środowisko docelowe zobfuskowanego kodu.
Dostępne wartości:
browser(domyślnie) — standardowe środowisko strony internetowej. Kod wynikowy jest identyczny jak dlanode, ale niektórych opcji przeznaczonych dla przeglądarki nie można używać ze środowiskiemnodebrowser-no-eval— tak samo jakbrowser, ale kod wynikowy nie używaeval(). Należy stosować, gdy strona docelowa ma politykę Content Security Policy zabraniającąeval/unsafe-eval.node— środowisko Node.js. Opcje przeznaczone dla przeglądarki są wyłączone (wymagająwindow/document, a w Node nie robiłyby nic lub zgłaszałyby błąd). Część mechanizmów obronnychvmSelfDefendingopartych na API dostępnych wyłącznie w przeglądarce — wykrywanie przeglądarki headless, odtwarzanie czystego realmu przy użyciu iframe, kontrole antyinspektorowe i sprawdzanie DOM — nie jest generowana dla tego środowiska.service-worker— kontekst Service Workera. Brakwindow, brakdocument, inny obiekt globalnyself.userscript— piaskownica menedżera userscriptów (np. Tampermonkey). Mechanizmy obronnevmSelfDefendingsą odpowiednio dostosowywane.bytenode— kod Node.js, który po obfuskacji zostanie skompilowany loaderem bytenode (kod bajtowy V8 z pamięci podręcznej,.jsc). Sam obfuskator nie uruchamiabytenode; generuje kod JavaScript po obfuskacji VM, którego środowisko uruchomieniowe jest zbudowane tak, aby przetrwało etap kompilacji przez bytenode, a mechanizmy obronnevmSelfDefendingsą odpowiednio dostosowywane. Aby otrzymać końcowy plik.jsc, należy samodzielnie uruchomićbytenodena zobfuskowanym kodzie wynikowym.
transformObjectKeys
Type: boolean Default: false
Włącza transformację kluczy obiektów.
Przykład:
// 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
Określa, które nieblokujące ostrzeżenia obfuskacji są zwracane przez metodę ObfuscationResult.getWarnings().
Dostępne wartości:
'all'(domyślnie) — zwracane są wszystkie ostrzeżenia.'none'— wszystkie ostrzeżenia są pomijane.- obiekt mapujący typy ostrzeżeń na wartości logiczne — typ przypisany do
falsejest pomijany; każdy typ nieobecny w mapie (lub przypisany dotrue) pozostaje włączony. Na przykład{ "VMGlobalFunctionNamesNotRenamed": false }zachowuje wszystkie ostrzeżenia z wyjątkiem tego jednego.
Typy ostrzeżeń:
VMGlobalFunctionNamesNotRenamed— przy włączonej opcjivmObfuscationnazwy deklaracji funkcji i klas najwyższego poziomu oraz zmiennych, którym przypisano wyrażenie funkcyjne, funkcję strzałkową lub wyrażenie klasowe, pozostały bez zmian (opcjarenameGlobalsjest wyłączona, a kod nie jest opakowany w IIFE), więc pozostają czytelne w wyniku, mimo że ciała funkcji są ukryte w postaci kodu bajtowego. Nazwy eksportowane nie są zgłaszane.VMTopLevelInitializerNotVirtualized— inicjalizatory zmiennych najwyższego poziomu pozostały przy obfuskacji VM zwykłym kodem JavaScript, ponieważ opcjavmWrapTopLevelInitializersjest wyłączona lub nie zdołała ich zwirtualizować.DynamicCodeRenameRisk— kod tworzy funkcję z ciągu znaków w czasie wykonania (bezpośrednieval, konstruktorFunctionlubfn.toString()wstrzyknięty do znacznika<script>/Workera), przez co może odwoływać się do identyfikatorów, których nazwy zmienił obfuskator.VMDynamicCodeSkipped— funkcja została pominięta przy generowaniu kodu bajtowego VM, ponieważ zawiera bezpośrednieval, dynamicznenew FunctionalboFunction(zob.vmForceCompileDynamicCode).VMSyncFunctionSkippedInAsyncMode— przy włączonej opcjivmAsyncExecutorfunkcja jawnie oznaczona w trybiecommentokazała się synchroniczna i została pominięta (w tym trybie wirtualizowane są wyłącznie funkcje asynchroniczne).VMAsyncGeneratorSkippedInAsyncMode— przy włączonej opcjivmAsyncExecutori aktywnym asynchronicznym getterze klucza nie udało się zwirtualizować oznaczonego generatora asynchronicznego (musi on zwracać swój iterator synchronicznie).BrowserTargetWithNodeStyleCode— kod wygląda na przeznaczony dla Node.js (np.require('fs'),__dirname,process.argv), podczas gdy opcjatargetjest ustawiona na środowisko przeglądarkowe.
vmObfuscation
Type: boolean Default: false
Włącza obfuskację opartą na kodzie bajtowym VM. Po jej włączeniu funkcje JavaScript są kompilowane do niestandardowego kodu bajtowego wykonywanego przez osadzoną maszynę wirtualną. Zapewnia to najwyższy poziom ochrony, ponieważ pierwotna logika kodu zostaje całkowicie przekształcona.
Przykład:
Czytelny kod w rodzaju return qty * price zamienia się w listę liczb, na przykład [0x15,0x03,0x17,...], którą potrafi wykonać wyłącznie osadzony interpreter VM. Pierwotna logika nie jest już widoczna jako kod JavaScript.
vmTargetFunctions
Type: string[] Default: []
Pozwala wskazać po nazwie dokładnie te funkcje najwyższego poziomu, które mają zostać objęte ochroną VM.
Przykład:
{
vmObfuscation: true,
vmTargetFunctions: ['someFunctionName']
}
Wynik: ochroną VM zostaną objęte wyłącznie te trzy funkcje. Cała reszta pozostanie zwykłym (choć nadal zobfuskowanym) kodem JavaScript. Idealne rozwiązanie do ochrony wrażliwej weryfikacji licencji lub logiki uwierzytelniania przy zachowaniu lekkości pozostałej części kodu.
vmExcludeFunctions
Type: string[] Default: []
Pozwala wskazać funkcje najwyższego poziomu, które nigdy nie mają być objęte ochroną VM. Ma pierwszeństwo przed pozostałymi ustawieniami.
Przykład:
{
vmObfuscation: true,
vmExcludeFunctions: ['someFunctionName']
}
Kiedy stosować: funkcje najwyższego poziomu krytyczne dla wydajności (pętle animacji, przetwarzanie danych w czasie rzeczywistym) można wykluczyć, aby uniknąć narzutu VM, chroniąc jednocześnie całą resztę.
vmTargetFunctionsMode
Type: string Default: root
Określa sposób wyboru funkcji i metod do obfuskacji VM.
Przykład – tryb 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'
}
Kiedy stosować: gdy potrzebna jest chirurgiczna kontrola nad tym, które dokładnie funkcje zostaną objęte ochroną VM, zwłaszcza funkcje zagnieżdżone zawierające wrażliwą logikę. W przeciwieństwie do vmTargetFunctions, które działa wyłącznie dla nazwanych funkcji najwyższego poziomu, tryb comment pozwala chronić dowolną funkcję w dowolnym miejscu kodu.
vmForceCompileDynamicCode
Type: boolean Default: false
Określa, co obfuskacja VM robi z funkcją zawierającą bezpośrednie wywołanie eval, new Function(...) lub Function(...).
Domyślnie taka funkcja (oraz każda funkcja zdefiniowana w jej wnętrzu) jest pomijana przy generowaniu kodu bajtowego VM, a w result.getWarnings() zgłaszane jest ostrzeżenie VMDynamicCodeSkipped. Dzieje się tak dlatego, że kod źródłowy budowany w czasie wykonania może odwoływać się do identyfikatorów z otaczającego łańcucha zasięgów — identyfikatorów, których nazwy zmienił obfuskator.
Po ustawieniu wartości true funkcja mimo wszystko zostaje przekształcona w kod bajtowy, a ostrzeżenie VMDynamicCodeSkipped nie jest już zgłaszane.
Osobne ostrzeżenie DynamicCodeRenameRisk jest zgłaszane niezależnie od tej opcji, ponieważ opisywane przez nie ryzyko związane ze zmianą nazw nie ma związku z pomijaniem funkcji przez VM — włączenie tej opcji w żaden sposób nie czyni tego wzorca bezpieczniejszym.
// Source code
function loadConfig(src) {
return eval(src);
}
loadConfig('1 + 2');
// Options
{
vmObfuscation: true,
vmForceCompileDynamicCode: true
}
Przy wyłączonej opcji (domyślnie) loadConfig pozostaje zwykłym kodem JavaScript. Przy włączonej opcji loadConfig jest kompilowana do kodu bajtowego VM jak każda inna funkcja. Należy z tego korzystać po sprawdzeniu miejsca wywołania i upewnieniu się, że kod budowany w czasie wykonania nie zależy od identyfikatorów z domknięcia, których nazwy zostały zmienione.
vmWrapTopLevelInitializers
Type: boolean Default: false
Opakowuje część inicjalizatorów zmiennych najwyższego poziomu w IIFE (natychmiast wywoływane wyrażenia funkcyjne), dzięki czemu mogą zostać poddane obfuskacji VM.
Co robi: Bez tej opcji stałe i zmienne najwyższego poziomu pozostają widoczne w wyniku:
// Input
const MY_STRING = "my-string";
// Output (without vmWrapTopLevelInitializers)
const MY_STRING = "my-string"; // String is visible!
Po włączeniu tej opcji inicjalizator zostaje opakowany w IIFE, które podlega obfuskacji VM:
// Input
const MY_STRING = "my-string";
// Output (with vmWrapTopLevelInitializers: true)
const MY_STRING = (() => { return /* VM bytecode call */ })(); // String hidden in bytecode
Uwaga: ta opcja działa wyłącznie wtedy, gdy vmTargetFunctionsMode ma wartość 'root' (domyślną).
Ostrzeżenia: za każdym razem, gdy przy obfuskacji VM inicjalizator najwyższego poziomu pozostanie zwykłym kodem JavaScript, zgłaszane jest ostrzeżenie VMTopLevelInitializerNotVirtualized z listą nazw zmiennych, których to dotyczy. Obejmuje ono: wyłączenie tej opcji, inicjalizatory, które opcja musiała pominąć (każdy wraz z powodem — np. inicjalizator odwołuje się do sąsiedniego deklaratora albo zawiera await najwyższego poziomu), oraz tryb vmAsyncExecutor, w którym synchronicznych wrapperów w ogóle nie da się zwirtualizować.
vmDynamicOpcodes
Type: boolean Default: false
Sprawia, że interpreter VM jest mniejszy i unikalny dla każdej kompilacji.
Co robi:
- Odfiltrowuje nieużywane instrukcje – jeśli kod nie korzysta z klas, instrukcje związane z klasami są całkowicie usuwane
- Losuje strukturę – kolejność procedur obsługi instrukcji jest tasowana przy każdej kompilacji
W efekcie wynik jest mniejszy, a każda kompilacja wygląda inaczej.
vmBytecodeEncoding
Type: boolean Default: false
Koduje każdą instrukcję kodu bajtowego. Instrukcje są dekodowane pojedynczo w trakcie wykonywania.
vmBytecodeArrayEncoding
Type: boolean Default: false
Koduje całą tablicę kodu bajtowego jako pojedynczy blok. Tablica jest dekodowana jednorazowo przy starcie, zanim rozpocznie się wykonywanie. Warto stosować razem z vmBytecodeEncoding, aby uzyskać dwie warstwy ochrony.
vmBytecodeArrayEncodingKey
Type: string Default: ''
Własny klucz szyfrujący dla kodowania tablicy kodu bajtowego. Po ustawieniu używany jest ten klucz zamiast domyślnego klucza wyprowadzanego ze środowiska. Klucz musi zostać dostarczony w czasie wykonania przez vmBytecodeArrayEncodingKeyGetter.
Ta opcja wynosi klucz szyfrujący na zewnątrz — nie jest on osadzony w samym zobfuskowanym kodzie. Klucz jest wprawdzie nadal dostępny w czasie wykonania (a więc nie jest naprawdę tajny), ale takie rozdzielenie uniemożliwia narzędziom do analizy statycznej znalezienie go na podstawie samego kodu.
Ważne: klucz musi być dostępny synchronicznie w momencie ładowania zobfuskowanego kodu. Należy korzystać z synchronicznych źródeł danych, takich jak ciasteczka, localStorage, sessionStorage, zmienne globalne lub elementy DOM (np. znaczniki meta wstrzykiwane przez serwer). Metod asynchronicznych, takich jak fetch(), nie można użyć bezpośrednio w wyrażeniu gettera klucza.
vmBytecodeArrayEncodingKeyGetter
Type: string Default: ''
Synchroniczne wyrażenie JavaScript, które zwraca klucz szyfrujący w czasie wykonania. Wyrażenie to jest obliczane w momencie załadowania zobfuskowanego kodu i musi zwrócić dokładnie ten sam klucz, który podano w vmBytecodeArrayEncodingKey. Aby uzyskiwać klucz asynchronicznie (jako Promise), należy włączyć opcję vmAsyncExecutor.
Uwaga: getter zwracający obiekt Promise wymaga opcji vmAsyncExecutor. Nie da się tego sprawdzić na etapie kompilacji, więc getter zwracający Promise przy wyłączonej opcji vmAsyncExecutor zawiedzie w czasie wykonania — dekoder otrzyma obiekt Promise zamiast klucza.
Zobfuskowany kod zadziała wyłącznie wtedy, gdy getter klucza zwróci dokładnie ten sam klucz, którego użyto podczas obfuskacji. Jeśli klucze się nie zgadzają, odszyfrowanie się nie powiedzie, a kod będzie generował śmieci lub błędy. Jeśli getter klucza zwróci undefined, null albo pusty ciąg, kod zgłosi błąd: „VM decryption key not available”.
Ważne: klucz należy trzymać poza tym samym plikiem/skryptem co zobfuskowany kod — umieszczenie go tam pozwala odzyskać go nawet czysto statycznym przeskanowaniem bundle’a. Zamiast tego należy przechowywać go w osobnym źródle: w ciasteczkach ustawianych przez serwer, w localStorage wypełnianym przez inny skrypt, w znaczniku meta HTML wstrzykiwanym przez serwer, w zmiennej globalnej ustawianej przez inny skrypt lub (przy włączonej opcji vmAsyncExecutor) pobierać go w czasie wykonania z własnego backendu.
Gdy klucz jest pobierany z backendu (przez vmAsyncExecutor), warto dodać na tym endpoincie kontrole oparte na sesji lub źródle żądania: prawdziwym użytkownikom (ważna sesja, oczekiwane nagłówki Origin/Referer) należy zwracać poprawny klucz, a podejrzanym żądaniom (np. z localhost lub nieoczekiwanego źródła, bez sesji) — klucz-śmieć. Prawdziwi użytkownicy pracują normalnie, natomiast kopia uruchomiona poza Twoim środowiskiem otrzymuje klucz, który niczego nie odszyfruje. Konkretna logika zależy od danej witryny.
Przykłady:
// 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())'
Przykład użycia:
// 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
Włącza asynchroniczny executor VM, dzięki któremu vmBytecodeArrayEncodingKeyGetter może zwracać obiekt Promise (asynchroniczny getter klucza) — klucz deszyfrujący może więc być pobierany w czasie wykonania (żądanie sieciowe, IndexedDB itp.), zamiast być dostępny synchronicznie w momencie ładowania kodu.
Zdecydowanie zalecane dla w pełni asynchronicznych baz kodu. W tym trybie wirtualizowane są wyłącznie funkcje async — funkcji synchronicznej nie da się uczynić asynchroniczną bez zamiany jej wartości zwracanej w Promise i zepsucia kodu wywołującego — więc kod asynchroniczny w całości uzyskuje największe pokrycie. Tryb działa również wtedy, gdy poziom główny jest synchroniczny (np. synchroniczne IIFE lub wrapper UMD): chronione są najbardziej zewnętrzne funkcje async znajdujące się w środku, a części synchroniczne pozostają bez zmian.
Co podlega transformacji: każda najbardziej zewnętrzna funkcja async, gdziekolwiek się pojawia (również zagnieżdżona w synchronicznych wrapperach). Najbardziej zewnętrzna funkcja async w każdym łańcuchu jest chronioną jednostką — wszystko w jej wnętrzu, zarówno synchroniczne, jak i asynchroniczne, zostaje skompilowane razem z nią. Funkcje synchroniczne i zwykłe generatory pozostają bez obfuskacji.
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
}
}
Pominięcia i ostrzeżenia. Generatory asynchroniczne również pozostają bez obfuskacji, gdy aktywny jest asynchroniczny getter klucza (generator asynchroniczny musi zwrócić swój iterator synchronicznie i nie może czekać na klucz). W domyślnym trybie vmTargetFunctionsMode: 'root' pominięcia są ciche (wybór jest automatyczny); w trybie comment za każdym razem, gdy jawnie oznaczonej funkcji nie da się zwirtualizować — okazała się synchroniczna albo jest generatorem asynchronicznym przy asynchronicznym getterze klucza — zgłaszane jest ostrzeżenie przez ObfuscationResult.getWarnings().
Asynchroniczny getter klucza wymaga dodatkowo opcji vmBytecodeArrayEncoding wraz z vmBytecodeArrayEncodingKeyGetter.
Przykład użycia:
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
Koduje cele skoków w kodzie bajtowym. Przesunięcia skoków są obliczane w czasie wykonania, co ukrywa strukturę przepływu sterowania (if/else, pętle itd.) przed analizą statyczną.
vmMacroOps
Type: boolean Default: false
Łączy typowe sekwencje instrukcji w pojedyncze opkody „makro”. Na przykład LOAD + ADD + STORE może stać się jedną instrukcją MACRO_ADD_TO_VAR. Utrudnia to rozpoznawanie wzorców i może poprawić wydajność.
vmDebugProtection
Type: boolean Default: false
Dodaje do środowiska uruchomieniowego VM wielowarstwowe zabezpieczenia przed debugowaniem, analizą oraz działaniem modeli LLM. Działa najlepiej ze środowiskami browser/browser-no-eval.
vmSelfDefending
Type: boolean Default: false
Dodaje do środowiska uruchomieniowego VM wielowarstwową ochronę: wykrywanie manipulacji, ochronę przed hookowaniem oraz przed inżynierią wsteczną.
⚠️ Ta opcja wymusza włączenie opcji vmBytecodeArrayEncoding.
⚠️ Wykrywanie wrażliwego środowiska. Ta opcja wiąże zobfuskowany kod z docelowym środowiskiem uruchomieniowym i wykorzystuje zaawansowany fingerprinting przeglądarki do wykrywania narzędzi automatyzujących. Kod chroniony tą opcją celowo przestanie działać, gdy zostanie uruchomiony w:
- Przeglądarkach headless (headless Chrome/Chromium, PhantomJS)
- Narzędziach do automatyzacji przeglądarek (Puppeteer, Playwright, Cypress, Selenium/ChromeDriver, Nightmare)
- Node.js (gdy
targetjest ustawiony nabrowser) - jsdom lub podobnych serwerowych emulacjach DOM
- Środowiskach, w których natywne wbudowane funkcje przeglądarki zostały podhaczone (hooked) lub podmienione
Kod będzie działał poprawnie w zwykłych przeglądarkach (Chrome, Firefox, Safari, Edge), w tym po załadowaniu wewnątrz elementów iframe, w rozszerzeniach przeglądarki (content scripts) oraz w Web Workerach. Jeśli konieczne jest uruchamianie automatycznych testów na chronionym kodzie, w kompilacjach testowych należy wyłączyć vmSelfDefending — ta opcja została zaprojektowana tak, aby uniemożliwiać automatyczną analizę, i nie może być bezpiecznie używana z żadnym frameworkiem automatyzującym.
Zdecydowanie zaleca się stosowanie jej wraz z vmDebugProtection, vmBytecodeArrayEncodingKey oraz vmBytecodeArrayEncodingKeyGetter.
vmDefenseHook
Type: { name: string, aliases?: object } Default: ''
vmDefenseHook przyjmuje obiekt z dwoma kluczami: name (wymagany) i aliases (opcjonalny).
name to globalna funkcja definiowana przez Twoją stronę hostującą, którą mechanizm obronny VM (vmDebugProtection / vmSelfDefending) wywołuje z obiektem sygnału po wykryciu wrogiego sygnału — debuggera lub inspektora, przeglądarki headless / automatyzującej, procesu agenta AI programującego kod, niedozwolonej domeny itp. Służy do raportowania zdarzenia do własnego backendu (np. przez navigator.sendBeacon). Hook jest czystym odbiornikiem telemetrii: jego wartość zwracana jest ignorowana, a brakujący lub zgłaszający wyjątek hook to cichy brak działania, który nigdy nie może wyłączyć mechanizmu obronnego. Aby zmienić to, co mechanizm obronny robi po wykryciu, należy użyć opcji vmDefenseReaction.
aliases opcjonalnie zmienia nazwy pól tego obiektu sygnału — opisano to poniżej w części Zmiana nazw pól sygnału.
Obiekt sygnału. Hook otrzymuje jeden signal:
source— konkretny detektor, który zadziałał (zob. tabelę).category— grupa, w ramach której raportuje:automation(przeglądarki nieobsługiwane przez człowieka),debugger(aktywny debugger/inspektor),sandbox(instrumentowany/fałszywy host),domain(naruszenie blokady domeny),tamper(wbudowane funkcje podmienione w czasie wykonania) lubintegrity(zmieniono kod samej VM).score/threshold— jak silnie zadziałał detektor oraz wartość, którą musiał osiągnąć; hook zadziała dopiero wtedy, gdyscore >= threshold. Większość kontroli działa na zasadzie „wszystko albo nic” (pojedynczy rozstrzygający sygnał);headlesssumuje kilka sygnałów dotyczących kształtu przeglądarki, więc jegoscorejest zwykle wyższy niżthreshold.
Rejestrowanie hooka. Należy zdefiniować go jako zwykłą zmienną globalną przed załadowaniem zobfuskowanego bundle’a — środowisko uruchomieniowe VM i jego mechanizmy obronne działają przed Twoim (chronionym) programem, więc wiele detekcji zachodzi już podczas startu:
// in your page, before the obfuscated script:
window.__vmDetection = function (signal) { navigator.sendBeacon('/vm-defense', JSON.stringify(signal)); };
// obfuscation option:
vmDefenseHook: { name: '__vmDetection' }
Hook zdefiniowany wewnątrz zobfuskowanego kodu źródłowego jest rejestrowany zbyt późno, aby wychwycić detekcje zachodzące podczas startu, a jeśli zostanie skompilowany do VM, nie da się do niego dotrzeć, dopóki nie uruchomi się Twój program. Jest on bezpieczny w obu przypadkach (brakujący hook nie robi nic, a zabezpieczenie przed ponownym wejściem zapobiega niekontrolowanemu działaniu), ale dla pełnego pokrycia należy rejestrować go z wyprzedzeniem. Aby mimo to chronić własną logikę raportowania, rejestrowany hook warto ograniczyć do jednolinijkowego bufora ((window.__vmDet = window.__vmDet || []).push(signal)) i odczytywać/wysyłać ten bufor z poziomu zobfuskowanego kodu.
Zmiana nazw pól sygnału (aliases). Domyślne wartości source/category to opisowe nazwy, więc każdy, kto instrumentuje callback (lub czyta wynik), może rozpoznać zabezpieczenie i wskazać, który detektor zadziałał. aliases zmienia nazwy pól sygnału na wybrane przez Ciebie nieprzejrzyste tokeny, stosowane wewnątrz VM przed wyemitowaniem sygnału, dzięki czemu te nazwy nigdy nie pojawiają się w wyniku ani nie docierają do callbacku. Twoja aplikacja zna własne odwzorowanie i przekazuje tokeny do backendu.
Aliasy działają per pole, rozdzielając zmianę nazw kluczy i wartości: każde pole przyjmuje key (nazwę właściwości otrzymywaną przez callback); tekstowe pola nazw source i category przyjmują też mapę values, natomiast score/threshold są liczbami i przyjmują wyłącznie key. Nazwy, które można odwzorować (wszystko inne jest odrzucane na etapie kompilacji):
- klucze pól —
source,category,score,threshold - wartości
source—headless,agent,node,debugger,timing,sandbox,domain,nativeHook,integrity - wartości
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> }
}
To zabezpieczenie przed fingerprintingiem, a nie utajnianie — odwzorowanie wciąż da się wywnioskować przez wielokrotne testowanie — więc jego jedyną korzyścią jest nieujawnianie stałych, samoopisujących się nazw. Nieustawione wpisy zachowują swoje domyślne nazwy.
Zwykły ciąg znaków (vmDefenseHook: '__vmDetection') jest akceptowany jako skrót dla { name: '__vmDetection' }, ale jest przestarzały — należy preferować postać obiektową.
vmDefenseReaction
Type: object Default: { automation: 'break', debugger: 'decoy', sandbox: 'decoy', domain: 'break', tamper: 'break', integrity: 'break' }
Konfiguruje sposób reakcji każdej kategorii detekcji. Nie włącza niczego — same mechanizmy obronne uruchamiają opcje vmSelfDefending, vmDebugProtection oraz vmDomainLock; ta opcja wybiera jedynie, jak włączony mechanizm obronny reaguje. Jednostką kontroli jest kategoria — każdy detektor w kategorii wprowadza reakcję przypisaną tej kategorii.
Każda kategoria grupuje detektory czuwające nad jednym rodzajem wrogiego warunku. Kategoria reaguje tylko wtedy, gdy włączona jest opcja emitująca jej detektory:
Każda kategoria odwzorowuje się na co najmniej jedną z opcji vmSelfDefending, vmDebugProtection i vmDomainLock; nie istnieje kategoria poza tymi trzema opcjami, a reakcja ustawiona dla kategorii, której opcja jest wyłączona, po prostu nie ma żadnego efektu.
Kluczami są te sześć nazw kategorii lub default (rozwiązanie awaryjne dla nieokreślonych kategorii). Wartości to:
break— natychmiast przerwij działaniedecoy— kontynuuj działanie na zatrutym stanie, po cichu generując błędne wynikinone— nie rób nic lokalnie (tylko telemetria)
Domyślne wartości poszczególnych kategorii pokazano powyżej; kategoria, której nie ustawisz (lub ustawisz na jej wartość domyślną), korzysta z tej wartości domyślnej. default obejmuje każdą kategorię, w tym te poprawne z założenia (integrity, tamper), więc { default: 'none' } to naprawdę nieprzerywająca kompilacja wyłącznie z telemetrią:
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
Sprawia, że znaczenie opkodów zależy od pozycji w kodzie bajtowym. Każda pozycja ma inne odwzorowanie opkodu na procedurę obsługi, wyprowadzane z ziarna, więc ten sam numer opkodu wykonuje różne operacje na różnych pozycjach.
vmCallContextOpcodes
Type: boolean Default: false
Sprawia, że chroniona funkcja zależy od miejsca, z którego jest wywoływana, dzięki czemu nie da się jej wyodrębnić z kodu i uruchomić ani przeanalizować samodzielnie — działa poprawnie wyłącznie wtedy, gdy jest wywoływana przez swoje rzeczywiste miejsca wywołań w programie. Ta opcja wpływa na wydajność w czasie wykonania.
Obecnie obsługiwane są wyłącznie następujące konstrukcje:
- deklaracje funkcji (
function f() {}); - wyrażenia funkcyjne i funkcje strzałkowe przypisane do zmiennej (
const f = () => {}); - prywatne metody instancji (
this.#m()).
W każdym przypadku funkcja musi być zawsze osiągana przez bezpośrednie wywołanie (f(), this.#m()). Jeśli zostanie zapisana w innej zmiennej, przekazana jako argument lub w inny sposób użyta jako wartość, pozostanie niechroniona. Funkcje asynchroniczne są obsługiwane; generatory — nie.
Ta opcja jest eksperymentalna i może zepsuć kod, dlatego przed użyciem należy dokładnie przetestować wynik.
vmStackEncoding
Type: boolean Default: false
Szyfruje wartości na stosie VM w trakcie wykonywania. Wartości są kodowane przy odkładaniu na stos i dekodowane przy zdejmowaniu, więc inspekcja pamięci pokazuje zaszyfrowane dane zamiast rzeczywistych wartości.
Ta opcja mocno wpływa na wydajność.
vmCompactDispatcher
Type: boolean Default: false
Używa pojedynczego executora VM zamiast dwóch (synchronicznego + generatorowego). Zmniejsza rozmiar zobfuskowanego kodu, ale dodaje około 20% narzutu wydajnościowego przy kodzie intensywnie korzystającym z rekurencji.
false(domyślnie): dwa executory — optymalna wydajność, większy wyniktrue: pojedynczy executor — mniejszy wynik, nieco wolniej
vmStringArrayBytecodeOnly
Type: boolean Default: false
Po włączeniu tablica ciągów wyłącznie wyodrębnia ciągi z danych kodu bajtowego — żadne inne ciągi w kodzie nie są przekształcane. Wymusza to włączenie stringArray, nawet jeśli nie ustawiono jej jawnie.
Dlaczego warto: wyodrębnianie wszystkich ciągów środowiska uruchomieniowego VM do tablicy ciągów jest powolne. Ta opcja obejmuje wyodrębnianiem do tablicy ciągów wyłącznie zawartość kodu bajtowego, poprawiając wydajność i chroniąc jednocześnie stałe kodu bajtowego.
- Gdy
vmBytecodeArrayEncoding: false— wyodrębniane są ciągi z pul stałych kodu bajtowego (tablicec) - Gdy
vmBytecodeArrayEncoding: true— wyodrębniane są zakodowane w base64 ciągi kodu bajtowego najwyższego poziomu stringArrayThresholdnadal steruje tym, jaki procent tych ciągów kodu bajtowego jest wyodrębniany
vmDomainLock
Type: string[] Default: []
⚠️ Ta opcja nie działa z target: 'node', target: 'service-worker' ani target: 'bytenode'
Ogranicza działanie zobfuskowanego kodu do określonych domen i/lub subdomen i jest znacznie trudniejsza do zlokalizowania i usunięcia niż domainLock.
Jeśli kod źródłowy nie jest uruchamiany w domenach wskazanych w tej opcji, przeglądarka zostanie przekierowana pod adres URL przekazany w opcji vmDomainLockRedirectUrl, a kolejne chronione wywołania będą zwracać nieprawidłowe wyniki, nawet jeśli przekierowanie zostanie zablokowane.
Wiele domen i subdomen
Kod można zablokować do więcej niż jednej domeny lub subdomeny. Na przykład, aby zablokować go tak, by działał wyłącznie w www.example.com, należy dodać www.example.com. Aby działał w domenie głównej wraz ze wszystkimi subdomenami (example.com, sub.example.com), należy użyć .example.com.
vmDomainLockRedirectUrl
Type: string Default: about:blank
⚠️ Ta opcja nie działa z target: 'node', target: 'service-worker' ani target: 'bytenode'
Pozwala przekierować przeglądarkę pod przekazany adres URL, jeśli kod źródłowy nie jest uruchamiany w domenach wskazanych w opcji vmDomainLock.
Preset Options
Wysoka obfuskacja, niska wydajność
Wydajność będzie znacznie niższa niż bez obfuskacji
{
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
}
Średnia obfuskacja, optymalna wydajność
Wydajność będzie niższa niż bez obfuskacji
{
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
}
Niska obfuskacja, wysoka wydajność
Wydajność pozostanie na względnie normalnym poziomie
{
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
}
Preset domyślny, wysoka wydajność
{
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 Ultra High – bardzo wysoka obfuskacja (maksymalne bezpieczeństwo)
Ten preset włącza obfuskację opartą na kodzie bajtowym VM ze wszystkimi funkcjami wzmacniającymi ochronę, w tym z pośrednim dyspozytorem (indirect dispatch). Zapewnia najsilniejszą ochronę, ale kosztem większego rozmiaru wyniku i znacznie wolniejszego wykonywania.
{
optionsPreset: 'vm-ultra-high-obfuscation'
}
Lub skonfiguruj poszczególne opcje osobno:
{
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 Anti-LLM (ochrona przed agentami AI)
Ten preset został zaprojektowany specjalnie tak, aby uniemożliwiać agentom AI i modelom LLM inżynierię wsteczną kodu bajtowego VM. Oparty na vm-default z włączoną samoobroną i ochroną przed debugowaniem. Lżejszy niż vm-high-obfuscation, ale specjalnie utwardzony przeciwko automatycznej analizie.
{
optionsPreset: 'vm-anti-llm'
}
Obejmuje:
- Obfuskację kodu bajtowego VM z tablicą ciągów (z
vm-default) vmSelfDefending— wykrywanie hooków, hash integralności, fingerprint kodu źródłowego, weryfikację czystego realmu przez iframe, wyprowadzanie klucza szyfrem ARXvmDebugProtection— kontrole antydebugujące w pętli dyspozytora VMdebugProtection: false— brak przestarzałej ochrony przed debugowaniem (ochrona przed debugowaniem VM jest lepsza)
VM High – wysoka obfuskacja (najwyższe bezpieczeństwo)
Ten preset włącza obfuskację opartą na kodzie bajtowym VM z większością funkcji wzmacniających ochronę. Zapewnia silną ochronę przy lepszej wydajności niż preset ultra-high.
{
optionsPreset: 'vm-high-obfuscation'
}
Lub skonfiguruj poszczególne opcje osobno:
{
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 Medium – średnia obfuskacja (zrównoważone bezpieczeństwo)
Ten preset włącza obfuskację opartą na kodzie bajtowym VM ze zrównoważonym zestawem funkcji wzmacniających ochronę. Dobry kompromis między bezpieczeństwem a wydajnością.
{
optionsPreset: 'vm-medium-obfuscation'
}
Lub skonfiguruj poszczególne opcje osobno:
{
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 Low – niska obfuskacja (podstawowe bezpieczeństwo, lepsza wydajność)
Ten preset włącza podstawową obfuskację opartą na kodzie bajtowym VM bez dodatkowych funkcji wzmacniających ochronę. Dobra równowaga między bezpieczeństwem a rozmiarem wyniku.
{
optionsPreset: 'vm-low-obfuscation'
}
Lub skonfiguruj poszczególne opcje osobno:
{
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 Default (VM + ochrona tablicą ciągów)
Ten preset łączy podstawową obfuskację opartą na kodzie bajtowym VM z ochroną tablicą ciągów. Dobry punkt wyjścia do obfuskacji VM z ochroną ciągów.
{
optionsPreset: 'vm-default'
}
Lub skonfiguruj poszczególne opcje osobno:
{
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
}
