Um deobfuscator ConfuserEx2 com suporte para anti tamper, compressor, constants, control flow e resource recovery.
Fork aprimorado do UnconfuserEx com suporte melhorado para variantes modernas do ConfuserEx2, recuperação anti-tamper, remoção de compressor, restauração de fluxo de controle e reconstrução de recursos.
https://github.com/user-attachments/assets/de2c7fd9-6736-4f39-83c0-3c25aa9c1f24
Se você já mexeu com amostras de malware, algumas delas são ofuscadas com ConfuserEx, e eu tentei alguns deobfuscadores públicos contra a versão mais recente, mas simplesmente não funcionavam, então decidi bifurcar um público que funcionava contra essa versão mais recente e apenas modificá-lo de acordo com minhas necessidades.
Este repositório é um fork de MadMin3r/UnconfuserEx. O crédito também vai para ele. O projeto original fez a parte difícil de criar um deobfuscador focado no ConfuserEx2 que realmente conseguia remover proteções reais.
É isso que este projeto faz. Executa uma lista de removedores em uma ordem fixa, reescreve corpos de métodos/recursos/metadados onde pode e escreve um novo assembly de volta. A parte importante é a ordem. O compressor e o anti-tamper precisam acontecer cedo, porque o resto do módulo pode nem ser IL real ainda.
A versão upstream já era útil, mas alguns casos continuavam aparecendo.
Um deles era o caminho LZMA. Algumas amostras fornecem bytes que parecem a carga útil de constantes/recursos, mas as propriedades LZMA são sem sentido. Se você passar isso diretamente para o decodificador, obtém tamanhos de dicionário estúpidos e, eventualmente, exceções como dimensões de array excedendo o intervalo suportado. Então esta versão verifica as propriedades, limita o tamanho do dicionário, limita o tamanho descompactado e sai antes que o decodificador aloque algo ridículo.
LZMA properties => CE FD 62 5F 9F
Invalid LZMA properties byte 0xCE or unreasonable dictionary size
Constantes tinham outro problema idiota, mas real. Grande parte do código do resolvedor espera que o ID na frente da chamada do getter seja um ldc.i4. Às vezes não é mais uma instrução. É uma pequena expressão aritmética.
ldc.i4 0x1234
ldc.i4 0x55
xor
call string <const getter>(int32)
O fork original vê xor, chama GetLdcI4Value() e morre porque xor obviamente não é uma carga de inteiro. Esta versão retrocede sobre a pequena sequência aritmética, emula a pilha, colapsa de volta em um único ldc.i4 e então deixa o resolvedor normal continuar.
Então, ao invés de tratar isso como uma proteção de constantes totalmente diferente, vira isto:
ldc.i4 0x1261
call string <const getter>(int32)
Então o caminho existente do resolvedor de constantes normal/x86 pode fazer seu trabalho.
O fluxo de controle era onde estava mais ou menos
O removedor de switch consegue lidar com a forma normal do dispatcher switch do ConfuserEx. Ele percorre blocos, recupera o próximo alvo, exclui blocos mortos e emite um corpo de método são. Mas existem amostras onde apenas parte do método é compreendida. Se você mutar metade de um método e depois descobrir que ele ainda está ofuscado, a saída é pior que inútil porque agora você tem IL quebrado e nenhuma maneira limpa de raciocinar sobre o que aconteceu.
Então esta versão tira um snapshot do corpo do método antes de tocá-lo:
instructions
exception handlers
Se a desofuscação lançar uma exceção, ou se o método ainda parecer ofuscado depois, o corpo original é restaurado. O log ainda pode dizer "este método não foi resolvido", mas o assembly não é silenciosamente corrompido só porque um método tinha um dispatcher estranho.
O fluxo de controle de jump/trampolim também ganhou seu próprio passe. Alguns métodos não são apenas dispatchers switch. São pequenos trampolins de branch encadeados até que o bloco real seja alcançado. Esses agora são detectados e dobrados, em vez de serem ignorados pelo caminho apenas de switch.
O removedor de compressor é a parte que precisa ser executada antes de todos os outros.
Stubs de compressor do ConfuserEx geralmente mantêm o assembly real comprimido, inicializam um pequeno loader, descomprimem a carga útil e a carregam em tempo de execução.
O removedor encontra a forma do loader, extrai a carga útil incorporada, descomprime e troca o módulo pelo assembly real. Layouts de compressor normal e compacto são ambos tratados.
[+] Compressor detected
[+] Extracted compressed module payload
[+] Decompressed real module
[+] Continuing pipeline on unpacked assembly
Anti-tamper tem dois caminhos agora.
Anti-tamper normal/dinâmico descriptografa corpos de métodos de seções protegidas e escreve os corpos restaurados de volta no módulo. Anti-tamper JIT é mais irritante porque os corpos devem ser materializados quando o tempo de execução os solicita.
A forma aproximada é:
find init
extract keys
find encrypted JIT body section
derive per method key
read body
write CilBody back
Isso ainda é baseado em padrão. Se o stub mudou o suficiente, vai falhar, obviamente.
Recursos são tratados de forma semelhante às constantes: encontrar o blob de recurso criptografado, recuperar a forma da chave/descriptografador, descriptografar, descomprimir se necessário, então colocar os recursos de volta onde as ferramentas .NET normais esperam.
Há também um caminho opcional de reconstrução de PE incorporado. Algumas amostras protegidas carregam um PE gerenciado dentro de um recurso. Com a reconstrução ativada, o removedor tenta analisar e reescrever essa carga útil também, em vez de deixar um assembly externo desofuscado com um interno intocado.
UnConfuserEx.exe sample.exe sample.clean.exe --rebuild-embedded-pe
Use isso quando você souber que a amostra esconde outro assembly gerenciado dentro de recursos. Se a carga útil não for um PE gerenciado, o caminho de reconstrução deve deixá-la em paz.
Compile:
dotnet build .\UnConfuserEx.sln -c Release
Execute:
.\UnConfuserEx\bin\Release\net9.0\UnConfuserEx.exe .\protected.exe
Ou forneça um caminho de saída explícito:
.\UnConfuserEx\bin\Release\net9.0\UnConfuserEx.exe .\protected.exe .\protected.clean.exe
Se você não fornecer um caminho de saída, ele escreve um ao lado da entrada com -deobfuscated adicionado ao nome.
Para cargas úteis gerenciadas incorporadas:
.\UnConfuserEx\bin\Release\net9.0\UnConfuserEx.exe .\protected.exe .\protected.clean.exe --rebuild-embedded-pe
Esta é a lista de suporte atual. Não significa que todos os forks possíveis do ConfuserEx funcionem. Significa que essas são as formas que o pipeline sabe procurar.
Provavelmente há mais escondido no código que esqueci de listar xD.
Os logs úteis são aqueles que informam qual estágio falhou, não apenas que a saída não funcionou.
Exemplo de um caminho de constantes que foi corrigido:
Constants detected, attempting to remove
Found 3 constant getter(s)
Detected constant decryption type is Dynamic
Decompressed constants blob to 18492 byte(s)
Resolving getter <Module>::???????? as String with 41 call site method(s)
Removed all instances of getter <Module>::????????
Exemplo de um método de fluxo de controle que é intencionalmente deixado em paz:
Removing obfuscation from method System.Void Example::Run()
Method System.Void Example::Run() still appears obfuscated after deobfuscation -- left original body intact
Removed obfuscation from 42 methods. Failed to remove from 0 methods. 1 methods left untouched
Esse segundo log não é perfeito, mas pelo menos é honesto
Um fork personalizado do ConfuserEx que altera todas as formas dos helpers.
Um getter de constantes que calcula seu ID através de uma bagunça total de fluxo de controle em vez de uma pequena expressão de pilha.
Um grafo de fluxo de controle onde o dispatcher depende de valores em tempo de execução que o emulador estático não conhece.
Helpers nativos que precisam de execução real em tempo de execução em vez de emulação IL.
Assemblies que já estavam quebrados antes de serem ofuscados.
Variantes de anti-tamper JIT com um layout de corpo criptografado diferente.
Se você quer que um problema seja útil, inclua dados suficientes para reproduzi-lo.
Remova as extensões de arquivo das amostras antes de enviá-las.
Arquive tudo junto e inclua isto:
Command:
UnConfuserEx.exe <target> <optional output>
Failure stage:
- compressor
- anti tamper
- constants
- control flow
- resources
- writing output
- runtime after deobfuscation
Expected result:
Actual result:
Console output:
Archive link:
Notes / investigation:
Se tudo o que você enviar for "não funciona", a resposta provavelmente será "é, pois é".




