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
Unwinder — Spoofing de pilha de chamadas para Rust | Kitploit
Ferramentas/GitHubGitHub/kudaes/unwinder
Evasão de IDS/IPSPós-ExploraçãoRed TeamingDesenvolvimento de PayloadsAtaque Adversário
GitHubkudaes/unwinder

Unwinder

Spoofing de pilha de chamadas para Rust

Ver Repositório
3843616há 1 anoRevisado 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

Conteúdo

  • SilentMoonWalk
    • Descrição
    • Créditos
    • Uso
      • Macro call_function!()
      • Macro indirect_syscall!()
      • Passagem de parâmetros
    • Exemplos
      • Chamando kernel32.dll!Sleep()
      • Chamando kernel32.dll!OpenProcess()
      • Chamando NtDelayExecution() como syscall indireto
      • Concatenar chamadas de macro
    • Considerações
      • Frame inicial
      • PoC
  • Substituição de pilha
    • Descrição
    • Como usar
    • Exemplo prático
    • Observações

SilentMoonWalk

Descrição

O Unwinder fornece uma weaponização completa da técnica SilentMoonWalk, permitindo obter spoofing de pilha de chamadas completo e estável em Rust.

Esta técnica possui as seguintes características:

  • Suporte para executar qualquer função arbitrária com até 11 parâmetros.
  • Suporte para executar syscalls indiretos (sem alocações adicionais de heap) com até 11 parâmetros.
  • A crate permite recuperar o valor retornado pelas funções chamadas por meio dela.
  • O processo de spoofing pode ser concatenado qualquer número de vezes sem aumentar o tamanho da pilha de chamadas.
  • TLS é usado para aumentar a eficiência durante o processo de spoofing.
  • O dinvoke_rs é usado para realizar qualquer chamada à API do Windows necessária pela crate.

Créditos

Créditos aos criadores da técnica SilentMoonWalk:

  • KlezVirus
  • Waldo-IRC
  • Trickster0

E, claro, um enorme agradecimento a namazso pelo thread no Twitter que inspirou todo este projeto.

Uso

Importe esta crate para o seu projeto adicionando a seguinte linha ao seu cargo.toml e compile no modo release:

[dependencies]
unwinder = "=0.1.4"

A funcionalidade principal desta crate foi encapsulada em duas macros:

  • A macro call_function!() permite executar qualquer função arbitrária com uma pilha de chamadas limpa.
  • A macro indirect_syscall!() executa o syscall indireto especificado com uma pilha de chamadas limpa.

Para usar qualquer uma destas macros, é necessário importar o tipo de dados std::ffi::c_void.

Ambas as macros retornam um *mut c_void que pode ser usado para recuperar o valor retornado pela função executada. Informações mais detalhadas na seção de exemplos.

Macro call_function

Esta macro é usada para chamar qualquer função desejada com uma pilha de chamadas limpa. A macro espera os seguintes parâmetros:

  • O primeiro parâmetro é o endereço de memória a ser chamado após o spoofing da pilha de chamadas. Este parâmetro deve ser passado como usize, isize ou um ponteiro.
  • O segundo parâmetro é um bool que indica se deve manter ou não o frame da função inicial. Se você não tiver certeza sobre isso, defina-o como false, o que sempre garante uma boa pilha de chamadas.
  • Os parâmetros seguintes são os argumentos a serem enviados para a função depois que a pilha de chamadas foi alvo de spoofing.

Macro indirect_syscall

Esta macro é usada para realizar qualquer syscall indireto desejado com uma pilha de chamadas limpa. A macro espera os seguintes parâmetros:

  • O primeiro parâmetro é uma string que contém o nome da função NT cujo syscall você deseja executar.
  • O segundo parâmetro é um bool que indica se deve manter ou não o frame da função inicial. Se você não tiver certeza sobre isso, defina-o como false, o que sempre garante uma boa pilha de chamadas.
  • Os parâmetros seguintes são os argumentos a serem enviados para a função NT.

