옵션 레퍼런스
목차
compact
config
controlFlowFlattening
controlFlowFlatteningThreshold
deadCodeInjection
deadCodeInjectionThreshold
debugProtection
debugProtectionInterval
disableConsoleOutput
domainLock
여러 도메인과 서브도메인
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
여러 도메인과 서브도메인
vmDomainLockRedirectUrl
Preset Options
높은 난독화, 낮은 성능
중간 난독화, 최적의 성능
낮은 난독화, 높은 성능
기본 프리셋, 높은 성능
VM Ultra High 난독화 (최고 수준의 보안)
VM Anti-LLM (AI 에이전트 보호)
VM High 난독화 (최고 수준의 보안)
VM Medium 난독화 (균형 잡힌 보안)
VM Low 난독화 (기본 보안, 더 나은 성능)
VM Default (VM + 문자열 배열 보호)
compact
Type: boolean Default: true
코드를 한 줄로 압축하여 출력합니다.
config
Type: string Default: ``
난독화 도구의 옵션이 포함된 JS/JSON 설정 파일의 이름입니다. 이 설정은 CLI에 직접 전달된 옵션으로 덮어써집니다.
controlFlowFlattening
Type: boolean Default: false
⚠️ 이 옵션은 성능에 큰 영향을 주며, 실행 속도가 최대 1.5배까지 느려질 수 있습니다. 제어 흐름 평탄화의 영향을 받을 노드의 비율을 설정하려면 controlFlowFlatteningThreshold 옵션을 사용하세요.
코드의 제어 흐름 평탄화를 활성화합니다. 제어 흐름 평탄화는 프로그램을 이해하기 어렵게 만드는 소스 코드의 구조 변환 기법입니다.
예시:
// input
(function(){
function foo () {
return function () {
var sum = 1 + 2;
console.log(1);
console.log(2);
console.log(3);
console.log(4);
console.log(5);
console.log(6);
}
}
foo()();
})();
// output
(function () {
function _0x3bfc5c() {
return function () {
var _0x3260a5 = {
'WtABe': '4|0|6|5|3|2|1',
'GokKo': function _0xf87260(_0x427a8e, _0x43354c) {
return _0x427a8e + _0x43354c;
}
};
var _0x1ad4d6 = _0x3260a5['WtABe']['split']('|'), _0x1a7b12 = 0x0;
while (!![]) {
switch (_0x1ad4d6[_0x1a7b12++]) {
case '0':
console['log'](0x1);
continue;
case '1':
console['log'](0x6);
continue;
case '2':
console['log'](0x5);
continue;
case '3':
console['log'](0x4);
continue;
case '4':
var _0x1f2f2f = _0x3260a5['GokKo'](0x1, 0x2);
continue;
case '5':
console['log'](0x3);
continue;
case '6':
console['log'](0x2);
continue;
}
break;
}
};
}
_0x3bfc5c()();
}());
controlFlowFlatteningThreshold
Type: number Default: 0.75 Min: 0 Max: 1
controlFlowFlattening 변환이 개별 노드에 적용될 확률입니다.
제어 흐름 변환이 많아지면 코드 실행이 느려지고 코드 크기가 커지므로, 이 설정은 코드 규모가 큰 경우에 특히 유용합니다.
controlFlowFlatteningThreshold: 0은 controlFlowFlattening: false와 동일합니다.
deadCodeInjection
Type: boolean Default: false
⚠️ 난독화된 코드의 크기가 크게 증가하므로(최대 200%), 코드 크기가 중요하지 않은 경우에만 사용하세요. 데드 코드 주입의 영향을 받을 노드의 비율을 설정하려면 deadCodeInjectionThreshold 옵션을 사용하세요.
⚠️ 이 옵션은 stringArray 옵션을 강제로 활성화합니다.
⚠️ 이 옵션은 vmObfuscation이 활성화되면 별도의 알림 없이 비활성화됩니다.
이 옵션을 사용하면 난독화된 코드에 임의의 데드 코드 블록이 추가됩니다.
예시:
// input
(function(){
if (true) {
var foo = function () {
console.log('abc');
};
var bar = function () {
console.log('def');
};
var baz = function () {
console.log('ghi');
};
var bark = function () {
console.log('jkl');
};
var hawk = function () {
console.log('mno');
};
foo();
bar();
baz();
bark();
hawk();
}
})();
// output
var _0x37b8 = [
'YBCtz',
'GlrkA',
'urPbb',
'abc',
'NMIhC',
'yZgAj',
'zrAId',
'EtyJA',
'log',
'mno',
'jkl',
'def',
'Quzya',
'IWbBa',
'ghi'
];
function _0x43a7(_0x12cf56, _0x587376) {
_0x43a7 = function (_0x2f87a8, _0x47eac2) {
_0x2f87a8 = _0x2f87a8 - (0x16a7 * 0x1 + 0x5 * 0x151 + -0x1c92);
var _0x341e03 = _0x37b8[_0x2f87a8];
return _0x341e03;
};
return _0x43a7(_0x12cf56, _0x587376);
}
(function () {
if (!![]) {
var _0xbbe28f = function () {
var _0x2fc85f = _0x43a7;
if (_0x2fc85f(0xaf) === _0x2fc85f(0xae)) {
_0x1dd94f[_0x2fc85f(0xb2)](_0x2fc85f(0xb5));
} else {
console[_0x2fc85f(0xb2)](_0x2fc85f(0xad));
}
};
var _0x5e46bc = function () {
var _0x15b472 = _0x43a7;
if (_0x15b472(0xb6) !== _0x15b472(0xaa)) {
console[_0x15b472(0xb2)](_0x15b472(0xb5));
} else {
_0x47eac2[_0x15b472(0xb2)](_0x15b472(0xad));
}
};
var _0x3669e8 = function () {
var _0x47a442 = _0x43a7;
if (_0x47a442(0xb7) !== _0x47a442(0xb0)) {
console[_0x47a442(0xb2)](_0x47a442(0xb8));
} else {
_0x24e0bf[_0x47a442(0xb2)](_0x47a442(0xb3));
}
};
var _0x28b05a = function () {
var _0x497902 = _0x43a7;
if (_0x497902(0xb1) === _0x497902(0xb1)) {
console[_0x497902(0xb2)](_0x497902(0xb4));
} else {
_0x59c9c6[_0x497902(0xb2)](_0x497902(0xb4));
}
};
var _0x402a54 = function () {
var _0x1906b7 = _0x43a7;
if (_0x1906b7(0xab) === _0x1906b7(0xac)) {
_0xb89cd0[_0x1906b7(0xb2)](_0x1906b7(0xb8));
} else {
console[_0x1906b7(0xb2)](_0x1906b7(0xb3));
}
};
_0xbbe28f();
_0x5e46bc();
_0x3669e8();
_0x28b05a();
_0x402a54();
}
}());
deadCodeInjectionThreshold
Type: number Default: 0.4 Min: 0 Max: 1
deadCodeInjection의 영향을 받을 노드의 비율을 설정합니다.
debugProtection
Type: boolean Default: false
⚠️ 개발자 도구를 열면 브라우저가 멈출 수 있습니다.
⚠️ 이 옵션은 vmObfuscation이 활성화되면 별도의 알림 없이 비활성화됩니다. 대신 vmDebugProtection을 사용하세요.
이 옵션은 개발자 도구의 debugger 기능을 사실상 사용할 수 없게 만듭니다(WebKit 기반 브라우저와 Mozilla Firefox 모두 해당).
debugProtectionInterval
Type: number Default: 0
⚠️ 브라우저가 멈출 수 있습니다! 사용에 따른 위험은 사용자가 부담합니다.
⚠️ 이 옵션은 vmObfuscation이 활성화되면 별도의 알림 없이 비활성화됩니다. 대신 vmDebugProtection을 사용하세요.
값을 설정하면 지정한 밀리초 간격으로 콘솔 탭에서 디버그 모드를 강제로 실행하여, 개발자 도구의 다른 기능을 사용하기 어렵게 만듭니다. debugProtection이 활성화된 경우에만 동작합니다. 권장 값은 2000에서 4000 밀리초 사이입니다.
disableConsoleOutput
Type: boolean Default: false
⚠️ 이 옵션은 모든 스크립트에서 전역적으로 console 호출을 비활성화합니다
console.log, console.info, console.error, console.warn, console.debug, console.exception, console.trace를 빈 함수로 대체하여 사용할 수 없게 만듭니다. 이로 인해 디버거를 사용하기가 더 어려워집니다.
domainLock
Type: string[] Default: []
⚠️ 이 옵션은 target: 'node', target: 'service-worker', target: 'bytenode'에서는 동작하지 않습니다
난독화된 소스 코드가 특정 도메인 및/또는 서브도메인에서만 실행되도록 제한합니다. 이렇게 하면 다른 사람이 소스 코드를 그대로 복사해 다른 곳에서 실행하기가 매우 어려워집니다.
이 옵션에 지정된 도메인에서 소스 코드가 실행되지 않는 경우, 브라우저는 domainLockRedirectUrl 옵션에 전달된 URL로 리디렉션됩니다.
여러 도메인과 서브도메인
코드를 두 개 이상의 도메인 또는 서브도메인에 잠글 수 있습니다. 예를 들어 코드가 **www.example.com**에서만 실행되도록 잠그려면 www.example.com을 추가하세요. 모든 서브도메인을 포함한 루트 도메인(example.com, sub.example.com)에서 동작하게 하려면 .example.com을 사용하세요.
domainLockRedirectUrl
Type: string Default: about:blank
⚠️ 이 옵션은 target: 'node', target: 'service-worker', target: 'bytenode'에서는 동작하지 않습니다
domainLock에 지정된 도메인에서 소스 코드가 실행되지 않는 경우, 브라우저를 전달된 URL로 리디렉션합니다
exclude
Type: string[] Default: []
난독화에서 제외할 파일을 지정하는 파일 이름 또는 glob 패턴입니다.
forceTransformStrings
Type: string[] Default: []
전달된 정규식 패턴과 일치하는 문자열 리터럴을 강제로 변환합니다.
⚠️ 이 옵션은 stringArrayThreshold(또는 향후 추가될 수 있는 다른 임계값)에 의해 변환되지 않아야 하는 문자열에만 영향을 줍니다
이 옵션은 reservedStrings 옵션보다 우선하지만, conditional comments보다 우선하지는 않습니다.
예시:
{
forceTransformStrings: [
'some-important-value',
'some-string_\d'
]
}
identifierNamesCache
Type: Object | null Default: null
이 옵션의 주된 목적은 여러 소스/파일을 난독화할 때 동일한 식별자 이름을 사용할 수 있도록 하는 것입니다.
현재 두 가지 유형의 식별자를 지원합니다:
- 전역 식별자:
- 모든 전역 식별자가 캐시에 기록됩니다;
- 일치하는 선언되지 않은 전역 식별자는 모두 캐시의 값으로 대체됩니다.
- 속성 식별자,
renameProperties옵션이 활성화된 경우에만 해당:- 모든 속성 식별자가 캐시에 기록됩니다;
- 일치하는 속성 식별자는 모두 캐시의 값으로 대체됩니다.
Node.js API
null 값을 전달하면 캐시가 완전히 비활성화됩니다.
빈 객체({})를 전달하면 식별자 이름이 캐시 객체(TIdentifierNamesCache 타입)에 기록됩니다. 이 캐시 객체는 ObfuscationResult 객체의 getIdentifierNamesCache 메서드를 호출하여 가져올 수 있습니다.
이렇게 얻은 캐시 객체는 이후 identifierNamesGenerator 옵션 값으로 사용할 수 있으며, 다음 소스를 난독화할 때 일치하는 모든 식별자 이름에 이 이름들이 적용됩니다.
예시:
const source1ObfuscationResult = JavaScriptObfuscator.obfuscate(
`
function foo(arg) {
console.log(arg)
}
function bar() {
var bark = 2;
}
`,
{
compact: false,
identifierNamesCache: {},
renameGlobals: true
}
)
console.log(source1ObfuscationResult.getIdentifierNamesCache());
/*
{
globalIdentifiers: {
foo: '_0x5de86d',
bar: '_0x2a943b'
}
}
*/
const source2ObfuscationResult = JavaScriptObfuscator.obfuscate(
`
// Expecting that these global functions are defined in another obfuscated file
foo(1);
bar();
// Expecting that this global function is defined in third-party package
baz();
`,
{
compact: false,
identifierNamesCache: source1ObfuscationResult.getIdentifierNamesCache(),
renameGlobals: true
}
)
console.log(source2ObfuscationResult.getObfuscatedCode());
/*
_0x5de86d(0x1);
_0x2a943b();
baz();
*/
CLI
CLI에는 별도의 --identifier-names-cache-path 옵션이 있으며, 식별자 이름 캐시를 읽고 쓰는 데 사용할 기존 .json 파일의 경로를 지정할 수 있습니다.
빈 파일의 경로를 전달하면 식별자 이름 캐시가 해당 파일에 기록됩니다.
캐시가 저장된 이 파일은 다시 --identifier-names-cache-path 옵션 값으로 사용할 수 있으며, 이후 파일들을 난독화할 때 일치하는 모든 식별자 이름에 이 이름들이 적용됩니다.
identifierNamesGenerator
Type: string Default: hexadecimal
식별자 이름 생성기를 설정합니다.
사용 가능한 값:
dictionary:identifiersDictionary목록에 있는 식별자 이름hexadecimal:_0xabc123형태의 식별자 이름mangled:a,b,c와 같은 짧은 식별자 이름mangled-shuffled:mangled와 동일하지만 알파벳 순서를 섞어서 사용
identifiersDictionary
Type: string[] Default: []
identifierNamesGenerator: dictionary 옵션에서 사용할 식별자 사전을 설정합니다. 사전의 각 식별자는 각 문자의 대소문자를 다르게 조합한 여러 변형으로 사용됩니다. 따라서 사전에 포함할 식별자 개수는 원본 소스 코드의 식별자 수에 따라 정해야 합니다.
identifiersPrefix
Type: string Default: ''
모든 전역 식별자에 사용할 접두사를 설정합니다.
여러 파일을 난독화할 때 이 옵션을 사용하세요. 이 옵션은 파일 간 전역 식별자 충돌을 방지하는 데 도움이 됩니다. 접두사는 파일마다 다르게 지정해야 합니다.
randomIdentifiersPrefix
Type: boolean Default: false
모든 전역 식별자에 시드 기반의 무작위 접두사(영숫자 6자)를 붙입니다. 같은 전역 스코프에 로드되는, 서로 별개로 난독화된 번들 간의 충돌을 피하려면 이 옵션을 사용하세요. 번들마다 고유한 identifiersPrefix를 직접 정할 필요가 없어집니다.
- 무작위 값은
seed옵션과 소스 코드 해시로부터 생성되므로, 동일한 시드로 재현 가능한 빌드를 수행하면 같은 접두사가 만들어집니다. identifiersPrefix와 함께 사용하면 사용자가 지정한 접두사 뒤에 무작위 문자가 덧붙습니다(예:myApp+ 무작위aBc123→myAppaBc123).vmObfuscation과 함께 사용하면 무작위 값이 기본vm접두사를 대체합니다. 무작위성만으로 이미 고유성이 보장되기 때문입니다.
ignoreImports
Type: boolean Default: false
require 임포트가 난독화되지 않도록 합니다. 런타임 환경이 어떤 이유로든 이러한 임포트에 정적 문자열만 허용하는 경우에 유용할 수 있습니다.
inputFileName
Type: string Default: ''
소스 코드가 담긴 입력 파일의 이름을 설정합니다. 이 이름은 소스 맵 생성 시 내부적으로 사용됩니다.
NodeJS API를 사용하면서 sourceMapSourcesMode 옵션 값이 sources인 경우에는 반드시 지정해야 합니다.
log
Type: boolean Default: false
정보를 콘솔에 기록하도록 활성화합니다.
numbersToExpressions
Type: boolean Default: false
숫자를 표현식으로 변환합니다
예시:
// input
const foo = 1234;
// output
const foo=-0xd93+-0x10b4+0x41*0x67+0x84e*0x3+-0xff8;
optionsPreset
Type: string Default: default
옵션 프리셋을 설정합니다.
사용 가능한 값:
vm-default;vm-low-obfuscation;vm-medium-obfuscation;vm-high-obfuscation;vm-ultra-high-obfuscation;vm-anti-llm;default;low-obfuscation;medium-obfuscation;high-obfuscation.
추가로 지정한 옵션은 모두 선택한 옵션 프리셋과 병합됩니다.
parseHtml
Type: boolean Default: false
HTML <script> 태그 안에 있는 JavaScript의 난독화를 활성화합니다.
이 옵션을 활성화하면 난독화 도구는 다음과 같이 동작합니다:
- 입력이 HTML인지 자동으로 감지합니다(
<!DOCTYPE,<html>,<head>,<body>,<script>태그의 존재 여부로 판단) data-javascript-obfuscator속성이 지정된<script>태그에서 JavaScript를 추출합니다- HTML 구조를 유지하면서 지정된 각 스크립트를 개별적으로 난독화합니다
- 난독화된 코드를 원래 위치에 다시 삽입합니다
중요: data-javascript-obfuscator 속성이 있는 스크립트만 난독화됩니다. 지정된 각 스크립트는 개별적으로, 서로 독립적으로 난독화됩니다. 따라서 다음 사항에 유의해야 합니다:
- 지정된 스크립트 태그 안의 코드는 독립적이어야 합니다. 즉, 다른 지정된 스크립트 태그에서 정의한 변수, 함수, 클래스를 참조해서는 안 됩니다
- 지정되지 않은 스크립트는 지정된 스크립트가 정의한 전역 값에 여전히 접근할 수 있습니다(
var선언이나 명시적인globalThis할당을 통해) - 이를 통해 어떤 스크립트를 보호할지 명시적으로 제어할 수 있습니다
난독화되는 스크립트(data-javascript-obfuscator 속성이 반드시 있어야 함):
<script data-javascript-obfuscator>- 일반 스크립트<script type="text/javascript" data-javascript-obfuscator>- 타입이 명시된 스크립트- 추가 속성(
id,class, 기타data-*등)이 있는 스크립트
건너뛰는 스크립트(변경되지 않음):
data-javascript-obfuscator속성이 없는 스크립트<script type="module">- ES 모듈(속성이 있어도 제외)<script src="...">- 외부 스크립트(속성이 있어도 제외)- 빈 스크립트 태그
참고: parseHtml이 활성화되면 소스 맵은 생성되지 않습니다. HTML 출력에 올바르게 매핑되지 않기 때문입니다.
예시:
// input
const html = `<!DOCTYPE html>
<html>
<body>
<!-- This script will NOT be obfuscated -->
<script>
var helper = 'utility';
</script>
<!-- This script WILL be obfuscated -->
<script data-javascript-obfuscator>
var greeting = 'Hello World';
console.log(greeting);
</script>
</body>
</html>`;
JavaScriptObfuscator.obfuscate(html, {
parseHtml: true,
stringArray: true
});
// output: HTML with only the marked script obfuscated
renameGlobals
Type: boolean Default: false
⚠️ 이 옵션은 코드를 손상시킬 수 있습니다. 동작 방식을 정확히 아는 경우에만 활성화하세요!
선언이 있는 전역 변수 및 함수 이름의 난독화를 활성화합니다.
이 옵션이 비활성화되어 있고 입력 코드가 전역 스코프에 함수나 클래스를 선언하는 경우(즉, 코드가 IIFE로 감싸여 있지 않은 경우), 다른 스크립트가 그 이름으로 참조할 수 있기 때문에 해당 이름은 난독화된 출력에도 그대로 유지됩니다. vmObfuscation을 사용하면 이러한 이름을 나열한 VMGlobalFunctionNamesNotRenamed 경고가 보고됩니다. 함수 본문은 바이트코드로 숨겨지지만, 읽을 수 있는 최상위 이름만으로도 (예를 들어 LLM에게) 코드가 무슨 일을 하는지 드러나기 때문입니다. 이러한 노출을 피하려면 코드를 IIFE로 감싸거나 이 옵션을 활성화하세요.
renameProperties
Type: boolean Default: false
⚠️ 이 옵션은 코드를 손상시킬 수 있습니다. 동작 방식을 정확히 아는 경우에만 활성화하세요!
속성 이름 변경을 활성화합니다. 모든 내장 DOM 속성과 JavaScript 코어 클래스의 속성은 제외됩니다.
이 옵션의 safe 모드와 unsafe 모드를 전환하려면 renamePropertiesMode 옵션을 사용하세요.
변경된 속성 이름의 형식을 지정하려면 identifierNamesGenerator 옵션을 사용하세요.
어떤 속성의 이름을 변경할지 제어하려면 reservedNames 옵션을 사용하세요.
예시:
// input
(function () {
const foo = {
prop1: 1,
prop2: 2,
calc: function () {
return this.prop1 + this.prop2;
}
};
console.log(foo.calc());
})();
// output
(function () {
const _0x46529b = {
'_0x10cec7': 0x1,
'_0xc1c0ca': 0x2,
'_0x4b961d': function () {
return this['_0x10cec7'] + this['_0xc1c0ca'];
}
};
console['log'](_0x46529b['_0x4b961d']());
}());
renamePropertiesMode
Type: string Default: safe
⚠️ safe 모드에서도 renameProperties 옵션은 코드를 손상시킬 수 있습니다.
renameProperties 옵션의 모드를 지정합니다:
safe-2.11.0릴리스 이후의 기본 동작입니다. 런타임 오류를 방지하기 위해 더 안전한 방식으로 속성 이름을 변경합니다. 이 모드에서는 일부 속성이 이름 변경 대상에서 제외됩니다.unsafe-2.11.0릴리스 이전의 기본 동작입니다. 아무런 제한 없이 안전하지 않은 방식으로 속성 이름을 변경합니다.
한 파일이 다른 파일의 속성을 사용하는 경우, identifierNamesCache 옵션을 사용하여 파일 간에 동일한 속성 이름이 유지되도록 하세요.
reservedNames
Type: string[] Default: []
전달된 정규식 패턴과 일치하는 식별자의 난독화 및 이름 생성을 비활성화합니다.
예시:
{
reservedNames: [
'^someVariable',
'functionParameter_\d'
]
}
reservedStrings
Type: string[] Default: []
전달된 정규식 패턴과 일치하는 문자열 리터럴의 변환을 비활성화합니다. 일치하는 문자열은 난독화된 출력에서도 그대로 보입니다.
VM 난독화를 사용할 때, 예약된 문자열은 그대로 보이도록 암호화되지 않은 별도의 배열에 저장됩니다. 모니터링용 API 엔드포인트나 라이브러리 식별자처럼 읽을 수 있는 상태로 남아야 하는 문자열에 유용합니다.
예시:
{
reservedStrings: [
'react-native',
'\.\/src\/test',
'some-string_\d'
]
}
seed
Type: string|number Default: 0
난수 생성기의 시드를 설정합니다. 반복 가능한 결과를 만들 때 유용합니다.
시드가 0이면 난수 생성기는 시드 없이 동작합니다.
selfDefending
Type: boolean Default: false
⚠️ 이 옵션으로 난독화한 뒤에는 난독화된 코드를 어떤 방식으로도 수정하지 마세요. 코드 압축과 같은 사소한 변경만으로도 자기 방어가 발동하여 코드가 더 이상 동작하지 않을 수 있습니다!
⚠️ 이 옵션은 compact 값을 강제로 true로 설정합니다
⚠️ 이 옵션은 vmObfuscation이 활성화되면 별도의 알림 없이 비활성화됩니다. 대신 vmSelfDefending을 사용하세요.
이 옵션은 출력 코드가 포맷팅과 변수 이름 변경에 견디도록 만듭니다. 난독화된 코드에 JavaScript 코드 정리 도구(beautifier)를 사용하면 코드가 더 이상 동작하지 않으므로, 코드를 이해하고 수정하기가 더 어려워집니다.
simplify
Type: boolean Default: true
코드 단순화를 통한 추가 난독화를 활성화합니다.
⚠️ 향후 릴리스에서는 boolean 리터럴의 난독화(true => !![])가 이 옵션 아래로 이동할 예정입니다.
예시:
// input
if (condition1) {
const foo = 1;
const bar = 2;
console.log(foo);
return bar;
} else if (condition2) {
console.log(1);
console.log(2);
console.log(3);
return 4;
} else {
return 5;
}
// output
if (condition1) {
const foo = 0x1, bar = 0x2;
return console['log'](foo), bar;
} else
return condition2 ? (console['log'](0x1), console['log'](0x2), console['log'](0x3), 0x4) : 0x5;
sourceMap
Type: boolean Default: false
난독화된 코드에 대한 소스 맵 생성을 활성화합니다.
소스 맵은 난독화된 JavaScript 소스 코드를 디버깅하는 데 도움이 됩니다. 프로덕션 환경에서 디버깅해야 한다면, 별도의 소스 맵 파일을 비공개 위치에 업로드한 뒤 브라우저가 해당 위치를 참조하도록 설정할 수 있습니다.
sourceMapBaseUrl
Type: string Default: ``
sourceMapMode: 'separate'일 때 소스 맵 임포트 URL에 사용할 기준 URL을 설정합니다.
CLI 예시:
javascript-obfuscator input.js --output out.js --source-map true --source-map-base-url 'http://localhost:9000'
결과:
//# sourceMappingURL=http://localhost:9000/out.js.map
sourceMapFileName
Type: string Default: ``
sourceMapMode: 'separate'일 때 출력되는 소스 맵의 파일 이름을 설정합니다.
CLI 예시:
javascript-obfuscator input.js --output out.js --source-map true --source-map-base-url 'http://localhost:9000' --source-map-file-name example
결과:
//# sourceMappingURL=http://localhost:9000/example.js.map
sourceMapMode
Type: string Default: separate
소스 맵 생성 모드를 지정합니다:
inline- 각 .js 파일 끝에 소스 맵을 추가합니다;separate- 소스 맵이 담긴 '.map' 파일을 별도로 생성합니다. CLI로 난독화 도구를 실행하는 경우, 난독화된 코드 파일 끝에 소스 맵 파일 링크//# sourceMappingUrl=file.js.map을 추가합니다.
sourceMapSourcesMode
Type: string Default: sources-content
소스 맵의 sources 및 sourcesContent 필드를 제어합니다:
sources-content- 형식만 갖춘sources필드를 추가하고, 원본 소스 코드가 담긴sourcesContent필드를 추가합니다;sources- 유효한 소스 정보가 담긴sources필드를 추가하고,sourcesContent필드는 추가하지 않습니다. NodeJS API를 사용할 때는sources필드 값으로 사용할inputFileName옵션을 반드시 지정해야 합니다.
splitStrings
Type: boolean Default: false
문자열 리터럴을 splitStringsChunkLength 옵션 값 길이의 조각으로 나눕니다.
예시:
// input
(function(){
var test = 'abcdefg';
})();
// output
(function(){
var _0x5a21 = 'ab' + 'cd' + 'ef' + 'g';
})();
splitStringsChunkLength
Type: number Default: 10
splitStrings 옵션에서 사용할 조각의 길이를 설정합니다.
stringArray
Type: boolean Default: true
문자열 리터럴을 제거하고 전용 배열에 넣습니다. 예를 들어 var m = "Hello World";의 문자열 "Hello World"는 var m = _0x12c456[0x1];과 같은 형태로 대체됩니다.
stringArrayCallsTransform
Type: boolean Default: false
⚠️ stringArray 옵션이 활성화되어 있어야 합니다
stringArray 호출의 변환을 활성화합니다. 이러한 호출의 모든 인자는 stringArrayCallsTransformThreshold 값에 따라 별도의 객체로 추출될 수 있습니다.
따라서 문자열 배열 호출을 자동으로 찾아내기가 훨씬 더 어려워집니다.
예시:
function foo() {
var k = {
c: 0x2f2,
d: '0x396',
e: '0x397',
f: '0x39a',
g: '0x39d',
h: 0x398,
l: 0x394,
m: '0x39b',
n: '0x39f',
o: 0x395,
p: 0x395,
q: 0x399,
r: '0x399'
};
var c = i(k.d, k.e);
var d = i(k.f, k.g);
var e = i(k.h, k.l);
var f = i(k.m, k.n);
function i(c, d) {
return b(c - k.c, d);
}
var g = i(k.o, k.p);
var h = i(k.q, k.r);
}
function j(c, d) {
var l = { c: 0x14b };
return b(c - -l.c, d);
}
console[j(-'0xa6', -'0xa6')](foo());
function b(c, d) {
var e = a();
b = function (f, g) {
f = f - 0xa3;
var h = e[f];
return h;
};
return b(c, d);
}
function a() {
var m = [
'string5',
'string1',
'log',
'string3',
'string6',
'string2',
'string4'
];
a = function () {
return m;
};
return a();
}
stringArrayCallsTransformThreshold
Type: number Default: 0.5
⚠️ stringArray와 stringArrayCallsTransformThreshold 옵션이 활성화되어 있어야 합니다
이 설정으로 문자열 배열 호출이 변환될 확률(0에서 1 사이)을 조정할 수 있습니다.
stringArrayEncoding
Type: string[] Default: []
⚠️ stringArray 옵션이 활성화되어 있어야 합니다
이 옵션은 스크립트의 실행 속도를 저하시킬 수 있습니다.
stringArray의 모든 문자열 리터럴을 base64 또는 rc4로 인코딩하고, 런타임에 이를 다시 디코딩하는 특수한 코드를 삽입합니다.
각 stringArray 값은 전달된 목록에서 무작위로 선택된 인코딩 방식으로 인코딩됩니다. 따라서 여러 인코딩 방식을 함께 사용할 수 있습니다.
사용 가능한 값:
'none'(boolean):stringArray값을 인코딩하지 않습니다'base64'(string):base64를 사용하여stringArray값을 인코딩합니다'rc4'(string):rc4를 사용하여stringArray값을 인코딩합니다.base64보다 약 30~50% 느리지만, 원래 값을 알아내기가 더 어렵습니다.
예를 들어 다음과 같은 옵션 값을 사용하면 일부 stringArray 값은 인코딩되지 않고, 일부 값은 base64와 rc4 인코딩으로 인코딩됩니다:
stringArrayEncoding: [
'none',
'base64',
'rc4'
]
stringArrayIndexesType
Type: string[] Default: ['hexadecimal-number']
⚠️ stringArray 옵션이 활성화되어 있어야 합니다
문자열 배열 호출 인덱스의 유형을 제어합니다.
각 stringArray 호출 인덱스는 전달된 목록에서 무작위로 선택된 유형으로 변환됩니다. 따라서 여러 유형을 함께 사용할 수 있습니다.
사용 가능한 값:
'hexadecimal-number'(default): 문자열 배열 호출 인덱스를 16진수 숫자로 변환합니다'hexadecimal-numeric-string': 문자열 배열 호출 인덱스를 16진수 숫자 문자열로 변환합니다
2.9.0 릴리스 이전의 javascript-obfuscator는 모든 문자열 배열 호출 인덱스를 hexadecimal-numeric-string 유형으로 변환했습니다. 이 방식은 수동 역난독화를 다소 어렵게 만들지만, 자동 역난독화 도구가 이러한 호출을 쉽게 탐지할 수 있게 합니다.
새로운 hexadecimal-number 유형은 코드에서 문자열 배열 호출 패턴을 자동으로 탐지하기 어렵게 만드는 것을 목표로 합니다.
앞으로 더 많은 유형이 추가될 예정입니다.
stringArrayIndexShift
Type: boolean Default: true
⚠️ stringArray 옵션이 활성화되어 있어야 합니다
모든 문자열 배열 호출에 추가적인 인덱스 시프트를 적용합니다
stringArrayRotate
Type: boolean Default: true
⚠️ stringArray가 활성화되어 있어야 합니다
stringArray 배열을 고정되고 무작위한(코드 난독화 시점에 생성된) 위치만큼 회전시킵니다. 이렇게 하면 추출된 문자열의 순서를 원래 위치와 대응시키기가 더 어려워집니다.
stringArrayShuffle
Type: boolean Default: true
⚠️ stringArray가 활성화되어 있어야 합니다
stringArray 배열의 항목 순서를 무작위로 섞습니다.
stringArrayWrappersCount
Type: number Default: 1
⚠️ stringArray 옵션이 활성화되어 있어야 합니다
각 루트 스코프 또는 함수 스코프 안에 생성할 string array 래퍼의 개수를 설정합니다.
각 스코프 안에 실제로 생성되는 래퍼 개수는 해당 스코프의 literal 노드 개수로 제한됩니다.
예시:
// Input
const foo = 'foo';
const bar = 'bar';
function test () {
const baz = 'baz';
const bark = 'bark';
const hawk = 'hawk';
}
const eagle = 'eagle';
// Output, stringArrayWrappersCount: 5
const _0x3f6c = [
'bark',
'bar',
'foo',
'eagle',
'hawk',
'baz'
];
const _0x48f96e = _0x2e13;
const _0x4dfed8 = _0x2e13;
const _0x55e970 = _0x2e13;
function _0x2e13(_0x33c4f5, _0x3f6c62) {
_0x2e13 = function (_0x2e1388, _0x60b1e) {
_0x2e1388 = _0x2e1388 - 0xe2;
let _0x53d475 = _0x3f6c[_0x2e1388];
return _0x53d475;
};
return _0x2e13(_0x33c4f5, _0x3f6c62);
}
const foo = _0x48f96e(0xe4);
const bar = _0x4dfed8(0xe3);
function test() {
const _0x1c262f = _0x2e13;
const _0x54d7a4 = _0x2e13;
const _0x5142fe = _0x2e13;
const _0x1392b0 = _0x1c262f(0xe7);
const _0x201a58 = _0x1c262f(0xe2);
const _0xd3a7fb = _0x1c262f(0xe6);
}
const eagle = _0x48f96e(0xe5);
stringArrayWrappersChainedCalls
Type: boolean Default: true
⚠️ stringArray와 stringArrayWrappersCount 옵션이 활성화되어 있어야 합니다
string array 래퍼 간의 연쇄 호출을 활성화합니다.
예시:
// Input
const foo = 'foo';
const bar = 'bar';
function test () {
const baz = 'baz';
const bark = 'bark';
function test1() {
const hawk = 'hawk';
const eagle = 'eagle';
}
}
// Output, stringArrayWrappersCount: 5, stringArrayWrappersChainedCalls: true
const _0x40c2 = [
'bar',
'bark',
'hawk',
'eagle',
'foo',
'baz'
];
const _0x31c087 = _0x3280;
const _0x31759a = _0x3280;
function _0x3280(_0x1f52ee, _0x40c2a2) {
_0x3280 = function (_0x3280a4, _0xf07b02) {
_0x3280a4 = _0x3280a4 - 0x1c4;
let _0x57a182 = _0x40c2[_0x3280a4];
return _0x57a182;
};
return _0x3280(_0x1f52ee, _0x40c2a2);
}
const foo = _0x31c087(0x1c8);
const bar = _0x31c087(0x1c4);
function test() {
const _0x848719 = _0x31759a;
const _0x2693bf = _0x31c087;
const _0x2c08e8 = _0x848719(0x1c9);
const _0x359365 = _0x2693bf(0x1c5);
function _0x175e90() {
const _0x310023 = _0x848719;
const _0x2302ef = _0x2693bf;
const _0x237437 = _0x310023(0x1c6);
const _0x56145c = _0x310023(0x1c7);
}
}
stringArrayWrappersParametersMaxCount
Type: number Default: 2
⚠️ stringArray 옵션이 활성화되어 있어야 합니다
⚠️ 현재 이 옵션은 stringArrayWrappersType 옵션 값이 function일 때 추가되는 래퍼에만 영향을 줍니다
문자열 배열 래퍼가 받을 수 있는 최대 매개변수 개수를 제어합니다.
기본값이자 최솟값은 2입니다. 권장 값은 2에서 5 사이입니다.
stringArrayWrappersType
Type: string Default: variable
⚠️ stringArray와 stringArrayWrappersCount 옵션이 활성화되어 있어야 합니다
stringArrayWrappersCount 옵션으로 추가되는 래퍼의 유형을 선택합니다.
사용 가능한 값:
'variable': 각 스코프 상단에 변수 래퍼를 추가합니다. 성능이 빠릅니다.'function': 각 스코프 안의 임의의 위치에 함수 래퍼를 추가합니다.variable보다 성능은 느리지만 더 강력한 난독화를 제공합니다.
성능 저하가 난독화된 애플리케이션에 큰 영향을 주지 않는다면, 더 높은 수준의 난독화를 위해 function 래퍼를 사용할 것을 적극 권장합니다.
'function' 옵션 값을 사용한 예시:
// input
const foo = 'foo';
function test () {
const bar = 'bar';
console.log(foo, bar);
}
test();
// output
const a = [
'log',
'bar',
'foo'
];
const foo = d(0x567, 0x568);
function b(c, d) {
b = function (e, f) {
e = e - 0x185;
let g = a[e];
return g;
};
return b(c, d);
}
function test() {
const c = e(0x51c, 0x51b);
function e (c, g) {
return b(c - 0x396, g);
}
console[f(0x51b, 0x51d)](foo, c);
function f (c, g) {
return b(c - 0x396, g);
}
}
function d (c, g) {
return b(g - 0x3e1, c);
}
test();
stringArrayThreshold
Type: number Default: 0.8 Min: 0 Max: 1
⚠️ stringArray 옵션이 활성화되어 있어야 합니다
이 설정으로 문자열 리터럴이 stringArray에 삽입될 확률(0에서 1 사이)을 조정할 수 있습니다.
string array를 반복적으로 호출하면 코드가 느려질 수 있으므로, 이 설정은 코드 규모가 큰 경우에 특히 유용합니다.
stringArrayThreshold: 0은 stringArray: false와 동일합니다.
strictMode
Type: boolean | null Default: null
난독화 도구가 JavaScript strict 모드와 관련하여 코드를 어떻게 다룰지 지정합니다.
사용 가능한 값:
null(기본값) - 코드에서 strict 모드를 자동으로 감지합니다. 코드에 명시적인'use strict'지시문, ES 모듈 문법, 클래스 메서드가 있으면 strict 모드로 간주합니다. 그렇지 않으면 sloppy 모드로 간주합니다.true- 명시적인'use strict'지시문이 없더라도 모든 코드를 strict 모드로 처리합니다. 코드가 strict 모드 컨텍스트에서 실행되는 경우(예: ES 모듈, 번들러, 최신 프레임워크)에 사용하세요.false- 명시적인 strict 모드 표시('use strict', ES 모듈, 클래스 메서드)가 있는 경우에만 strict 모드로 처리합니다. 상위 스코프로부터의 상속은 JS 명세에 따라 그대로 적용됩니다.
target
Type: string Default: browser
난독화된 코드의 대상 환경을 설정합니다.
사용 가능한 값:
browser(기본값) — 일반적인 웹 페이지 환경입니다. 출력 코드는node와 동일하지만, 일부 브라우저 전용 옵션은node대상과 함께 사용할 수 없습니다browser-no-eval—browser와 동일하지만 출력 코드가eval()을 사용하지 않습니다. 대상 페이지의 Content Security Policy가eval/unsafe-eval을 금지하는 경우에 사용하세요.node— Node.js 환경입니다. 브라우저 전용 옵션은 비활성화됩니다(이러한 옵션은window/document를 필요로 하므로 Node에서는 아무 동작도 하지 않거나 오류를 발생시킵니다). 브라우저 전용 API에 의존하는 일부vmSelfDefending방어 기능(헤드리스 브라우저 탐지, iframe 기반 클린 렐름 복구, 인스펙터 방지 및 DOM 검사)은 이 대상에서는 생성되지 않습니다.service-worker— Service Worker 컨텍스트입니다.window와document가 없으며self전역 객체가 다릅니다.userscript— 유저스크립트 관리자 샌드박스(예: Tampermonkey)입니다.vmSelfDefending방어 기능이 그에 맞게 조정됩니다.bytenode— 난독화 후 bytenode 로더(V8 캐시 바이트코드.jsc)로 컴파일할 Node.js 코드입니다. 난독화 도구가 직접bytenode를 실행하지는 않으며, bytenode의 컴파일 단계를 견딜 수 있도록 런타임이 구성된 VM 난독화 JavaScript를 생성하고vmSelfDefending방어 기능을 그에 맞게 조정합니다. 최종.jsc파일을 만들려면 난독화된 결과물에 직접bytenode를 실행해야 합니다.
transformObjectKeys
Type: boolean Default: false
객체 키의 변환을 활성화합니다.
예시:
// input
(function(){
var object = {
foo: 'test1',
bar: {
baz: 'test2'
}
};
})();
// output
var _0x4735 = [
'foo',
'baz',
'bar',
'test1',
'test2'
];
function _0x390c(_0x33d6b6, _0x4735f4) {
_0x390c = function (_0x390c37, _0x1eed85) {
_0x390c37 = _0x390c37 - 0x198;
var _0x2275f8 = _0x4735[_0x390c37];
return _0x2275f8;
};
return _0x390c(_0x33d6b6, _0x4735f4);
}
(function () {
var _0x17d1b7 = _0x390c;
var _0xc9b6bb = {};
_0xc9b6bb[_0x17d1b7(0x199)] = _0x17d1b7(0x19c);
var _0x3d959a = {};
_0x3d959a[_0x17d1b7(0x198)] = _0x17d1b7(0x19b);
_0x3d959a[_0x17d1b7(0x19a)] = _0xc9b6bb;
var _0x41fd86 = _0x3d959a;
}());
warnings
Type: string | object Default: all
ObfuscationResult.getWarnings() 메서드를 통해 전달되는 치명적이지 않은 난독화 경고 중 어떤 것을 내보낼지 제어합니다.
사용 가능한 값:
'all'(기본값) — 모든 경고를 내보냅니다.'none'— 모든 경고를 숨깁니다.- 경고 유형을 불리언 값에 대응시킨 객체 —
false로 지정한 유형은 숨겨지고, 목록에 없거나true로 지정한 유형은 그대로 활성화됩니다. 예를 들어{ "VMGlobalFunctionNamesNotRenamed": false }는 해당 경고만 제외하고 나머지 모든 경고를 유지합니다.
경고 유형:
VMGlobalFunctionNamesNotRenamed—vmObfuscation을 사용할 때 최상위 함수 선언, 클래스 선언, 그리고 함수/화살표 함수/클래스 표현식이 할당된 변수의 이름이 그대로 유지되었습니다(renameGlobals옵션이 비활성화되어 있고 코드가 IIFE로 감싸여 있지 않은 경우). 본문은 바이트코드로 숨겨지지만 이러한 이름은 출력에서 그대로 읽힙니다. export된 이름은 보고되지 않습니다.VMTopLevelInitializerNotVirtualized—vmWrapTopLevelInitializers가 비활성화되어 있거나 가상화할 수 없었기 때문에, VM 난독화에서도 최상위 변수 초기화 식이 일반 JavaScript로 남았습니다.DynamicCodeRenameRisk— 코드가 런타임에 문자열로부터 함수를 생성하며(직접eval,Function생성자, 또는<script>/Worker에 삽입되는fn.toString()), 난독화 도구가 이름을 바꾼 식별자를 참조할 수 있습니다.VMDynamicCodeSkipped— 함수에 직접eval/ 동적new Function/Function이 포함되어 있어 VM 바이트코드 변환에서 제외되었습니다(vmForceCompileDynamicCode참고).VMSyncFunctionSkippedInAsyncMode—vmAsyncExecutor가 활성화된 상태에서,comment모드로 직접 지정한 함수가 동기 함수여서 제외되었습니다(이 모드에서는 비동기 함수만 가상화됩니다).VMAsyncGeneratorSkippedInAsyncMode—vmAsyncExecutor와 비동기 키 게터가 활성화된 상태에서, 지정된 async 제너레이터를 가상화할 수 없었습니다(이터레이터를 동기적으로 반환해야 하기 때문입니다).BrowserTargetWithNodeStyleCode—target옵션이 브라우저 계열 환경으로 설정되어 있는데, 코드는 Node.js를 대상으로 하는 것으로 보입니다(예:require('fs'),__dirname,process.argv).
vmObfuscation
Type: boolean Default: false
VM 기반 바이트코드 난독화를 활성화합니다. 이 옵션을 활성화하면 JavaScript 함수가 맞춤형 바이트코드로 컴파일되어, 결과물에 내장된 가상 머신 위에서 실행됩니다. 원본 코드의 로직이 완전히 변환되므로 가장 높은 수준의 보호를 제공합니다.
예시:
return qty * price처럼 읽을 수 있던 코드가 [0x15,0x03,0x17,...]과 같은 숫자 목록으로 바뀌며, 내장된 VM 인터프리터만이 이를 실행할 수 있습니다. 원본 로직은 더 이상 JavaScript 형태로 드러나지 않습니다.
vmTargetFunctions
Type: string[] Default: []
VM 보호를 적용할 최상위 함수를 이름으로 정확히 지정합니다.
예시:
{
vmObfuscation: true,
vmTargetFunctions: ['someFunctionName']
}
결과: 지정한 세 함수만 VM으로 보호됩니다. 나머지는 모두 일반(하지만 여전히 난독화된) JavaScript로 남습니다. 코드의 나머지 부분을 가볍게 유지하면서 민감한 라이선스 검사나 인증 로직을 보호하는 데 적합합니다.
vmExcludeFunctions
Type: string[] Default: []
VM 보호를 적용하지 않을 최상위 함수를 지정합니다. 다른 설정보다 우선합니다.
예시:
{
vmObfuscation: true,
vmExcludeFunctions: ['someFunctionName']
}
언제 사용하나요: 성능이 중요한 최상위 함수(애니메이션 루프, 실시간 데이터 처리 등)를 제외하면 VM 오버헤드를 피하면서 나머지 코드는 그대로 보호할 수 있습니다.
vmTargetFunctionsMode
Type: string Default: root
VM 난독화 대상 함수/메서드를 선택하는 방식을 제어합니다.
예시 - Comment 모드:
// Source code
function regularFunction() {
return 'not virtualized';
}
/* javascript-obfuscator:vm */
function sensitiveFunction() {
return 'this will be VM-protected';
}
function outer() {
/* javascript-obfuscator:vm */
function nestedSensitive() {
return 'nested but still VM-protected';
}
return nestedSensitive();
}
// Obfuscator options
{
vmObfuscation: true,
vmTargetFunctionsMode: 'comment'
}
언제 사용하나요: 어떤 함수에 VM 보호를 적용할지 정밀하게 제어해야 할 때, 특히 민감한 로직이 들어 있는 중첩 함수를 보호할 때 사용합니다. 최상위의 이름 있는 함수에만 적용되는 vmTargetFunctions와 달리, comment 모드에서는 코드 어디에 있는 함수든 보호할 수 있습니다.
vmForceCompileDynamicCode
Type: boolean Default: false
직접 eval, new Function(...), Function(...) 호출이 포함된 함수를 VM 난독화가 어떻게 처리할지 제어합니다.
기본적으로 이러한 함수(그리고 그 안에 정의된 모든 함수)는 VM 바이트코드 변환에서 제외되며, result.getWarnings()를 통해 VMDynamicCodeSkipped 경고가 보고됩니다. 런타임에 생성되는 소스가 주변 스코프 체인의 식별자, 즉 난독화 도구가 이름을 바꾼 식별자를 참조할 수 있기 때문입니다.
true로 설정하면 해당 함수도 바이트코드로 변환되며, VMDynamicCodeSkipped 경고는 더 이상 발생하지 않습니다.
별도의 DynamicCodeRenameRisk 경고는 이 옵션과 관계없이 계속 발생합니다. 이 경고가 알리는 이름 변경 위험은 VM 변환 제외 여부와 무관하며, 이 옵션을 켠다고 해서 해당 패턴이 더 안전해지는 것은 아니기 때문입니다.
// Source code
function loadConfig(src) {
return eval(src);
}
loadConfig('1 + 2');
// Options
{
vmObfuscation: true,
vmForceCompileDynamicCode: true
}
옵션이 꺼져 있으면(기본값) loadConfig는 일반 JavaScript로 남습니다. 옵션이 켜져 있으면 loadConfig도 다른 함수와 마찬가지로 VM 바이트코드로 컴파일됩니다. 호출 지점을 직접 검토하여 런타임에 생성되는 코드가 이름이 변경된 클로저 식별자에 의존하지 않는다는 것을 확인한 경우에 사용하세요.
vmWrapTopLevelInitializers
Type: boolean Default: false
일부 최상위 변수 초기화 식을 IIFE(즉시 실행 함수 표현식)로 감싸서 VM 난독화가 가능하도록 만듭니다.
동작 방식: 이 옵션을 사용하지 않으면 최상위 상수와 변수가 출력에 그대로 드러납니다:
// Input
const MY_STRING = "my-string";
// Output (without vmWrapTopLevelInitializers)
const MY_STRING = "my-string"; // String is visible!
이 옵션을 활성화하면 초기화 식이 IIFE로 감싸지고 VM 난독화가 적용됩니다:
// Input
const MY_STRING = "my-string";
// Output (with vmWrapTopLevelInitializers: true)
const MY_STRING = (() => { return /* VM bytecode call */ })(); // String hidden in bytecode
참고: 이 옵션은 vmTargetFunctionsMode가 'root'(기본값)일 때만 동작합니다.
경고: VM 난독화에서 최상위 초기화 식이 일반 JavaScript로 남는 경우에는 언제나, 해당 변수 이름을 나열한 VMTopLevelInitializerNotVirtualized 경고가 보고됩니다. 여기에는 이 옵션이 비활성화된 경우, 이 옵션이 건너뛸 수밖에 없었던 초기화 식(각각 이유가 함께 표시됩니다. 예를 들어 초기화 식이 같은 선언문의 다른 선언자를 참조하거나 최상위 await를 포함하는 경우), 그리고 동기 래퍼를 아예 가상화할 수 없는 vmAsyncExecutor 모드가 모두 포함됩니다.
vmDynamicOpcodes
Type: boolean Default: false
VM 인터프리터를 더 작게 만들고 빌드마다 고유하게 만듭니다.
동작 방식:
- 사용하지 않는 명령어 제거 - 코드에서 클래스를 사용하지 않으면 클래스 관련 명령어가 완전히 제거됩니다
- 구조 무작위화 - 명령어 핸들러의 순서가 빌드마다 섞입니다
그 결과 출력 크기가 작아지고 빌드마다 결과물이 달라집니다.
vmBytecodeEncoding
Type: boolean Default: false
각 바이트코드 명령어를 인코딩합니다. 명령어는 실행 중에 하나씩 디코딩됩니다.
vmBytecodeArrayEncoding
Type: boolean Default: false
바이트코드 배열 전체를 하나의 블록으로 인코딩합니다. 배열은 실행이 시작되기 전에 한 번 디코딩됩니다. 두 겹의 보호를 적용하려면 vmBytecodeEncoding과 함께 사용하세요.
vmBytecodeArrayEncodingKey
Type: string Default: ''
바이트코드 배열 인코딩에 사용할 사용자 지정 암호화 키입니다. 이 값을 설정하면 기본적으로 환경에서 파생되는 키 대신 이 키가 사용됩니다. 키는 런타임에 vmBytecodeArrayEncodingKeyGetter를 통해 제공해야 합니다.
이 옵션은 암호화 키를 외부로 분리합니다. 즉, 키가 난독화된 코드 자체에 내장되지 않습니다. 키는 여전히 런타임에 접근 가능하므로 완전한 비밀은 아니지만, 이렇게 분리하면 정적 분석 도구가 코드만 살펴봐서는 키를 찾아낼 수 없습니다.
중요: 난독화된 코드가 로드될 때 키를 동기적으로 사용할 수 있어야 합니다. 쿠키, localStorage, sessionStorage, 전역 변수, DOM 요소(예: 서버가 주입한 meta 태그)와 같은 동기 저장소를 사용하세요. fetch()와 같은 비동기 방식은 키 게터 표현식에서 직접 사용할 수 없습니다.
vmBytecodeArrayEncodingKeyGetter
Type: string Default: ''
런타임에 암호화 키를 반환하는 동기 JavaScript 표현식입니다. 이 표현식은 난독화된 코드가 로드될 때 평가되며, vmBytecodeArrayEncodingKey에 제공한 것과 동일한 키를 반환해야 합니다. 키를 비동기적으로(Promise) 해석하려면 vmAsyncExecutor를 활성화하세요.
참고: Promise를 반환하는 게터에는 vmAsyncExecutor가 필요합니다. 이는 빌드 시점에 확인할 수 없으므로, vmAsyncExecutor가 꺼진 상태에서 Promise 게터를 사용하면 런타임에 실패합니다. 디코더가 키 대신 Promise를 받기 때문입니다.
난독화된 코드는 키 게터가 난독화 시점에 사용된 것과 정확히 동일한 키를 반환할 때만 동작합니다. 키가 일치하지 않으면 복호화에 실패하여 코드가 의미 없는 값이나 오류를 만들어냅니다. 키 게터가 undefined, null, 빈 문자열을 반환하면 코드는 "VM decryption key not available" 오류를 발생시킵니다.
중요: 키를 난독화된 코드와 같은 파일/스크립트에 두지 마세요. 그곳에 키를 인라인하면 번들을 순수하게 정적으로 스캔하는 것만으로도 키를 복원할 수 있습니다. 대신 별도의 소스에 저장하세요. 서버가 설정한 쿠키, 다른 스크립트가 채운 localStorage, 서버가 주입한 HTML meta 태그, 다른 스크립트가 설정한 전역 변수, 또는 (vmAsyncExecutor를 사용하여) 런타임에 백엔드에서 가져온 값 등이 있습니다.
키를 (vmAsyncExecutor를 통해) 백엔드에서 가져오는 경우, 해당 엔드포인트에 세션 기반 또는 오리진 기반 검사를 추가하세요. 실제 사용자(유효한 세션, 예상되는 Origin/Referer)에게는 올바른 키를 반환하고, 의심스러운 요청(예: localhost/예상치 못한 오리진, 세션 없음)에는 의미 없는 키를 반환하세요. 실제 사용자는 정상적으로 실행되지만, 사용자의 환경 밖에서 실행되는 복사본은 아무것도 복호화하지 못하는 키를 받게 됩니다. 구체적인 로직은 사이트에 따라 다릅니다.
예시:
// From cookie
vmBytecodeArrayEncodingKeyGetter: "document.cookie.match(/vmKey=([^;]+)/)?.[1]"
// From localStorage
vmBytecodeArrayEncodingKeyGetter: "localStorage.getItem('vmKey')"
// From global variable
vmBytecodeArrayEncodingKeyGetter: "window.__VM_KEY__"
// From meta tag (server-injected)
vmBytecodeArrayEncodingKeyGetter: "document.querySelector('meta[name=\"vm-key\"]').content"
// From nested object
vmBytecodeArrayEncodingKeyGetter: "window.config.encryption.key"
// From backend, async (requires vmAsyncExecutor)
vmBytecodeArrayEncodingKeyGetter: 'fetch("/vm-key").then((res) => res.text())'
사용 예시:
// Build time
JavaScriptObfuscator.obfuscate(code, {
vmObfuscation: true,
vmBytecodeArrayEncoding: true,
vmBytecodeArrayEncodingKey: 'mySecretKey123',
vmBytecodeArrayEncodingKeyGetter: 'window.__VM_KEY__'
});
// Runtime - key must be set before obfuscated code runs
window.__VM_KEY__ = 'mySecretKey123';
vmAsyncExecutor
Type: boolean Default: false
비동기 VM 실행기를 활성화합니다. 이를 통해 vmBytecodeArrayEncodingKeyGetter가 Promise를 반환할 수 있게 되어(비동기 키 게터), 코드가 로드될 때 동기적으로 키를 준비할 필요 없이 런타임에 키를 가져올 수 있습니다(네트워크 요청, IndexedDB 등).
완전히 비동기로 작성된 코드베이스에 적극 권장됩니다. 이 모드에서는 async 함수만 가상화됩니다. 동기 함수는 반환값을 Promise로 바꾸어 호출부를 깨뜨리지 않고서는 비동기로 만들 수 없기 때문입니다. 따라서 전반적으로 async로 작성된 코드가 가장 넓은 범위로 보호됩니다. 루트가 동기인 경우(예: 동기 IIFE / UMD 래퍼)에도 여전히 동작합니다. 그 안의 가장 바깥쪽 async 함수들이 보호되고, 동기 부분은 그대로 남습니다.
변환되는 대상: 위치에 관계없이 모든 가장 바깥쪽 async 함수입니다(동기 래퍼 안에 중첩된 것도 포함). 각 체인에서 가장 바깥쪽 async가 보호 단위이며, 그 안에 있는 모든 것은 동기든 비동기든 함께 컴파일됩니다. 동기 함수와 일반 제너레이터는 난독화되지 않은 채로 남습니다.
function foo() { // sync — left as-is
function bar() {} // sync — left as-is
async function baz() { // transformed
// any code here, including calls to other async or sync functions
}
async function bark() { // transformed
// any code here, including calls to other async or sync functions
}
}
건너뛰기와 경고. 비동기 키 게터가 활성화된 경우 async 제너레이터도 난독화되지 않은 채로 남습니다(async 제너레이터는 이터레이터를 동기적으로 반환해야 하므로 키를 기다릴 수 없습니다). 기본값인 vmTargetFunctionsMode: 'root'에서는 건너뛰기가 별도의 알림 없이 이루어지지만(선택이 자동으로 진행됨), comment 모드에서는 직접 지정한 함수를 가상화할 수 없을 때마다(함수가 동기로 판명되었거나, 비동기 키 게터 아래의 async 제너레이터인 경우) ObfuscationResult.getWarnings()를 통해 경고가 발생합니다.
비동기 키 게터에는 추가로 vmBytecodeArrayEncodingKeyGetter를 지정한 vmBytecodeArrayEncoding이 필요합니다.
사용 예시:
JavaScriptObfuscator.obfuscate(code, {
vmObfuscation: true,
vmAsyncExecutor: true,
vmBytecodeArrayEncoding: true,
vmBytecodeArrayEncodingKey: 'mySecretKey123',
// the key getter may now return a Promise
vmBytecodeArrayEncodingKeyGetter: 'fetch("/vm-key").then((res) => res.text())'
});
vmJumpsEncoding
Type: boolean Default: false
바이트코드의 점프 대상을 인코딩합니다. 점프 오프셋이 런타임에 계산되어, 정적 분석으로부터 제어 흐름 구조(if/else, 반복문 등)를 숨깁니다.
vmMacroOps
Type: boolean Default: false
자주 쓰이는 명령어 시퀀스를 하나의 "매크로" 옵코드로 결합합니다. 예를 들어 LOAD + ADD + STORE가 하나의 MACRO_ADD_TO_VAR 명령어가 될 수 있습니다. 이는 패턴 인식을 방해하며 성능을 향상시킬 수 있습니다.
vmDebugProtection
Type: boolean Default: false
VM 런타임에 다층적인 디버깅 방지, 분석 방지, LLM 대응 방어 기능을 추가합니다. browser/browser-no-eval 대상에서 가장 잘 동작합니다.
vmSelfDefending
Type: boolean Default: false
VM 런타임에 다층적인 변조 탐지, 후킹 방지, 리버스 엔지니어링 방지 보호 기능을 추가합니다.
⚠️ 이 옵션은 vmBytecodeArrayEncoding을 강제로 활성화합니다.
⚠️ 민감한 환경 탐지. 이 옵션은 난독화된 코드를 대상 런타임 환경에 결속시키고, 고급 브라우저 핑거프린팅을 사용해 자동화 도구를 탐지합니다. 이 옵션으로 보호된 코드는 다음 환경에서 실행될 때 의도적으로 동작하지 않습니다:
- 헤드리스 브라우저(헤드리스 Chrome/Chromium, PhantomJS)
- 브라우저 자동화 도구(Puppeteer, Playwright, Cypress, Selenium/ChromeDriver, Nightmare)
- Node.js(
target이browser로 설정된 경우) - jsdom 또는 이와 유사한 서버 측 DOM 에뮬레이션
- 네이티브 브라우저 빌트인이 후킹되거나 교체된 환경
이 코드는 일반 브라우저(Chrome, Firefox, Safari, Edge)에서는 올바르게 동작하며, iframe 내부, 브라우저 확장 프로그램(콘텐츠 스크립트), Web Worker에서 로드되는 경우에도 마찬가지입니다. 보호된 코드에 대해 자동화 테스트를 실행해야 한다면, 테스트 빌드에서는 vmSelfDefending을 비활성화하세요. 이 옵션은 자동화된 분석을 막기 위해 설계되었으며 어떤 자동화 프레임워크와도 안전하게 함께 사용할 수 없습니다.
vmDebugProtection, vmBytecodeArrayEncodingKey, vmBytecodeArrayEncodingKeyGetter와 함께 사용할 것을 적극 권장합니다.
vmDefenseHook
Type: { name: string, aliases?: object } Default: ''
vmDefenseHook은 두 개의 키를 가진 객체를 받습니다: name(필수)과 aliases(선택).
name은 호스트 페이지가 정의하는 전역 함수로, VM 방어 기능(vmDebugProtection / vmSelfDefending)이 적대적 시그널(디버거나 인스펙터, 헤드리스 / 자동화 브라우저, AI 코딩 에이전트 프로세스, 허용되지 않은 도메인 등)을 탐지했을 때 시그널 객체를 인자로 이 함수를 호출합니다. 이 함수를 사용하여 이벤트를 백엔드에 보고하세요(예: navigator.sendBeacon). 훅은 순수한 텔레메트리 싱크입니다. 반환값은 무시되며, 훅이 없거나 예외를 던지더라도 조용히 무시될 뿐 방어 기능을 결코 비활성화할 수 없습니다. 탐지 시 방어 기능이 수행하는 동작을 바꾸려면 vmDefenseReaction을 사용하세요.
aliases는 선택적으로 해당 시그널 객체의 필드 이름을 바꿉니다. 아래 시그널 필드 이름 바꾸기에서 다룹니다.
시그널 객체. 훅은 하나의 signal을 받습니다:
source— 발동한 구체적인 탐지기(표 참고).category— 해당 탐지기가 보고되는 그룹:automation(사람이 아닌 브라우저),debugger(디버거/인스펙터가 활성화됨),sandbox(계측된/가짜 호스트),domain(도메인 잠금 위반),tamper(빌트인이 런타임에 패치됨),integrity(VM 자체 코드가 변경됨).score/threshold— 탐지기가 얼마나 강하게 발동했는지와 도달해야 했던 값. 훅은score >= threshold일 때만 발동합니다. 대부분의 검사는 전부 아니면 전무(하나의 결정적 시그널)이며,headless는 여러 브라우저 형태 시그널을 합산하므로score가 보통threshold보다 높습니다.
훅 등록하기. 난독화된 번들이 로드되기 전에 일반 전역 함수로 정의하세요. VM 런타임과 그 방어 기능은 (보호된) 프로그램보다 먼저 실행되므로, 많은 탐지가 시작 시점에 발동합니다:
// in your page, before the obfuscated script:
window.__vmDetection = function (signal) { navigator.sendBeacon('/vm-defense', JSON.stringify(signal)); };
// obfuscation option:
vmDefenseHook: { name: '__vmDetection' }
난독화된 소스 안에 정의된 훅은 시작 시점의 탐지를 잡기에는 너무 늦게 등록되며, VM으로 컴파일되면 프로그램이 실행되기 전까지 도달할 수 없습니다. 어느 쪽이든 안전하게 처리되지만(훅이 없으면 아무 동작도 하지 않고, 재진입 방지 장치가 폭주를 막습니다), 완전한 커버리지를 원한다면 미리 등록하세요. 그러면서도 보고 로직을 보호하려면, 등록하는 훅은 한 줄짜리 버퍼((window.__vmDet = window.__vmDet || []).push(signal))로 유지하고 그 버퍼를 난독화된 코드에서 읽어 전송하세요.
시그널 필드 이름 바꾸기(aliases). 기본 source/category 값은 설명적인 이름이므로, 콜백을 계측하는(또는 출력을 읽는) 사람은 누구든 보호 기능과 어떤 탐지기가 발동했는지 알아볼 수 있습니다. aliases는 시그널 필드를 사용자가 선택한 알아볼 수 없는 토큰으로 바꿉니다. 이 변환은 시그널이 발생하기 전에 VM 내부에서 적용되므로, 그 이름들은 출력에 나타나거나 콜백에 도달하는 일이 없습니다. 앱은 자신의 매핑을 알고 있으므로 그 토큰을 백엔드로 전달합니다.
별칭은 필드별로 지정하며, 키 이름 변경과 값 이름 변경을 분리합니다. 각 필드는 key(콜백이 받는 속성 이름)를 받습니다. 문자열 이름 필드인 source와 category는 values 맵도 받는 반면, score/threshold는 숫자이므로 key만 받습니다. 매핑할 수 있는 이름은 다음과 같습니다(그 밖의 것은 빌드 시점에 거부됩니다):
- 필드 키 —
source,category,score,threshold source값 —headless,agent,node,debugger,timing,sandbox,domain,nativeHook,integritycategory값 —automation,debugger,sandbox,domain,tamper,integrity
vmDefenseHook: {
name: '__vmDetection',
aliases: {
source: { key: 'a8Qm', values: { headless: 'xP4m9Q' } },
category: { key: 'p3Tx', values: { automation: 'bQ7s1M' } },
score: { key: 's1' },
threshold: { key: 't1' }
}
// the callback now receives e.g. { a8Qm: 'xP4m9Q', p3Tx: 'bQ7s1M', s1: <score>, t1: <threshold> }
}
이것은 핑거프린트 회피이지 비밀 유지가 아닙니다. 매핑은 반복적인 테스트로 여전히 추론될 수 있으므로, 그 유일한 이점은 안정적이고 자명한 이름을 노출하지 않는다는 것뿐입니다. 지정하지 않은 항목은 기본 이름을 유지합니다.
단순 문자열(vmDefenseHook: '__vmDetection')은 { name: '__vmDetection' }의 축약형으로 허용되지만 더 이상 사용되지 않습니다. 객체 형태를 사용하는 것이 좋습니다.
vmDefenseReaction
Type: object Default: { automation: 'break', debugger: 'decoy', sandbox: 'decoy', domain: 'break', tamper: 'break', integrity: 'break' }
각 탐지 카테고리가 어떻게 반응할지 구성합니다. 이 옵션은 아무것도 활성화하지 않습니다. 방어 기능 자체는 vmSelfDefending, vmDebugProtection, vmDomainLock으로 켜지며, 이 옵션은 활성화된 방어 기능이 어떻게 반응할지만 선택합니다. 카테고리가 제어의 단위이며, 한 카테고리의 모든 탐지기는 그 카테고리의 반응을 실행합니다.
각 카테고리는 한 종류의 적대적 조건을 감시하는 탐지기들을 묶습니다. 카테고리는 그 탐지기를 내보내는 옵션이 활성화된 경우에만 반응합니다:
모든 카테고리는 vmSelfDefending, vmDebugProtection, vmDomainLock 중 하나 이상에 대응됩니다. 이 세 옵션 밖의 카테고리는 없으며, 옵션이 꺼진 카테고리에 반응을 설정해도 아무런 효과가 없습니다.
키는 이 여섯 개의 카테고리 이름, 또는 default(지정되지 않은 카테고리에 대한 대체값)입니다. 값은 다음과 같습니다:
break— 즉시 중단합니다decoy— 오염된 상태로 계속 실행하며, 조용히 잘못된 결과를 만들어냅니다none— 로컬에서는 아무 동작도 하지 않습니다(텔레메트리만)
카테고리별 기본값은 위에 나와 있습니다. 설정하지 않은(또는 기본값으로 설정한) 카테고리는 그 기본값을 사용합니다. default는 올바름이 보장되는 카테고리(integrity, tamper)를 포함하여 모든 카테고리에 적용되므로, { default: 'none' }은 진정으로 코드를 중단시키지 않는 텔레메트리 전용 빌드가 됩니다:
vmDefenseReaction: { default: 'none' } // never break — pair with vmDefenseHook
vmDefenseReaction: { automation: 'none', domain: 'break' } // tolerate automation FPs, still break on a bad domain
vmStatefulOpcodes
Type: boolean Default: false
옵코드의 의미가 바이트코드 내 위치에 따라 달라지도록 만듭니다. 각 위치는 시드로부터 파생된 서로 다른 옵코드-핸들러 매핑을 가지므로, 동일한 옵코드 번호가 위치에 따라 다른 연산을 수행합니다.
vmCallContextOpcodes
Type: boolean Default: false
보호된 함수가 어디서 호출되는지에 의존하도록 만들어, 코드에서 떼어내 단독으로 실행하거나 분석할 수 없게 합니다. 함수는 프로그램 내의 실제 호출 지점을 통해 호출될 때만 올바르게 동작합니다. 이 옵션은 런타임 성능에 영향을 줍니다.
현재는 다음 구조만 지원됩니다:
- 함수 선언(
function f() {}); - 변수에 할당된 함수 표현식과 화살표 함수(
const f = () => {}); - 인스턴스 private 메서드(
this.#m()).
어느 경우든 함수는 항상 직접 호출(f(), this.#m())로 도달해야 합니다. 다른 변수에 저장되거나, 인자로 전달되거나, 그 밖의 방식으로 값으로 사용되면 보호되지 않습니다. async 함수는 지원되지만 제너레이터는 지원되지 않습니다.
이 옵션은 실험적이며 코드를 손상시킬 수 있으므로, 사용하기 전에 출력을 철저히 테스트하세요.
vmStackEncoding
Type: boolean Default: false
실행 중 VM 스택의 값을 암호화합니다. 값은 푸시될 때 인코딩되고 팝될 때 디코딩되므로, 메모리 검사에서는 실제 값 대신 암호화된 데이터가 보입니다.
이 옵션은 성능에 큰 영향을 줍니다.
vmCompactDispatcher
Type: boolean Default: false
이중 실행기(동기 + 제너레이터) 대신 단일 VM 실행기를 사용합니다. 난독화된 코드 크기를 줄이지만, 재귀가 많은 코드에서는 약 20%의 성능 오버헤드가 추가됩니다.
false(기본값): 이중 실행기 — 최적의 성능, 더 큰 출력true: 단일 실행기 — 더 작은 출력, 약간 느림
vmStringArrayBytecodeOnly
Type: boolean Default: false
이 옵션을 활성화하면 문자열 배열이 바이트코드 데이터에서 만 문자열을 추출하며, 코드의 다른 문자열은 변환되지 않습니다. 이 옵션은 stringArray가 명시적으로 설정되지 않았더라도 강제로 활성화합니다.
사용하는 이유: 모든 VM 런타임 문자열을 문자열 배열로 추출하는 것은 느립니다. 이 옵션은 바이트코드 콘텐츠만 문자열 배열 추출 대상으로 삼아, 바이트코드 상수는 그대로 보호하면서 성능을 향상시킵니다.
vmBytecodeArrayEncoding: false일 때 — 바이트코드 상수 풀(c배열) 안의 문자열이 추출됩니다vmBytecodeArrayEncoding: true일 때 — 최상위의 base64로 인코딩된 바이트코드 문자열이 추출됩니다stringArrayThreshold는 그 바이트코드 문자열 중 몇 퍼센트를 추출할지 계속 제어합니다
vmDomainLock
Type: string[] Default: []
⚠️ 이 옵션은 target: 'node', target: 'service-worker', target: 'bytenode'에서는 동작하지 않습니다
난독화된 코드를 특정 도메인 및/또는 서브도메인으로 제한하며, domainLock보다 찾아내고 제거하기가 훨씬 어렵습니다.
이 옵션에 지정된 도메인에서 소스 코드가 실행되지 않는 경우, 브라우저는 vmDomainLockRedirectUrl에 전달된 URL로 리디렉션되며, 리디렉션이 억제되더라도 이후의 보호된 호출은 잘못된 결과를 반환합니다.
여러 도메인과 서브도메인
코드를 두 개 이상의 도메인 또는 서브도메인에 잠글 수 있습니다. 예를 들어 코드가 **www.example.com**에서만 실행되도록 잠그려면 www.example.com을 추가하세요. 모든 서브도메인을 포함한 루트 도메인(example.com, sub.example.com)에서 동작하게 하려면 .example.com을 사용하세요.
vmDomainLockRedirectUrl
Type: string Default: about:blank
⚠️ 이 옵션은 target: 'node', target: 'service-worker', target: 'bytenode'에서는 동작하지 않습니다
vmDomainLock에 지정된 도메인에서 소스 코드가 실행되지 않는 경우, 브라우저를 전달된 URL로 리디렉션합니다.
Preset Options
높은 난독화, 낮은 성능
난독화하지 않은 경우보다 성능이 훨씬 느려집니다
{
compact: true,
controlFlowFlattening: true,
controlFlowFlatteningThreshold: 1,
deadCodeInjection: true,
deadCodeInjectionThreshold: 1,
debugProtection: true,
debugProtectionInterval: 4000,
disableConsoleOutput: true,
identifierNamesGenerator: 'hexadecimal',
log: false,
numbersToExpressions: true,
renameGlobals: false,
selfDefending: true,
simplify: true,
splitStrings: true,
splitStringsChunkLength: 5,
strictMode: null,
stringArray: true,
stringArrayCallsTransform: true,
stringArrayEncoding: ['rc4'],
stringArrayIndexShift: true,
stringArrayRotate: true,
stringArrayShuffle: true,
stringArrayWrappersCount: 5,
stringArrayWrappersChainedCalls: true,
stringArrayWrappersParametersMaxCount: 5,
stringArrayWrappersType: 'function',
stringArrayThreshold: 1,
transformObjectKeys: true
}
중간 난독화, 최적의 성능
난독화하지 않은 경우보다 성능이 느려집니다
{
compact: true,
controlFlowFlattening: true,
controlFlowFlatteningThreshold: 0.75,
deadCodeInjection: true,
deadCodeInjectionThreshold: 0.4,
debugProtection: false,
debugProtectionInterval: 0,
disableConsoleOutput: true,
identifierNamesGenerator: 'hexadecimal',
log: false,
numbersToExpressions: true,
renameGlobals: false,
selfDefending: true,
simplify: true,
splitStrings: true,
splitStringsChunkLength: 10,
strictMode: null,
stringArray: true,
stringArrayCallsTransform: true,
stringArrayCallsTransformThreshold: 0.75,
stringArrayEncoding: ['base64'],
stringArrayIndexShift: true,
stringArrayRotate: true,
stringArrayShuffle: true,
stringArrayWrappersCount: 2,
stringArrayWrappersChainedCalls: true,
stringArrayWrappersParametersMaxCount: 4,
stringArrayWrappersType: 'function',
stringArrayThreshold: 0.75,
transformObjectKeys: true
}
낮은 난독화, 높은 성능
성능이 비교적 정상적인 수준으로 유지됩니다
{
compact: true,
controlFlowFlattening: false,
deadCodeInjection: false,
debugProtection: false,
debugProtectionInterval: 0,
disableConsoleOutput: true,
identifierNamesGenerator: 'hexadecimal',
log: false,
numbersToExpressions: false,
renameGlobals: false,
selfDefending: true,
simplify: true,
splitStrings: false,
strictMode: null,
stringArray: true,
stringArrayCallsTransform: false,
stringArrayEncoding: [],
stringArrayIndexShift: true,
stringArrayRotate: true,
stringArrayShuffle: true,
stringArrayWrappersCount: 1,
stringArrayWrappersChainedCalls: true,
stringArrayWrappersParametersMaxCount: 2,
stringArrayWrappersType: 'variable',
stringArrayThreshold: 0.75
}
기본 프리셋, 높은 성능
{
compact: true,
controlFlowFlattening: false,
deadCodeInjection: false,
debugProtection: false,
debugProtectionInterval: 0,
disableConsoleOutput: false,
identifierNamesGenerator: 'hexadecimal',
log: false,
numbersToExpressions: false,
renameGlobals: false,
selfDefending: false,
simplify: true,
splitStrings: false,
strictMode: null,
stringArray: true,
stringArrayCallsTransform: false,
stringArrayCallsTransformThreshold: 0.5,
stringArrayEncoding: [],
stringArrayIndexShift: true,
stringArrayRotate: true,
stringArrayShuffle: true,
stringArrayWrappersCount: 1,
stringArrayWrappersChainedCalls: true,
stringArrayWrappersParametersMaxCount: 2,
stringArrayWrappersType: 'variable',
stringArrayThreshold: 0.75
}
VM Ultra High 난독화 (최고 수준의 보안)
이 프리셋은 간접 디스패치를 포함한 모든 강화 기능과 함께 VM 기반 바이트코드 난독화를 활성화합니다. 가장 강력한 보호를 제공하지만 출력 크기가 더 크고 실행 속도가 훨씬 느립니다.
{
optionsPreset: 'vm-ultra-high-obfuscation'
}
또는 개별적으로 구성할 수 있습니다:
{
compact: true,
simplify: true,
identifierNamesGenerator: 'mangled-shuffled',
vmObfuscation: true,
vmForceCompileDynamicCode: false,
vmWrapTopLevelInitializers: true,
vmDynamicOpcodes: true,
vmBytecodeEncoding: true,
vmBytecodeArrayEncoding: true,
vmBytecodeArrayEncodingKey: '',
vmBytecodeArrayEncodingKeyGetter: '',
vmAsyncExecutor: false,
vmJumpsEncoding: true,
vmMacroOps: true,
vmDebugProtection: true,
vmSelfDefending: true,
vmDefenseHook: '',
vmDefenseReaction: {
automation: 'break',
debugger: 'decoy',
sandbox: 'decoy',
domain: 'break',
tamper: 'break',
integrity: 'break'
},
vmStatefulOpcodes: true,
vmCallContextOpcodes: false,
vmStackEncoding: true,
vmCompactDispatcher: true,
controlFlowFlattening: true,
controlFlowFlatteningThreshold: 0.5,
deadCodeInjection: true,
deadCodeInjectionThreshold: 0.5,
debugProtection: true,
debugProtectionInterval: 4000,
disableConsoleOutput: true,
identifierNamesGenerator: 'hexadecimal',
log: false,
numbersToExpressions: true,
renameGlobals: false,
selfDefending: true,
simplify: true,
splitStrings: true,
splitStringsChunkLength: 5,
strictMode: null,
stringArray: true,
stringArrayCallsTransform: true,
stringArrayEncoding: ['rc4'],
stringArrayIndexShift: true,
stringArrayRotate: true,
stringArrayShuffle: true,
stringArrayWrappersCount: 5,
stringArrayWrappersChainedCalls: true,
stringArrayWrappersParametersMaxCount: 5,
stringArrayWrappersType: 'function',
stringArrayThreshold: 0.5,
transformObjectKeys: true
}
VM Anti-LLM (AI 에이전트 보호)
이 프리셋은 AI 에이전트와 LLM이 VM 바이트코드로 변환된 코드를 리버스 엔지니어링하지 못하도록 특별히 설계되었습니다. vm-default를 기반으로 자기 방어와 디버그 보호를 활성화합니다. vm-high-obfuscation보다 가볍지만 자동화된 분석에 대해 특별히 강화되어 있습니다.
{
optionsPreset: 'vm-anti-llm'
}
포함 내용:
- 문자열 배열이 적용된 VM 바이트코드 난독화(
vm-default에서) vmSelfDefending— 후킹 방지 탐지, 무결성 해시, 소스 핑거프린트, iframe 클린 렐름 검증, ARX 암호 키 파생vmDebugProtection— VM 디스패치 루프 내 디버깅 방지 검사debugProtection: false— 레거시 디버그 보호 없음(VM 디버그 보호가 더 우수함)
VM High 난독화 (최고 수준의 보안)
이 프리셋은 대부분의 강화 기능과 함께 VM 기반 바이트코드 난독화를 활성화합니다. ultra-high 프리셋보다 나은 성능으로 강력한 보호를 제공합니다.
{
optionsPreset: 'vm-high-obfuscation'
}
또는 개별적으로 구성할 수 있습니다:
{
compact: true,
simplify: true,
identifierNamesGenerator: 'mangled-shuffled',
vmObfuscation: true,
vmForceCompileDynamicCode: false,
vmWrapTopLevelInitializers: true,
vmDynamicOpcodes: true,
vmBytecodeEncoding: true,
vmBytecodeArrayEncoding: true,
vmBytecodeArrayEncodingKey: '',
vmBytecodeArrayEncodingKeyGetter: '',
vmAsyncExecutor: false,
vmJumpsEncoding: true,
vmMacroOps: true,
vmDebugProtection: true,
vmSelfDefending: true,
vmDefenseHook: '',
vmDefenseReaction: {
automation: 'break',
debugger: 'decoy',
sandbox: 'decoy',
domain: 'break',
tamper: 'break',
integrity: 'break'
},
vmStatefulOpcodes: true,
vmCallContextOpcodes: false,
vmStackEncoding: true,
vmCompactDispatcher: false
}
VM Medium 난독화 (균형 잡힌 보안)
이 프리셋은 균형 잡힌 강화 기능 세트와 함께 VM 기반 바이트코드 난독화를 활성화합니다. 보안과 성능 사이의 좋은 절충안입니다.
{
optionsPreset: 'vm-medium-obfuscation'
}
또는 개별적으로 구성할 수 있습니다:
{
compact: true,
simplify: true,
identifierNamesGenerator: 'mangled-shuffled',
vmObfuscation: true,
vmForceCompileDynamicCode: false,
vmWrapTopLevelInitializers: true,
vmDynamicOpcodes: true,
vmBytecodeEncoding: true,
vmBytecodeArrayEncoding: false,
vmBytecodeArrayEncodingKey: '',
vmBytecodeArrayEncodingKeyGetter: '',
vmAsyncExecutor: false,
vmJumpsEncoding: true,
vmMacroOps: true,
vmDebugProtection: true,
vmSelfDefending: false,
vmDefenseHook: '',
vmDefenseReaction: {
automation: 'break',
debugger: 'decoy',
sandbox: 'decoy',
domain: 'break',
tamper: 'break',
integrity: 'break'
},
vmStatefulOpcodes: false,
vmCallContextOpcodes: false,
vmStackEncoding: false,
vmCompactDispatcher: false
}
VM Low 난독화 (기본 보안, 더 나은 성능)
이 프리셋은 추가 강화 기능 없이 기본적인 VM 기반 바이트코드 난독화를 활성화합니다. 보안과 출력 크기 사이의 좋은 균형을 제공합니다.
{
optionsPreset: 'vm-low-obfuscation'
}
또는 개별적으로 구성할 수 있습니다:
{
compact: true,
simplify: true,
identifierNamesGenerator: 'mangled-shuffled',
vmObfuscation: true,
vmForceCompileDynamicCode: false,
vmWrapTopLevelInitializers: true,
vmDynamicOpcodes: false,
vmBytecodeEncoding: false,
vmBytecodeArrayEncoding: false,
vmBytecodeArrayEncodingKey: '',
vmBytecodeArrayEncodingKeyGetter: '',
vmAsyncExecutor: false,
vmJumpsEncoding: false,
vmMacroOps: false,
vmDebugProtection: false,
vmSelfDefending: false,
vmDefenseHook: '',
vmDefenseReaction: {
automation: 'break',
debugger: 'decoy',
sandbox: 'decoy',
domain: 'break',
tamper: 'break',
integrity: 'break'
},
vmStatefulOpcodes: false,
vmCallContextOpcodes: false,
vmStackEncoding: false,
vmCompactDispatcher: false
}
VM Default (VM + 문자열 배열 보호)
이 프리셋은 기본적인 VM 기반 바이트코드 난독화와 문자열 배열 보호를 결합합니다. 문자열 보호를 곁들인 VM 난독화의 좋은 출발점입니다.
{
optionsPreset: 'vm-default'
}
또는 개별적으로 구성할 수 있습니다:
{
compact: true,
simplify: true,
identifierNamesGenerator: 'mangled-shuffled',
vmObfuscation: true,
vmForceCompileDynamicCode: false,
vmWrapTopLevelInitializers: true,
vmDynamicOpcodes: true,
vmBytecodeEncoding: false,
vmBytecodeArrayEncoding: true,
vmStringArrayBytecodeOnly: true,
vmAsyncExecutor: false,
vmJumpsEncoding: false,
vmMacroOps: false,
vmDebugProtection: false,
vmSelfDefending: false,
vmDefenseHook: '',
vmDefenseReaction: {
automation: 'break',
debugger: 'decoy',
sandbox: 'decoy',
domain: 'break',
tamper: 'break',
integrity: 'break'
},
vmStatefulOpcodes: false,
vmCallContextOpcodes: false,
vmStackEncoding: false,
vmCompactDispatcher: false,
stringArray: true,
stringArrayRotate: true,
stringArrayShuffle: true,
stringArrayThreshold: 1,
stringArrayIndexShift: true,
stringArrayIndexesType: ['hexadecimal-number'],
stringArrayCallsTransform: true,
stringArrayCallsTransformThreshold: 1,
stringArrayWrappersCount: 3,
stringArrayWrappersType: 'function',
stringArrayWrappersParametersMaxCount: 5,
stringArrayWrappersChainedCalls: true,
stringArrayEncoding: ['base64'],
splitStrings: true,
splitStringsChunkLength: 6
}
compact
Type: boolean Default: true
코드를 한 줄로 압축하여 출력합니다.
config
Type: string Default: ``
난독화 도구의 옵션이 포함된 JS/JSON 설정 파일의 이름입니다. 이 설정은 CLI에 직접 전달된 옵션으로 덮어써집니다.
controlFlowFlattening
Type: boolean Default: false
⚠️ 이 옵션은 성능에 큰 영향을 주며, 실행 속도가 최대 1.5배까지 느려질 수 있습니다. 제어 흐름 평탄화의 영향을 받을 노드의 비율을 설정하려면 controlFlowFlatteningThreshold 옵션을 사용하세요.
코드의 제어 흐름 평탄화를 활성화합니다. 제어 흐름 평탄화는 프로그램을 이해하기 어렵게 만드는 소스 코드의 구조 변환 기법입니다.
예시:
// input
(function(){
function foo () {
return function () {
var sum = 1 + 2;
console.log(1);
console.log(2);
console.log(3);
console.log(4);
console.log(5);
console.log(6);
}
}
foo()();
})();
// output
(function () {
function _0x3bfc5c() {
return function () {
var _0x3260a5 = {
'WtABe': '4|0|6|5|3|2|1',
'GokKo': function _0xf87260(_0x427a8e, _0x43354c) {
return _0x427a8e + _0x43354c;
}
};
var _0x1ad4d6 = _0x3260a5['WtABe']['split']('|'), _0x1a7b12 = 0x0;
while (!![]) {
switch (_0x1ad4d6[_0x1a7b12++]) {
case '0':
console['log'](0x1);
continue;
case '1':
console['log'](0x6);
continue;
case '2':
console['log'](0x5);
continue;
case '3':
console['log'](0x4);
continue;
case '4':
var _0x1f2f2f = _0x3260a5['GokKo'](0x1, 0x2);
continue;
case '5':
console['log'](0x3);
continue;
case '6':
console['log'](0x2);
continue;
}
break;
}
};
}
_0x3bfc5c()();
}());
controlFlowFlatteningThreshold
Type: number Default: 0.75 Min: 0 Max: 1
controlFlowFlattening 변환이 개별 노드에 적용될 확률입니다.
제어 흐름 변환이 많아지면 코드 실행이 느려지고 코드 크기가 커지므로, 이 설정은 코드 규모가 큰 경우에 특히 유용합니다.
controlFlowFlatteningThreshold: 0은 controlFlowFlattening: false와 동일합니다.
deadCodeInjection
Type: boolean Default: false
⚠️ 난독화된 코드의 크기가 크게 증가하므로(최대 200%), 코드 크기가 중요하지 않은 경우에만 사용하세요. 데드 코드 주입의 영향을 받을 노드의 비율을 설정하려면 deadCodeInjectionThreshold 옵션을 사용하세요.
⚠️ 이 옵션은 stringArray 옵션을 강제로 활성화합니다.
⚠️ 이 옵션은 vmObfuscation이 활성화되면 별도의 알림 없이 비활성화됩니다.
이 옵션을 사용하면 난독화된 코드에 임의의 데드 코드 블록이 추가됩니다.
예시:
// input
(function(){
if (true) {
var foo = function () {
console.log('abc');
};
var bar = function () {
console.log('def');
};
var baz = function () {
console.log('ghi');
};
var bark = function () {
console.log('jkl');
};
var hawk = function () {
console.log('mno');
};
foo();
bar();
baz();
bark();
hawk();
}
})();
// output
var _0x37b8 = [
'YBCtz',
'GlrkA',
'urPbb',
'abc',
'NMIhC',
'yZgAj',
'zrAId',
'EtyJA',
'log',
'mno',
'jkl',
'def',
'Quzya',
'IWbBa',
'ghi'
];
function _0x43a7(_0x12cf56, _0x587376) {
_0x43a7 = function (_0x2f87a8, _0x47eac2) {
_0x2f87a8 = _0x2f87a8 - (0x16a7 * 0x1 + 0x5 * 0x151 + -0x1c92);
var _0x341e03 = _0x37b8[_0x2f87a8];
return _0x341e03;
};
return _0x43a7(_0x12cf56, _0x587376);
}
(function () {
if (!![]) {
var _0xbbe28f = function () {
var _0x2fc85f = _0x43a7;
if (_0x2fc85f(0xaf) === _0x2fc85f(0xae)) {
_0x1dd94f[_0x2fc85f(0xb2)](_0x2fc85f(0xb5));
} else {
console[_0x2fc85f(0xb2)](_0x2fc85f(0xad));
}
};
var _0x5e46bc = function () {
var _0x15b472 = _0x43a7;
if (_0x15b472(0xb6) !== _0x15b472(0xaa)) {
console[_0x15b472(0xb2)](_0x15b472(0xb5));
} else {
_0x47eac2[_0x15b472(0xb2)](_0x15b472(0xad));
}
};
var _0x3669e8 = function () {
var _0x47a442 = _0x43a7;
if (_0x47a442(0xb7) !== _0x47a442(0xb0)) {
console[_0x47a442(0xb2)](_0x47a442(0xb8));
} else {
_0x24e0bf[_0x47a442(0xb2)](_0x47a442(0xb3));
}
};
var _0x28b05a = function () {
var _0x497902 = _0x43a7;
if (_0x497902(0xb1) === _0x497902(0xb1)) {
console[_0x497902(0xb2)](_0x497902(0xb4));
} else {
_0x59c9c6[_0x497902(0xb2)](_0x497902(0xb4));
}
};
var _0x402a54 = function () {
var _0x1906b7 = _0x43a7;
if (_0x1906b7(0xab) === _0x1906b7(0xac)) {
_0xb89cd0[_0x1906b7(0xb2)](_0x1906b7(0xb8));
} else {
console[_0x1906b7(0xb2)](_0x1906b7(0xb3));
}
};
_0xbbe28f();
_0x5e46bc();
_0x3669e8();
_0x28b05a();
_0x402a54();
}
}());
deadCodeInjectionThreshold
Type: number Default: 0.4 Min: 0 Max: 1
deadCodeInjection의 영향을 받을 노드의 비율을 설정합니다.
debugProtection
Type: boolean Default: false
⚠️ 개발자 도구를 열면 브라우저가 멈출 수 있습니다.
⚠️ 이 옵션은 vmObfuscation이 활성화되면 별도의 알림 없이 비활성화됩니다. 대신 vmDebugProtection을 사용하세요.
이 옵션은 개발자 도구의 debugger 기능을 사실상 사용할 수 없게 만듭니다(WebKit 기반 브라우저와 Mozilla Firefox 모두 해당).
debugProtectionInterval
Type: number Default: 0
⚠️ 브라우저가 멈출 수 있습니다! 사용에 따른 위험은 사용자가 부담합니다.
⚠️ 이 옵션은 vmObfuscation이 활성화되면 별도의 알림 없이 비활성화됩니다. 대신 vmDebugProtection을 사용하세요.
값을 설정하면 지정한 밀리초 간격으로 콘솔 탭에서 디버그 모드를 강제로 실행하여, 개발자 도구의 다른 기능을 사용하기 어렵게 만듭니다. debugProtection이 활성화된 경우에만 동작합니다. 권장 값은 2000에서 4000 밀리초 사이입니다.
disableConsoleOutput
Type: boolean Default: false
⚠️ 이 옵션은 모든 스크립트에서 전역적으로 console 호출을 비활성화합니다
console.log, console.info, console.error, console.warn, console.debug, console.exception, console.trace를 빈 함수로 대체하여 사용할 수 없게 만듭니다. 이로 인해 디버거를 사용하기가 더 어려워집니다.
domainLock
Type: string[] Default: []
⚠️ 이 옵션은 target: 'node', target: 'service-worker', target: 'bytenode'에서는 동작하지 않습니다
난독화된 소스 코드가 특정 도메인 및/또는 서브도메인에서만 실행되도록 제한합니다. 이렇게 하면 다른 사람이 소스 코드를 그대로 복사해 다른 곳에서 실행하기가 매우 어려워집니다.
이 옵션에 지정된 도메인에서 소스 코드가 실행되지 않는 경우, 브라우저는 domainLockRedirectUrl 옵션에 전달된 URL로 리디렉션됩니다.
여러 도메인과 서브도메인
코드를 두 개 이상의 도메인 또는 서브도메인에 잠글 수 있습니다. 예를 들어 코드가 **www.example.com**에서만 실행되도록 잠그려면 www.example.com을 추가하세요. 모든 서브도메인을 포함한 루트 도메인(example.com, sub.example.com)에서 동작하게 하려면 .example.com을 사용하세요.
domainLockRedirectUrl
Type: string Default: about:blank
⚠️ 이 옵션은 target: 'node', target: 'service-worker', target: 'bytenode'에서는 동작하지 않습니다
domainLock에 지정된 도메인에서 소스 코드가 실행되지 않는 경우, 브라우저를 전달된 URL로 리디렉션합니다
exclude
Type: string[] Default: []
난독화에서 제외할 파일을 지정하는 파일 이름 또는 glob 패턴입니다.
forceTransformStrings
Type: string[] Default: []
전달된 정규식 패턴과 일치하는 문자열 리터럴을 강제로 변환합니다.
⚠️ 이 옵션은 stringArrayThreshold(또는 향후 추가될 수 있는 다른 임계값)에 의해 변환되지 않아야 하는 문자열에만 영향을 줍니다
이 옵션은 reservedStrings 옵션보다 우선하지만, conditional comments보다 우선하지는 않습니다.
예시:
{
forceTransformStrings: [
'some-important-value',
'some-string_\d'
]
}
identifierNamesCache
Type: Object | null Default: null
이 옵션의 주된 목적은 여러 소스/파일을 난독화할 때 동일한 식별자 이름을 사용할 수 있도록 하는 것입니다.
현재 두 가지 유형의 식별자를 지원합니다:
- 전역 식별자:
- 모든 전역 식별자가 캐시에 기록됩니다;
- 일치하는 선언되지 않은 전역 식별자는 모두 캐시의 값으로 대체됩니다.
- 속성 식별자,
renameProperties옵션이 활성화된 경우에만 해당:- 모든 속성 식별자가 캐시에 기록됩니다;
- 일치하는 속성 식별자는 모두 캐시의 값으로 대체됩니다.
Node.js API
null 값을 전달하면 캐시가 완전히 비활성화됩니다.
빈 객체({})를 전달하면 식별자 이름이 캐시 객체(TIdentifierNamesCache 타입)에 기록됩니다. 이 캐시 객체는 ObfuscationResult 객체의 getIdentifierNamesCache 메서드를 호출하여 가져올 수 있습니다.
이렇게 얻은 캐시 객체는 이후 identifierNamesGenerator 옵션 값으로 사용할 수 있으며, 다음 소스를 난독화할 때 일치하는 모든 식별자 이름에 이 이름들이 적용됩니다.
예시:
const source1ObfuscationResult = JavaScriptObfuscator.obfuscate(
`
function foo(arg) {
console.log(arg)
}
function bar() {
var bark = 2;
}
`,
{
compact: false,
identifierNamesCache: {},
renameGlobals: true
}
)
console.log(source1ObfuscationResult.getIdentifierNamesCache());
/*
{
globalIdentifiers: {
foo: '_0x5de86d',
bar: '_0x2a943b'
}
}
*/
const source2ObfuscationResult = JavaScriptObfuscator.obfuscate(
`
// Expecting that these global functions are defined in another obfuscated file
foo(1);
bar();
// Expecting that this global function is defined in third-party package
baz();
`,
{
compact: false,
identifierNamesCache: source1ObfuscationResult.getIdentifierNamesCache(),
renameGlobals: true
}
)
console.log(source2ObfuscationResult.getObfuscatedCode());
/*
_0x5de86d(0x1);
_0x2a943b();
baz();
*/
CLI
CLI에는 별도의 --identifier-names-cache-path 옵션이 있으며, 식별자 이름 캐시를 읽고 쓰는 데 사용할 기존 .json 파일의 경로를 지정할 수 있습니다.
빈 파일의 경로를 전달하면 식별자 이름 캐시가 해당 파일에 기록됩니다.
캐시가 저장된 이 파일은 다시 --identifier-names-cache-path 옵션 값으로 사용할 수 있으며, 이후 파일들을 난독화할 때 일치하는 모든 식별자 이름에 이 이름들이 적용됩니다.
identifierNamesGenerator
Type: string Default: hexadecimal
식별자 이름 생성기를 설정합니다.
사용 가능한 값:
dictionary:identifiersDictionary목록에 있는 식별자 이름hexadecimal:_0xabc123형태의 식별자 이름mangled:a,b,c와 같은 짧은 식별자 이름mangled-shuffled:mangled와 동일하지만 알파벳 순서를 섞어서 사용
identifiersDictionary
Type: string[] Default: []
identifierNamesGenerator: dictionary 옵션에서 사용할 식별자 사전을 설정합니다. 사전의 각 식별자는 각 문자의 대소문자를 다르게 조합한 여러 변형으로 사용됩니다. 따라서 사전에 포함할 식별자 개수는 원본 소스 코드의 식별자 수에 따라 정해야 합니다.
identifiersPrefix
Type: string Default: ''
모든 전역 식별자에 사용할 접두사를 설정합니다.
여러 파일을 난독화할 때 이 옵션을 사용하세요. 이 옵션은 파일 간 전역 식별자 충돌을 방지하는 데 도움이 됩니다. 접두사는 파일마다 다르게 지정해야 합니다.
randomIdentifiersPrefix
Type: boolean Default: false
모든 전역 식별자에 시드 기반의 무작위 접두사(영숫자 6자)를 붙입니다. 같은 전역 스코프에 로드되는, 서로 별개로 난독화된 번들 간의 충돌을 피하려면 이 옵션을 사용하세요. 번들마다 고유한 identifiersPrefix를 직접 정할 필요가 없어집니다.
- 무작위 값은
seed옵션과 소스 코드 해시로부터 생성되므로, 동일한 시드로 재현 가능한 빌드를 수행하면 같은 접두사가 만들어집니다. identifiersPrefix와 함께 사용하면 사용자가 지정한 접두사 뒤에 무작위 문자가 덧붙습니다(예:myApp+ 무작위aBc123→myAppaBc123).vmObfuscation과 함께 사용하면 무작위 값이 기본vm접두사를 대체합니다. 무작위성만으로 이미 고유성이 보장되기 때문입니다.
ignoreImports
Type: boolean Default: false
require 임포트가 난독화되지 않도록 합니다. 런타임 환경이 어떤 이유로든 이러한 임포트에 정적 문자열만 허용하는 경우에 유용할 수 있습니다.
inputFileName
Type: string Default: ''
소스 코드가 담긴 입력 파일의 이름을 설정합니다. 이 이름은 소스 맵 생성 시 내부적으로 사용됩니다.
NodeJS API를 사용하면서 sourceMapSourcesMode 옵션 값이 sources인 경우에는 반드시 지정해야 합니다.
log
Type: boolean Default: false
정보를 콘솔에 기록하도록 활성화합니다.
numbersToExpressions
Type: boolean Default: false
숫자를 표현식으로 변환합니다
예시:
// input
const foo = 1234;
// output
const foo=-0xd93+-0x10b4+0x41*0x67+0x84e*0x3+-0xff8;
optionsPreset
Type: string Default: default
옵션 프리셋을 설정합니다.
사용 가능한 값:
vm-default;vm-low-obfuscation;vm-medium-obfuscation;vm-high-obfuscation;vm-ultra-high-obfuscation;vm-anti-llm;default;low-obfuscation;medium-obfuscation;high-obfuscation.
추가로 지정한 옵션은 모두 선택한 옵션 프리셋과 병합됩니다.
parseHtml
Type: boolean Default: false
HTML <script> 태그 안에 있는 JavaScript의 난독화를 활성화합니다.
이 옵션을 활성화하면 난독화 도구는 다음과 같이 동작합니다:
- 입력이 HTML인지 자동으로 감지합니다(
<!DOCTYPE,<html>,<head>,<body>,<script>태그의 존재 여부로 판단) data-javascript-obfuscator속성이 지정된<script>태그에서 JavaScript를 추출합니다- HTML 구조를 유지하면서 지정된 각 스크립트를 개별적으로 난독화합니다
- 난독화된 코드를 원래 위치에 다시 삽입합니다
중요: data-javascript-obfuscator 속성이 있는 스크립트만 난독화됩니다. 지정된 각 스크립트는 개별적으로, 서로 독립적으로 난독화됩니다. 따라서 다음 사항에 유의해야 합니다:
- 지정된 스크립트 태그 안의 코드는 독립적이어야 합니다. 즉, 다른 지정된 스크립트 태그에서 정의한 변수, 함수, 클래스를 참조해서는 안 됩니다
- 지정되지 않은 스크립트는 지정된 스크립트가 정의한 전역 값에 여전히 접근할 수 있습니다(
var선언이나 명시적인globalThis할당을 통해) - 이를 통해 어떤 스크립트를 보호할지 명시적으로 제어할 수 있습니다
난독화되는 스크립트(data-javascript-obfuscator 속성이 반드시 있어야 함):
<script data-javascript-obfuscator>- 일반 스크립트<script type="text/javascript" data-javascript-obfuscator>- 타입이 명시된 스크립트- 추가 속성(
id,class, 기타data-*등)이 있는 스크립트
건너뛰는 스크립트(변경되지 않음):
data-javascript-obfuscator속성이 없는 스크립트<script type="module">- ES 모듈(속성이 있어도 제외)<script src="...">- 외부 스크립트(속성이 있어도 제외)- 빈 스크립트 태그
참고: parseHtml이 활성화되면 소스 맵은 생성되지 않습니다. HTML 출력에 올바르게 매핑되지 않기 때문입니다.
예시:
// input
const html = `<!DOCTYPE html>
<html>
<body>
<!-- This script will NOT be obfuscated -->
<script>
var helper = 'utility';
</script>
<!-- This script WILL be obfuscated -->
<script data-javascript-obfuscator>
var greeting = 'Hello World';
console.log(greeting);
</script>
</body>
</html>`;
JavaScriptObfuscator.obfuscate(html, {
parseHtml: true,
stringArray: true
});
// output: HTML with only the marked script obfuscated
renameGlobals
Type: boolean Default: false
⚠️ 이 옵션은 코드를 손상시킬 수 있습니다. 동작 방식을 정확히 아는 경우에만 활성화하세요!
선언이 있는 전역 변수 및 함수 이름의 난독화를 활성화합니다.
이 옵션이 비활성화되어 있고 입력 코드가 전역 스코프에 함수나 클래스를 선언하는 경우(즉, 코드가 IIFE로 감싸여 있지 않은 경우), 다른 스크립트가 그 이름으로 참조할 수 있기 때문에 해당 이름은 난독화된 출력에도 그대로 유지됩니다. vmObfuscation을 사용하면 이러한 이름을 나열한 VMGlobalFunctionNamesNotRenamed 경고가 보고됩니다. 함수 본문은 바이트코드로 숨겨지지만, 읽을 수 있는 최상위 이름만으로도 (예를 들어 LLM에게) 코드가 무슨 일을 하는지 드러나기 때문입니다. 이러한 노출을 피하려면 코드를 IIFE로 감싸거나 이 옵션을 활성화하세요.
renameProperties
Type: boolean Default: false
⚠️ 이 옵션은 코드를 손상시킬 수 있습니다. 동작 방식을 정확히 아는 경우에만 활성화하세요!
속성 이름 변경을 활성화합니다. 모든 내장 DOM 속성과 JavaScript 코어 클래스의 속성은 제외됩니다.
이 옵션의 safe 모드와 unsafe 모드를 전환하려면 renamePropertiesMode 옵션을 사용하세요.
변경된 속성 이름의 형식을 지정하려면 identifierNamesGenerator 옵션을 사용하세요.
어떤 속성의 이름을 변경할지 제어하려면 reservedNames 옵션을 사용하세요.
예시:
// input
(function () {
const foo = {
prop1: 1,
prop2: 2,
calc: function () {
return this.prop1 + this.prop2;
}
};
console.log(foo.calc());
})();
// output
(function () {
const _0x46529b = {
'_0x10cec7': 0x1,
'_0xc1c0ca': 0x2,
'_0x4b961d': function () {
return this['_0x10cec7'] + this['_0xc1c0ca'];
}
};
console['log'](_0x46529b['_0x4b961d']());
}());
renamePropertiesMode
Type: string Default: safe
⚠️ safe 모드에서도 renameProperties 옵션은 코드를 손상시킬 수 있습니다.
renameProperties 옵션의 모드를 지정합니다:
safe-2.11.0릴리스 이후의 기본 동작입니다. 런타임 오류를 방지하기 위해 더 안전한 방식으로 속성 이름을 변경합니다. 이 모드에서는 일부 속성이 이름 변경 대상에서 제외됩니다.unsafe-2.11.0릴리스 이전의 기본 동작입니다. 아무런 제한 없이 안전하지 않은 방식으로 속성 이름을 변경합니다.
한 파일이 다른 파일의 속성을 사용하는 경우, identifierNamesCache 옵션을 사용하여 파일 간에 동일한 속성 이름이 유지되도록 하세요.
reservedNames
Type: string[] Default: []
전달된 정규식 패턴과 일치하는 식별자의 난독화 및 이름 생성을 비활성화합니다.
예시:
{
reservedNames: [
'^someVariable',
'functionParameter_\d'
]
}
reservedStrings
Type: string[] Default: []
전달된 정규식 패턴과 일치하는 문자열 리터럴의 변환을 비활성화합니다. 일치하는 문자열은 난독화된 출력에서도 그대로 보입니다.
VM 난독화를 사용할 때, 예약된 문자열은 그대로 보이도록 암호화되지 않은 별도의 배열에 저장됩니다. 모니터링용 API 엔드포인트나 라이브러리 식별자처럼 읽을 수 있는 상태로 남아야 하는 문자열에 유용합니다.
예시:
{
reservedStrings: [
'react-native',
'\.\/src\/test',
'some-string_\d'
]
}
seed
Type: string|number Default: 0
난수 생성기의 시드를 설정합니다. 반복 가능한 결과를 만들 때 유용합니다.
시드가 0이면 난수 생성기는 시드 없이 동작합니다.
selfDefending
Type: boolean Default: false
⚠️ 이 옵션으로 난독화한 뒤에는 난독화된 코드를 어떤 방식으로도 수정하지 마세요. 코드 압축과 같은 사소한 변경만으로도 자기 방어가 발동하여 코드가 더 이상 동작하지 않을 수 있습니다!
⚠️ 이 옵션은 compact 값을 강제로 true로 설정합니다
⚠️ 이 옵션은 vmObfuscation이 활성화되면 별도의 알림 없이 비활성화됩니다. 대신 vmSelfDefending을 사용하세요.
이 옵션은 출력 코드가 포맷팅과 변수 이름 변경에 견디도록 만듭니다. 난독화된 코드에 JavaScript 코드 정리 도구(beautifier)를 사용하면 코드가 더 이상 동작하지 않으므로, 코드를 이해하고 수정하기가 더 어려워집니다.
simplify
Type: boolean Default: true
코드 단순화를 통한 추가 난독화를 활성화합니다.
⚠️ 향후 릴리스에서는 boolean 리터럴의 난독화(true => !![])가 이 옵션 아래로 이동할 예정입니다.
예시:
// input
if (condition1) {
const foo = 1;
const bar = 2;
console.log(foo);
return bar;
} else if (condition2) {
console.log(1);
console.log(2);
console.log(3);
return 4;
} else {
return 5;
}
// output
if (condition1) {
const foo = 0x1, bar = 0x2;
return console['log'](foo), bar;
} else
return condition2 ? (console['log'](0x1), console['log'](0x2), console['log'](0x3), 0x4) : 0x5;
sourceMap
Type: boolean Default: false
난독화된 코드에 대한 소스 맵 생성을 활성화합니다.
소스 맵은 난독화된 JavaScript 소스 코드를 디버깅하는 데 도움이 됩니다. 프로덕션 환경에서 디버깅해야 한다면, 별도의 소스 맵 파일을 비공개 위치에 업로드한 뒤 브라우저가 해당 위치를 참조하도록 설정할 수 있습니다.
sourceMapBaseUrl
Type: string Default: ``
sourceMapMode: 'separate'일 때 소스 맵 임포트 URL에 사용할 기준 URL을 설정합니다.
CLI 예시:
javascript-obfuscator input.js --output out.js --source-map true --source-map-base-url 'http://localhost:9000'
결과:
//# sourceMappingURL=http://localhost:9000/out.js.map
sourceMapFileName
Type: string Default: ``
sourceMapMode: 'separate'일 때 출력되는 소스 맵의 파일 이름을 설정합니다.
CLI 예시:
javascript-obfuscator input.js --output out.js --source-map true --source-map-base-url 'http://localhost:9000' --source-map-file-name example
결과:
//# sourceMappingURL=http://localhost:9000/example.js.map
sourceMapMode
Type: string Default: separate
소스 맵 생성 모드를 지정합니다:
inline- 각 .js 파일 끝에 소스 맵을 추가합니다;separate- 소스 맵이 담긴 '.map' 파일을 별도로 생성합니다. CLI로 난독화 도구를 실행하는 경우, 난독화된 코드 파일 끝에 소스 맵 파일 링크//# sourceMappingUrl=file.js.map을 추가합니다.
sourceMapSourcesMode
Type: string Default: sources-content
소스 맵의 sources 및 sourcesContent 필드를 제어합니다:
sources-content- 형식만 갖춘sources필드를 추가하고, 원본 소스 코드가 담긴sourcesContent필드를 추가합니다;sources- 유효한 소스 정보가 담긴sources필드를 추가하고,sourcesContent필드는 추가하지 않습니다. NodeJS API를 사용할 때는sources필드 값으로 사용할inputFileName옵션을 반드시 지정해야 합니다.
splitStrings
Type: boolean Default: false
문자열 리터럴을 splitStringsChunkLength 옵션 값 길이의 조각으로 나눕니다.
예시:
// input
(function(){
var test = 'abcdefg';
})();
// output
(function(){
var _0x5a21 = 'ab' + 'cd' + 'ef' + 'g';
})();
splitStringsChunkLength
Type: number Default: 10
splitStrings 옵션에서 사용할 조각의 길이를 설정합니다.
stringArray
Type: boolean Default: true
문자열 리터럴을 제거하고 전용 배열에 넣습니다. 예를 들어 var m = "Hello World";의 문자열 "Hello World"는 var m = _0x12c456[0x1];과 같은 형태로 대체됩니다.
stringArrayCallsTransform
Type: boolean Default: false
⚠️ stringArray 옵션이 활성화되어 있어야 합니다
stringArray 호출의 변환을 활성화합니다. 이러한 호출의 모든 인자는 stringArrayCallsTransformThreshold 값에 따라 별도의 객체로 추출될 수 있습니다.
따라서 문자열 배열 호출을 자동으로 찾아내기가 훨씬 더 어려워집니다.
예시:
function foo() {
var k = {
c: 0x2f2,
d: '0x396',
e: '0x397',
f: '0x39a',
g: '0x39d',
h: 0x398,
l: 0x394,
m: '0x39b',
n: '0x39f',
o: 0x395,
p: 0x395,
q: 0x399,
r: '0x399'
};
var c = i(k.d, k.e);
var d = i(k.f, k.g);
var e = i(k.h, k.l);
var f = i(k.m, k.n);
function i(c, d) {
return b(c - k.c, d);
}
var g = i(k.o, k.p);
var h = i(k.q, k.r);
}
function j(c, d) {
var l = { c: 0x14b };
return b(c - -l.c, d);
}
console[j(-'0xa6', -'0xa6')](foo());
function b(c, d) {
var e = a();
b = function (f, g) {
f = f - 0xa3;
var h = e[f];
return h;
};
return b(c, d);
}
function a() {
var m = [
'string5',
'string1',
'log',
'string3',
'string6',
'string2',
'string4'
];
a = function () {
return m;
};
return a();
}
stringArrayCallsTransformThreshold
Type: number Default: 0.5
⚠️ stringArray와 stringArrayCallsTransformThreshold 옵션이 활성화되어 있어야 합니다
이 설정으로 문자열 배열 호출이 변환될 확률(0에서 1 사이)을 조정할 수 있습니다.
stringArrayEncoding
Type: string[] Default: []
⚠️ stringArray 옵션이 활성화되어 있어야 합니다
이 옵션은 스크립트의 실행 속도를 저하시킬 수 있습니다.
stringArray의 모든 문자열 리터럴을 base64 또는 rc4로 인코딩하고, 런타임에 이를 다시 디코딩하는 특수한 코드를 삽입합니다.
각 stringArray 값은 전달된 목록에서 무작위로 선택된 인코딩 방식으로 인코딩됩니다. 따라서 여러 인코딩 방식을 함께 사용할 수 있습니다.
사용 가능한 값:
'none'(boolean):stringArray값을 인코딩하지 않습니다'base64'(string):base64를 사용하여stringArray값을 인코딩합니다'rc4'(string):rc4를 사용하여stringArray값을 인코딩합니다.base64보다 약 30~50% 느리지만, 원래 값을 알아내기가 더 어렵습니다.
예를 들어 다음과 같은 옵션 값을 사용하면 일부 stringArray 값은 인코딩되지 않고, 일부 값은 base64와 rc4 인코딩으로 인코딩됩니다:
stringArrayEncoding: [
'none',
'base64',
'rc4'
]
stringArrayIndexesType
Type: string[] Default: ['hexadecimal-number']
⚠️ stringArray 옵션이 활성화되어 있어야 합니다
문자열 배열 호출 인덱스의 유형을 제어합니다.
각 stringArray 호출 인덱스는 전달된 목록에서 무작위로 선택된 유형으로 변환됩니다. 따라서 여러 유형을 함께 사용할 수 있습니다.
사용 가능한 값:
'hexadecimal-number'(default): 문자열 배열 호출 인덱스를 16진수 숫자로 변환합니다'hexadecimal-numeric-string': 문자열 배열 호출 인덱스를 16진수 숫자 문자열로 변환합니다
2.9.0 릴리스 이전의 javascript-obfuscator는 모든 문자열 배열 호출 인덱스를 hexadecimal-numeric-string 유형으로 변환했습니다. 이 방식은 수동 역난독화를 다소 어렵게 만들지만, 자동 역난독화 도구가 이러한 호출을 쉽게 탐지할 수 있게 합니다.
새로운 hexadecimal-number 유형은 코드에서 문자열 배열 호출 패턴을 자동으로 탐지하기 어렵게 만드는 것을 목표로 합니다.
앞으로 더 많은 유형이 추가될 예정입니다.
stringArrayIndexShift
Type: boolean Default: true
⚠️ stringArray 옵션이 활성화되어 있어야 합니다
모든 문자열 배열 호출에 추가적인 인덱스 시프트를 적용합니다
stringArrayRotate
Type: boolean Default: true
⚠️ stringArray가 활성화되어 있어야 합니다
stringArray 배열을 고정되고 무작위한(코드 난독화 시점에 생성된) 위치만큼 회전시킵니다. 이렇게 하면 추출된 문자열의 순서를 원래 위치와 대응시키기가 더 어려워집니다.
stringArrayShuffle
Type: boolean Default: true
⚠️ stringArray가 활성화되어 있어야 합니다
stringArray 배열의 항목 순서를 무작위로 섞습니다.
stringArrayWrappersCount
Type: number Default: 1
⚠️ stringArray 옵션이 활성화되어 있어야 합니다
각 루트 스코프 또는 함수 스코프 안에 생성할 string array 래퍼의 개수를 설정합니다.
각 스코프 안에 실제로 생성되는 래퍼 개수는 해당 스코프의 literal 노드 개수로 제한됩니다.
예시:
// Input
const foo = 'foo';
const bar = 'bar';
function test () {
const baz = 'baz';
const bark = 'bark';
const hawk = 'hawk';
}
const eagle = 'eagle';
// Output, stringArrayWrappersCount: 5
const _0x3f6c = [
'bark',
'bar',
'foo',
'eagle',
'hawk',
'baz'
];
const _0x48f96e = _0x2e13;
const _0x4dfed8 = _0x2e13;
const _0x55e970 = _0x2e13;
function _0x2e13(_0x33c4f5, _0x3f6c62) {
_0x2e13 = function (_0x2e1388, _0x60b1e) {
_0x2e1388 = _0x2e1388 - 0xe2;
let _0x53d475 = _0x3f6c[_0x2e1388];
return _0x53d475;
};
return _0x2e13(_0x33c4f5, _0x3f6c62);
}
const foo = _0x48f96e(0xe4);
const bar = _0x4dfed8(0xe3);
function test() {
const _0x1c262f = _0x2e13;
const _0x54d7a4 = _0x2e13;
const _0x5142fe = _0x2e13;
const _0x1392b0 = _0x1c262f(0xe7);
const _0x201a58 = _0x1c262f(0xe2);
const _0xd3a7fb = _0x1c262f(0xe6);
}
const eagle = _0x48f96e(0xe5);
stringArrayWrappersChainedCalls
Type: boolean Default: true
⚠️ stringArray와 stringArrayWrappersCount 옵션이 활성화되어 있어야 합니다
string array 래퍼 간의 연쇄 호출을 활성화합니다.
예시:
// Input
const foo = 'foo';
const bar = 'bar';
function test () {
const baz = 'baz';
const bark = 'bark';
function test1() {
const hawk = 'hawk';
const eagle = 'eagle';
}
}
// Output, stringArrayWrappersCount: 5, stringArrayWrappersChainedCalls: true
const _0x40c2 = [
'bar',
'bark',
'hawk',
'eagle',
'foo',
'baz'
];
const _0x31c087 = _0x3280;
const _0x31759a = _0x3280;
function _0x3280(_0x1f52ee, _0x40c2a2) {
_0x3280 = function (_0x3280a4, _0xf07b02) {
_0x3280a4 = _0x3280a4 - 0x1c4;
let _0x57a182 = _0x40c2[_0x3280a4];
return _0x57a182;
};
return _0x3280(_0x1f52ee, _0x40c2a2);
}
const foo = _0x31c087(0x1c8);
const bar = _0x31c087(0x1c4);
function test() {
const _0x848719 = _0x31759a;
const _0x2693bf = _0x31c087;
const _0x2c08e8 = _0x848719(0x1c9);
const _0x359365 = _0x2693bf(0x1c5);
function _0x175e90() {
const _0x310023 = _0x848719;
const _0x2302ef = _0x2693bf;
const _0x237437 = _0x310023(0x1c6);
const _0x56145c = _0x310023(0x1c7);
}
}
stringArrayWrappersParametersMaxCount
Type: number Default: 2
⚠️ stringArray 옵션이 활성화되어 있어야 합니다
⚠️ 현재 이 옵션은 stringArrayWrappersType 옵션 값이 function일 때 추가되는 래퍼에만 영향을 줍니다
문자열 배열 래퍼가 받을 수 있는 최대 매개변수 개수를 제어합니다.
기본값이자 최솟값은 2입니다. 권장 값은 2에서 5 사이입니다.
stringArrayWrappersType
Type: string Default: variable
⚠️ stringArray와 stringArrayWrappersCount 옵션이 활성화되어 있어야 합니다
stringArrayWrappersCount 옵션으로 추가되는 래퍼의 유형을 선택합니다.
사용 가능한 값:
'variable': 각 스코프 상단에 변수 래퍼를 추가합니다. 성능이 빠릅니다.'function': 각 스코프 안의 임의의 위치에 함수 래퍼를 추가합니다.variable보다 성능은 느리지만 더 강력한 난독화를 제공합니다.
성능 저하가 난독화된 애플리케이션에 큰 영향을 주지 않는다면, 더 높은 수준의 난독화를 위해 function 래퍼를 사용할 것을 적극 권장합니다.
'function' 옵션 값을 사용한 예시:
// input
const foo = 'foo';
function test () {
const bar = 'bar';
console.log(foo, bar);
}
test();
// output
const a = [
'log',
'bar',
'foo'
];
const foo = d(0x567, 0x568);
function b(c, d) {
b = function (e, f) {
e = e - 0x185;
let g = a[e];
return g;
};
return b(c, d);
}
function test() {
const c = e(0x51c, 0x51b);
function e (c, g) {
return b(c - 0x396, g);
}
console[f(0x51b, 0x51d)](foo, c);
function f (c, g) {
return b(c - 0x396, g);
}
}
function d (c, g) {
return b(g - 0x3e1, c);
}
test();
stringArrayThreshold
Type: number Default: 0.8 Min: 0 Max: 1
⚠️ stringArray 옵션이 활성화되어 있어야 합니다
이 설정으로 문자열 리터럴이 stringArray에 삽입될 확률(0에서 1 사이)을 조정할 수 있습니다.
string array를 반복적으로 호출하면 코드가 느려질 수 있으므로, 이 설정은 코드 규모가 큰 경우에 특히 유용합니다.
stringArrayThreshold: 0은 stringArray: false와 동일합니다.
strictMode
Type: boolean | null Default: null
난독화 도구가 JavaScript strict 모드와 관련하여 코드를 어떻게 다룰지 지정합니다.
사용 가능한 값:
null(기본값) - 코드에서 strict 모드를 자동으로 감지합니다. 코드에 명시적인'use strict'지시문, ES 모듈 문법, 클래스 메서드가 있으면 strict 모드로 간주합니다. 그렇지 않으면 sloppy 모드로 간주합니다.true- 명시적인'use strict'지시문이 없더라도 모든 코드를 strict 모드로 처리합니다. 코드가 strict 모드 컨텍스트에서 실행되는 경우(예: ES 모듈, 번들러, 최신 프레임워크)에 사용하세요.false- 명시적인 strict 모드 표시('use strict', ES 모듈, 클래스 메서드)가 있는 경우에만 strict 모드로 처리합니다. 상위 스코프로부터의 상속은 JS 명세에 따라 그대로 적용됩니다.
target
Type: string Default: browser
난독화된 코드의 대상 환경을 설정합니다.
사용 가능한 값:
browser(기본값) — 일반적인 웹 페이지 환경입니다. 출력 코드는node와 동일하지만, 일부 브라우저 전용 옵션은node대상과 함께 사용할 수 없습니다browser-no-eval—browser와 동일하지만 출력 코드가eval()을 사용하지 않습니다. 대상 페이지의 Content Security Policy가eval/unsafe-eval을 금지하는 경우에 사용하세요.node— Node.js 환경입니다. 브라우저 전용 옵션은 비활성화됩니다(이러한 옵션은window/document를 필요로 하므로 Node에서는 아무 동작도 하지 않거나 오류를 발생시킵니다). 브라우저 전용 API에 의존하는 일부vmSelfDefending방어 기능(헤드리스 브라우저 탐지, iframe 기반 클린 렐름 복구, 인스펙터 방지 및 DOM 검사)은 이 대상에서는 생성되지 않습니다.service-worker— Service Worker 컨텍스트입니다.window와document가 없으며self전역 객체가 다릅니다.userscript— 유저스크립트 관리자 샌드박스(예: Tampermonkey)입니다.vmSelfDefending방어 기능이 그에 맞게 조정됩니다.bytenode— 난독화 후 bytenode 로더(V8 캐시 바이트코드.jsc)로 컴파일할 Node.js 코드입니다. 난독화 도구가 직접bytenode를 실행하지는 않으며, bytenode의 컴파일 단계를 견딜 수 있도록 런타임이 구성된 VM 난독화 JavaScript를 생성하고vmSelfDefending방어 기능을 그에 맞게 조정합니다. 최종.jsc파일을 만들려면 난독화된 결과물에 직접bytenode를 실행해야 합니다.
transformObjectKeys
Type: boolean Default: false
객체 키의 변환을 활성화합니다.
예시:
// input
(function(){
var object = {
foo: 'test1',
bar: {
baz: 'test2'
}
};
})();
// output
var _0x4735 = [
'foo',
'baz',
'bar',
'test1',
'test2'
];
function _0x390c(_0x33d6b6, _0x4735f4) {
_0x390c = function (_0x390c37, _0x1eed85) {
_0x390c37 = _0x390c37 - 0x198;
var _0x2275f8 = _0x4735[_0x390c37];
return _0x2275f8;
};
return _0x390c(_0x33d6b6, _0x4735f4);
}
(function () {
var _0x17d1b7 = _0x390c;
var _0xc9b6bb = {};
_0xc9b6bb[_0x17d1b7(0x199)] = _0x17d1b7(0x19c);
var _0x3d959a = {};
_0x3d959a[_0x17d1b7(0x198)] = _0x17d1b7(0x19b);
_0x3d959a[_0x17d1b7(0x19a)] = _0xc9b6bb;
var _0x41fd86 = _0x3d959a;
}());
warnings
Type: string | object Default: all
ObfuscationResult.getWarnings() 메서드를 통해 전달되는 치명적이지 않은 난독화 경고 중 어떤 것을 내보낼지 제어합니다.
사용 가능한 값:
'all'(기본값) — 모든 경고를 내보냅니다.'none'— 모든 경고를 숨깁니다.- 경고 유형을 불리언 값에 대응시킨 객체 —
false로 지정한 유형은 숨겨지고, 목록에 없거나true로 지정한 유형은 그대로 활성화됩니다. 예를 들어{ "VMGlobalFunctionNamesNotRenamed": false }는 해당 경고만 제외하고 나머지 모든 경고를 유지합니다.
경고 유형:
VMGlobalFunctionNamesNotRenamed—vmObfuscation을 사용할 때 최상위 함수 선언, 클래스 선언, 그리고 함수/화살표 함수/클래스 표현식이 할당된 변수의 이름이 그대로 유지되었습니다(renameGlobals옵션이 비활성화되어 있고 코드가 IIFE로 감싸여 있지 않은 경우). 본문은 바이트코드로 숨겨지지만 이러한 이름은 출력에서 그대로 읽힙니다. export된 이름은 보고되지 않습니다.VMTopLevelInitializerNotVirtualized—vmWrapTopLevelInitializers가 비활성화되어 있거나 가상화할 수 없었기 때문에, VM 난독화에서도 최상위 변수 초기화 식이 일반 JavaScript로 남았습니다.DynamicCodeRenameRisk— 코드가 런타임에 문자열로부터 함수를 생성하며(직접eval,Function생성자, 또는<script>/Worker에 삽입되는fn.toString()), 난독화 도구가 이름을 바꾼 식별자를 참조할 수 있습니다.VMDynamicCodeSkipped— 함수에 직접eval/ 동적new Function/Function이 포함되어 있어 VM 바이트코드 변환에서 제외되었습니다(vmForceCompileDynamicCode참고).VMSyncFunctionSkippedInAsyncMode—vmAsyncExecutor가 활성화된 상태에서,comment모드로 직접 지정한 함수가 동기 함수여서 제외되었습니다(이 모드에서는 비동기 함수만 가상화됩니다).VMAsyncGeneratorSkippedInAsyncMode—vmAsyncExecutor와 비동기 키 게터가 활성화된 상태에서, 지정된 async 제너레이터를 가상화할 수 없었습니다(이터레이터를 동기적으로 반환해야 하기 때문입니다).BrowserTargetWithNodeStyleCode—target옵션이 브라우저 계열 환경으로 설정되어 있는데, 코드는 Node.js를 대상으로 하는 것으로 보입니다(예:require('fs'),__dirname,process.argv).
vmObfuscation
Type: boolean Default: false
VM 기반 바이트코드 난독화를 활성화합니다. 이 옵션을 활성화하면 JavaScript 함수가 맞춤형 바이트코드로 컴파일되어, 결과물에 내장된 가상 머신 위에서 실행됩니다. 원본 코드의 로직이 완전히 변환되므로 가장 높은 수준의 보호를 제공합니다.
예시:
return qty * price처럼 읽을 수 있던 코드가 [0x15,0x03,0x17,...]과 같은 숫자 목록으로 바뀌며, 내장된 VM 인터프리터만이 이를 실행할 수 있습니다. 원본 로직은 더 이상 JavaScript 형태로 드러나지 않습니다.
vmTargetFunctions
Type: string[] Default: []
VM 보호를 적용할 최상위 함수를 이름으로 정확히 지정합니다.
예시:
{
vmObfuscation: true,
vmTargetFunctions: ['someFunctionName']
}
결과: 지정한 세 함수만 VM으로 보호됩니다. 나머지는 모두 일반(하지만 여전히 난독화된) JavaScript로 남습니다. 코드의 나머지 부분을 가볍게 유지하면서 민감한 라이선스 검사나 인증 로직을 보호하는 데 적합합니다.
vmExcludeFunctions
Type: string[] Default: []
VM 보호를 적용하지 않을 최상위 함수를 지정합니다. 다른 설정보다 우선합니다.
예시:
{
vmObfuscation: true,
vmExcludeFunctions: ['someFunctionName']
}
언제 사용하나요: 성능이 중요한 최상위 함수(애니메이션 루프, 실시간 데이터 처리 등)를 제외하면 VM 오버헤드를 피하면서 나머지 코드는 그대로 보호할 수 있습니다.
vmTargetFunctionsMode
Type: string Default: root
VM 난독화 대상 함수/메서드를 선택하는 방식을 제어합니다.
예시 - Comment 모드:
// Source code
function regularFunction() {
return 'not virtualized';
}
/* javascript-obfuscator:vm */
function sensitiveFunction() {
return 'this will be VM-protected';
}
function outer() {
/* javascript-obfuscator:vm */
function nestedSensitive() {
return 'nested but still VM-protected';
}
return nestedSensitive();
}
// Obfuscator options
{
vmObfuscation: true,
vmTargetFunctionsMode: 'comment'
}
언제 사용하나요: 어떤 함수에 VM 보호를 적용할지 정밀하게 제어해야 할 때, 특히 민감한 로직이 들어 있는 중첩 함수를 보호할 때 사용합니다. 최상위의 이름 있는 함수에만 적용되는 vmTargetFunctions와 달리, comment 모드에서는 코드 어디에 있는 함수든 보호할 수 있습니다.
vmForceCompileDynamicCode
Type: boolean Default: false
직접 eval, new Function(...), Function(...) 호출이 포함된 함수를 VM 난독화가 어떻게 처리할지 제어합니다.
기본적으로 이러한 함수(그리고 그 안에 정의된 모든 함수)는 VM 바이트코드 변환에서 제외되며, result.getWarnings()를 통해 VMDynamicCodeSkipped 경고가 보고됩니다. 런타임에 생성되는 소스가 주변 스코프 체인의 식별자, 즉 난독화 도구가 이름을 바꾼 식별자를 참조할 수 있기 때문입니다.
true로 설정하면 해당 함수도 바이트코드로 변환되며, VMDynamicCodeSkipped 경고는 더 이상 발생하지 않습니다.
별도의 DynamicCodeRenameRisk 경고는 이 옵션과 관계없이 계속 발생합니다. 이 경고가 알리는 이름 변경 위험은 VM 변환 제외 여부와 무관하며, 이 옵션을 켠다고 해서 해당 패턴이 더 안전해지는 것은 아니기 때문입니다.
// Source code
function loadConfig(src) {
return eval(src);
}
loadConfig('1 + 2');
// Options
{
vmObfuscation: true,
vmForceCompileDynamicCode: true
}
옵션이 꺼져 있으면(기본값) loadConfig는 일반 JavaScript로 남습니다. 옵션이 켜져 있으면 loadConfig도 다른 함수와 마찬가지로 VM 바이트코드로 컴파일됩니다. 호출 지점을 직접 검토하여 런타임에 생성되는 코드가 이름이 변경된 클로저 식별자에 의존하지 않는다는 것을 확인한 경우에 사용하세요.
vmWrapTopLevelInitializers
Type: boolean Default: false
일부 최상위 변수 초기화 식을 IIFE(즉시 실행 함수 표현식)로 감싸서 VM 난독화가 가능하도록 만듭니다.
동작 방식: 이 옵션을 사용하지 않으면 최상위 상수와 변수가 출력에 그대로 드러납니다:
// Input
const MY_STRING = "my-string";
// Output (without vmWrapTopLevelInitializers)
const MY_STRING = "my-string"; // String is visible!
이 옵션을 활성화하면 초기화 식이 IIFE로 감싸지고 VM 난독화가 적용됩니다:
// Input
const MY_STRING = "my-string";
// Output (with vmWrapTopLevelInitializers: true)
const MY_STRING = (() => { return /* VM bytecode call */ })(); // String hidden in bytecode
참고: 이 옵션은 vmTargetFunctionsMode가 'root'(기본값)일 때만 동작합니다.
경고: VM 난독화에서 최상위 초기화 식이 일반 JavaScript로 남는 경우에는 언제나, 해당 변수 이름을 나열한 VMTopLevelInitializerNotVirtualized 경고가 보고됩니다. 여기에는 이 옵션이 비활성화된 경우, 이 옵션이 건너뛸 수밖에 없었던 초기화 식(각각 이유가 함께 표시됩니다. 예를 들어 초기화 식이 같은 선언문의 다른 선언자를 참조하거나 최상위 await를 포함하는 경우), 그리고 동기 래퍼를 아예 가상화할 수 없는 vmAsyncExecutor 모드가 모두 포함됩니다.
vmDynamicOpcodes
Type: boolean Default: false
VM 인터프리터를 더 작게 만들고 빌드마다 고유하게 만듭니다.
동작 방식:
- 사용하지 않는 명령어 제거 - 코드에서 클래스를 사용하지 않으면 클래스 관련 명령어가 완전히 제거됩니다
- 구조 무작위화 - 명령어 핸들러의 순서가 빌드마다 섞입니다
그 결과 출력 크기가 작아지고 빌드마다 결과물이 달라집니다.
vmBytecodeEncoding
Type: boolean Default: false
각 바이트코드 명령어를 인코딩합니다. 명령어는 실행 중에 하나씩 디코딩됩니다.
vmBytecodeArrayEncoding
Type: boolean Default: false
바이트코드 배열 전체를 하나의 블록으로 인코딩합니다. 배열은 실행이 시작되기 전에 한 번 디코딩됩니다. 두 겹의 보호를 적용하려면 vmBytecodeEncoding과 함께 사용하세요.
vmBytecodeArrayEncodingKey
Type: string Default: ''
바이트코드 배열 인코딩에 사용할 사용자 지정 암호화 키입니다. 이 값을 설정하면 기본적으로 환경에서 파생되는 키 대신 이 키가 사용됩니다. 키는 런타임에 vmBytecodeArrayEncodingKeyGetter를 통해 제공해야 합니다.
이 옵션은 암호화 키를 외부로 분리합니다. 즉, 키가 난독화된 코드 자체에 내장되지 않습니다. 키는 여전히 런타임에 접근 가능하므로 완전한 비밀은 아니지만, 이렇게 분리하면 정적 분석 도구가 코드만 살펴봐서는 키를 찾아낼 수 없습니다.
중요: 난독화된 코드가 로드될 때 키를 동기적으로 사용할 수 있어야 합니다. 쿠키, localStorage, sessionStorage, 전역 변수, DOM 요소(예: 서버가 주입한 meta 태그)와 같은 동기 저장소를 사용하세요. fetch()와 같은 비동기 방식은 키 게터 표현식에서 직접 사용할 수 없습니다.
vmBytecodeArrayEncodingKeyGetter
Type: string Default: ''
런타임에 암호화 키를 반환하는 동기 JavaScript 표현식입니다. 이 표현식은 난독화된 코드가 로드될 때 평가되며, vmBytecodeArrayEncodingKey에 제공한 것과 동일한 키를 반환해야 합니다. 키를 비동기적으로(Promise) 해석하려면 vmAsyncExecutor를 활성화하세요.
참고: Promise를 반환하는 게터에는 vmAsyncExecutor가 필요합니다. 이는 빌드 시점에 확인할 수 없으므로, vmAsyncExecutor가 꺼진 상태에서 Promise 게터를 사용하면 런타임에 실패합니다. 디코더가 키 대신 Promise를 받기 때문입니다.
난독화된 코드는 키 게터가 난독화 시점에 사용된 것과 정확히 동일한 키를 반환할 때만 동작합니다. 키가 일치하지 않으면 복호화에 실패하여 코드가 의미 없는 값이나 오류를 만들어냅니다. 키 게터가 undefined, null, 빈 문자열을 반환하면 코드는 "VM decryption key not available" 오류를 발생시킵니다.
중요: 키를 난독화된 코드와 같은 파일/스크립트에 두지 마세요. 그곳에 키를 인라인하면 번들을 순수하게 정적으로 스캔하는 것만으로도 키를 복원할 수 있습니다. 대신 별도의 소스에 저장하세요. 서버가 설정한 쿠키, 다른 스크립트가 채운 localStorage, 서버가 주입한 HTML meta 태그, 다른 스크립트가 설정한 전역 변수, 또는 (vmAsyncExecutor를 사용하여) 런타임에 백엔드에서 가져온 값 등이 있습니다.
키를 (vmAsyncExecutor를 통해) 백엔드에서 가져오는 경우, 해당 엔드포인트에 세션 기반 또는 오리진 기반 검사를 추가하세요. 실제 사용자(유효한 세션, 예상되는 Origin/Referer)에게는 올바른 키를 반환하고, 의심스러운 요청(예: localhost/예상치 못한 오리진, 세션 없음)에는 의미 없는 키를 반환하세요. 실제 사용자는 정상적으로 실행되지만, 사용자의 환경 밖에서 실행되는 복사본은 아무것도 복호화하지 못하는 키를 받게 됩니다. 구체적인 로직은 사이트에 따라 다릅니다.
예시:
// From cookie
vmBytecodeArrayEncodingKeyGetter: "document.cookie.match(/vmKey=([^;]+)/)?.[1]"
// From localStorage
vmBytecodeArrayEncodingKeyGetter: "localStorage.getItem('vmKey')"
// From global variable
vmBytecodeArrayEncodingKeyGetter: "window.__VM_KEY__"
// From meta tag (server-injected)
vmBytecodeArrayEncodingKeyGetter: "document.querySelector('meta[name=\"vm-key\"]').content"
// From nested object
vmBytecodeArrayEncodingKeyGetter: "window.config.encryption.key"
// From backend, async (requires vmAsyncExecutor)
vmBytecodeArrayEncodingKeyGetter: 'fetch("/vm-key").then((res) => res.text())'
사용 예시:
// Build time
JavaScriptObfuscator.obfuscate(code, {
vmObfuscation: true,
vmBytecodeArrayEncoding: true,
vmBytecodeArrayEncodingKey: 'mySecretKey123',
vmBytecodeArrayEncodingKeyGetter: 'window.__VM_KEY__'
});
// Runtime - key must be set before obfuscated code runs
window.__VM_KEY__ = 'mySecretKey123';
vmAsyncExecutor
Type: boolean Default: false
비동기 VM 실행기를 활성화합니다. 이를 통해 vmBytecodeArrayEncodingKeyGetter가 Promise를 반환할 수 있게 되어(비동기 키 게터), 코드가 로드될 때 동기적으로 키를 준비할 필요 없이 런타임에 키를 가져올 수 있습니다(네트워크 요청, IndexedDB 등).
완전히 비동기로 작성된 코드베이스에 적극 권장됩니다. 이 모드에서는 async 함수만 가상화됩니다. 동기 함수는 반환값을 Promise로 바꾸어 호출부를 깨뜨리지 않고서는 비동기로 만들 수 없기 때문입니다. 따라서 전반적으로 async로 작성된 코드가 가장 넓은 범위로 보호됩니다. 루트가 동기인 경우(예: 동기 IIFE / UMD 래퍼)에도 여전히 동작합니다. 그 안의 가장 바깥쪽 async 함수들이 보호되고, 동기 부분은 그대로 남습니다.
변환되는 대상: 위치에 관계없이 모든 가장 바깥쪽 async 함수입니다(동기 래퍼 안에 중첩된 것도 포함). 각 체인에서 가장 바깥쪽 async가 보호 단위이며, 그 안에 있는 모든 것은 동기든 비동기든 함께 컴파일됩니다. 동기 함수와 일반 제너레이터는 난독화되지 않은 채로 남습니다.
function foo() { // sync — left as-is
function bar() {} // sync — left as-is
async function baz() { // transformed
// any code here, including calls to other async or sync functions
}
async function bark() { // transformed
// any code here, including calls to other async or sync functions
}
}
건너뛰기와 경고. 비동기 키 게터가 활성화된 경우 async 제너레이터도 난독화되지 않은 채로 남습니다(async 제너레이터는 이터레이터를 동기적으로 반환해야 하므로 키를 기다릴 수 없습니다). 기본값인 vmTargetFunctionsMode: 'root'에서는 건너뛰기가 별도의 알림 없이 이루어지지만(선택이 자동으로 진행됨), comment 모드에서는 직접 지정한 함수를 가상화할 수 없을 때마다(함수가 동기로 판명되었거나, 비동기 키 게터 아래의 async 제너레이터인 경우) ObfuscationResult.getWarnings()를 통해 경고가 발생합니다.
비동기 키 게터에는 추가로 vmBytecodeArrayEncodingKeyGetter를 지정한 vmBytecodeArrayEncoding이 필요합니다.
사용 예시:
JavaScriptObfuscator.obfuscate(code, {
vmObfuscation: true,
vmAsyncExecutor: true,
vmBytecodeArrayEncoding: true,
vmBytecodeArrayEncodingKey: 'mySecretKey123',
// the key getter may now return a Promise
vmBytecodeArrayEncodingKeyGetter: 'fetch("/vm-key").then((res) => res.text())'
});
vmJumpsEncoding
Type: boolean Default: false
바이트코드의 점프 대상을 인코딩합니다. 점프 오프셋이 런타임에 계산되어, 정적 분석으로부터 제어 흐름 구조(if/else, 반복문 등)를 숨깁니다.
vmMacroOps
Type: boolean Default: false
자주 쓰이는 명령어 시퀀스를 하나의 "매크로" 옵코드로 결합합니다. 예를 들어 LOAD + ADD + STORE가 하나의 MACRO_ADD_TO_VAR 명령어가 될 수 있습니다. 이는 패턴 인식을 방해하며 성능을 향상시킬 수 있습니다.
vmDebugProtection
Type: boolean Default: false
VM 런타임에 다층적인 디버깅 방지, 분석 방지, LLM 대응 방어 기능을 추가합니다. browser/browser-no-eval 대상에서 가장 잘 동작합니다.
vmSelfDefending
Type: boolean Default: false
VM 런타임에 다층적인 변조 탐지, 후킹 방지, 리버스 엔지니어링 방지 보호 기능을 추가합니다.
⚠️ 이 옵션은 vmBytecodeArrayEncoding을 강제로 활성화합니다.
⚠️ 민감한 환경 탐지. 이 옵션은 난독화된 코드를 대상 런타임 환경에 결속시키고, 고급 브라우저 핑거프린팅을 사용해 자동화 도구를 탐지합니다. 이 옵션으로 보호된 코드는 다음 환경에서 실행될 때 의도적으로 동작하지 않습니다:
- 헤드리스 브라우저(헤드리스 Chrome/Chromium, PhantomJS)
- 브라우저 자동화 도구(Puppeteer, Playwright, Cypress, Selenium/ChromeDriver, Nightmare)
- Node.js(
target이browser로 설정된 경우) - jsdom 또는 이와 유사한 서버 측 DOM 에뮬레이션
- 네이티브 브라우저 빌트인이 후킹되거나 교체된 환경
이 코드는 일반 브라우저(Chrome, Firefox, Safari, Edge)에서는 올바르게 동작하며, iframe 내부, 브라우저 확장 프로그램(콘텐츠 스크립트), Web Worker에서 로드되는 경우에도 마찬가지입니다. 보호된 코드에 대해 자동화 테스트를 실행해야 한다면, 테스트 빌드에서는 vmSelfDefending을 비활성화하세요. 이 옵션은 자동화된 분석을 막기 위해 설계되었으며 어떤 자동화 프레임워크와도 안전하게 함께 사용할 수 없습니다.
vmDebugProtection, vmBytecodeArrayEncodingKey, vmBytecodeArrayEncodingKeyGetter와 함께 사용할 것을 적극 권장합니다.
vmDefenseHook
Type: { name: string, aliases?: object } Default: ''
vmDefenseHook은 두 개의 키를 가진 객체를 받습니다: name(필수)과 aliases(선택).
name은 호스트 페이지가 정의하는 전역 함수로, VM 방어 기능(vmDebugProtection / vmSelfDefending)이 적대적 시그널(디버거나 인스펙터, 헤드리스 / 자동화 브라우저, AI 코딩 에이전트 프로세스, 허용되지 않은 도메인 등)을 탐지했을 때 시그널 객체를 인자로 이 함수를 호출합니다. 이 함수를 사용하여 이벤트를 백엔드에 보고하세요(예: navigator.sendBeacon). 훅은 순수한 텔레메트리 싱크입니다. 반환값은 무시되며, 훅이 없거나 예외를 던지더라도 조용히 무시될 뿐 방어 기능을 결코 비활성화할 수 없습니다. 탐지 시 방어 기능이 수행하는 동작을 바꾸려면 vmDefenseReaction을 사용하세요.
aliases는 선택적으로 해당 시그널 객체의 필드 이름을 바꿉니다. 아래 시그널 필드 이름 바꾸기에서 다룹니다.
시그널 객체. 훅은 하나의 signal을 받습니다:
source— 발동한 구체적인 탐지기(표 참고).category— 해당 탐지기가 보고되는 그룹:automation(사람이 아닌 브라우저),debugger(디버거/인스펙터가 활성화됨),sandbox(계측된/가짜 호스트),domain(도메인 잠금 위반),tamper(빌트인이 런타임에 패치됨),integrity(VM 자체 코드가 변경됨).score/threshold— 탐지기가 얼마나 강하게 발동했는지와 도달해야 했던 값. 훅은score >= threshold일 때만 발동합니다. 대부분의 검사는 전부 아니면 전무(하나의 결정적 시그널)이며,headless는 여러 브라우저 형태 시그널을 합산하므로score가 보통threshold보다 높습니다.
훅 등록하기. 난독화된 번들이 로드되기 전에 일반 전역 함수로 정의하세요. VM 런타임과 그 방어 기능은 (보호된) 프로그램보다 먼저 실행되므로, 많은 탐지가 시작 시점에 발동합니다:
// in your page, before the obfuscated script:
window.__vmDetection = function (signal) { navigator.sendBeacon('/vm-defense', JSON.stringify(signal)); };
// obfuscation option:
vmDefenseHook: { name: '__vmDetection' }
난독화된 소스 안에 정의된 훅은 시작 시점의 탐지를 잡기에는 너무 늦게 등록되며, VM으로 컴파일되면 프로그램이 실행되기 전까지 도달할 수 없습니다. 어느 쪽이든 안전하게 처리되지만(훅이 없으면 아무 동작도 하지 않고, 재진입 방지 장치가 폭주를 막습니다), 완전한 커버리지를 원한다면 미리 등록하세요. 그러면서도 보고 로직을 보호하려면, 등록하는 훅은 한 줄짜리 버퍼((window.__vmDet = window.__vmDet || []).push(signal))로 유지하고 그 버퍼를 난독화된 코드에서 읽어 전송하세요.
시그널 필드 이름 바꾸기(aliases). 기본 source/category 값은 설명적인 이름이므로, 콜백을 계측하는(또는 출력을 읽는) 사람은 누구든 보호 기능과 어떤 탐지기가 발동했는지 알아볼 수 있습니다. aliases는 시그널 필드를 사용자가 선택한 알아볼 수 없는 토큰으로 바꿉니다. 이 변환은 시그널이 발생하기 전에 VM 내부에서 적용되므로, 그 이름들은 출력에 나타나거나 콜백에 도달하는 일이 없습니다. 앱은 자신의 매핑을 알고 있으므로 그 토큰을 백엔드로 전달합니다.
별칭은 필드별로 지정하며, 키 이름 변경과 값 이름 변경을 분리합니다. 각 필드는 key(콜백이 받는 속성 이름)를 받습니다. 문자열 이름 필드인 source와 category는 values 맵도 받는 반면, score/threshold는 숫자이므로 key만 받습니다. 매핑할 수 있는 이름은 다음과 같습니다(그 밖의 것은 빌드 시점에 거부됩니다):
- 필드 키 —
source,category,score,threshold source값 —headless,agent,node,debugger,timing,sandbox,domain,nativeHook,integritycategory값 —automation,debugger,sandbox,domain,tamper,integrity
vmDefenseHook: {
name: '__vmDetection',
aliases: {
source: { key: 'a8Qm', values: { headless: 'xP4m9Q' } },
category: { key: 'p3Tx', values: { automation: 'bQ7s1M' } },
score: { key: 's1' },
threshold: { key: 't1' }
}
// the callback now receives e.g. { a8Qm: 'xP4m9Q', p3Tx: 'bQ7s1M', s1: <score>, t1: <threshold> }
}
이것은 핑거프린트 회피이지 비밀 유지가 아닙니다. 매핑은 반복적인 테스트로 여전히 추론될 수 있으므로, 그 유일한 이점은 안정적이고 자명한 이름을 노출하지 않는다는 것뿐입니다. 지정하지 않은 항목은 기본 이름을 유지합니다.
단순 문자열(vmDefenseHook: '__vmDetection')은 { name: '__vmDetection' }의 축약형으로 허용되지만 더 이상 사용되지 않습니다. 객체 형태를 사용하는 것이 좋습니다.
vmDefenseReaction
Type: object Default: { automation: 'break', debugger: 'decoy', sandbox: 'decoy', domain: 'break', tamper: 'break', integrity: 'break' }
각 탐지 카테고리가 어떻게 반응할지 구성합니다. 이 옵션은 아무것도 활성화하지 않습니다. 방어 기능 자체는 vmSelfDefending, vmDebugProtection, vmDomainLock으로 켜지며, 이 옵션은 활성화된 방어 기능이 어떻게 반응할지만 선택합니다. 카테고리가 제어의 단위이며, 한 카테고리의 모든 탐지기는 그 카테고리의 반응을 실행합니다.
각 카테고리는 한 종류의 적대적 조건을 감시하는 탐지기들을 묶습니다. 카테고리는 그 탐지기를 내보내는 옵션이 활성화된 경우에만 반응합니다:
모든 카테고리는 vmSelfDefending, vmDebugProtection, vmDomainLock 중 하나 이상에 대응됩니다. 이 세 옵션 밖의 카테고리는 없으며, 옵션이 꺼진 카테고리에 반응을 설정해도 아무런 효과가 없습니다.
키는 이 여섯 개의 카테고리 이름, 또는 default(지정되지 않은 카테고리에 대한 대체값)입니다. 값은 다음과 같습니다:
break— 즉시 중단합니다decoy— 오염된 상태로 계속 실행하며, 조용히 잘못된 결과를 만들어냅니다none— 로컬에서는 아무 동작도 하지 않습니다(텔레메트리만)
카테고리별 기본값은 위에 나와 있습니다. 설정하지 않은(또는 기본값으로 설정한) 카테고리는 그 기본값을 사용합니다. default는 올바름이 보장되는 카테고리(integrity, tamper)를 포함하여 모든 카테고리에 적용되므로, { default: 'none' }은 진정으로 코드를 중단시키지 않는 텔레메트리 전용 빌드가 됩니다:
vmDefenseReaction: { default: 'none' } // never break — pair with vmDefenseHook
vmDefenseReaction: { automation: 'none', domain: 'break' } // tolerate automation FPs, still break on a bad domain
vmStatefulOpcodes
Type: boolean Default: false
옵코드의 의미가 바이트코드 내 위치에 따라 달라지도록 만듭니다. 각 위치는 시드로부터 파생된 서로 다른 옵코드-핸들러 매핑을 가지므로, 동일한 옵코드 번호가 위치에 따라 다른 연산을 수행합니다.
vmCallContextOpcodes
Type: boolean Default: false
보호된 함수가 어디서 호출되는지에 의존하도록 만들어, 코드에서 떼어내 단독으로 실행하거나 분석할 수 없게 합니다. 함수는 프로그램 내의 실제 호출 지점을 통해 호출될 때만 올바르게 동작합니다. 이 옵션은 런타임 성능에 영향을 줍니다.
현재는 다음 구조만 지원됩니다:
- 함수 선언(
function f() {}); - 변수에 할당된 함수 표현식과 화살표 함수(
const f = () => {}); - 인스턴스 private 메서드(
this.#m()).
어느 경우든 함수는 항상 직접 호출(f(), this.#m())로 도달해야 합니다. 다른 변수에 저장되거나, 인자로 전달되거나, 그 밖의 방식으로 값으로 사용되면 보호되지 않습니다. async 함수는 지원되지만 제너레이터는 지원되지 않습니다.
이 옵션은 실험적이며 코드를 손상시킬 수 있으므로, 사용하기 전에 출력을 철저히 테스트하세요.
vmStackEncoding
Type: boolean Default: false
실행 중 VM 스택의 값을 암호화합니다. 값은 푸시될 때 인코딩되고 팝될 때 디코딩되므로, 메모리 검사에서는 실제 값 대신 암호화된 데이터가 보입니다.
이 옵션은 성능에 큰 영향을 줍니다.
vmCompactDispatcher
Type: boolean Default: false
이중 실행기(동기 + 제너레이터) 대신 단일 VM 실행기를 사용합니다. 난독화된 코드 크기를 줄이지만, 재귀가 많은 코드에서는 약 20%의 성능 오버헤드가 추가됩니다.
false(기본값): 이중 실행기 — 최적의 성능, 더 큰 출력true: 단일 실행기 — 더 작은 출력, 약간 느림
vmStringArrayBytecodeOnly
Type: boolean Default: false
이 옵션을 활성화하면 문자열 배열이 바이트코드 데이터에서 만 문자열을 추출하며, 코드의 다른 문자열은 변환되지 않습니다. 이 옵션은 stringArray가 명시적으로 설정되지 않았더라도 강제로 활성화합니다.
사용하는 이유: 모든 VM 런타임 문자열을 문자열 배열로 추출하는 것은 느립니다. 이 옵션은 바이트코드 콘텐츠만 문자열 배열 추출 대상으로 삼아, 바이트코드 상수는 그대로 보호하면서 성능을 향상시킵니다.
vmBytecodeArrayEncoding: false일 때 — 바이트코드 상수 풀(c배열) 안의 문자열이 추출됩니다vmBytecodeArrayEncoding: true일 때 — 최상위의 base64로 인코딩된 바이트코드 문자열이 추출됩니다stringArrayThreshold는 그 바이트코드 문자열 중 몇 퍼센트를 추출할지 계속 제어합니다
vmDomainLock
Type: string[] Default: []
⚠️ 이 옵션은 target: 'node', target: 'service-worker', target: 'bytenode'에서는 동작하지 않습니다
난독화된 코드를 특정 도메인 및/또는 서브도메인으로 제한하며, domainLock보다 찾아내고 제거하기가 훨씬 어렵습니다.
이 옵션에 지정된 도메인에서 소스 코드가 실행되지 않는 경우, 브라우저는 vmDomainLockRedirectUrl에 전달된 URL로 리디렉션되며, 리디렉션이 억제되더라도 이후의 보호된 호출은 잘못된 결과를 반환합니다.
여러 도메인과 서브도메인
코드를 두 개 이상의 도메인 또는 서브도메인에 잠글 수 있습니다. 예를 들어 코드가 **www.example.com**에서만 실행되도록 잠그려면 www.example.com을 추가하세요. 모든 서브도메인을 포함한 루트 도메인(example.com, sub.example.com)에서 동작하게 하려면 .example.com을 사용하세요.
vmDomainLockRedirectUrl
Type: string Default: about:blank
⚠️ 이 옵션은 target: 'node', target: 'service-worker', target: 'bytenode'에서는 동작하지 않습니다
vmDomainLock에 지정된 도메인에서 소스 코드가 실행되지 않는 경우, 브라우저를 전달된 URL로 리디렉션합니다.
Preset Options
높은 난독화, 낮은 성능
난독화하지 않은 경우보다 성능이 훨씬 느려집니다
{
compact: true,
controlFlowFlattening: true,
controlFlowFlatteningThreshold: 1,
deadCodeInjection: true,
deadCodeInjectionThreshold: 1,
debugProtection: true,
debugProtectionInterval: 4000,
disableConsoleOutput: true,
identifierNamesGenerator: 'hexadecimal',
log: false,
numbersToExpressions: true,
renameGlobals: false,
selfDefending: true,
simplify: true,
splitStrings: true,
splitStringsChunkLength: 5,
strictMode: null,
stringArray: true,
stringArrayCallsTransform: true,
stringArrayEncoding: ['rc4'],
stringArrayIndexShift: true,
stringArrayRotate: true,
stringArrayShuffle: true,
stringArrayWrappersCount: 5,
stringArrayWrappersChainedCalls: true,
stringArrayWrappersParametersMaxCount: 5,
stringArrayWrappersType: 'function',
stringArrayThreshold: 1,
transformObjectKeys: true
}
중간 난독화, 최적의 성능
난독화하지 않은 경우보다 성능이 느려집니다
{
compact: true,
controlFlowFlattening: true,
controlFlowFlatteningThreshold: 0.75,
deadCodeInjection: true,
deadCodeInjectionThreshold: 0.4,
debugProtection: false,
debugProtectionInterval: 0,
disableConsoleOutput: true,
identifierNamesGenerator: 'hexadecimal',
log: false,
numbersToExpressions: true,
renameGlobals: false,
selfDefending: true,
simplify: true,
splitStrings: true,
splitStringsChunkLength: 10,
strictMode: null,
stringArray: true,
stringArrayCallsTransform: true,
stringArrayCallsTransformThreshold: 0.75,
stringArrayEncoding: ['base64'],
stringArrayIndexShift: true,
stringArrayRotate: true,
stringArrayShuffle: true,
stringArrayWrappersCount: 2,
stringArrayWrappersChainedCalls: true,
stringArrayWrappersParametersMaxCount: 4,
stringArrayWrappersType: 'function',
stringArrayThreshold: 0.75,
transformObjectKeys: true
}
낮은 난독화, 높은 성능
성능이 비교적 정상적인 수준으로 유지됩니다
{
compact: true,
controlFlowFlattening: false,
deadCodeInjection: false,
debugProtection: false,
debugProtectionInterval: 0,
disableConsoleOutput: true,
identifierNamesGenerator: 'hexadecimal',
log: false,
numbersToExpressions: false,
renameGlobals: false,
selfDefending: true,
simplify: true,
splitStrings: false,
strictMode: null,
stringArray: true,
stringArrayCallsTransform: false,
stringArrayEncoding: [],
stringArrayIndexShift: true,
stringArrayRotate: true,
stringArrayShuffle: true,
stringArrayWrappersCount: 1,
stringArrayWrappersChainedCalls: true,
stringArrayWrappersParametersMaxCount: 2,
stringArrayWrappersType: 'variable',
stringArrayThreshold: 0.75
}
기본 프리셋, 높은 성능
{
compact: true,
controlFlowFlattening: false,
deadCodeInjection: false,
debugProtection: false,
debugProtectionInterval: 0,
disableConsoleOutput: false,
identifierNamesGenerator: 'hexadecimal',
log: false,
numbersToExpressions: false,
renameGlobals: false,
selfDefending: false,
simplify: true,
splitStrings: false,
strictMode: null,
stringArray: true,
stringArrayCallsTransform: false,
stringArrayCallsTransformThreshold: 0.5,
stringArrayEncoding: [],
stringArrayIndexShift: true,
stringArrayRotate: true,
stringArrayShuffle: true,
stringArrayWrappersCount: 1,
stringArrayWrappersChainedCalls: true,
stringArrayWrappersParametersMaxCount: 2,
stringArrayWrappersType: 'variable',
stringArrayThreshold: 0.75
}
VM Ultra High 난독화 (최고 수준의 보안)
이 프리셋은 간접 디스패치를 포함한 모든 강화 기능과 함께 VM 기반 바이트코드 난독화를 활성화합니다. 가장 강력한 보호를 제공하지만 출력 크기가 더 크고 실행 속도가 훨씬 느립니다.
{
optionsPreset: 'vm-ultra-high-obfuscation'
}
또는 개별적으로 구성할 수 있습니다:
{
compact: true,
simplify: true,
identifierNamesGenerator: 'mangled-shuffled',
vmObfuscation: true,
vmForceCompileDynamicCode: false,
vmWrapTopLevelInitializers: true,
vmDynamicOpcodes: true,
vmBytecodeEncoding: true,
vmBytecodeArrayEncoding: true,
vmBytecodeArrayEncodingKey: '',
vmBytecodeArrayEncodingKeyGetter: '',
vmAsyncExecutor: false,
vmJumpsEncoding: true,
vmMacroOps: true,
vmDebugProtection: true,
vmSelfDefending: true,
vmDefenseHook: '',
vmDefenseReaction: {
automation: 'break',
debugger: 'decoy',
sandbox: 'decoy',
domain: 'break',
tamper: 'break',
integrity: 'break'
},
vmStatefulOpcodes: true,
vmCallContextOpcodes: false,
vmStackEncoding: true,
vmCompactDispatcher: true,
controlFlowFlattening: true,
controlFlowFlatteningThreshold: 0.5,
deadCodeInjection: true,
deadCodeInjectionThreshold: 0.5,
debugProtection: true,
debugProtectionInterval: 4000,
disableConsoleOutput: true,
identifierNamesGenerator: 'hexadecimal',
log: false,
numbersToExpressions: true,
renameGlobals: false,
selfDefending: true,
simplify: true,
splitStrings: true,
splitStringsChunkLength: 5,
strictMode: null,
stringArray: true,
stringArrayCallsTransform: true,
stringArrayEncoding: ['rc4'],
stringArrayIndexShift: true,
stringArrayRotate: true,
stringArrayShuffle: true,
stringArrayWrappersCount: 5,
stringArrayWrappersChainedCalls: true,
stringArrayWrappersParametersMaxCount: 5,
stringArrayWrappersType: 'function',
stringArrayThreshold: 0.5,
transformObjectKeys: true
}
VM Anti-LLM (AI 에이전트 보호)
이 프리셋은 AI 에이전트와 LLM이 VM 바이트코드로 변환된 코드를 리버스 엔지니어링하지 못하도록 특별히 설계되었습니다. vm-default를 기반으로 자기 방어와 디버그 보호를 활성화합니다. vm-high-obfuscation보다 가볍지만 자동화된 분석에 대해 특별히 강화되어 있습니다.
{
optionsPreset: 'vm-anti-llm'
}
포함 내용:
- 문자열 배열이 적용된 VM 바이트코드 난독화(
vm-default에서) vmSelfDefending— 후킹 방지 탐지, 무결성 해시, 소스 핑거프린트, iframe 클린 렐름 검증, ARX 암호 키 파생vmDebugProtection— VM 디스패치 루프 내 디버깅 방지 검사debugProtection: false— 레거시 디버그 보호 없음(VM 디버그 보호가 더 우수함)
VM High 난독화 (최고 수준의 보안)
이 프리셋은 대부분의 강화 기능과 함께 VM 기반 바이트코드 난독화를 활성화합니다. ultra-high 프리셋보다 나은 성능으로 강력한 보호를 제공합니다.
{
optionsPreset: 'vm-high-obfuscation'
}
또는 개별적으로 구성할 수 있습니다:
{
compact: true,
simplify: true,
identifierNamesGenerator: 'mangled-shuffled',
vmObfuscation: true,
vmForceCompileDynamicCode: false,
vmWrapTopLevelInitializers: true,
vmDynamicOpcodes: true,
vmBytecodeEncoding: true,
vmBytecodeArrayEncoding: true,
vmBytecodeArrayEncodingKey: '',
vmBytecodeArrayEncodingKeyGetter: '',
vmAsyncExecutor: false,
vmJumpsEncoding: true,
vmMacroOps: true,
vmDebugProtection: true,
vmSelfDefending: true,
vmDefenseHook: '',
vmDefenseReaction: {
automation: 'break',
debugger: 'decoy',
sandbox: 'decoy',
domain: 'break',
tamper: 'break',
integrity: 'break'
},
vmStatefulOpcodes: true,
vmCallContextOpcodes: false,
vmStackEncoding: true,
vmCompactDispatcher: false
}
VM Medium 난독화 (균형 잡힌 보안)
이 프리셋은 균형 잡힌 강화 기능 세트와 함께 VM 기반 바이트코드 난독화를 활성화합니다. 보안과 성능 사이의 좋은 절충안입니다.
{
optionsPreset: 'vm-medium-obfuscation'
}
또는 개별적으로 구성할 수 있습니다:
{
compact: true,
simplify: true,
identifierNamesGenerator: 'mangled-shuffled',
vmObfuscation: true,
vmForceCompileDynamicCode: false,
vmWrapTopLevelInitializers: true,
vmDynamicOpcodes: true,
vmBytecodeEncoding: true,
vmBytecodeArrayEncoding: false,
vmBytecodeArrayEncodingKey: '',
vmBytecodeArrayEncodingKeyGetter: '',
vmAsyncExecutor: false,
vmJumpsEncoding: true,
vmMacroOps: true,
vmDebugProtection: true,
vmSelfDefending: false,
vmDefenseHook: '',
vmDefenseReaction: {
automation: 'break',
debugger: 'decoy',
sandbox: 'decoy',
domain: 'break',
tamper: 'break',
integrity: 'break'
},
vmStatefulOpcodes: false,
vmCallContextOpcodes: false,
vmStackEncoding: false,
vmCompactDispatcher: false
}
VM Low 난독화 (기본 보안, 더 나은 성능)
이 프리셋은 추가 강화 기능 없이 기본적인 VM 기반 바이트코드 난독화를 활성화합니다. 보안과 출력 크기 사이의 좋은 균형을 제공합니다.
{
optionsPreset: 'vm-low-obfuscation'
}
또는 개별적으로 구성할 수 있습니다:
{
compact: true,
simplify: true,
identifierNamesGenerator: 'mangled-shuffled',
vmObfuscation: true,
vmForceCompileDynamicCode: false,
vmWrapTopLevelInitializers: true,
vmDynamicOpcodes: false,
vmBytecodeEncoding: false,
vmBytecodeArrayEncoding: false,
vmBytecodeArrayEncodingKey: '',
vmBytecodeArrayEncodingKeyGetter: '',
vmAsyncExecutor: false,
vmJumpsEncoding: false,
vmMacroOps: false,
vmDebugProtection: false,
vmSelfDefending: false,
vmDefenseHook: '',
vmDefenseReaction: {
automation: 'break',
debugger: 'decoy',
sandbox: 'decoy',
domain: 'break',
tamper: 'break',
integrity: 'break'
},
vmStatefulOpcodes: false,
vmCallContextOpcodes: false,
vmStackEncoding: false,
vmCompactDispatcher: false
}
VM Default (VM + 문자열 배열 보호)
이 프리셋은 기본적인 VM 기반 바이트코드 난독화와 문자열 배열 보호를 결합합니다. 문자열 보호를 곁들인 VM 난독화의 좋은 출발점입니다.
{
optionsPreset: 'vm-default'
}
또는 개별적으로 구성할 수 있습니다:
{
compact: true,
simplify: true,
identifierNamesGenerator: 'mangled-shuffled',
vmObfuscation: true,
vmForceCompileDynamicCode: false,
vmWrapTopLevelInitializers: true,
vmDynamicOpcodes: true,
vmBytecodeEncoding: false,
vmBytecodeArrayEncoding: true,
vmStringArrayBytecodeOnly: true,
vmAsyncExecutor: false,
vmJumpsEncoding: false,
vmMacroOps: false,
vmDebugProtection: false,
vmSelfDefending: false,
vmDefenseHook: '',
vmDefenseReaction: {
automation: 'break',
debugger: 'decoy',
sandbox: 'decoy',
domain: 'break',
tamper: 'break',
integrity: 'break'
},
vmStatefulOpcodes: false,
vmCallContextOpcodes: false,
vmStackEncoding: false,
vmCompactDispatcher: false,
stringArray: true,
stringArrayRotate: true,
stringArrayShuffle: true,
stringArrayThreshold: 1,
stringArrayIndexShift: true,
stringArrayIndexesType: ['hexadecimal-number'],
stringArrayCallsTransform: true,
stringArrayCallsTransformThreshold: 1,
stringArrayWrappersCount: 3,
stringArrayWrappersType: 'function',
stringArrayWrappersParametersMaxCount: 5,
stringArrayWrappersChainedCalls: true,
stringArrayEncoding: ['base64'],
splitStrings: true,
splitStringsChunkLength: 6
}