Correções pequenas e focadas são melhores do que reescritas enormes.
Se você adicionar suporte a uma nova forma de proteção, mantenha-a isolada no removedor que a possui. Se você adicionar comportamento de fallback, garanta que a falha não corrompa o assembly de saída. Se você mexer no fluxo de controle, assuma que a amostra estranha que você corrigiu não é a única amostra estranha que existe :DDD.
Apenas NÃO torne a ferramenta mais difícil de depurar.
Este projeto é baseado em MadMin3r/UnconfuserEx.
O projeto original forneceu a base e a maior parte do pipeline central de desofuscação. Este fork foca em melhorar a confiabilidade, adicionar suporte a variantes adicionais de proteção e lidar com casos extremos observados em amostras do mundo real.
Este projeto começou como uma ferramenta prática de engenharia reversa, em vez de um exercício de engenharia de software. O foco sempre foi recuperar assemblies protegidos de forma confiável, em vez de manter uma qualidade de código perfeita.
Esta ferramenta é destinada a análise autorizada de malware, engenharia reversa, recuperação de software, interoperabilidade e pesquisa educacional.
Os usuários são responsáveis por cumprir as leis aplicáveis e obter qualquer autorização necessária antes de analisar, acessar ou processar software ou sistemas.
A Zypherion Technologies não autoriza o uso ilegal desta ferramenta e se isenta de responsabilidade por uso indevido por terceiros.
Nada neste repositório ou em www.zypherion.tech constitui aconselhamento jurídico.