
암호학적 구별 불가능성 난독화 기법을 기반으로 한 JavaScript 난독화 도구
이 프로젝트는 구별 불가능성 난독화(indistinguishability obfuscation)를 달성하지 않습니다. 이 제품을 사용하여 비밀을 보호해서는 안 됩니다. 이 도구는 리버스 엔지니어링을 방지하기 위한 것이 아니라 방해하기 위한 목적으로 존재합니다.

인간과 LLM 모두가 코드를 읽고 분석하기 매우 어렵게 만들도록 설계된 JavaScript 난독화 도구입니다. TypeScript로 작성되었으며, 동료 검토를 거친 암호학적 난독화 연구의 기법들을 구현합니다.
npm install
npm run build
# Basic usage
node dist/index.js input.js > output.js
# With target token budget (default: 2,000,000)
node dist/index.js --target-tokens 500000 input.js > output.js
# Minimal obfuscation (small output)
node dist/index.js --target-tokens 10000 input.js > output.js
# Maximum bloat (10M tokens)
node dist/index.js --target-tokens 10000000 input.js > output.js
# Using environment variable
INPUT_FILE=input.js node dist/index.js > output.js
# Help
node dist/index.js --help
| 옵션 | 기본값 | 설명 |
|---|---|---|
--target-tokens <n> | 2000000 | 토큰 단위의 대상 출력 크기. 작은 입력은 이 한도까지 부풀려집니다. 큰 입력은 예산 내에 유지되도록 덜 부풀려집니다. |
--help, -h | 도움말 메시지 표시 |
npm run build # Compile TypeScript to dist/
npm run start # Run the obfuscator (reads input.js)
npm run test # Run the test suite
npm run obfuscate-package # Run compatibility tests against npm packages
const { obfuscate } = require('./dist/obfuscator');
const code = 'function add(a, b) { return a + b; }';
const obfuscated = obfuscate(code);
// With options
const obfuscated = obfuscate(code, { targetTokens: 500000 });
난독화 도구는 4개 단계에 걸쳐 20개의 변환을 적용합니다. 각 단계는 이전 단계를 기반으로 합니다.
데드 코드는 두 가지 생성 전략으로 여러 지점에 주입됩니다:
| 전략 | 소스 | 설명 |
|---|---|---|
| 템플릿 기반 | transforms/deadCodeInjection.ts | 9가지 템플릿 유형: 루프 누적, 배열 구축, 객체 조작, 문자열 연결, 중첩 조건문, try/catch, while 카운트다운, switch 계산, 비트 연산 체인. 템플릿은 실제 스코프 변수를 참조합니다. |
데드 코드 주입 지점:
여러 변환은 동료 검토를 거친 암호학적 난독화 연구에서 영감을 받았습니다:
두 가지 검증 도구가 난독화 품질을 측정하며, src/verification/에 있습니다:
verification/nullCircuitTest.ts)실제 함수와 "null" 함수(동일한 형태, 아무것도 하지 않음)를 난독화한 다음 14가지 구조적 지표를 비교하여 얼마나 구별 가능한지 점수를 매깁니다. 유사도가 높을수록 난독화 품질이 좋습니다.
import { runNullCircuitTest } from './verification/nullCircuitTest';
const result = runNullCircuitTest(realCode, paramCount, stmtCount, threshold, targetTokens);
console.log('Similarity:', result.similarity); // 0.0-1.0
verification/unobfuscatableTests.ts)Paper 1의 불가능성 증명에서 가져온 7가지 테스트 케이스로, 난독화된 코드에서 비밀을 추출하려 시도합니다:
import { runAllTests, printSummary } from './verification/unobfuscatableTests';
console.log(printSummary(runAllTests(10000)));
테스트 항목: 포인트 함수(비밀번호), 매직 넘버, 카나리 문자열, 내장 키, URL, 정규식 패턴, 제어 흐름 서명.
--target-tokens 옵션은 데드 코드 주입(주요 볼륨 조절 수단)을 조정하는 팽창 예산을 통해 출력 크기를 제어합니다. 예산에 따라 활성화되는 변환:
| 예산 비율 | 활성화되는 변환 |
|---|---|
| > 3 | 안티 디버그, 트립와이어, CFF, 불투명 술어, 쉼표 병합 |
| > 5 | 프록시 함수, 속성 키 인코딩, 노이즈 주입, 자체 무결성 |
| > 8 | 컨텍스트 창 소진 |
| > 10 | 전역 변수 인코딩 |
데드 코드 배율은 1배(비율 30)에서 150배(비율 1500+)까지 확장되며, 데드 switch case와 불투명 술어 분기의 수와 크기를 제어합니다.
src/
index.ts CLI entry point
obfuscator.ts Main pipeline orchestrator (20 transforms)
options.ts Budget system and options
types.ts AST type definitions
random.ts Random Unicode name generation (6-16 chars, 16 script ranges)
ast.ts AST node factory functions
keywords.ts Dynamic keyword discovery (globalThis + window package)
globals.ts Global state management (null-prototype maps)
substitute.ts Identifier substitution utilities
declarations.d.ts Module type declarations
passes/
firstPass.ts Identifier cataloging
secondPass.ts Identifier substitution + string encoding
thirdPass.ts Dummy parameter injection
transforms/
antiDebug.ts eval("debugger") traps + setInterval loops
tripwires.ts Punctured program secret-input checks [Paper 4]
noiseInjection.ts LPN-inspired arithmetic noise [Paper 7]
controlFlowFlattening.ts while/switch + modular arithmetic dispatch [Paper 3]
opaquePredicates.ts 15 always-true/false math predicates
proxyFunctions.ts Call graph flattening dispatchers
contextExhaustion.ts Ternary/void noise for LLM context filling
commaExpressions.ts Statement merging via comma operator
globalVariableEncoding.ts eval+replace for globals
propertyKeyEncoding.ts Computed property access with per-scope registries
numberEncoding.ts 11 bitwise/arithmetic encoding strategies
selfIntegrity.ts Anti-tamper runtime checks [Paper 10]
stringArrayExtraction.ts Chained XOR + sparse position errors [Papers 2, 9]
deadCodeInjection.ts Template + mutation-based dead code [Paper 3]
verification/
nullCircuitTest.ts Dead code quality scoring [Paper 10]
unobfuscatableTests.ts Secret extraction test cases [Paper 1]
__tests__/ 300+ unit tests across 21 suites
tools/
obfuscate-package.ts Webpack-based npm package compatibility testing
tests/
input*.js Original test input files
# Run all tests
npm test
# Run a specific test suite
npx jest controlFlowFlattening
npx jest tripwires
npx jest noiseInjection
# Test against npm packages (clones repos, webpack-bundles, obfuscates, runs tests)
npm run obfuscate-package # All 10 packages
npm run obfuscate-package -- minimist semver # Specific packages
tools/obfuscate-package.ts 도구는 실제 npm 패키지를 대상으로 난독화 도구를 테스트합니다:
| 경로 | 내용 |
|---|---|
dist/obfuscated/<package>/bundle.js | 각 패키지의 난독화된 webpack 번들 |
dist/obfuscated/report.json | 번들 크기, 난독화 상태, 테스트 출력이 포함된 전체 JSON 보고서 |
MIT - Copyright 2026 Nicholas Starke
| 순서 | 변환 | 파일 | 설명 |
|---|
| 1 | 안티 디버그 트랩 | transforms/antiDebug.ts | eval("debugger") 문과 소수 간격(5초setInterval 루프 10 |
| 2 | 펑처드 프로그램 트립와이어 | transforms/tripwires.ts | 매개변수 해시를 비밀 값과 비교하는 숨겨진 검사를 내장합니다. 5가지 해시 패턴(비트별 핑거프린트, 모듈러 연산, charCodeAt, 숫자 해시, typeof+length). 비밀 입력 시 조용한 상태 손상, 바쁜 루프, 또는 예외를 트리거합니다. [논문 4] |
| 3 | LPN 노이즈 주입 | transforms/noiseInjection.ts | 산술 계산의 분할 경로를 통해 무작위 노이즈를 추가하고 상쇄합니다. 6가지 패턴: 덧셈/뺄셈, XOR, 곱셈/나눗셈, 분할 이중 변수, 계산된 해시 체인, 비트 회전. 전체 상쇄를 추적하지 않으면 중간 값은 의미가 없습니다. [논문 7] |
| 순서 | 변환 | 파일 | 설명 |
|---|
| 4 | 제어 흐름 평탄화 | transforms/controlFlowFlattening.ts | 함수 본문을 while(true) { switch((_s * P) % M) { ... } } 상태 머신으로 변환하며, 모듈러 연산 디스패치를 사용합니다. case 값은 무작위 소수 매개변수를 사용하여 (stateId * multiplier) % modulus로 인코딩됩니다. [논문 3] |
| 5 | 불투명 술어 | transforms/opaquePredicates.ts | 항상 true 또는 false로 평가되지만 수학적으로 증명하기 어려운 if 조건을 주입합니다(예: (x*x+x)%2===0). 모듈러 연산, 비트 연산, 타입 검사 범주에 걸친 15가지 술어 공식. |
| 6 | 프록시 함수 | transforms/proxyFunctions.ts | 모든 함수 호출을 두 개의 디스패처를 통해 라우팅합니다: 단순 호출은 _fc(fn, ...args), 메서드 호출은 _mc(obj, prop, ...args). 복원력을 위해 지역 변수에 캡처된 Function.prototype.apply를 사용합니다. |
| 7 | 컨텍스트 창 소진 | transforms/contextExhaustion.ts | 표현식을 불투명 조건을 가진 깊게 중첩된 삼항 연산자, void 표현식 체인, 조건부 void 패딩으로 감쌉니다. LLM이 컨텍스트 창 토큰을 노이즈에 낭비하도록 강제합니다. |
| 8 | 쉼표 표현식 병합 | transforms/commaExpressions.ts | 연속된 표현식 문을 단일 쉼표 표현식으로 축소합니다: a(); b(); return c()는 return a(), b(), c()가 됩니다. |
| 순서 | 패스 | 파일 | 설명 |
|---|
| 9 | 패스 1: 카탈로그 | passes/firstPass.ts | AST를 순회하며 모든 식별자를 카탈로그화하고, 각 식별자에 16개 문자 체계 범위(CJK, 한글, 그리스어, 키릴 문자, 데바나가리, 태국어, 아랍어, 가타카나 등)에서 추출한 무작위 6~16자 유니코드 이름을 할당하는 전역 맵을 구축합니다. |
| 10 | 패스 2: 치환 | passes/secondPass.ts | 모든 식별자 이름을 난독화된 유니코드 등가물로 대체합니다. require() 인수를 String.fromCharCode(...)로 인코딩합니다. 정적 import/export 소스를 유니코드 이스케이프 문자열 리터럴로 인코딩합니다. 클래스 superClass 참조, 템플릿 리터럴 표현식, 구조 분해 패턴을 치환합니다. |
| 11 | 패스 3: 더미 매개변수 | passes/thirdPass.ts | 모든 함수 선언과 표현식에 0~15개의 무작위 미사용 매개변수를 주입합니다. 나머지(rest) 매개변수가 있는 함수는 건너뜁니다. 모든 주석을 제거합니다. |
| 순서 | 변환 | 파일 | 설명 |
|---|
| 12 | 전역 변수 인코딩 | transforms/globalVariableEncoding.ts | 전역(globalThis + window 패키지에서 동적으로 발견)에 대한 참조를 eval("Name<suffix>".replace(new RegExp("<suffix>$"), ""))로 대체합니다. 두 문자열 모두 문자열 배열을 통과합니다. |
| 13 | 속성 키 인코딩 | transforms/propertyKeyEncoding.ts | 점 접근을 범위별 레지스트리를 사용하는 계산된 접근으로 변환합니다. 모든 접미사가 런타임에 .replace()를 통해 동일한 속성 이름으로 해석되므로 범위 간 접근이 작동합니다. |
| 14 | 숫자 인코딩 | transforms/numberEncoding.ts | 11가지 인코딩 전략: 시프트+덧셈, XOR 항등, 보수, 나눗셈, 중첩 시프트, 이중 NOT, 모듈러 등. 각 인스턴스는 고유하게 생성됩니다. 속성 키와 switch case 값은 건너뜁니다. |
| 15 | 자체 무결성 검증 | transforms/selfIntegrity.ts | 런타임 검사 2~4개를 주입합니다: eval 네이티브 코드 검증, Function.prototype.toString 무결성, 타이밍 이상 탐지, 코드 구조 검증. 변조 방지 응답: 바쁜 대기, 예외 발생, 조용한 손상. [논문 10] |
| 16 | 문자열 배열 추출 | transforms/stringArrayExtraction.ts | 모든 문자열을 연쇄 XOR 복호화(항목 N의 키는 항목 N-1의 디코딩된 내용에 의존)와 희소 위치 의존 오류 패턴(각 문자는 서로 다른 XOR 키를 가지며, 선택된 위치에 LPN에서 영감을 받은 희소 오류가 있음)을 사용하는 단일 배열로 수집합니다. [논문 2, 9] |
| 17 | 콘솔 스텁 | obfuscator.ts | 모든 console 메서드를 동적으로 발견하여 각각을 no-op 함수로 설정합니다. |
| 18 | Terser 축소화 | obfuscator.ts | terser를 통해 공백/서식을 제거합니다(mangle: false, compress: false). terser가 출력을 파싱할 수 없는 경우 정규식 기반 제거로 폴백합니다. |
| 변이 기반 | transforms/deadCodeInjection.ts | 실제 문(statement)을 복제하고 변이시킵니다: 동치 그룹 내에서 연산자를 교체하고, 상수를 교란하며, 식별자 이름을 변경합니다. 구조만으로는 실제 코드와 구별할 수 없는 AST 구조적으로 동일한 데드 코드를 생성합니다. [논문 3] |
| 논문 | 저자 | 구현된 기법 |
|---|
| [논문 1] On the (Im)possibility of Obfuscating Programs | Barak, Goldreich, Impagliazzo, Rudich, Sahai, Vadhan, Yang | 난독화 불가 함수 테스트 케이스 — 비밀이 난독화 후에도 유지되는지 테스트하는 검증 도구 |
| [논문 2] Candidate iO and Functional Encryption for all Circuits | Garg, Gentry, Halevi, Raykova, Sahai, Waters | 연쇄 문자열 복호화 — 각 항목의 키가 이전에 디코딩된 문자열에 의존하는 Kilian 스타일 무작위화 |
| [논문 3] iO from the Multilinear Subgroup Elimination Assumption | Gentry, Lewko, Sahai, Waters | 변이 기반 데드 코드 (실제 코드와 구조적으로 동일); CFF의 모듈러 연산 상태 전이 |
| [논문 4] How to Use iO: Deniable Encryption, and More | Sahai, Waters | 펑처드 프로그램 트립와이어 — 비밀 입력 시 트리거되는 숨겨진 검사 |
| [논문 7] iO from Well-Founded Assumptions | Jain, Lin, Sahai | 숫자 계산의 LPN 기반 노이즈 주입 |
| [논문 9] iO from Bilinear Maps and LPN Variants | Ragavan, Vafa, Vaikuntanathan | 위치 의존 오류 패턴을 가진 희소 XOR 인코딩 |
| [논문 10] iO of Null Quantum Circuits and Applications | Bartusek, Malavolta | 데드 코드 품질 검증을 위한 널 회로 테스트; 자체 무결성 검증 (이중 모드) |