04 - Engenharia Reversa e Extração de Configurações
video: https://youtu.be/... no frontmatter da nota.Engenharia Reversa e Extração de Configurações
Nota 04 do capítulo 25, dedicada à engenharia reversa com foco em CTI, onde o objetivo não é entender todo o binário, e sim extrair o que sustenta o caso.
A extração de configuração, com C2s, identificadores de campanha e chaves, é o produto de maior valor analítico da engenharia reversa aplicada.
Dialoga com as notas 02 e 03, com o agrupamento de campanhas do capítulo 05 e com as regras YARA da nota 05.
1. Contexto e Posicionamento na Biblioteca
A engenharia reversa aplicada a CTI tem um objetivo estreito e produtivo: extrair do binário o que as camadas de triagem, estática e dinâmica não conseguiram entregar. Em quase todos os casos práticos, isso significa uma coisa, a configuração do malware, o bloco de dados decifrado em runtime que carrega endpoints de C2, identificadores de build e campanha, chaves criptográficas, endereços de carteira e parâmetros operacionais. A configuração é o elo vivo entre a amostra e a infraestrutura da campanha, e é ela que permite ao analista rastrear a operação do adversário ao longo das semanas seguintes, muito depois de o hash da amostra ter perdido valor.
O posicionamento na esteira do capítulo é o de camada mais custosa e seletiva. A triagem da nota 01 classificou, a estática da nota 02 extraiu o que o arquivo entrega parado, a dinâmica da nota 03 capturou o comportamento; a engenharia reversa entra quando o esforço adicional se paga, tipicamente em amostras evasivas, em configurações cifradas com chave derivada, e em campanhas que a organização precisa acompanhar por tempo longo. A decisão de investir é de gestão de esforço, e a seção 6 formaliza critérios para essa decisão, porque horas de reversão são sempre um custo de oportunidade frente a outras filas da equipe.
2. O Que Procurar: Funções Críticas no Binário
A reversão voltada a CTI não desmonta o binário linearmente, e sim caça funções específicas cuja presença é predizível por convenção de desenvolvimento de malware. O fluxo típico de um loader organiza o código em blocos reconhecíveis, e identificar o bloco certo reduz horas de análise. Os alvos prioritários estão listados abaixo, com a pista estática que costuma apontar para cada um.
- Rotina de decifração de configuração: identificada pela chamada a CryptDecrypt, por implementações manuais de RC4 ou AES visíveis como laços de deslocamento e XOR, ou por acesso ao bloco de dados de alta entropia visto na nota 02.
- Resolução dinâmica de APIs: identificada por LoadLibraryA e GetProcAddress em laço, que reconstrói os nomes de função escondidos da IAT e desbloqueia a leitura do restante do código.
- Rotina de comunicação com C2: identificada por strings de URIs, por chamadas a WinHTTP ou sockets, e pelo empacotamento dos dados enviados.
- Rotina de desempacotamento do payload: identificada por VirtualAlloc seguida de cópia e salto de execução, que define o tamanho do shellcode entregue.
- Derivação de chave: identificada por uso de CryptDeriveKey, MD5 ou SHA sobre valores fixos do binário, que revela de onde a chave de config nasce.
O CAPA da Mandiant automatiza parte dessa caça, mapeando o binário contra um corpus de capacidades e apontando funções candidatas a injeção, persistência e comunicação de rede. No Ghidra, o FLIRT e as assinaturas da comunidade identificam funções de biblioteca e reduzem o ruído antes do foco manual, e o script de análise automática já entrega uma árvore de funções ordenada por referências cruzadas, que é o mapa inicial da caça.
3. Fluxo de Trabalho em Ghidra e IDA
O fluxo profissional combina desmontagem estática com depuração assistida, porque a configuração frequentemente é decifrada com dados que só existem em execução. O roteiro abaixo assume Ghidra, mas transpõe diretamente para IDA Pro ou Binary Ninja, com comandos equivalentes de script.
# 1. Importar a amostra desempacotada herdada das notas anteriores
# (binario extraido do recurso RCDATA na nota 02, ou dump da nota 03)
ghidra-headless analyzeHeadless ./projeto GhidraProj -import LDR_payload.bin
# 2. Aplicar assinaturas FLIRT e rodar o CAPA sobre o binario
capa LDR_payload.bin -f json > capa_report.json
# 3. Localizar a funcao que aponta para o bloco de config (xrefs do endereco
# do bloco de alta entropia mapeado na nota 02) e renomear:
# FUN_00402a10 -> ConfigDecrypt
# 4. Definir o tipo de retorno e exportar o pseudocodigo da funcao
# (janela de decompilacao, exportar para evidencia do caso)
# 5. Executar a amostra no depurador com breakpoint na ConfigDecrypt
# x64dbg: bp no endereco da funcao, dumpar o buffer apos o retorno
A combinação decisiva é o pseudocódigo do descompilador para entender a lógica e o depurador para obter os dados reais. A depuração deve ocorrer na mesma VM da nota 03, com snapshot e isolamento, pois o payload decifrado é executável vivo. O dump do buffer retornado pela ConfigDecrypt, salto em memória ou registro em disco, é o artefato que a seção seguinte transforma na configuração legível, e esse dump deve ser registrado na ficha do caso com hash próprio, mantendo a cadeia de evidências.
4. Configuração de Malware: Anatomia e Valor Analítico
A configuração é o parâmetro de fábrica da campanha: o operador do malware preenche campos num painel ou builder, o builder cifra o bloco e o embute no build, e cada vítima recebe o mesmo bloco. Essa estrutura tem consequência analítica direta, pois a configuração sobrevive a recompilações e a mudanças de empacotador, e portanto sustenta agrupamento de campanhas e rastreamento de infraestrutura com muito mais estabilidade que strings ou hashes. Os campos típicos e seu uso analítico estão na tabela abaixo.
| Campo típico | Conteúdo | Uso em CTI |
|---|---|---|
| C2 e painel de exfiltração | URLs, IPs, portas | Infraestrutura para bloqueio, hunting de rede e monitoramento de registro de domínio |
| Campaign ID e build ID | Identificadores alfanuméricos | Agrupamento de amostras e correlação de vítimas no painel do adversário |
| Chave criptográfica | Chave RC4, AES ou XOR | Decifração de tráfego capturado e validação de config de outras amostras |
| Mutex e nome de serviço | Strings de identidade | Detecção de endpoint estável e identificação de família |
| Endereços de carteira | Carteiras de substituição | Vigilância financeira e correlação com campanhas de clippers |
| Intervalos e flags operacionais | Sleep, retry, módulos habilitados | Caracterização de versão e evolução do builder |
O valor de longo prazo vem da série temporal: o mesmo build ID com C2 diferente indica rotação de infraestrutura; o C2 idêntico em builds diferentes indica reaproveitamento de painel; a chave criptográfica constante entre campanhas indica que o operador não rotaciona material, o que permite decifrar tráfego capturado historicamente. Essas leituras são exatamente o material que o agrupamento de campanhas do capítulo 05 consome, e nenhuma outra fonte da biblioteca produz essa visão com a mesma precisão.
5. Extractors Públicos e Scripts de Automação
A extração de configuração é problema resolvido o suficiente para ter ecossistema próprio, e o analista deve consultá-lo antes de investir em reversão manual. O MWCP, da Mandiant, padroniza parsers de configuração em Python, com um contrato de campos e testes; o MACE aborda o problema por similaridade, decifrando configs de novas amostras com base em parsers existentes; e o CAPE, da nota 03, executa extractors embutidos durante a sandbox e entrega a configuração no relatório quando a família é suportada. Repositórios comunitários de decodificadores, herdeiros do legado RATDecoders, cobrem as famílias de RAT e stealer mais difundidas.
# Esqueleto de parser MWCP para o stealer ficticio do caso, rodando sobre o
# dump do bloco de config obtido na secao 3. RC4 e o algoritmo identificado
# no pseudocodigo da ConfigDecrypt, com chave fixa de 16 bytes no binario.
from mwcp.parser import Parser
from mwcp import FileObject, reporting
from cryptography.hazmat.primitives.ciphers import Arc4
class SombraStealer(Parser):
DESCRIPTION = "SombraStealer config extractor"
AUTHOR = "Equipe de CTI"
@classmethod
def identify(cls, file_object: FileObject) -> bool:
# Ancora de 8 bytes no inicio do bloco de config, vista na nota 02
return file_object.data.startswith(bytes.fromhex("c65a1b90"))
def run(self):
data = self.file_object.data
key = data[8:24]
blob = data[24:]
cipher = Arc4(key)
plaintext = cipher.decrypt(blob)
self.reporter.add_report_item("config", {
"c2_panel": plaintext[0:64].split(b"\x00")[0].decode("utf-8", "ignore"),
"campaign_id": plaintext[64:72].decode("utf-8", "ignore"),
"rc4_key": key.hex(),
})
O script ilustra o contrato básico de qualquer extractor: uma âncora de identificação estável, a decifração com a chave extraída ou embutida, e o mapeamento dos campos para uma estrutura padronizada. Quando a família não é suportada por nenhum extractor público, esse mesmo esqueleto é o destino da reversão manual, e o parser produzido entra no repositório interno ao lado das regras YARA da nota 05, formando o par de caracterização da família, regra para detectar e extractor para enriquecer.
6. Exemplo Documentado: Extração de Config do SombraStealer
O caso fictício que serve de fio condutor do capítulo fecha aqui. O payload extraído na nota 02 e detonado na nota 03 revelou, em memória, um bloco decifrado que o Procmon não explicava; a hipótese era configuração cifrada com RC4, sustentada pelo pseudocódigo da função renomeada ConfigDecrypt. O roteiro executado segue abaixo, com os achados documentados passo a passo.
# 1. Localizar o xref do bloco de alta entropia em .data (0x0043A120)
# Ghidra: References to 0x0043A120 aponta para FUN_00402a10 (ConfigDecrypt)
# 2. Pseudocodigo da ConfigDecrypt mostra: chave = bytes 8 a 24 do bloco,
# corpo decifrado com RC4, e retorno de struct com 6 campos
# 3. Dump do bloco bruto em x64dbg com breakpoint no retorno da funcao
# Bloco de 0x1F8 bytes salvo como config_dump.bin
# 4. Decifragem local do dump com a chave extraída (script da secao 5)
python3 sombra_config_parser.py config_dump.bin
# 5. Validar C2 decifrado contra o trafego capturado na nota 03
# POST /gate.php confirma o mesmo host e user-agent da config
A configuração decifrada produziu a ficha abaixo, registrada na evidência do caso com TLP:AMBER+STRICT herdado da triagem.
| Campo | Valor decifrado |
|---|---|
| Painel C2 | hxxp://203.0.113.42:8085/gate |
| Backup C2 | hxxp://198.51.100.77:8085/gate |
| Campaign ID | SOM-BRT-2026-01 |
| Build ID | SG-2.4.1 |
| Chave RC4 | c65a1b90e3f2a7d4b6c8e0f1a2b3c4d5 |
| Mutex | Global\Sombra-Mtx-0142 |
| Carteira de substituição | bc1qexample9x8v7t6r5e4w3q2p1o0n9m8l7k6j5h4 |
| Sleep | 120 segundos |
A leitura analítica da ficha demonstra o porquê do esforço. O Campaign ID SOM-BRT-2026-01 vincula a amostra à série de anexos de boleto do setor financeiro, confirmando a hipótese registrada na triagem da nota 01; o Build ID 2.4.1 permite buscar outras amostras da mesma versão em retrohunt da nota 05; e a chave RC4 decifra o tráfego capturado na nota 03, expondo o corpo das requisições de exfiltração de teste e confirmando o formato esperado pelo painel. O esforço total foi de meio dia de analista, e o retorno é a infraestrutura ativa da campanha, insumo que nenhuma camada anterior produziria.
7. Quando Vale o Esforço: Critérios de Decisão
A reversão custa dias e as filas da equipe não perdoam, então o critério de investimento precisa ser explícito e escrito. O esforço se paga quando pelo menos uma das condições abaixo é verdadeira, e a decisão deve ser registrada na ficha do caso, com o mesmo rigor da rota definida na triagem.
- A amostra é de campanha direcionada contra a organização, com expectativa de recorrência e necessidade de rastrear infraestrutura por semanas.
- A família é relevante para o setor, mas sem extractor público disponível, e o volume de amostras justifica construir o parser interno.
- A sandbox da nota 03 foi evadida de forma sustentada, e a condição de evasão só se esclarece lendo o código.
- A configuração decifrada desbloqueia outra investigação, como decifrar tráfego capturado ou vincular campanhas no agrupamento do capítulo 05.
O esforço não se paga quando a necessidade é responder a um incidente fechado com hash e bloqueios, quando um extractor público cobre a família, ou quando a curiosidade técnica é o único motor. Nessas situações, a estática e a dinâmica já entregam o IOC suficiente, e a reversão entra como dívida técnica registrada para um momento de menor pressão, e não como desvio da fila.
8. Erros Comuns e Pontos de Atenção
O erro mais custoso é entrar em reversão sem hipótese, desmontando o binário linearmente na esperança de entender tudo. A reversão voltada a CTI é caça dirigida por pistas estáticas e dinâmicas, e o analista que não anota os endereços dos blocos de alta entropia e os xrefs antes de abrir o descompilador gasta o primeiro turno apenas reencontrando o que as notas anteriores já sabiam. O erro simétrico é confiar no dump de memória sem validação: buffers decifrados em runtime podem conter lixo de execução, e a validação contra tráfego capturado ou contra segunda amostra é obrigatória antes de disseminar campos como IOC.
Completam a lista os itens abaixo.
- Reverter a amostra empacotada em vez do payload desempacotado herdado da nota 02, gastando horas contra o packer em vez de contra a lógica.
- Esquecer que o depurador executa código vivo, rodando a depuração fora da VM isolada da nota 03.
- Publicar chave de configuração e Campaign ID sem passar pelo filtro do TLP do caso, entregando ao adversário o formato que o denuncia.
- Tratar extractor público como veredito automático, sem conferir se a versão do parser cobre a versão do build analisado.
- Não versionar o parser interno produzido, perdendo o investimento quando a próxima amostra da família chegar.
- Assumir que campos vazios na config significam análise errada, quando a flag desabilitada no builder é explicação frequente.
9. Integração com o Restante da Biblioteca
A configuração extraída é o insumo de maior densidade analítica que a esteira do capítulo produz, e seu destino atravessa a biblioteca. No capítulo 05, os Campaign IDs e a rotação de C2 alimentam o agrupamento de campanhas e a análise de infraestrutura adversária; no capítulo 03, os endpoints decifrados entram no ciclo de vida de IOCs com contexto e confiança altos, pois vieram do próprio binário em vez de feeds de terceiros; e no capítulo 08, os campos de infraestrutura viram hipóteses de caça em DNS, HTTP e TLS.
Na camada de detecção e resposta, o par regra YARA da nota 05 e parser da família forma o pacote de caracterização que o PRT.5 implanta e que o capítulo 18 versiona como código. O SIM.4 recebe os campos de config como material de teste de detecção de IOCs, e a resposta a incidente do capítulo 13 consulta a ficha de configuração para saber o que buscar nos hosts afetados, do mutex à carteira de substituição. O ciclo se fecha quando a próxima variante da família chega à triagem da nota 01 e a ficha do caso anterior acelera a rota, transformando o investimento em reversão em vantagem cumulativa da equipe.