Skip to content
KitploitKITPLOIT
FerramentasExploitsBlog
Log in
Enviar
FerramentasExploitsBlog
Enviar

Ferramentas de Hacking, PenTest e Cibersegurança para o seu Arsenal de Segurança!

Kitploit é um diretório de ferramentas de hacking, cibersegurança e pentesting. Descubra as últimas atualizações de projetos para encontrar vulnerabilidades, analisar sistemas, automatizar testes e fortalecer sua segurança.

··Feeds·Contato·Privacidade·© 2026 Kitploit

Diretório de Ferramentas

Categorias

Ver todas as categorias
Loading categories
DeathSleep — Uma implementação de PoC para uma técnica de evasão que encerra a thread atual e a restaura antes de retomar a execução, enquanto implementa alterações de proteção de página durante a não execução. | Kitploit
Ferramentas/GitHubGitHub/janoglezcampos/deathsleep
ExploraçãoAnálise de MalwareRed TeamingDesenvolvimento de Payloads
GitHubjanoglezcampos/deathsleep

DeathSleep

Uma implementação de PoC para uma técnica de evasão que encerra a thread atual e a restaura antes de retomar a execução, enquanto implementa alterações de proteção de página durante a não execução.

Ver Repositório
538778há 4 anosRevisado pelo Kitploit

Mais Populares

Ver todos →

Descubra as ferramentas mais usadas pela nossa comunidade.

Explore todas as ferramentas

Navegue pela nossa coleção de ferramentas

Ver todas as ferramentas →
Compartilhar

██████╗ ███████╗ █████╗ ████████╗██╗ ██╗███████╗██╗ ███████╗███████╗██████╗ ██╔══██╗██╔════╝██╔══██╗╚══██╔══╝██║ ██║██╔════╝██║ ██╔════╝██╔════╝██╔══██╗ ██║ ██║█████╗ ███████║ ██║ ███████║███████╗██║ █████╗ █████╗ ██████╔╝ ██║ ██║██╔══╝ ██╔══██║ ██║ ██╔══██║╚════██║██║ ██╔══╝ ██╔══╝ ██╔═══╝ ██████╔╝███████╗██║ ██║ ██║ ██║ ██║███████║███████╗███████╗███████╗██║
╚═════╝ ╚══════╝╚═╝ ╚═╝ ╚═╝ ╚═╝ ╚═╝╚══════╝╚══════╝╚══════╝╚══════╝╚═╝

Uma implementação PoC para uma técnica de evasão que termina a thread atual e a restaura antes de retomar a execução, enquanto implementa alterações de proteção de página durante a não execução.

Introdução

Métodos de suspensão e ofuscação são bem conhecidos na comunidade de maldev, com diferentes implementações. Eles têm o objetivo de se esconder de scanners de memória durante a suspensão, geralmente alterando proteções de página e até adicionando recursos interessantes como criptografar o shellcode, mas há outro ponto importante para esconder nosso shellcode: esconder a thread de execução atual. Spoofing da pilha é legal, mas depois de pensar um pouco sobre isso, pensei que não há necessidade de fazer spoofing da pilha... se não houver pilha :)

A usabilidade desta técnica fica a critério do leitor, mas de qualquer forma, acho que é uma maneira legal de revisar alguns tópicos e aprender um pouco de maldev para quem, como eu, está começando neste mundo.

A implementação principal mostrada aqui contém tudo que precisamos retirar da pilha na seção de dados, como variáveis globais, mas uma implementação movendo tudo para o heap será publicada em breve. Ela visa mostrar algumas modificações-chave que precisam ser feitas para tornar este código pic e injetável.

Este repositório espelhado entre GitHub e GitLab.


O que está acontecendo?

Primeiramente

Tudo o que foi declarado aqui vem do meu entendimento dos diferentes tópicos abordados, seja por leitura ou por experiência durante o desenvolvimento. Estou ciente de que não sou um especialista e a última coisa que quero é espalhar desinformação, então se você acha que algo não está correto, adoraria que você me avisasse, pode me contatar no twitter ou abrir issues neste repositório. Muito obrigado pela sua compreensão. :)

Fundamentos

O objetivo principal desta técnica é claro: encerrar a thread atual e restaurá-la antes de retomar a execução, mas o que exatamente isso significa e quais novas restrições impõe?

Para ser capaz de restaurar a execução, precisamos salvar duas coisas antes de encerrar a thread: primeiro, o estado da CPU, e segundo, a pilha, e efetivamente configurá-los novamente depois que a nova thread for lançada.