Passagem de parâmetros

Para passar argumentos de diferentes tipos para estas duas macros, as seguintes considerações devem ser levadas em conta:

  • Qualquer tipo de dado básico que possa ser convertido para usize (u8-u64, i8-i64, bool, etc.) pode ser passado diretamente para as macros.
  • Structs e unions de tamanho 8, 16, 32 ou 64 bits são passados como se fossem inteiros do mesmo tamanho.
  • Estruturas e unions com tamanho maior que 64 bits devem ser passadas como um ponteiro.
  • Strings (&str e String) devem ser passadas como um ponteiro.
  • Ponteiros nulos (ptr::null(), ptr::null_mut(), etc.) são passados como 0 (não importa se é u8, u16, i32 ou qualquer outro).
  • Parâmetros de ponto flutuante e dupla precisão não são suportados atualmente.
  • Qualquer outro tipo de dado deve ser passado como um ponteiro.

Exemplos

Chamando Sleep

let k32 = dinvoke_rs::dinvoke::get_module_base_address("kernel32.dll");
let sleep = dinvoke_rs::dinvoke::get_function_address(k32, "Sleep"); // Memory address of kernel32.dll!Sleep() 
let miliseconds = 1000i32;
unwinder::call_function!(sleep, false, miliseconds);

Chamando OpenProcess

let k32 = dinvoke_rs::dinvoke::get_module_base_address("kernel32.dll"); 
let open_process: isize = dinvoke_rs::dinvoke::get_function_address(k32, "Openprocess");
let desired_access: u32 = 0x1000;
let inherit = 0i32;
let pid = 20628i32;
let handle = unwinder::call_function!(open_process, false, desired_access, inherit, pid); // returns *mut c_void
let handle: HANDLE = std::mem::transmute(handle);
println!("Handle id: {:x}", handle.0);

Observe que a macro retorna um *mut c_void que pode ser convertido diretamente para um HANDLE, já que ambos os tipos de dados têm o mesmo tamanho. Isso permite acessar o valor retornado por OpenProcess, que é o novo handle para o processo alvo.

Chamando NtDelayExecution como syscall indireto

let large = 0x8000000000000000 as u64; // Sleep indefinitely
let large: *mut i64 = std::mem::transmute(&large);
let alertable = false;
let ntstatus = unwinder::indirect_syscall!("NtDelayExecution", false, alertable, large); // returns *mut c_void
println!("ntstatus: {:x}", ntstatus as i32);

Observe que a macro retorna um *mut c_void que pode ser usado para recuperar o NTSTATUS retornado por NtDelayExecution.

Concatenar chamadas de macro

O processo de spoofing pode ser concatenado qualquer número de vezes sem um incremento anormal no tamanho da pilha de chamadas. O fluxo de execução também será preservado. O código a seguir é um exemplo disso:

fn main()
{
	function_a();
}

fn function_a()
{
	unsafe
	{
		let func_b = function_b as usize;
		call_function!(func_b, false);
		println!("function_a done.");
	}
}

fn function_b()
{
	unsafe
	{
		let func_c = function_c as usize;
		call_function!(func_c, false);
		println!("function_b done.")
	}
}

fn function_c()
{
	unsafe
	{
		let large = 0x0000000000000000 as u64; // Don't sleep so we return to function_b, allowing to check the execution flow preservation.
		let large: *mut i64 = std::mem::transmute(&large);
		let alertable = false;
		let ntstatus = unwinder::indirect_syscall!("NtDelayExecution", false, alertable, large);
		println!("ntstatus: {:x}", (ntstatus as usize) as i32); //NTSTATUS is a i32, although that second casting is not really required in this case.
	}
}

Considerações

Frame inicial

Se você definir o segundo parâmetro como true (em ambas as macros), o processo de spoofing tentará manter o frame do endereço de início da thread na pilha de chamadas para aumentar a legitimidade.

Pilha de chamadas com spoofing mantendo o módulo principal.

Baixar ferramenta