1 pontos por GN⁺ 2025-05-13 | 1 comentários | Compartilhar no WhatsApp
  • 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 ForceIntegrity em DllCharacteristics do PE; na implementação final, foi usado o Taskmgr.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.bin e 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 CreateProcessA nã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.exe falhava ao pedir ao WSC o registro de um antivírus era WscServiceUtils::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 WinDefend para 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 cmd contendo o SID WinDefend, mas embora a chamada COM retornasse STATUS_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 DllCharacteristics do PE
  • A flag em DllCharacteristics verificada por CSecurityVerificationManager::CreateExternalBaseFromPESettings era 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.exe no lugar de cmd.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 wscsvc nã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-loader usava um ctx.bin contendo parâmetros serializados para passar dados a defendnot.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.bin tomava como base a pasta padrão do módulo Taskmgr.exe, e não de nodefend.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

 
GN⁺ 2025-05-13
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 Defender e depois criar um arquivo vazio no lugar

    • Política de Grupo ainda funciona muito bem, então mantive um controlador de domínio local no homelab para alterar automaticamente apenas as políticas do Defender para todos os usuários
    • Um produto popular funcionava quase da mesma forma e acabou derrubando junto algo como 25% de toda a internet
    • É estranho o Windows não detectar esse tipo de alteração com manifestos assinados
  • Para 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 DMCA
    Talvez 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 forma

    • Pelo que entendi, ele usou a casca de outra ferramenta antivírus para contornar os requisitos de assinatura. Entendo que é uma zona cinzenta, e acho que talvez dê para argumentar que é uso transformativo, mas não sou advogado
    • Isso mesmo. Ele violou a lei de direitos autorais ao copiar partes de um programa antivírus existente
      Logo 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...

    • Alguém versado em magia de C++ consegue explicar o que está acontecendo e por que dizem que é amaldiçoado?
    • Por limitações de tempo, eu não quis implementar RAII manualmente para os objetos relacionados a COM. Ainda assim, pretendo mudar isso na próxima atualização
    • Não sei o que há de amaldiçoado nisso. A assinatura no ponto de chamada é um pouco diferente por gosto pessoal, mas uso esse padrão em várias partes do meu código
      Por exemplo, a linguagem D tem embutido na linguagem o conceito de uma instrução que é executada no fim do escopo
    • “Código é a forma como você trata seus colegas” - Michael Feather, https://x.com/mfeathers/status/1031176879577780224
      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

    • No texto está escrito: “a parte do sistema que gerencia essa bagunça é chamada de Windows Security Center, ou WSC, abreviado”
  • Por que alguém iria querer desativar o WSC?

    • Pode ser por desempenho, ou para desenvolvimento de malware ou hacking
    • Se você for um atacante, pode tentar contar com a sorte de não haver outro produto de detecção e resposta de endpoint instalado. Se houver, ele quase certamente vai interceptar
      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
    • É meu hardware, então só faço com ele o que eu quiser
    • Todo software antivírus é, no mínimo, um powervirus. Não quero me preocupar com alguém se metendo como babá para dizer que netcat.exe não pode
    • Porque não há motivo para querer instalar deliberadamente um rootkit em si mesmo
  • Li 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