Como estraguei minhas férias fazendo engenharia reversa do WSC
(blog.es3n1n.eu)- O defendnot, criado durante uma viagem a Seul, era uma ferramenta para desativar o Windows Defender chamando diretamente a API do serviço Windows Security Center (WSC), e acabou levando a vários dias de engenharia reversa
- A ferramenta anterior, no-defender, registrava no WSC a presença de outro antivírus usando código de antivírus já existente; depois de alcançar cerca de 1,5 mil estrelas no GitHub, foi removida após um pedido de DMCA da empresa de antivírus
- No início, a chamada da API COM do WSC foi reproduzida em cerca de 1 hora, mas o WSC validava o processo chamador, então o acesso era negado em processos comuns
- A análise mostrou que o WSC verificava o SID do WinDefend, privilégios de administrador, assinatura e a flag
ForceIntegrityemDllCharacteristicsdo PE; na implementação final, foi usado oTaskmgr.exe - A implementação foi concluída em um ambiente envolvendo um MacBook arm64, um PC remoto nos EUA, latência de 210 ms no Parsec e até uma VM da Shadow.tech, corrigindo um erro de caminho do
ctx.bine um problema nas condições de energia do autorun
Contexto de como o defendnot surgiu
- defendnot é uma ferramenta que desativa o Windows Defender usando diretamente a API do serviço Windows Security Center
- O ponto central da implementação não foi tanto a chamada ao WSC em si, mas contornar uma a uma as condições de validação e o ambiente de trabalho inconveniente que bloqueavam isso
- Uma documentação técnica mais detalhada do WSC deverá ser publicada depois por outra pessoa
O no-defender de um ano atrás e o DMCA
- Cerca de um ano atrás, o no-defender, publicado anteriormente, usava a API do Windows para antivírus para desligar o Windows Defender
- Essa API servia para informar ao sistema que “há outro antivírus no sistema, então não é necessário executar verificações do Defender”
- O componente do sistema que gerencia essa área é o Windows Security Center (WSC)
- O no-defender funcionava forçando o registro desse antivírus no WSC por meio de código de terceiros de um antivírus existente
- Poucas semanas após a publicação, ele alcançou cerca de 1,5 mil stars, e quando a empresa do antivírus usado enviou um pedido de takedown por DMCA, o conteúdo do repositório foi apagado e o assunto foi encerrado
A análise do WSC recomeça durante uma viagem a Seul
- Enquanto estava hospedado em um Airbnb em Seul, MrBruh examinou o no-defender e enviou uma mensagem dizendo que estava investigando se seria possível fazer uma implementação “limpa”, sem binários de antivírus
- Normalmente eu levo um notebook x86 separado para tarefas como CTF ou reversing em x86, mas nessa viagem eu estava apenas com um MacBook M4Pro
- Mesmo em condições desfavoráveis, sem equipamento adequado para reversing em x86, comecei a analisar o WSC usando o tempo antes de meus amigos acordarem
Dia 1: reprodução da API COM do WSC e primeira negação de acesso
- MrBruh forneceu os binários mais recentes do WSC, e a implementação de registro no WSC do antivírus usado anteriormente serviu como referência
- O WSC tem uma API COM usada por antivírus, e reproduzi em cerca de 1 hora as chamadas que o antivírus existente fazia
- Testei inicializando o Windows arm64 no Parallels, mas o resultado foi access denied
- Pela experiência anterior, eu já sabia que o WSC valida o processo que faz a chamada à API, e inicialmente suspeitei que fosse uma verificação de assinatura
- Quando injetei código no processo que o antivírus existente usava para tarefas do WSC, as chamadas COM para registrar um novo antivírus e atualizar o estado passaram a funcionar normalmente
Tentativa de remover os binários de antivírus
- Para evitar que o novo projeto recebesse outra contestação da empresa de antivírus, tentei usar binários fornecidos pelo sistema em vez de binários de antivírus
- O primeiro processo escolhido foi
cmd.exe, mas as chamadas à API do WSC foram rejeitadas - Ao examinar
wscsvc.dll, havia código verificando se o processo chamador era PPL - Um processo criado com um simples
CreateProcessAnão era um processo protegido por PPL, e naquela madrugada não consegui avançar mais
Dia 2: montagem de um ambiente de depuração remota desconfortável
- No MacBook arm64 era difícil lidar adequadamente com Windows x86, e eu queria evitar trabalhar em arm64 ou ficar sem poder usar o x64dbg
- O amigo pindos liberou acesso ao PC dele, e usei Parsec para conexão remota
- Como eu estava acessando, da Coreia, um PC nos EUA, a latência média era de cerca de 210 ms
- Na época, o fluxo de trabalho era extremamente incômodo
- Compilar o módulo com MSVC no Windows arm64 do Parallels
- Compartilhar os artefatos de build entre hóspede e host por uma pasta compartilhada
- Copiar os artefatos para a VM no PC do pindos via AnyDesk
- Depurar o serviço WSC em um ambiente com 210 ms de latência no Parsec
- O ambiente era tão inconveniente que reduzia bastante a velocidade de desenvolvimento e análise
Depuração do serviço WSC e o SID do WinDefend
- O serviço WSC é uma DLL executada pelo
svchost, e o principal fator que impedia a conexão do depurador era a proteção PPL - Na VM, ativei o modo de teste e usei um driver que removia o PPL do processo-alvo com algumas linhas de código em modo kernel
- O ponto em que
cmd.exefalhava ao pedir ao WSC o registro de um antivírus eraWscServiceUtils::CreateExternalBaseFromCaller - Essa função se passa pelo cliente RPC e depois verifica se o token do processo chamador contém o SID
WinDefend - Como eu ainda não entendia bem o funcionamento dos tokens do Windows, concluí que bastaria se passar por
WinDefendpara passar na checagem - Com privação de sono, também interpretei de forma errada que o binário do antivírus existente passava por essa verificação
IsMember
Tentativa de se passar por WinDefend e fracasso
- Depois de estudar tokens do Windows por algumas horas, implementei a ideia de executar com um token que incluísse o SID do WinDefend para passar na checagem do WSC
- Executei o código com o
cmdcontendo o SIDWinDefend, mas embora a chamada COM retornasseSTATUS_SUCCESS, o registro efetivo do novo antivírus não acontecia - No fim, essa abordagem não foi útil, e seria preciso validar tudo de novo no dia seguinte
Dia 3: reconstrução do algoritmo real de validação
- Ao verificar novamente, percebi que o binário do antivírus existente não passava pela checagem do SID do WinDefend
- Passar por essa checagem fazia com que o objeto WSC do Windows Defender fosse manipulado, mas não permitia desativar o Defender diretamente apenas com chamadas ao WSC, então isso não servia
- Removi o código de impersonação de WinDefend e analisei o outro ramo da condicional
- Nesse ramo, o binário chamador era verificado quanto a:
- se o processo estava em estado elevated
- se a assinatura do binário era válida
- se havia uma determinada flag em
DllCharacteristicsdo PE
- A flag em
DllCharacteristicsverificada porCSecurityVerificationManager::CreateExternalBaseFromPESettingsera ForceIntegrity - Criei no repositório do defendnot, na pasta
wsc-binary-check, um código que reproduzia a verificação de binários feita pelo WSC e o testei com binários do System32
Uso do Taskmgr.exe e o bug do ctx.bin
- Como o amigo precisava usar o PC novamente, passei a acessar a VM diretamente pelo Parsec, mas com codificação por software o ambiente ficou ainda mais lento
- Usei
Taskmgr.exeno lugar decmd.exe, mas ainda assim ocorria um erro de RPC - Por causa da latência e dos problemas de entrada, ficou difícil depurar na mesma VM, e por recomendação assinei o shadow.tech, pagando US$ 30
- A VM da Shadow.tech tinha uma versão do Windows mais antiga, em que o código do
wscsvcnão estava tão inlined em uma única função como na versão mais recente, e o resultado da descompilação também era mais legível - A causa real do erro era que o nome do AV enviado ao WSC estava incorreto
defendnot-loaderusava umctx.bincontendo parâmetros serializados para passar dados adefendnot.dll- Havia um IPC separado para rastreamento de estado, mas a passagem de configuração ainda mantinha o método com
ctx.bin, resquício do antigo código do no-defender - A função que procurava o caminho de
ctx.bintomava como base a pasta padrão do móduloTaskmgr.exe, e não denodefend.dll - Como resultado, um byte nulo era passado como nome do AV, e o WSC rejeitava esse buffer
- Depois de corrigir o problema de caminho, o teste funcionou
Limpeza de código e problema com autorun
- Para terminar no mesmo dia, fui até as 8 da manhã limpando o código e implementando funções adicionais
- Entre essas funções extras estava a capacidade de se adicionar ao autorun
- Às 8 da manhã, apenas o autorun ainda não funcionava corretamente; testei vários métodos sem sucesso e depois fui dormir
- No dia seguinte, ao verificar novamente, descobri que a causa eram duas caixas de seleção relacionadas à energia ao criar a tarefa no Agendador de Tarefas
- Como o notebook não estava conectado à energia AC, a tarefa não era executada, e ao desativar essas flags o autorun passou a funcionar
- Depois disso, passei mais algumas horas organizando o código e concluí o trabalho
Encerramento
- O trabalho em si foi divertido, mas os problemas de ambiente e o fluxo repetitivo de depuração remota ao longo de vários dias foram uma experiência que eu não gostaria de repetir
- Em especial, o MacBook arm64, a VM x86 remota, a alta latência, a codificação lenta e o bug de caminho de arquivo que só apareceu mais tarde elevaram bastante a dificuldade de implementação
- Uma documentação mais técnica sobre o WSC deverá ser publicada separadamente depois
1 comentários
Comentários do Hacker News
O método mais invasivo, mas eficaz, que encontrei para desativar o Defender foi inicializar por um USB Linux live, renomear
C:\ProgramData\Microsoft\Windows Defendere depois criar um arquivo vazio no lugarPara referência, WSC é a sigla de Windows Security Center
Fiquei bem confuso com a expressão
the antivirus I was using. Não entendi por que a empresa do antivírus teria motivo para enviar ao autor uma solicitação de remoção por DMCATalvez queira dizer que o autor fez engenharia reversa de outro antivírus e colocou parte dele em um projeto open source. Mas também aparece um título como
Impersonating WinDefend, então fico curioso se, no fim das contas, o autor violou a lei de direitos autorais de alguma formaLogo antes do parágrafo citado há uma explicação dizendo que “o projeto usou código de terceiros de um antivírus já existente e forçou esse antivírus a se registrar no WSC como antivírus”
Esse código parece amaldiçoado:
https://github.com/es3n1n/defendnot/blob/master/defendnot-lo...
Se quiser saber o que realmente está acontecendo, é aqui:
https://github.com/es3n1n/defendnot/blob/master/cxx-shared/s...
Por exemplo, a linguagem D tem embutido na linguagem o conceito de uma instrução que é executada no fim do escopo
Em resumo, não foi escrito por IA. Esse código adia uma chamada de função até o momento em que o objeto sai de escopo. A implementação cria, com macros C, uma sintaxe mais curta que omite parte da definição necessária de lambdas/funções anônimas em C e gera um nome de variável único para gerenciar a chamada adiada
Só que a sintaxe resultante evita a convenção comum de usar maiúsculas para indicar macros C e, à primeira vista, parece uma chamada de função em um ponteiro de objeto. Se você não estiver acostumado a esse padrão, ou espera que macros apareçam de outro jeito, pode ser confuso
Para algumas pessoas, isso é comum e útil o bastante para ser visto quase como um idiom em certos contextos. A explicação técnica em https://news.ycombinator.com/item?id=43959403#43960905 destrincha bem o funcionamento da macro
Fiz engenharia reversa dos desktops virtuais do Windows durante as férias, e isso tornou minhas férias muito melhores. Minha melhor lembrança do ano passado foi perceber que engenharia reversa é muito divertida
Também aprendi muita coisa interessante; há uma camada de mensagens não documentada por baixo do RPC do Windows: https://csandker.io/2022/05/24/Offensive-Windows-IPC-3-ALPC....
Sempre descubro que, se a foto de perfil é de personagem de anime, o texto vai ser bom. Salvei para quando eu tiver de voltar a um ambiente Windows ruim no futuro
Para quem ficou curioso: WSC é a sigla de Windows Security Center. Eu também tive que procurar
Por que alguém iria querer desativar o WSC?
Se você for um fornecedor de EDR, isso é uma chamada de API ofuscada que pode ser usada para suprimir ou desativar o Windows Firewall. Por exemplo, imagino que a CrowdStrike possa tanto usar o Windows Firewall quanto uma implementação própria
netcat.exenão podeLi recentemente https://nostarch.com/windows-security-internals, e este texto ficou muito mais interessante por causa disso
Eu já tinha uma noção de como esse tipo de funcionamento nos bastidores do Windows ocorre, mas o timing foi ótimo. O último capítulo desse livro também se aprofunda bastante em tokens e SIDs, como o autor deste texto abordou