
Um ofuscador de JavaScript baseado em técnicas de ofuscação de indistinguibilidade criptográfica.
Este projeto não alcança ofuscação de indistinguibilidade. Você não deve usar este produto para proteger segredos. Ele existe para dificultar a engenharia reversa, não para impedi-la
Um ofuscador de JavaScript projetado para tornar o código extremamente difícil de ler e analisar tanto para humanos quanto para LLMs. Escrito em TypeScript. Implementa técnicas de pesquisa criptográfica de ofuscação revisada por pares.
npm install
npm run build
# Uso básico
node dist/index.js input.js > output.js
# Com orçamento de tokens alvo (padrão: 2.000.000)
node dist/index.js --target-tokens 500000 input.js > output.js
# Ofuscação mínima (saída pequena)
node dist/index.js --target-tokens 10000 input.js > output.js
# Inchaço máximo (10M de tokens)
node dist/index.js --target-tokens 10000000 input.js > output.js
# Usando variável de ambiente
INPUT_FILE=input.js node dist/index.js > output.js
# Ajuda
node dist/index.js --help
| Opção | Padrão | Descrição |
|---|---|---|
--target-tokens <n> | 2000000 | Tamanho alvo da saída em tokens. Entradas pequenas são inchadas até esse limite. Entradas grandes produzem menos inchaço para permanecer dentro do orçamento. |
--help, -h | Exibe a mensagem de ajuda |
npm run build # Compila TypeScript para dist/
npm run start # Executa o ofuscador (lê input.js)
npm run test # Executa a suíte de testes
npm run obfuscate-package # Executa testes de compatibilidade contra pacotes npm
const { obfuscate } = require('./dist/obfuscator');
const code = 'function add(a, b) { return a + b; }';
const obfuscated = obfuscate(code);
// Com opções
const obfuscated = obfuscate(code, { targetTokens: 500000 });
O ofuscador aplica 20 transformações em 4 fases. Cada etapa se baseia na anterior.
| Ordem | Transformação | Arquivo | Descrição |
|---|---|---|---|
| 1 | Armadilhas Anti-Debug | transforms/antiDebug.ts | Injeta instruções eval("debugger") e 10-20 loops de setInterval com intervalos de números primos (5s-600s) que disparam repetidamente breakpoints de depuração. Cada instância usa strings codificadas únicas. |
| 2 | Armadilhas de Programa Perfurado | transforms/tripwires.ts | Embute verificações ocultas que comparam hashes de parâmetros com valores secretos. 5 padrões de hash (impressão digital bit a bit, aritmética modular, charCodeAt, hash numérico, typeof+length). Dispara corrupção silenciosa de estado, loops ocupados ou lança exceções em entradas secretas. [Paper 4] |
| 3 | Injeção de Ruído LPN | transforms/noiseInjection.ts | Adiciona e cancela ruído aleatório por meio de caminhos divididos em cálculos aritméticos. 6 padrões: add/sub, XOR, mul/div, divisão em variável dupla, cadeia de hash computada, rotação de bits. Valores intermediários são sem sentido sem rastrear a anulação completa. [Paper 7] |
| Ordem | Transformação | Arquivo | Descrição |
|---|---|---|---|
| 4 | Achatamento de Fluxo de Controle | transforms/controlFlowFlattening.ts | Converte corpos de funções em máquinas de estado while(true) { switch((_s * P) % M) { ... } } com despacho de aritmética modular — os valores de caso são codificados por meio de (stateId * multiplier) % modulus usando parâmetros primos aleatórios. [Paper 3] |
| 5 | Predicados Opacos | transforms/opaquePredicates.ts | Injeta condições if que sempre avaliam para verdadeiro ou falso, mas são matematicamente difíceis de provar (por exemplo, (x*x+x)%2===0). 15 fórmulas de predicado em categorias de aritmética modular, operações bit a bit e verificação de tipo. |
| 6 | Funções Proxy | transforms/proxyFunctions.ts | Roteia todas as chamadas de função por meio de dois despachantes: _fc(fn, ...args) para chamadas simples, _mc(obj, prop, ...args) para chamadas de método. Usa Function.prototype.apply capturado em uma variável local para maior resiliência. |
| 7 | Exaustão da Janela de Contexto | transforms/contextExhaustion.ts | Envolve expressões em ternários profundamente aninhados com condições opacas, cadeias de expressões void e preenchimento condicional com void. Força LLMs a desperdiçar tokens da janela de contexto com ruído. |
| 8 | Mesclagem de Expressões com Vírgula | transforms/commaExpressions.ts | Colapsa instruções de expressão consecutivas em expressões de vírgula únicas: a(); b(); return c() torna-se return a(), b(), c(). |
| Ordem | Passo | Arquivo | Descrição |
|---|---|---|---|
| 9 | Passo 1: Catalogação | passes/firstPass.ts | Percorre a AST e cataloga cada identificador, construindo um mapa de globais que atribui a cada um um nome Unicode aleatório de 6 a 16 caracteres extraído de 16 intervalos de scripts (CJK, Hangul, Grego, Cirílico, Devanágari, Tailandês, Árabe, Katakana, etc.). |
| 10 | Passo 2: Substituição | passes/secondPass.ts | Substitui todos os nomes de identificadores por seus equivalentes Unicode ofuscados. Codifica argumentos de require() como String.fromCharCode(...). Codifica fontes estáticas de import/export como literais de string com escape unicode. Substitui referências de superClass, expressões de template literal e padrões de desestruturação. |
| 11 | Passo 3: Parâmetros Fantasma | passes/thirdPass.ts | Injeta de 0 a 15 parâmetros aleatórios não utilizados em toda declaração e expressão de função. Ignora funções com parâmetros rest. Remove todos os comentários. |
| Ordem | Transformação | Arquivo | Descrição |
|---|---|---|---|
| 12 | Codificação de Variáveis Globais | transforms/globalVariableEncoding.ts | Substitui referências a globais (descobertas dinamicamente do pacote globalThis + window) por eval("Name<suffix>".replace(new RegExp("<suffix>$"), "")). Ambas as strings passam pelo array de strings. |
| 13 | Codificação de Chaves de Propriedade | transforms/propertyKeyEncoding.ts | Converte acesso por ponto em acesso computado com registros por escopo. O acesso entre escopos funciona porque todos os sufixos resolvem para o mesmo nome de propriedade em tempo de execução via .replace(). |
| 14 | Codificação de Números | transforms/numberEncoding.ts | 11 estratégias de codificação: shift+add, identidade XOR, complemento, divisão, shifts aninhados, duplo NOT, modular, etc. Cada instância é gerada de forma única. Ignora chaves de propriedade e valores de casos de switch. |
| 15 | Verificação de Integridade Própria | transforms/selfIntegrity.ts | Injeta 2-4 verificações em tempo de execução: verificação de código nativo de eval, integridade de Function.prototype.toString, detecção de anomalias de temporização, validação de estrutura de código. Respostas anti-adulteração: espera ocupada, lançamento de exceção, corrupção silenciosa. [Paper 10] |
| 16 | Extração de Array de Strings | transforms/stringArrayExtraction.ts | Coleta todas as strings em um único array com descriptografia XOR encadeada (a chave para a entrada N depende do conteúdo decodificado da entrada N-1) e padrões de erro esparsos dependentes da posição (cada caractere recebe uma chave XOR diferente, com erros esparsos inspirados em LPN em posições selecionadas). [Papers 2, 9] |
| 17 | Stubs de Console | obfuscator.ts | Descobre dinamicamente todos os métodos de console e define cada um como uma função no-op. |
| 18 | Minificação com Terser | obfuscator.ts | Remove espaços em branco/formatação via terser (, ). Recorre à remoção baseada em regex se o terser não conseguir analisar a saída. |
O código morto é injetado em vários pontos com duas estratégias de geração:
| Estratégia | Fonte | Descrição |
|---|---|---|
| Baseada em modelos | transforms/deadCodeInjection.ts | 9 tipos de modelo: acúmulo em loop, construção de arrays, manipulação de objetos, concatenação de strings, condicionais aninhadas, try/catch, contagem regressiva com while, switch computado, cadeias de operações bit a bit. Os modelos referenciam variáveis reais do escopo. |
| Baseada em mutação | transforms/deadCodeInjection.ts | Clona instruções REAIS e as muta: troca operadores dentro de grupos de equivalência, perturba constantes, renomeia identificadores. Produz código morto estruturalmente idêntico à AST que é indistinguível do código real apenas pela estrutura. [Paper 3] |
Pontos de injeção de código morto:
Várias transformações são inspiradas em pesquisa criptográfica de ofuscação revisada por pares:
| Artigo | Autores | Técnica Implementada |
|---|---|---|
| [Paper 1] On the (Im)possibility of Obfuscating Programs | Barak, Goldreich, Impagliazzo, Rudich, Sahai, Vadhan, Yang | Casos de teste de funções inofuscáveis — ferramenta de verificação que testa se segredos sobrevivem à ofuscação |
| [Paper 2] Candidate iO and Functional Encryption for all Circuits | Garg, Gentry, Halevi, Raykova, Sahai, Waters | Descriptografia encadeada de strings — randomização estilo Kilian em que a chave de cada entrada depende da string decodificada anterior |
| [Paper 3] iO from the Multilinear Subgroup Elimination Assumption | Gentry, Lewko, Sahai, Waters | Código morto baseado em mutação (estruturalmente idêntico ao código real); transições de estado com aritmética modular no CFF |
| [Paper 4] How to Use iO: Deniable Encryption, and More | Sahai, Waters | Armadilhas de programa perfurado — verificações ocultas que disparam em entradas secretas |
| [Paper 7] iO from Well-Founded Assumptions | Jain, Lin, Sahai | Injeção de ruído inspirada em LPN em cálculos numéricos |
| [Paper 9] iO from Bilinear Maps and LPN Variants | Ragavan, Vafa, Vaikuntanathan | Codificação XOR esparsa com padrões de erro dependentes da posição |
| [Paper 10] iO of Null Quantum Circuits and Applications | Bartusek, Malavolta | Teste de circuito nulo para verificação de qualidade do código morto; verificação de integridade própria (modo duplo) |
Duas ferramentas de verificação medem a qualidade da ofuscação, localizadas em src/verification/:
verification/nullCircuitTest.ts)Ofusca uma função real e uma função "nula" (mesma forma, não faz nada) e então compara 14 métricas estruturais para pontuar o quão distinguíveis elas são. Maior similaridade = melhor ofuscação.
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)7 casos de teste das provas de impossibilidade do Paper 1 que tentam extrair segredos de código ofuscado:
import { runAllTests, printSummary } from './verification/unobfuscatableTests';
console.log(printSummary(runAllTests(10000)));
Testes: função de ponto (senha), números mágicos, strings canário, chaves embutidas, URLs, padrões de regex, assinaturas de fluxo de controle.
A opção --target-tokens controla o tamanho da saída por meio de um orçamento de inchaço que escala a injeção de código morto (a principal alavanca de volume). Transformações limitadas pelo orçamento:
| Proporção do Orçamento | Transformações Ativadas |
|---|---|
| > 3 | Anti-debug, armadilhas, CFF, predicados opacos, mesclagem com vírgula |
| > 5 | Funções proxy, codificação de chaves de propriedade, injeção de ruído, integridade própria |
| > 8 | Exaustão da janela de contexto |
| > 10 | Codificação de variáveis globais |
O multiplicador de código morto escala de 1x (proporção 30) a 150x (proporção 1500+), controlando o número e o tamanho dos casos de switch mortos e dos ramos de predicados opacos.
src/
index.ts Ponto de entrada da CLI
obfuscator.ts Orquestrador principal do pipeline (20 transformações)
options.ts Sistema de orçamento e opções
types.ts Definições de tipos da AST
random.ts Geração de nomes Unicode aleatórios (6-16 caracteres, 16 intervalos de scripts)
ast.ts Funções de fábrica de nós da AST
keywords.ts Descoberta dinâmica de palavras-chave (pacote globalThis + window)
globals.ts Gerenciamento de estado global (mapas com protótipo nulo)
substitute.ts Utilitários de substituição de identificadores
declarations.d.ts Declarações de tipos de módulos
passes/
firstPass.ts Catalogação de identificadores
secondPass.ts Substituição de identificadores + codificação de strings
thirdPass.ts Injeção de parâmetros fantasma
transforms/
antiDebug.ts Armadilhas eval("debugger") + loops de setInterval
tripwires.ts Verificações de entrada secreta de programa perfurado [Paper 4]
noiseInjection.ts Ruído aritmético inspirado em LPN [Paper 7]
controlFlowFlattening.ts Despacho com while/switch + aritmética modular [Paper 3]
opaquePredicates.ts 15 predicados matemáticos sempre verdadeiros/falsos
proxyFunctions.ts Despachantes de achatamento de grafo de chamadas
contextExhaustion.ts Ruído com ternários/void para preenchimento de contexto de LLMs
commaExpressions.ts Mesclagem de instruções via operador vírgula
globalVariableEncoding.ts eval+replace para globais
propertyKeyEncoding.ts Acesso computado a propriedades com registros por escopo
numberEncoding.ts 11 estratégias de codificação bit a bit/aritmética
selfIntegrity.ts Verificações de tempo de execução anti-adulteração [Paper 10]
stringArrayExtraction.ts XOR encadeado + erros esparsos de posição [Papers 2, 9]
deadCodeInjection.ts Código morto baseado em modelos + mutação [Paper 3]
verification/
nullCircuitTest.ts Pontuação de qualidade do código morto [Paper 10]
unobfuscatableTests.ts Casos de teste de extração de segredos [Paper 1]
__tests__/ 300+ testes unitários em 21 suítes
tools/
obfuscate-package.ts Teste de compatibilidade de pacotes npm baseado em webpack
tests/
input*.js Arquivos originais de entrada de teste
# Executa todos os testes
npm test
# Executa uma suíte de testes específica
npx jest controlFlowFlattening
npx jest tripwires
npx jest noiseInjection
# Testa com pacotes npm (clona repositórios, empacota com webpack, ofusca, executa testes)
npm run obfuscate-package # Todos os 10 pacotes
npm run obfuscate-package -- minimist semver # Pacotes específicos
A ferramenta tools/obfuscate-package.ts testa o ofuscador contra pacotes npm reais:
| Caminho | Conteúdo |
|---|---|
dist/obfuscated/<package>/bundle.js | O bundle webpack ofuscado de cada pacote |
dist/obfuscated/report.json | Relatório JSON completo com tamanhos de bundle, status da ofuscação, saída dos testes |
MIT - Copyright 2026 Nicholas Starke
mangle: falsecompress: false