Eu falei sobre novas restrições que surgirão nesta técnica, e há duas grandes: Primeiro, precisamos armazenar fora da pilha qualquer coisa necessária desde o momento em que a thread termina até que a pilha seja restaurada, e como você verá, isso cria alguns novos desafios.

Segundo, sempre precisamos de pelo menos outra thread em execução em nosso processo, já que estamos encerrando nossa thread; se não houver outras threads, o processo terminará. Não acho que isso seja um grande problema, já que a maioria dos agentes é injetada em outros processos, podemos assumir que esse processo manterá pelo menos uma thread em execução.

Componentes do DeathSleep:

Podemos ver neste PoC 4 funções principais:

  • Programa principal: É onde você escreveria o código do seu agente, e é a parte do código que fará uso do DeathSleep
  • Função Awake: é o ponto de entrada de todas as nossas threads, e é responsável por salvar o ponto inicial da pilha que iremos restaurar. Também é responsável por restaurar a pilha e o contexto da CPU quando necessário, ou apenas lançar nosso programa principal.
  • DeathSleep: é a função principal desta técnica, e é responsável por fazer backup do contexto da thread e da pilha, e também por configurar tudo para que a mágica aconteça.
  • Rebirth: Uma função simples apenas responsável por lançar nossas novas threads.

Salvando a pilha.

Quando estamos prestes a salvar a pilha, surge uma pergunta: quanto da pilha precisa ser salvo?

Vamos revisar primeiro o que está na pilha depois que chamamos a função DeathSleep (esta é a função que salva o contexto, a pilha e prepara tudo para a ofuscação e restauração)

Como podemos ver, cada função tem três partes:

  • Espaço de sombra: é um espaço de 32 bytes, alocado pelo chamador, mas usado pelo chamado. Pelo que sei e pude ver, sua função principal é armazenar, se necessário, os argumentos passados para a função chamada em registradores, mas pode ser usado para qualquer coisa que a função chamada decidir.
  • Endereço de retorno: é o endereço da próxima instrução a ser executada na função chamadora, empurrado pela instrução CALL, para que a instrução RET na função chamada apenas pegue esse endereço e "pule" para ele quando terminar.
  • Espaço da pilha da função: é o espaço reservado pela função chamada para armazenar o valor dos registradores que precisam ser restaurados e o valor de suas variáveis locais.

A porção mínima da pilha que obviamente precisamos salvar é tudo dentro do nosso programa principal, ou seja, seu espaço de sombra, seu endereço de retorno e tudo até a função DeathSleep. Qualquer coisa antes disso não é realmente necessária (salvar a pilha usada pela função de entrada tem suas vantagens, mas discutiremos isso depois), pois essa é a pilha usada pelas rotinas do Windows para lançar nossa nova thread. Além disso, decidi também armazenar o espaço de sombra da função DeathSleep (não realmente necessário, mas facilita o cálculo do Rsp no momento do despertar).

Então, no final, estamos salvando isto:

Como encontrar nossos endereços de pilha:

Cada função em uma compilação padrão deve ser composta de 3 partes: prólogo, código da função e epílogo.

O Rsp (ponteiro de pilha) deve ser modificado apenas no prólogo e epílogo da função. O prólogo aumenta o ponteiro de pilha (lembre-se, aumentar a pilha significa reduzir endereços, já que eles vão em direções opostas), para salvar registradores, armazenar todas as suas variáveis locais e depois armazenar o espaço de sombra, e o epílogo faz exatamente o oposto.

Isso significa que o ponteiro de pilha dentro do código da função deve sempre apontar para o final do espaço de sombra (roxo na imagem acima), e a soma do tamanho da pilha da função e do espaço de sombra pode ser encontrada calculando quanto o prólogo aumenta o ponteiro de pilha. Esse valor pode ser facilmente calculado usando as informações contidas nas tabelas de desenrolamento; uma explicação sobre seu uso não será abordada aqui, mas, em resumo, essas tabelas são usadas para permitir que qualquer outra thread ou processo mova-se corretamente pela pilha para ver seu conteúdo, tratar exceções ou analisá-la.

Capturando e preparando o contexto para restaurar.

Capturar o contexto é provavelmente uma das coisas mais fáceis de fazer, pois podemos simplesmente usar RtlCaptureContext() na primeira linha do DeathSleep, antes que qualquer modificação seja feita nos registradores não voláteis. Ainda precisamos fazer duas modificações no contexto onde iremos restaurar a execução.

Baixar ferramenta