Telemetria e reações das defesas da VM
Reporte as detecções das defesas da VM ao seu backend com vmDefenseHook e ajuste como cada categoria de detecção reage com vmDefenseReaction - de um build totalmente não destrutivo, apenas de telemetria, a um que quebra imediatamente em um bundle roubado.
Assistir
Obfuscator.io Defense Reactions: Break, Decoy, and the VM Defense Hook
O problema
As defesas da VM - vmSelfDefending, vmDebugProtection e vmDomainLock - agem localmente: quando um depurador, ferramenta de automação, ambiente adulterado ou domínio não autorizado é detectado, o código protegido quebra ou silenciosamente envenena seus próprios resultados. Isso detém o atacante, mas, por padrão, você nunca fica sabendo. Você não tem como saber com que frequência seu bundle está sendo sondado, qual detector disparou ou se uma defesa está quebrando para um usuário legítimo.
Duas opções fecham essa lacuna. Nenhuma delas ativa qualquer defesa - elas apenas observam e orientam as defesas que você já ativou:
vmDefenseHook- um callback global que recebe um objeto de sinal toda vez que uma defesa detecta algo. Use-o para enviar telemetria ao seu backend.vmDefenseReaction- um mapa por categoria que seleciona como uma defesa ativada reage: quebrar, decoy ou não fazer nada localmente.
As duas opções foram introduzidas na v7.1.0, mas todos os exemplos aqui usam a forma de objeto vmDefenseHook: { name }, que requer
a v7.4.0. Versões anteriores aceitavam uma string simples (vmDefenseHook: '__vmDetection'); essa forma é rejeitada a partir da v8.0.0, então
use a forma de objeto em todos os casos.
Receita 1 - reportar detecções ao seu backend
Passo 1 - registre uma função de hook global, antes que o bundle ofuscado carregue
O runtime da VM e suas defesas rodam antes do seu programa protegido, então muitas detecções disparam durante a inicialização. Defina o hook como um global simples na página host, antes da tag de script ofuscada:
Passo 2 - aponte vmDefenseHook para ela
A opção é um objeto cujo name é a função global a ser chamada (aliases é opcional - veja abaixo):
No painel, o campo VM Defense Hook aparece na seção Proteção avançada assim que pelo menos uma defesa (vmSelfDefending, vmDebugProtection ou vmDomainLock) está ativada.
Passo 3 - receba o sinal no seu backend
Toda detecção chama o hook com um único objeto signal:
source- o detector específico:headless,node,agent,agentBrowser,domain,debugger,sandbox,nativeHook,timingouintegrity. A partir da v7.4.0, os antigos detectoresenveinspectorreportam sobsource: 'debugger'.agentBrowserreporta sobcategory: 'automation'e roda em targets de navegador comvmDebugProtection(v7.9.0+).category-automation,debugger,sandbox,domain,tamperouintegrity. A origemnodereporta sobcategory: 'debugger'(v7.4.0+).score,threshold- a pontuação da detecção e o limiar que ela cruzou
Um endpoint de recebimento mínimo (mostrado com Express; qualquer backend que aceite um POST funciona). Ele normaliza o corpo para um array, então também lida com a forma em lote enviada pelo padrão de buffer abaixo:
O hook é apenas para reporte - seu valor de retorno é ignorado, e um hook ausente ou que lança
exceção é um no-op silencioso. Ele nunca pode desativar uma defesa, então um atacante que apague ou quebre seu hook
não ganha nada. Para mudar o que uma defesa faz, use vmDefenseReaction (Receita 2).
Defina o hook na página host, não dentro do código-fonte ofuscado
Para telemetria, você quer capturar cada detecção, e muitas disparam na inicialização - um hook definido dentro do bundle ofuscado é registrado tarde demais para capturar essas e, se for compilado pela VM, não pode ser alcançado até que seu programa rode. De qualquer forma, ele permanece seguro (um hook ausente vira no-op, e um hook que dispara ele próprio uma detecção não é chamado de novo recursivamente), mas, para cobertura completa, registre-o antecipadamente na página host.
A única exceção é um hook que reage apenas a uma detecção em tempo de execução - como uma limpeza quando um depurador é aberto durante o uso. Esse hook pode viver dentro do bundle ofuscado; veja a Receita 3.
Para ainda proteger sua lógica de reporte, mantenha o hook registrado como um buffer de uma linha e esvazie-o a partir do seu código ofuscado:
Renomeando os campos do sinal (aliases)
Os valores padrão de source / category são nomes descritivos, então qualquer pessoa que instrumente o callback (ou leia a saída) pode reconhecer a proteção e qual detector disparou. aliases renomeia os campos do sinal para tokens opacos de sua escolha, aplicados dentro da VM antes de o sinal ser emitido, de modo que esses nomes nunca aparecem na saída nem chegam ao callback. Seu app conhece o próprio mapeamento e encaminha os tokens ao seu backend.
Os aliases são por campo: cada um recebe uma key (o nome da propriedade que o callback recebe); os campos de nome do tipo string source e category também recebem um mapa values, enquanto score / threshold são números e recebem apenas uma key. Entradas não definidas mantêm seus nomes padrão.
No painel, a seção Aliases de sinal fica abaixo do campo VM Defense Hook.
Isto é evitar fingerprint, não sigilo - o mapeamento ainda pode ser inferido por testes repetidos, então seu único benefício é não expor nomes estáveis e autoexplicativos.
Receita 2 - ajustar as reações padrão
vmDefenseReaction configura como cada categoria de detecção reage. Ela não ativa nada - as próprias defesas são ligadas por vmSelfDefending, vmDebugProtection e vmDomainLock; esta opção apenas seleciona como uma defesa ativada reage. A categoria é a unidade de controle: todo detector de uma categoria aplica a reação daquela categoria, e uma reação definida para uma categoria cuja opção está desligada simplesmente não tem efeito.
| Categoria | Ativada por | Reage quando |
|---|---|---|
automation | vmSelfDefending ou vmDebugProtection | O código está sendo controlado por software em vez de uma pessoa: um navegador headless ou automatizado, um framework de scraping / testes ou um agente de código de IA percorrendo a página. |
debugger | vmDebugProtection ou vmSelfDefending | Alguém tem um depurador ou o inspetor de ferramentas de desenvolvedor do navegador aberto e está percorrendo o código em execução para entendê-lo. |
sandbox | vmDebugProtection | O código não está rodando em um navegador real - ele foi transportado para um ambiente JavaScript emulado ou controlado por script para ser executado e estudado offline. |
domain | vmDomainLock | O código está rodando em um site que você não autorizou: um host que não está na sua lista de permissões vmDomainLock (por exemplo, seu bundle copiado para o domínio de outra pessoa). |
tamper | vmSelfDefending | O ambiente JavaScript ao redor da VM foi modificado para observá-la ou sequestrá-la, como funções nativas do navegador substituídas por versões instrumentadas. |
integrity | vmSelfDefending | O próprio código do bundle protegido foi editado ou modificado desde que você o gerou. |
As chaves são esses seis nomes de categoria, ou default (um fallback para categorias não especificadas). Os valores são:
break- quebra imediatamentedecoy- continua rodando em estado envenenado, produzindo silenciosamente resultados errados.decoyprecisa devmDebugProtectionouvmDomainLockem um target de navegador; caso contrário, age comobreak.none- não faz nada localmente (apenas telemetria)
Uma categoria que você não define recai sobre os padrões internos:
default alcança todas as categorias, incluindo integrity e tamper, então { default: 'none' } é um build genuinamente não destrutivo, apenas de telemetria:
No painel, os seletores VM Defense Reactions aparecem na seção Proteção avançada assim que uma defesa é ativada; cada categoria só é editável enquanto uma defesa que emite seus detectores estiver ligada.
Receita 3 - execute sua própria lógica antes de uma defesa quebrar
O hook não é apenas para reporte - ele também é o único lugar confiável para executar sua própria resposta antes de uma defesa reagir. Quando um depurador é aberto em uma página em execução, você pode querer limpar o que está na tela, ou substituir a visualização por uma página 404, antes de o código quebrar.
Por que o hook em vez de código em outro lugar do seu app: break interrompe todo o bytecode subsequente, então um teardown que roda depois de uma defesa disparar - especialmente quando ele mesmo é ofuscado pela VM - é exatamente o que o break impede de executar. O hook dispara no ponto da detecção antes de a reação ser aplicada, de forma síncrona - então uma função síncrona que ele chama termina primeiro, e depois o break interrompe a VM.
Defina a resposta como seu vmDefenseHook. Como a detecção debugger dispara em tempo de execução - depois que seu programa carregou e definiu o hook - o hook pode fazer parte do seu código-fonte ofuscado e é compilado em bytecode junto com o resto do bundle. Ramifique com base em signal.category para que cada condição receba a resposta certa, mantenha o trabalho síncrono e então deixe a reação rodar:
Isto se aplica a detecções que disparam enquanto seu app está rodando - veja Quando compilar o hook em bytecode funciona abaixo.
Tenha estes pontos em mente:
- Apenas trabalho síncrono tem garantia de terminar primeiro. A reação roda na instrução logo após o hook retornar. Chamadas do tipo dispare-e-esqueça que delegam imediatamente estão ok (
navigator.sendBeacon, edições síncronas de DOM e canvas); trabalho que você agenda para depois - umsetTimeout, uma continuação de promise, umawait- não está, e qualquer coisa que precise de mais bytecode da VM não vai rodar, porque é isso que obreakinterrompe. - O hook roda antes da reação; ele não a substitui. Seu valor de retorno é ignorado, e ele não pode cancelar, atrasar ou mudar o que a reação faz. Use-o para agir antes do break, não para vetá-lo - para mudar a própria reação, use
vmDefenseReaction(Receita 2).
Quando compilar o hook em bytecode funciona
Colocar o hook dentro do bundle ofuscado dessa forma funciona apenas porque a detecção debugger dispara em tempo de execução. A VM dispara vmDefenseHook enquanto ainda está viva, depois que seu programa carregou e definiu o hook, então o hook compilado em bytecode é decodificado e executado primeiro, e depois o break. É isso que protege o próprio código-fonte do hook.
Isso não funciona para detecções que disparam na inicialização - automation, sandbox, domain ou um depurador já aberto quando a página carrega - porque nesse momento o hook compilado em bytecode ainda não está definido, então a defesa não encontra nenhuma função para chamar. Para essas, registre o hook como um global simples na página host, como na Receita 1. Na dúvida, um global simples na página host cobre toda detecção que chega ao hook; a compilação em bytecode apenas adiciona proteção para o próprio código-fonte do hook, e apenas para detecções em tempo de execução.
Da telemetria à imposição
Visibilidade e imposição não precisam ser lançadas juntas. Implante as defesas em duas etapas: primeiro um build que apenas reporta e, depois - quando a telemetria estiver limpa -, um que reage.
Passo 1 - publique um build somente de observação
Ative todas as defesas que você pretende usar, aponte vmDefenseHook para o seu endpoint e desligue todas as reações. Cada detector ainda roda e reporta cada ocorrência ao seu backend, mas nada quebra:
Passo 2 - revise os sinais coletados
Depois que o build receber tráfego real, procure detecções que o uso legítimo disparou. As duas mais comuns:
- ocorrências de
automationvindas dos seus próprios testes end-to-end ou do monitoramento de disponibilidade - construa esses artefatos sem as defesas em vez de tolerar a categoria em produção. - ocorrências de
domainvindas de um host de staging ou preview que você esqueceu de incluir na lista de permissõesvmDomainLock- adicione o host.
Prefira corrigir a causa a suavizar uma reação: cada categoria deixada em none é um detector que um atacante pode ignorar com segurança.
Passo 3 - ative as reações
Remova a sobrescrita default: 'none' para que as reações internas por categoria sejam aplicadas; essa única linha é toda a mudança. Se uma categoria continuar produzindo falsos positivos que você não consegue eliminar, deixe apenas essa categoria em none (por exemplo, vmDefenseReaction: { automation: 'none' }) e aplique o restante.
Mantenha vmDefenseHook definido depois que a imposição estiver ligada - o hook dispara independentemente da reação,
então você mantém visibilidade sobre quem está sondando seu bundle enquanto as defesas agem.
