Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Welcome

This is a growing set of exercises in which simple Rust programs are compiled into binaries and analyzed step by step with reverse engineering tools.

The goal is to start from the simplest possible PE binaries and gradually move toward more complex Rust applications that showcase features such as:

  • Basic console I/O
  • Control flow (loops, branching, pattern matching)
  • Functions and modules
  • Error handling
  • Structs, enums, traits
  • Heap allocations and dynamic memory
  • Generics and lifetimes
  • Concurrency and async Rust
  • Integration with external libraries

Environment Details

The exact output of compiled binaries will vary slightly depending on your compiler version, target architecture, and operating system. To make results reproducible, here are the specifics of the environment I’ll be using throughout this book:

rustc --version --verbose
rustc 1.88.0 (6b00bc388 2025-06-23)
binary: rustc
commit-hash: 6b00bc3880198600130e1cf62b8f8a93494488cc
commit-date: 2025-06-23
host: x86_64-pc-windows-msvc
release: 1.88.0
LLVM version: 20.1.5

The host field (x86_64-pc-windows-msvc) indicates the target platform: 64-bit Intel/AMD (x86_64), Windows OS (windows), and MSVC toolchain (msvc). This affects calling conventions, linking, and debug info (like PDB files)

systeminfo | findstr /B /C:"OS"
OS Name:                       Microsoft Windows 11 Home
OS Version:                    10.0.26100 N/A Build 26100
OS Manufacturer:               Microsoft Corporation
OS Configuration:              Standalone Workstation
OS Build Type:                 Multiprocessor Free

The examples in this book are tool-agnostic. You can explore them with whatever reverse engineering workflow you prefer.

Personally, I’ll be experimenting with RetDec, Ghidra, IDA Pro, and x64dbg, but readers are encouraged to use their own favorite tools, whether that’s Radare2, Binary Ninja, Hopper, or anything else.

For quick PE analysis and disassembly, I’ve also created a lightweight Rust-based tool, peanalyse, which can show PE headers, image base, entrypoint, and disassemble code directly from a binary."

Exercises

git clone https://github.com/Jozefpodlecki/reverse-engineering-exercises

0-empty

source

Navigate to the project folder and compile with optimizations:

cd 0-empty
rustc -C opt-level=3 -C debuginfo=0 -o main-o3.exe main.rs

The binary under study is built from the source in this repository, which consists of nothing more than an empty Rust main function.

Despite the trivial source, the resulting executable still pulls in Rust’s standard runtime and the Windows CRT. This means the file contains initialization code, runtime setup, and exit handling beyond what the high-level program expresses.

In the following sections we’ll explore how the binary is structured, which subsystems it links against, and how control flows from the Windows loader into Rust’s runtime before eventually returning to the operating system.

Entry point of a PE executable:

peanalyse -i main.exe --entry
Architecture: Pe64
AddressOfEntryPoint (RVA): 0x00014280
ImageBase:                0x140000000
EntryPoint (VA):          0x140014280

Examine the first few instructions executed.

objdump -D main-o3.exe --start-address=0x140014280 --stop-address=0x140014290

main-o3.exe:     file format pei-x86-64


Disassembly of section .text:

0000000140014280 <.text+0x13280>:
   140014280:   48 83 ec 28             sub    $0x28,%rsp
   140014284:   e8 e3 02 00 00          call   0x14001456c
   140014289:   48 83 c4 28             add    $0x28,%rsp
   14001428d:   e9 72 fe ff ff          jmp    0x140014104

When decompiled in Ghidra, it appears as:

ulong __cdecl mainCRTStartup(void *param_1)

{
  ulong uVar1;
  
  __security_init_cookie();
  uVar1 = __scrt_common_main_seh();
  return uVar1;
}

First, __security_init_cookie initializes the compiler's stack buffer overflow protection cookie by generating a pseudo-random value using the system time, thread ID, process ID, and performance counter; it ensures the cookie is never the default sentinel value and stores both the cookie and its complement for use in stack security checks.

source

void __cdecl __security_init_cookie(void)

{
  DWORD DVar1;
  _FILETIME local_res8;
  LARGE_INTEGER local_res10;
  _FILETIME local_18 [2];
  
  if (__security_cookie == 0x2b992ddfa232) {
    local_res8.dwLowDateTime = 0;
    local_res8.dwHighDateTime = 0;
    GetSystemTimeAsFileTime(&local_res8);
    local_18[0] = local_res8;
    DVar1 = GetCurrentThreadId();
    local_18[0] = (_FILETIME)((ulonglong)local_18[0] ^ (ulonglong)DVar1);
    DVar1 = GetCurrentProcessId();
    local_18[0] = (_FILETIME)((ulonglong)local_18[0] ^ (ulonglong)DVar1);
    QueryPerformanceCounter(&local_res10);
    __security_cookie =
         ((ulonglong)local_res10.s.LowPart << 0x20 ^
          CONCAT44(local_res10.s.HighPart,local_res10.s.LowPart) ^ (ulonglong)local_18[0] ^
         (ulonglong)local_18) & 0xffffffffffff;
    if (__security_cookie == 0x2b992ddfa232) {
      __security_cookie = 0x2b992ddfa233;
    }
  }
  __security_cookie_complement = ~__security_cookie;
  return;
}

__scrt_common_main_seh initializes the C runtime, acquires a startup lock to ensure thread-safe setup, runs global constructors via _initterm_e and _initterm, executes dynamic TLS init and destructor callbacks if present, retrieves argc, argv, and the environment, calls main() with these values, and then performs CRT and OS cleanup by calling _cexit() or exit() depending on whether the application is managed.

__scrt_fastfail triggers an immediate program termination using a low-level fast-fail mechanism. It checks for CPU support for the fast fail instruction, optionally invokes the debugger hook, captures the CPU context, performs stack unwinding if possible, and invokes UnhandledExceptionFilter. If no debugger handles the exception, it ensures the process terminates without normal cleanup, signaling a critical unrecoverable error.

__scrt_initialize_crt sets up CRT state for the module, marks DLL initialization if needed, detects CPU features via __isa_available_init, and determines whether the runtime environment should be initialized.

int __cdecl __scrt_common_main_seh(void)

{
  char **_Argv;
  bool bVar1;
  bool bVar2;
  int iVar3;
  _func___cdecl_void_void_ptr_ulong_void_ptr **pp_Var4;
  char **_Env;
  undefined8 *puVar5;
  int *piVar6;
  
  bVar1 = __scrt_initialize_crt(exe);
  if (!bVar1) {
                    /* WARNING: Subroutine does not return */
    __scrt_fastfail(7);
  }
  bVar1 = false;
  bVar2 = __scrt_acquire_startup_lock();
  if (__scrt_current_native_startup_state == initializing) {
                    /* WARNING: Subroutine does not return */
    __scrt_fastfail(7);
  }
  if (__scrt_current_native_startup_state == uninitialized) {
    __scrt_current_native_startup_state = initializing;
    iVar3 = _initterm_e(&__xi_a,&__xi_z);
    if (iVar3 != 0) {
      return 0xff;
    }
    _initterm(&__xc_a,&__xc_z);
    __scrt_current_native_startup_state = initialized;
  }
  else {
    bVar1 = true;
  }
  __scrt_release_startup_lock(bVar2);
  pp_Var4 = __scrt_get_dyn_tls_init_callback();
  if ((*pp_Var4 != (_func___cdecl_void_void_ptr_ulong_void_ptr *)0x0) &&
     (bVar2 = __scrt_is_nonwritable_in_current_image(pp_Var4), bVar2)) {
    _guard_dispatch_icall_nop();
  }
  pp_Var4 = __scrt_get_dyn_tls_dtor_callback();
  if ((*pp_Var4 != (_func___cdecl_void_void_ptr_ulong_void_ptr *)0x0) &&
     (bVar2 = __scrt_is_nonwritable_in_current_image(pp_Var4), bVar2)) {
    _register_thread_local_exe_atexit_callback(*pp_Var4);
  }
  _Env = (char **)_get_initial_narrow_environment();
  puVar5 = (undefined8 *)__p___argv();
  _Argv = (char **)*puVar5;
  piVar6 = (int *)__p___argc();
  iVar3 = main(*piVar6,_Argv,_Env);
  bVar2 = __scrt_is_managed_app();
  if (bVar2) {
    if (!bVar1) {
      _cexit();
    }
    __scrt_uninitialize_crt(true,false);
    return iVar3;
  }

  exit(iVar3);
}

lang_start_internal init

int __cdecl main(int _Argc,char **_Argv,char **_Env)
{
  int extraout_EAX;
  
  std::rt::lang_start_internal();
  return extraout_EAX;
}

Summary

The PE entry -> mainCRTStartup -> __scrt_common_main_seh -> lang_start_internal -> main() chain handles runtime initialization, CRT setup, and exception handling before executing the user-defined main().

1-no-std

source

This exercise explores a minimal Windows executable written in Rust. The program is compiled without the standard library (#![no_std]) and does not link against the C runtime.

All functionality — writing to the console and exiting the process — is implemented manually using Windows API calls.

cd no-std
cargo build --release
peanalyse -i no-std.exe --entry
Architecture: Pe64
AddressOfEntryPoint (RVA): 0x00001000
ImageBase:                0x140000000
EntryPoint (VA):          0x140001000

The program’s entry point is at 0x140001000.

Disassembly

cd target/release
peanalyse -i no-std.exe --disassemble-from-addr=0x140001000
0x140001000: sub        rsp, 0x28
0x140001004: mov        ecx, 0xfffffff5
0x140001009: call       qword ptr [rip + 0x1009] ; target = 0x140002018
0x14000100F: mov        qword ptr [rsp + 0x20], 0
0x140001018: lea        rdx, [rip + 0x1009]  ; target = 0x140002028
0x14000101F: mov        rcx, rax
0x140001022: mov        r8d, 0xc
0x140001028: xor        r9d, r9d
0x14000102B: call       qword ptr [rip + 0xfcf] ; target = 0x140002000
0x140001031: mov        ecx, 0x2710
0x140001036: call       qword ptr [rip + 0xfcc] ; target = 0x140002008
0x14000103C: xor        ecx, ecx
0x14000103E: call       qword ptr [rip + 0xfcc] ; target = 0x140002010
0x140001044: int3
0x140001000: sub        rsp, 0x28

Reserve 0x28 bytes (40 bytes) on the stack for local variables / alignment.

0x140001004: mov        ecx, 0xfffffff5
pub const STD_OUTPUT_HANDLE: STD_HANDLE = 4294967285u32;

0xfffffff5 is the signed 32-bit representation of 4294967285u32.

RIP-relative addressing for calls

Calls use RIP-relative addressing to locate the thunk table:

0x140001009: call       qword ptr [rip + 0x1009]

Resolving:

0x140001009 + 6 + 0x1009 = 0x140002018

Thunk table contents

peanalyse -i no-std.exe --read-addr=0x140002018
0x140002018 - 0x2228

Each thunk entry holds the RVA of the corresponding IAT slot:

IAT entries patched by the loader

peanalyse -i no-std.exe --iat-entries
DLL: kernel32.dll
  WriteConsoleA @ RVA 0x00002238 VA 0x140002238 (hint 1296)
  Sleep @ RVA 0x00002248 VA 0x140002248 (hint 1192)
  ExitProcess @ RVA 0x00002250 VA 0x140002250 (hint 274)
  GetStdHandle @ RVA 0x00002228 VA 0x140002228 (hint 621)
Example flow: GetStdHandle
0x140001009: call qword ptr [rip + 0x1001]
   → resolves to 0x140002010 (thunk entry, fixed at compile time)
   → thunk entry contains pointer to 0x140002218 (true IAT slot)
   → loader patches [0x140002218] with &kernel32!GetStdHandle
   → final call jumps into kernel32.dll

Lastly

0x14000100F: mov        qword ptr [rsp + 0x20], 0
0x140001018: lea        rdx, [rip + 0x1009]  ; target = 0x140002028
0x14000101F: mov        rcx, rax
0x140001022: mov        r8d, 0xc
0x140001028: xor        r9d, r9d
0x14000102B: call       qword ptr [rip + 0xfcf] ; target = 0x140002000

Microsoft x64 calling convention. rcx → 1st argument rdx → 2nd argument r8 → 3rd r9 → 4th Additional stack space (shadow space) is already reserved at [rsp..rsp+0x20].

It is the caller's responsibility to allocate 32 bytes of "shadow space" on the stack right before calling the function (regardless of the actual number of parameters used), and to pop the stack after the call.

Resources

magic-string

Very simple password checker

source

peanalyse -i magic-string.exe --entry
Architecture: Pe64
AddressOfEntryPoint (RVA): 0x000177E0
ImageBase:                0x140000000
EntryPoint (VA):          0x1400177E0

mainCRTStartup 0x1400177E0

sub rsp,28
call <magic-string.__security_init_cookie>
add rsp,28
jmp <magic-string.__scrt_common_main_seh> # 0x140017664

__scrt_common_main_seh 0x140017664

mov qword ptr ss:[rsp+8],rbx
mov qword ptr ss:[rsp+10],rsi
push rdi
sub rsp,30
mov ecx,1
call <magic-string.__scrt_initialize_crt>
test al,al
...
mov r8,rdi
mov rdx,rbx
mov ecx,dword ptr ds:[rax]
call <magic-string.main> # 0x140001310
...
add rsp,30
pop rdi
ret 

Initializes CRT and calls main..
Standard SEH (Structured Exception Handling) setup.

main 0x140001310

sub rsp,38
mov r9,rdx
movsxd r8,ecx
lea rax,qword ptr ds:[<sub_7FF6AB8E1100>] ; function pointer to Rust closure
mov qword ptr ss:[rsp+30],rax
mov byte ptr ss:[rsp+20],0
lea rdx,qword ptr ds:[7FF6AB8FA3A0]
lea rcx,qword ptr ss:[rsp+30]
call <magic-string.std::rt::lang_start_internal::h5830dd6b2696abe8> # 0x140003080
nop 
add rsp,38
ret 

Converts main to a trait object (dyn Fn() -> i32).
Calls lang_start_internal with a fat pointer.

lang_start_internal 0x140003080

push rbp
push rsi
push rdi
sub rsp,A0
lea rbp,qword ptr ss:[rsp+80]
mov qword ptr ss:[rbp],FFFFFFFFFFFFFFFE
mov rsi,rdx
mov rdi,rcx
...
mov eax,dword ptr ds:[<_tls_index>]
mov rdx,qword ptr gs:[58]
mov rax,qword ptr ds:[rdx+rax*8]
mov qword ptr ds:[rax+8],rcx
mov qword ptr ds:[7FF6AB904220],rcx
mov rcx,rdi
call qword ptr ds:[rsi+28]
...
ret 

Implements Rust runtime startup and panic handling.
Calls the main closure via vtable ([rsi+28]).

Fat pointer (dyn Fn() -> i32 + Sync)

sub rsp,28
mov rcx,qword ptr ds:[rcx]
call <magic-string.sub_7FF6AB8E1020> # 0x140001020
xor eax,eax
add rsp,28
ret 

First stub: loads data pointer from fat pointer.

0x140001020

sub rsp,28
call rcx # 0x140001100
nop 
add rsp,28
ret 

Second stub: trampoline calls the real rust_main.

rust_main

push rbp
sub rsp,80
lea rbp,qword ptr ss:[rsp+80]
mov qword ptr ss:[rbp-8],FFFFFFFFFFFFFFFE
mov qword ptr ss:[rbp-28],0
mov qword ptr ss:[rbp-20],1
mov qword ptr ss:[rbp-18],0
call <magic-string.std::io::stdio::stdin::hb37ee29cfde5d31f>
mov qword ptr ss:[rbp-10],rax
lea rcx,qword ptr ss:[rbp-10]
lea rdx,qword ptr ss:[rbp-28]
call <magic-string.std::io::stdio::Stdin::read_line::h9f941692afe5412c>
test al,1
jne magic-string.7FF6AB8E1219
cmp qword ptr ss:[rbp-18],14
jne magic-string.7FF6AB8E1181
mov rax,qword ptr ss:[rbp-20]
movdqu xmm0,xmmword ptr ds:[rax]
movd xmm1,dword ptr ds:[rax+10]
pcmpeqb xmm1,xmmword ptr ds:[<__xmm@00000000000000000000000077626e41>]
pcmpeqb xmm0,xmmword ptr ds:[<__xmm@233d7138577448503841673436394c75>]
pand xmm0,xmm1
pmovmskb eax,xmm0
cmp eax,FFFF
je magic-string.7FF6AB8E11EA
lea rax,qword ptr ds:[7FF6AB8FA460]
mov qword ptr ss:[rbp-58],rax
mov qword ptr ss:[rbp-50],1
mov qword ptr ss:[rbp-48],8
pxor xmm0,xmm0
movdqu xmmword ptr ss:[rbp-40],xmm0
lea rcx,qword ptr ss:[rbp-58]
call <magic-string.std::io::stdio::_print::h033ee6824b02a35e>
call <magic-string.std::io::stdio::stdin::hb37ee29cfde5d31f>
mov qword ptr ss:[rbp-10],rax
lea rcx,qword ptr ss:[rbp-10]
lea rdx,qword ptr ss:[rbp-28]
call <magic-string.std::io::stdio::Stdin::read_line::h9f941692afe5412c>
test al,1
jne magic-string.7FF6AB8E1247
mov rdx,qword ptr ss:[rbp-28]
test rdx,rdx
je magic-string.7FF6AB8E11E0
mov rcx,qword ptr ss:[rbp-20]
mov r8d,1
call <magic-string.__rustc::__rust_dealloc>
nop 
add rsp,80
pop rbp
ret 

Read Line

lea rcx,qword ptr ss:[rbp-10]
lea rdx,qword ptr ss:[rbp-28]
call <magic-string.std::io::stdio::Stdin::read_line::h9f941692afe5412c>
test al,1
jne magic-string.7FF6AB8E1219
  • read_line writes the input directly into the stack-allocated buffer at [rbp-28]
  • The number of bytes read is stored at [rbp-18].

Input Length Check

cmp qword ptr ss:[rbp-18],14
jne magic-string.7FF6AB8E1181
  • rbp-18 stores the number of bytes read from stdin.
  • Compares it against 0x14 (20 decimal).
  • If input length ≠ 20 → jump to “Denied” handler.

String Comparison (SIMD)

mov rax,[rbp-20]       ; pointer to buffer
movdqu xmm0,[rax]       ; first 16 bytes
movd xmm1,[rax+16]      ; next 4 bytes
pcmpeqb xmm1,[__xmm@000000…] ; compare bytes with constant1
pcmpeqb xmm0,[__xmm@233d…]   ; compare bytes with constant2
pand xmm0,xmm1
pmovmskb eax,xmm0
cmp eax,FFFF

Load input into XMM registers

  • xmm0 = first 16 bytes of user input.
  • xmm1 = next 4 bytes of user input (loaded with movd).

Compare bytes against constants

  • pcmpeqb xmm0, [pattern2] → sets each byte in xmm0 to 0xFF if equal, 0x00 if not.
  • pcmpeqb xmm1, [pattern1] → same for xmm1.

Combine results

  • pand xmm0, xmm1 → bitwise AND of the results.

Ensures all bytes must match across both chunks.

Extract mask

  • pmovmskb eax, xmm0 → extract the MSB of each byte into a 16-bit mask in eax.

Check full match

  • cmp eax, 0xFFFF → all 16 bytes in xmm0 matched.

If not all match → jump to Denied handler.

LabelValue
__xmm@000...77626e41"uL964gA8PHtW8q=#"
__xmm@233d...34639…"Anbw"
Full target string"uL964gA8PHtW8q=#Anbw"

Resources

  • https://binarydefense.com/resources/blog/digging-through-rust-to-find-gold-extracting-secrets-from-rust-malware/

string-clone

This program demonstrates the use of the rand crate for random string generation and includes a String cloning operation, both of which we will examine during reverse engineering.

source

0x140000240

Function Prologue / Stack Setup

00007FF70D261240 | 55                               | push rbp                                
00007FF70D261241 | 41:57                            | push r15                                
00007FF70D261243 | 41:56                            | push r14                                
00007FF70D261245 | 41:55                            | push r13                                
00007FF70D261247 | 41:54                            | push r12                                
00007FF70D261249 | 56                               | push rsi                                
00007FF70D26124A | 57                               | push rdi                                
00007FF70D26124B | 53                               | push rbx                                
00007FF70D26124C | 48:81EC 98000000                 | sub rsp,98                              
00007FF70D261253 | 48:8DAC24 80000000               | lea rbp,qword ptr ss:[rsp+80]           

Local Variable Initialization

00007FF70D26125B | 48:C745 10 FEFFFFFF              | mov qword ptr ss:[rbp+10],FFFFFFFFFFFFF 
00007FF70D261263 | 48:C745 F8 00000000              | mov qword ptr ss:[rbp-8],0              
00007FF70D26126B | 48:C745 00 08000000              | mov qword ptr ss:[rbp],8                
00007FF70D261273 | 48:C745 08 00000000              | mov qword ptr ss:[rbp+8],0        

Allocates 152 bytes (0x98) on the stack for:

  • Vec internals (collector)
  • String temporaries (str in the loop)
  • RNG state / loop counters
  • Establishes rbp as a base pointer to simplify access to local variables.

RNG Initialization

00007FF70D26127B | E8 40040000                      | call <string-clone._$LT$rand..rngs..thr 
00007FF70D261280 | 48:89C6                          | mov rsi,rax                             
00007FF70D261283 | 48:8945 C8                       | mov qword ptr ss:[rbp-38],rax

rsi holds RNG state for later random sampling.

Buffer check

00007FF70D261287 | 48:8D78 10                       | lea rdi,qword ptr ds:[rax+10]           
00007FF70D26128B | 48:8B88 50010000                 | mov rcx,qword ptr ds:[rax+150]          
00007FF70D261292 | 48:83F9 40                       | cmp rcx,40                              
00007FF70D261296 | 72 39                            | jb string-clone.7FF70D2612D1

RNG Refill / Update

00007FF70D261298 | 48:8D8E 10010000                 | lea rcx,qword ptr ds:[rsi+110]          
00007FF70D26129F | 48:8B86 48010000                 | mov rax,qword ptr ds:[rsi+148]          
00007FF70D2612A6 | 48:85C0                          | test rax,rax                            
00007FF70D2612A9 | 7E 1C                            | jle string-clone.7FF70D2612C7           
00007FF70D2612AB | 48:05 00FFFFFF                   | add rax,FFFFFFFFFFFFFF00                
00007FF70D2612B1 | 48:8986 48010000                 | mov qword ptr ds:[rsi+148],rax          
00007FF70D2612B8 | BA 06000000                      | mov edx,6                               
00007FF70D2612BD | 49:89F8                          | mov r8,rdi                              
00007FF70D2612C0 | E8 6B040000                      | call <string-clone.rand_chacha::guts::refill_wide::hc43b38d823048efe>
00007FF70D2612C5 | EB 08                            | jmp string-clone.7FF70D2612CF           
00007FF70D2612C7 | 48:89FA                          | mov rdx,rdi                             
00007FF70D2612CA | E8 E1FDFFFF                      | call <string-clone.sub_7FF70D2610B0>    

RNG Value Fetch / Scaling

00007FF70D2612CF | 31C9                             | xor ecx,ecx                             
00007FF70D2612D1 | 8B548E 10                        | mov edx,dword ptr ds:[rsi+rcx*4+10]
00007FF70D2612D5 | 48:8D41 01                       | lea rax,qword ptr ds:[rcx+1]            
00007FF70D2612D9 | 48:8986 50010000                 | mov qword ptr ds:[rsi+150],rax
00007FF70D2612E0 | 48:8D1C92                        | lea rbx,qword ptr ds:[rdx+rdx*4]        
00007FF70D2612E4 | 49:89DF                          | mov r15,rbx                             
00007FF70D2612E7 | 49:C1EF 20                       | shr r15,20

Scales RNG value to desired range

shr and lea are used for modulo/rejection to avoid bias

RNG Rejection / Bias Check

00007FF70D2612EB | 83FB FC                          | cmp ebx,FFFFFFFC
00007FF70D2612EE | 72 5E                            | jb string-clone.7FF70D26134E            

Loop Counter / Iteration Setup

00007FF70D2612F0 | 48:83F9 3F                       | cmp rcx,3F                              
00007FF70D2612F4 | 75 3C                            | jne string-clone.7FF70D261332           
00007FF70D2612F6 | 48:89F1                          | mov rcx,rsi                             
00007FF70D2612F9 | 48:81C1 10010000                 | add rcx,110                             
00007FF70D261300 | 48:8B86 48010000                 | mov rax,qword ptr ds:[rsi+148]          
00007FF70D261307 | 48:85C0                          | test rax,rax                            
00007FF70D26130A | 7E 1C                            | jle string-clone.7FF70D261328           
00007FF70D26130C | 48:05 00FFFFFF                   | add rax,FFFFFFFFFFFFFF00                
00007FF70D261312 | 48:8986 48010000                 | mov qword ptr ds:[rsi+148],rax          
00007FF70D261319 | BA 06000000                      | mov edx,6                               
00007FF70D26131E | 49:89F8                          | mov r8,rdi                              
00007FF70D261321 | E8 0A040000                      | call <string-clone.rand_chacha::guts::refill_wide::hc43b38d823048efe>
00007FF70D261326 | EB 08                            | jmp string-clone.7FF70D261330           
00007FF70D261328 | 48:89FA                          | mov rdx,rdi                             
00007FF70D26132B | E8 80FDFFFF                      | call <string-clone.sub_7FF70D2610B0>    
00007FF70D261330 | 31C0                             | xor eax,eax                             
00007FF70D261332 | 8B4C86 10                        | mov ecx,dword ptr ds:[rsi+rax*4+10]     
00007FF70D261336 | 48:FFC0                          | inc rax                                 
00007FF70D261339 | 48:8986 50010000                 | mov qword ptr ds:[rsi+150],rax          
00007FF70D261340 | 48:8D0489                        | lea rax,qword ptr ds:[rcx+rcx*4]        
00007FF70D261344 | 48:C1E8 20                       | shr rax,20                              
00007FF70D261348 | 01C3                             | add ebx,eax                             
00007FF70D26134A | 49:83D7 00                       | adc r15,0                               
00007FF70D26134E | 48:8B45 C8                       | mov rax,qword ptr ss:[rbp-38]           
00007FF70D261352 | 48:FF08                          | dec qword ptr ds:[rax]                  
00007FF70D261355 | 75 09                            | jne string-clone.7FF70D261360           
00007FF70D261357 | 48:8D4D C8                       | lea rcx,qword ptr ss:[rbp-38]           
00007FF70D26135B | E8 40030000                      | call <string-clone.alloc::rc::Rc$LT$T$C 
00007FF70D261360 | 41:83C7 05                       | add r15d,5                              
00007FF70D261364 | 45:31E4                          | xor r12d,r12d                           
00007FF70D261367 | BE 08000000                      | mov esi,8                               
00007FF70D26136C | 48:8D7D B0                       | lea rdi,qword ptr ss:[rbp-50]           
00007FF70D261370 | 48:8D5D C8                       | lea rbx,qword ptr ss:[rbp-38]           
00007FF70D261374 | 4C:8D6D A0                       | lea r13,qword ptr ss:[rbp-60]           
00007FF70D261378 | 45:31F6                          | xor r14d,r14d                           
00007FF70D26137B | EB 06                            | jmp string-clone.7FF70D261383           
00007FF70D26137D | 0F1F00                           | nop dword ptr ds:[rax],eax              

This exercise explores how Rust represents function trait objects at a low level. Specifically, we examine:

fn_trait: &(dyn Fn() -> i32 + Sync + RefUnwindSafe)

This is a trait object reference: a pointer to a function-like value that is thread-safe (Sync) and panic-safe (RefUnwindSafe).

source

Setting up the Trait Object

00007FF7C1D914B0 | 48:83EC 38       | sub rsp,38          ; allocate 56 bytes stack
00007FF7C1D914B4 | 48:8D4C24 36     | lea rcx,[rsp+36]   ; closure environment pointer (data)
00007FF7C1D914B9 | 48:8D15 687F0100 | lea rdx,[vtable]   ; vtable pointer
00007FF7C1D914D2 | E8 69FEFFFF      | call call_fn_trait  ; call the wrapper function

Loading the fat pointer

00007FF7C1D91425 | 48:8B4C24 20 | mov rcx,qword ptr ss:[rsp+20]  
00007FF7C1D9142A | 48:8B5424 28 | mov rdx,qword ptr ss:[rsp+28]  
00007FF7C1D9142F | FF52 28      | call qword ptr ds:[rdx+28]                                                        |

RCX = closure environment pointer (data) RDX = vtable pointer (vtable) call [rdx+28] = calls FnOnce::call_once via vtable.

Trait Object Layout

struct FnVtable {
    void* drop_in_place;     // offset 0x00
    unsigned long long size; // offset 0x08
    unsigned long long align;// offset 0x10
    void* call;              // offset 0x18 (Fn::call)
    void* call_mut;          // offset 0x20 (FnMut::call_mut)
    void* call_once;         // offset 0x28 (FnOnce::call_once)
};

struct FnTraitObject {
    void* data;              // 0x00 (closure environment)
    void* vtable;            // 0x08 (pointer to FnVtable)
};

Observing in x64dbg

Struct tab → Parse Header → Display Type

Define FnVtable

Map RCX → data and RDX → vtable.

Step into call_once via vtable to see the constant returned.

Return value appears in RAX:

Closure Execution void* call

00007FF7C1D911C0 | 48:83EC 38                       | sub rsp,38                                                   | function.rs:250
00007FF7C1D911C4 | 48:894C24 30                     | mov qword ptr ss:[rsp+30],rcx                                |
00007FF7C1D911C9 | E8 32000000                      | call <fn_trait_object.core::ops::function::FnOnce::call_once |
00007FF7C1D911CE | 90                               | nop                                                          |
00007FF7C1D911CF | 48:83C4 38                       | add rsp,38                                                   |
00007FF7C1D911D3 | C3                               | ret                                                          |                            |

Closure Execution void* call_mut, void* call_once

00007FF7C1D91500 | 50                               | push rax                                                     | main.rs:18
00007FF7C1D91501 | 48:890C24                        | mov qword ptr ss:[rsp],rcx                                   |
00007FF7C1D91505 | B8 87D61200                      | mov eax,12D687                                               |
00007FF7C1D9150A | 59                               | pop rcx                                                      |
00007FF7C1D9150B | C3                               | ret                                                          |                                                       |
#![allow(unused)]
fn main() {
let closure = || 1234567;
}

The closure simply loads the constant 1234567 into RAX

Captured variables example

#![allow(unused)]
fn main() {
let a = 1234567i32;
let b = 99u64;
let closure = || {
    a + b as i32
};
}

It compiles the closure into a struct-like environment containing these captured values.

This environment is passed as a pointer (RCX) to the generated closure code when called via a trait object.

00007FF7FA7914C0 | 48:83EC 48           | sub rsp,48           ; allocate 72 bytes for closure
00007FF7FA7914C4 | C74424 2C 87D61200   | mov dword ptr [rsp+2C],12D687  ; store 'a' (1234567)
00007FF7FA7914CC | 48:C74424 30 63000000| mov qword ptr [rsp+30],63      ; store 'b' (99)
00007FF7FA7914D5 | 48:8D4424 2C         | lea rax,[rsp+2C]    ; load address of 'a'
00007FF7FA7914DA | 48:894424 38         | mov [rsp+38],rax    ; save pointer in closure env
00007FF7FA7914DF | 48:8D4424 30         | lea rax,[rsp+30]    ; load address of 'b'
00007FF7FA7914E4 | 48:894424 40         | mov [rsp+40],rax    ; save pointer in closure env

[rsp+38] = pointer to a

[rsp+40] = pointer to b

This closure environment is what RCX will point to when the closure is called.

Inside the Closure

00007FF7FA791544 | 48:894C24 30 | mov [rsp+30], rcx

Store RCX, which points to the closure environment, on the stack at [rsp+30].

00007FF7FA791549 | 48:8B4424 30 | mov rax, [rsp+30]
00007FF7FA79154E | 48:8B00      | mov rax, [rax]
00007FF7FA791551 | 48:894424 38 | mov [rsp+38], rax

Load the closure environment pointer from [rsp+30] into RAX.

Dereference it ([rax]) to get the first vtable pointer (often drop_in_place).

Store this in [rsp+38] — this is now the first field of the fat pointer/closure struct.

00007FF7FA791556 | 48:8B4424 30 | mov rax, [rsp+30]
00007FF7FA79155B | 48:8B40 08   | mov rax, [rax+8]
00007FF7FA79155F | 48:894424 40 | mov [rsp+40], rax

Reload closure env pointer from [rsp+30] into RAX.

Dereference [rax+8] — second field of the environment (often the pointer to captured data).

Store at [rsp+40].

00007FF7FA791564 | 48:8B01         | mov rax,[rcx]       ; load pointer to 'a'
00007FF7FA791567 | 8B00            | mov eax,[rax]       ; load value of 'a'
00007FF7FA791569 | 48:8B49 08      | mov rcx,[rcx+8]     ; load pointer to 'b'
00007FF7FA79156D | 48:8B09         | mov rcx,[rcx]       ; load value of 'b'
00007FF7FA791570 | 01C8            | add eax,ecx         ; perform addition a + b

RCX points to the closure environment.

[RCX] = pointer to a, [RCX+8] = pointer to b.

mov eax,[rax] and mov rcx,[rcx] dereference the pointers to get the actual values.

add eax, ecx computes the closure result.

This exercise explores how

source

Function Prologue

00007FF7C3EE8C70 | 55           | push rbp
...
00007FF7C3EE8C7C | 48:81EC B8020000 | sub rsp,2B8

Allocate 696 bytes on stack for

  • Local variables (like buffer, windivert, tx, etc.)
  • Rust runtime bookkeeping (Vec metadata, thread closure captures)

Zeroing / Initializing memory

00007FF7C3EE8CC1 | 0F57C0        | xorps xmm0,xmm0
00007FF7C3EE8CC4 | 0F2983 80000000 | movaps xmmword ptr ds:[rbx+80],xmm0
00007FF7C3EE8CCB | 0F2983 00010000 | movaps xmmword ptr ds:[rbx+100],xmm0
00007FF7C3EE8CD2 | 66:C783 80010000 0000 | mov word ptr ds:[rbx+180],0
00007FF7C3EE8CDB | 48:C783 88010000 00000000 | mov qword ptr ds:[rbx+188],0

Stack alignment & frame pointers

00007FF7C3EE8C83 | 48:8DAC24 80000000 | lea rbp,qword ptr ss:[rsp+80]
00007FF7C3EE8C8B | 48:83E4 80        | and rsp,FFFFFFFFFFFFFF80
00007FF7C3EE8C8F | 48:89E3           | mov rbx,rsp

Memory allocation

00007FF7C3EE8D15 | 0FB605 25D40200 | movzx eax,byte ptr ds:[<__rust_no_alloc_shim_is_unstable>]
00007FF7C3EE8D1C | B9 00020000      | mov ecx,200
00007FF7C3EE8D21 | BA 80000000      | mov edx,80
00007FF7C3EE8D26 | E8 A5260000      | call <windivert.__rustc::__rust_alloc>
00007FF7C3EE8D2B | 48:85C0         | test rax,rax

Rust runtime is calling __rust_alloc to allocate heap memory:

rcx, rdx = allocation size and alignment.

rax = pointer to allocated memory.

test rax, rax checks if allocation failed (None if null).

Copying strings / data

00007FF7C3EE8D37 | 48:8D93 80000000 | lea rdx,qword ptr ds:[rbx+80]
00007FF7C3EE8D44 | 48:89C1         | mov rcx,rax
00007FF7C3EE8D47 | E8 10BE0100     | call <windivert.memcpy>

Channel setup and threads

00007FF7C3EE8D99 | 4C:8D43 68 | lea r8,qword ptr ds:[rbx+68]
00007FF7C3EE8D9D | E8 CE130000 | call <windivert.std::thread::Builder::spawn_unchecked>

This is spawning a thread in Rust.

Arguments: stack pointers, local buffer, and channel sender (tx) are passed as thread closure environment.

Rust runtime handles closure captures in memory and passes a pointer to spawn_unchecked.

00007FF7C3EE83E0 | 55                               | push rbp                                                                                     |
00007FF7C3EE83E1 | 41:57                            | push r15                                                                                     |
00007FF7C3EE83E3 | 41:56                            | push r14                                                                                     |
00007FF7C3EE83E5 | 41:55                            | push r13                                                                                     |
00007FF7C3EE83E7 | 41:54                            | push r12                                                                                     |
00007FF7C3EE83E9 | 56                               | push rsi                                                                                     |
00007FF7C3EE83EA | 57                               | push rdi                                                                                     |
00007FF7C3EE83EB | 53                               | push rbx                                                                                     |
00007FF7C3EE83EC | 48:81EC 28010000                 | sub rsp,128                                                                                  |
00007FF7C3EE83F3 | 48:8DAC24 80000000               | lea rbp,qword ptr ss:[rsp+80]                                                                |
00007FF7C3EE83FB | 48:C785 A0000000 FEFFFFFF        | mov qword ptr ss:[rbp+A0],FFFFFFFFFFFFFFFE                                                   |
00007FF7C3EE8406 | 48:894D 68                       | mov qword ptr ss:[rbp+68],rcx                                                                |
00007FF7C3EE840A | 48:8D41 10                       | lea rax,qword ptr ds:[rcx+10]                                                                | rax:&"tcp.SrcPort == "
00007FF7C3EE840E | 48:8945 40                       | mov qword ptr ss:[rbp+40],rax                                                                |
00007FF7C3EE8412 | 48:8D05 77B60100                 | lea rax,qword ptr ds:[<core::fmt::num::imp::_$LT$impl$u20$core..fmt..Display$u20$for$u20$i32 | rax:&"tcp.SrcPort == "
00007FF7C3EE8419 | 48:8945 48                       | mov qword ptr ss:[rbp+48],rax                                                                | [rbp+48]:core::fmt::num::imp::_$LT$impl$u20$core..fmt..Display$u20$for$u20$i32$GT$::fmt::h2816672a2b9a7a5a
00007FF7C3EE841D | 48:8D05 84FD0100                 | lea rax,qword ptr ds:[7FF7C3F081A8]                                                          | rax:&"tcp.SrcPort == ", 00007FF7C3F081A8:&"tcp.SrcPort == "
00007FF7C3EE8424 | 48:8945 C0                       | mov qword ptr ss:[rbp-40],rax                                                                | [rbp-40]:&"tcp.SrcPort == "
00007FF7C3EE8428 | 48:C745 C8 01000000              | mov qword ptr ss:[rbp-38],1                                                                  |
00007FF7C3EE8430 | 48:C745 E0 00000000              | mov qword ptr ss:[rbp-20],0                                                                  |
00007FF7C3EE8438 | 48:8D45 40                       | lea rax,qword ptr ss:[rbp+40]                                                                |
00007FF7C3EE843C | 48:8945 D0                       | mov qword ptr ss:[rbp-30],rax                                                                |
00007FF7C3EE8440 | 48:C745 D8 01000000              | mov qword ptr ss:[rbp-28],1                                                                  |
00007FF7C3EE8448 | 48:8D8D 80000000                 | lea rcx,qword ptr ss:[rbp+80]                                                                |
00007FF7C3EE844F | 48:8D55 C0                       | lea rdx,qword ptr ss:[rbp-40]                                                                | [rbp-40]:&"tcp.SrcPort == "
00007FF7C3EE8453 | E8 886F0100                      | call <windivert.alloc::fmt::format::format_inner::hfc6b6ff323357fe5>                         |
00007FF7C3EE8458 | 0F1085 80000000                  | movups xmm0,xmmword ptr ss:[rbp+80]                                                          |
00007FF7C3EE845F | 0F2945 40                        | movaps xmmword ptr ss:[rbp+40],xmm0                                                          |
00007FF7C3EE8463 | 48:8B85 90000000                 | mov rax,qword ptr ss:[rbp+90]                                                                |
00007FF7C3EE846A | 48:8945 50                       | mov qword ptr ss:[rbp+50],rax                                                                |
00007FF7C3EE846E | 48:8D8D 80000000                 | lea rcx,qword ptr ss:[rbp+80]                                                                |
00007FF7C3EE8475 | 48:8D55 40                       | lea rdx,qword ptr ss:[rbp+40]                                                                |
00007FF7C3EE8479 | 41:B9 05000000                   | mov r9d,5                                                                                    |
00007FF7C3EE847F | 45:31C0                          | xor r8d,r8d                                                                                  |
00007FF7C3EE8482 | E8 391B0000                      | call <windivert.windivert::divert::WinDivert$LT$windivert..layer..NetworkLayer$GT$::network: |
00007FF7C3EE8487 | 48:B8 0700000000000080           | mov rax,8000000000000007                                                                     | rax:&"tcp.SrcPort == "
00007FF7C3EE8491 | 48:3985 80000000                 | cmp qword ptr ss:[rbp+80],rax                                                                |
00007FF7C3EE8498 | 0F85 A5020000                    | jne windivert.7FF7C3EE8743                                                                   |
00007FF7C3EE849E | 48:8B85 88000000                 | mov rax,qword ptr ss:[rbp+88]                                                                |
00007FF7C3EE84A5 | 8B8D 90000000                    | mov ecx,dword ptr ss:[rbp+90]                                                                |
00007FF7C3EE84AB | 48:8945 B0                       | mov qword ptr ss:[rbp-50],rax                                                                |
00007FF7C3EE84AF | 894D B8                          | mov dword ptr ss:[rbp-48],ecx                                                                |
00007FF7C3EE84B2 | 0FB605 88DC0200                  | movzx eax,byte ptr ds:[<__rust_no_alloc_shim_is_unstable>]                                   |
00007FF7C3EE84B9 | B9 FFFF0000                      | mov ecx,FFFF                                                                                 |
00007FF7C3EE84BE | BA 01000000                      | mov edx,1                                                                                    |
00007FF7C3EE84C3 | E8 382F0000                      | call <windivert.__rustc::__rust_alloc_zeroed>                                                |
00007FF7C3EE84C8 | 48:8945 70                       | mov qword ptr ss:[rbp+70],rax                                                                |
00007FF7C3EE84CC | 48:85C0                          | test rax,rax                                                                                 | rax:&"tcp.SrcPort == "
00007FF7C3EE84CF | 75 1B                            | jne windivert.7FF7C3EE84EC                                                                   |
00007FF7C3EE84D1 | 4C:8D05 08FD0100                 | lea r8,qword ptr ds:[7FF7C3F081E0]                                                           | 00007FF7C3F081E0:&"src\\main.rs"
00007FF7C3EE84D8 | B9 01000000                      | mov ecx,1                                                                                    |
00007FF7C3EE84DD | BA FFFF0000                      | mov edx,FFFF                                                                                 |
00007FF7C3EE84E2 | E8 6CDB0100                      | call <windivert.alloc::raw_vec::handle_error::h5d55154af761dff4>                             |
00007FF7C3EE84E7 | E9 B1020000                      | jmp windivert.7FF7C3EE879D                                                                   |
00007FF7C3EE84EC | 48:8D75 C0                       | lea rsi,qword ptr ss:[rbp-40]                                                                | [rbp-40]:&"tcp.SrcPort == "
00007FF7C3EE84F0 | 48:8D7D B0                       | lea rdi,qword ptr ss:[rbp-50]                                                                |
00007FF7C3EE84F4 | 49:BD 0100000000000080           | mov r13,8000000000000001                                                                     |
00007FF7C3EE84FE | 48:8D9D 80000000                 | lea rbx,qword ptr ss:[rbp+80]                                                                |
00007FF7C3EE8505 | 41:BC 01000000                   | mov r12d,1                                                                                   |
00007FF7C3EE850B | EB 14                            | jmp windivert.7FF7C3EE8521                                                                   |
00007FF7C3EE850D | 0F1F00                           | nop dword ptr ds:[rax],eax                                                                   |
00007FF7C3EE8510 | 48:8D0455 00000000               | lea rax,qword ptr ds:[rdx*2]                                                                 | rax:&"tcp.SrcPort == "
00007FF7C3EE8518 | 48:85C0                          | test rax,rax                                                                                 | rax:&"tcp.SrcPort == "
00007FF7C3EE851B | 0F85 5F010000                    | jne windivert.7FF7C3EE8680                                                                   |
00007FF7C3EE8521 | 41:B9 FFFF0000                   | mov r9d,FFFF                                                                                 |
00007FF7C3EE8527 | 48:89F1                          | mov rcx,rsi                                                                                  |
00007FF7C3EE852A | 48:89FA                          | mov rdx,rdi                                                                                  |
00007FF7C3EE852D | 4C:8B45 70                       | mov r8,qword ptr ss:[rbp+70]                                                                 |
00007FF7C3EE8531 | E8 EA2E0000                      | call <windivert.windivert::divert::blocking::_$LT$impl$u20$windivert..divert..WinDivert$LT$w |
00007FF7C3EE8536 | 48:8B45 C0                       | mov rax,qword ptr ss:[rbp-40]                                                                | [rbp-40]:&"tcp.SrcPort == "
00007FF7C3EE853A | 4C:39E8                          | cmp rax,r13                                                                                  | rax:&"tcp.SrcPort == "
00007FF7C3EE853D | 0F84 51010000                    | je windivert.7FF7C3EE8694                                                                    |
00007FF7C3EE8543 | 48:8945 60                       | mov qword ptr ss:[rbp+60],rax                                                                |
00007FF7C3EE8547 | 48:8B45 C8                       | mov rax,qword ptr ss:[rbp-38]                                                                |
00007FF7C3EE854B | 48:8945 78                       | mov qword ptr ss:[rbp+78],rax                                                                |
00007FF7C3EE854F | 4C:8B7D D0                       | mov r15,qword ptr ss:[rbp-30]                                                                |
00007FF7C3EE8553 | 4D:85FF                          | test r15,r15                                                                                 |
00007FF7C3EE8556 | 0F88 27020000                    | js windivert.7FF7C3EE8783                                                                    |
00007FF7C3EE855C | 74 22                            | je windivert.7FF7C3EE8580                                                                    |
00007FF7C3EE855E | 0FB605 DCDB0200                  | movzx eax,byte ptr ds:[<__rust_no_alloc_shim_is_unstable>]                                   |
00007FF7C3EE8565 | BA 01000000                      | mov edx,1                                                                                    |
00007FF7C3EE856A | 4C:89F9                          | mov rcx,r15                                                                                  |
00007FF7C3EE856D | E8 5E2E0000                      | call <windivert.__rustc::__rust_alloc>                                                       |
00007FF7C3EE8572 | 48:85C0                          | test rax,rax                                                                                 | rax:&"tcp.SrcPort == "
00007FF7C3EE8575 | 0F84 0D020000                    | je windivert.7FF7C3EE8788                                                                    |
00007FF7C3EE857B | 49:89C6                          | mov r14,rax                                                                                  | rax:&"tcp.SrcPort == "
00007FF7C3EE857E | EB 06                            | jmp windivert.7FF7C3EE8586                                                                   |
00007FF7C3EE8580 | 41:BE 01000000                   | mov r14d,1                                                                                   |
00007FF7C3EE8586 | 4C:89F1                          | mov rcx,r14                                                                                  |
00007FF7C3EE8589 | 48:8B55 78                       | mov rdx,qword ptr ss:[rbp+78]                                                                |
00007FF7C3EE858D | 4D:89F8                          | mov r8,r15                                                                                   |
00007FF7C3EE8590 | E8 C7C50100                      | call <windivert.memcpy>                                                                      |
00007FF7C3EE8595 | 48:8B4D 68                       | mov rcx,qword ptr ss:[rbp+68]                                                                |
00007FF7C3EE8599 | 48:8B01                          | mov rax,qword ptr ds:[rcx]                                                                   | rax:&"tcp.SrcPort == "
00007FF7C3EE859C | 48:8B51 08                       | mov rdx,qword ptr ds:[rcx+8]                                                                 |
00007FF7C3EE85A0 | 48:83F8 02                       | cmp rax,2                                                                                    | rax:&"tcp.SrcPort == "
00007FF7C3EE85A4 | 74 3A                            | je windivert.7FF7C3EE85E0                                                                    |
00007FF7C3EE85A6 | 83F8 01                          | cmp eax,1                                                                                    |
00007FF7C3EE85A9 | 75 65                            | jne windivert.7FF7C3EE8610                                                                   |
00007FF7C3EE85AB | 4C:89BD 80000000                 | mov qword ptr ss:[rbp+80],r15                                                                |
00007FF7C3EE85B2 | 4C:89B5 88000000                 | mov qword ptr ss:[rbp+88],r14                                                                |
00007FF7C3EE85B9 | 4C:89BD 90000000                 | mov qword ptr ss:[rbp+90],r15                                                                |
00007FF7C3EE85C0 | C74424 20 00CA9A3B               | mov dword ptr ss:[rsp+20],3B9ACA00                                                           |
00007FF7C3EE85C8 | 48:89F1                          | mov rcx,rsi                                                                                  |
00007FF7C3EE85CB | 49:89D8                          | mov r8,rbx                                                                                   |
00007FF7C3EE85CE | E8 2D9DFFFF                      | call <windivert.std::sync::mpmc::list::Channel$LT$T$GT$::send::hccb9013442662364>            |
00007FF7C3EE85D3 | EB 63                            | jmp windivert.7FF7C3EE8638                                                                   |
00007FF7C3EE85D5 | 66662E:0F1F8400 00000000         | nop word ptr ds:[rax+rax],ax                                                                 |
00007FF7C3EE85E0 | 4C:89BD 80000000                 | mov qword ptr ss:[rbp+80],r15                                                                |
00007FF7C3EE85E7 | 4C:89B5 88000000                 | mov qword ptr ss:[rbp+88],r14                                                                |
00007FF7C3EE85EE | 4C:89BD 90000000                 | mov qword ptr ss:[rbp+90],r15                                                                |
00007FF7C3EE85F5 | C74424 20 00CA9A3B               | mov dword ptr ss:[rsp+20],3B9ACA00                                                           |
00007FF7C3EE85FD | 48:89F1                          | mov rcx,rsi                                                                                  |
00007FF7C3EE8600 | 49:89D8                          | mov r8,rbx                                                                                   |
00007FF7C3EE8603 | E8 28D3FFFF                      | call <windivert.std::sync::mpmc::zero::Channel$LT$T$GT$::send::h6f8bab36c27d44da>            |
00007FF7C3EE8608 | EB 2E                            | jmp windivert.7FF7C3EE8638                                                                   |
00007FF7C3EE860A | 66:0F1F4400 00                   | nop word ptr ds:[rax+rax],ax                                                                 |
00007FF7C3EE8610 | 4C:89BD 80000000                 | mov qword ptr ss:[rbp+80],r15                                                                |
00007FF7C3EE8617 | 4C:89B5 88000000                 | mov qword ptr ss:[rbp+88],r14                                                                |
00007FF7C3EE861E | 4C:89BD 90000000                 | mov qword ptr ss:[rbp+90],r15                                                                |
00007FF7C3EE8625 | C74424 20 00CA9A3B               | mov dword ptr ss:[rsp+20],3B9ACA00                                                           |
00007FF7C3EE862D | 48:89F1                          | mov rcx,rsi                                                                                  |
00007FF7C3EE8630 | 49:89D8                          | mov r8,rbx                                                                                   |
00007FF7C3EE8633 | E8 C8ADFFFF                      | call <windivert.std::sync::mpmc::array::Channel$LT$T$GT$::send::h3f0d389a1efe5b98>           |
00007FF7C3EE8638 | 48:8B45 C0                       | mov rax,qword ptr ss:[rbp-40]                                                                | [rbp-40]:&"tcp.SrcPort == "
00007FF7C3EE863C | 48:83F8 02                       | cmp rax,2                                                                                    | rax:&"tcp.SrcPort == "
00007FF7C3EE8640 | 48:8B55 60                       | mov rdx,qword ptr ss:[rbp+60]                                                                |
00007FF7C3EE8644 | 0F84 C6FEFFFF                    | je windivert.7FF7C3EE8510                                                                    |
00007FF7C3EE864A | 48:8B4D C8                       | mov rcx,qword ptr ss:[rbp-38]                                                                |
00007FF7C3EE864E | A8 01                            | test al,1                                                                                    |
00007FF7C3EE8650 | 0F84 C3000000                    | je windivert.7FF7C3EE8719                                                                    |
00007FF7C3EE8656 | 48:8D45 C8                       | lea rax,qword ptr ss:[rbp-38]                                                                |
00007FF7C3EE865A | 0F1040 08                        | movups xmm0,xmmword ptr ds:[rax+8]                                                           | rax+08:anon.95dd94260625f633aaffbc1dd64e9bca.29.llvm.18142701166963205077+3F8
00007FF7C3EE865E | 0F2985 80000000                  | movaps xmmword ptr ss:[rbp+80],xmm0                                                          |
00007FF7C3EE8665 | 48:89C8                          | mov rax,rcx                                                                                  | rax:&"tcp.SrcPort == "
00007FF7C3EE8668 | 48:F7D8                          | neg rax                                                                                      | rax:&"tcp.SrcPort == "
00007FF7C3EE866B | 0F80 9FFEFFFF                    | jo windivert.7FF7C3EE8510                                                                    |
00007FF7C3EE8671 | EB 6A                            | jmp windivert.7FF7C3EE86DD                                                                   |
00007FF7C3EE8673 | 666666662E:0F1F8400 00000000     | nop word ptr ds:[rax+rax],ax                                                                 |
00007FF7C3EE8680 | 41:B8 01000000                   | mov r8d,1                                                                                    |
00007FF7C3EE8686 | 48:8B4D 78                       | mov rcx,qword ptr ss:[rbp+78]                                                                |
00007FF7C3EE868A | E8 512D0000                      | call <windivert.__rustc::__rust_dealloc>                                                     |
00007FF7C3EE868F | E9 8DFEFFFF                      | jmp windivert.7FF7C3EE8521                                                                   |
00007FF7C3EE8694 | 48:8D45 C8                       | lea rax,qword ptr ss:[rbp-38]                                                                |
00007FF7C3EE8698 | 0F1000                           | movups xmm0,xmmword ptr ds:[rax]                                                             | rax:&"tcp.SrcPort == "
00007FF7C3EE869B | 0F1048 10                        | movups xmm1,xmmword ptr ds:[rax+10]                                                          | rax+10:"src\\main.rs"
00007FF7C3EE869F | 0F298D 90000000                  | movaps xmmword ptr ss:[rbp+90],xmm1                                                          |
00007FF7C3EE86A6 | 0F2985 80000000                  | movaps xmmword ptr ss:[rbp+80],xmm0                                                          |
00007FF7C3EE86AD | 48:8D05 44FB0100                 | lea rax,qword ptr ds:[7FF7C3F081F8]                                                          | rax:&"tcp.SrcPort == ", 00007FF7C3F081F8:&"src\\main.rs"
00007FF7C3EE86B4 | 48:894424 20                     | mov qword ptr ss:[rsp+20],rax                                                                |
00007FF7C3EE86B9 | 48:8D0D 90F70100                 | lea rcx,qword ptr ds:[7FF7C3F07E50]                                                          | 00007FF7C3F07E50:"called `Result::unwrap()` on an `Err` value"
00007FF7C3EE86C0 | 4C:8D0D 69F70100                 | lea r9,qword ptr ds:[7FF7C3F07E30]                                                           |
00007FF7C3EE86C7 | 4C:8D85 80000000                 | lea r8,qword ptr ss:[rbp+80]                                                                 |
00007FF7C3EE86CE | BA 2B000000                      | mov edx,2B                                                                                   | 2B:'+'
00007FF7C3EE86D3 | E8 28DE0100                      | call <windivert.core::result::unwrap_failed::h70751bb42e9051bd>                              |
00007FF7C3EE86D8 | E9 C0000000                      | jmp windivert.7FF7C3EE879D                                                                   |
00007FF7C3EE86DD | 48:894D C0                       | mov qword ptr ss:[rbp-40],rcx                                                                | [rbp-40]:&"tcp.SrcPort == "
00007FF7C3EE86E1 | 0F2885 80000000                  | movaps xmm0,xmmword ptr ss:[rbp+80]                                                          |
00007FF7C3EE86E8 | 0F1145 C8                        | movups xmmword ptr ss:[rbp-38],xmm0                                                          |
00007FF7C3EE86EC | 48:8D05 1DFB0100                 | lea rax,qword ptr ds:[7FF7C3F08210]                                                          | rax:&"tcp.SrcPort == ", 00007FF7C3F08210:&"src\\main.rs"
00007FF7C3EE86F3 | 48:894424 20                     | mov qword ptr ss:[rsp+20],rax                                                                |
00007FF7C3EE86F8 | 48:8D0D 51F70100                 | lea rcx,qword ptr ds:[7FF7C3F07E50]                                                          | 00007FF7C3F07E50:"called `Result::unwrap()` on an `Err` value"
00007FF7C3EE86FF | 4C:8D0D 7AF70100                 | lea r9,qword ptr ds:[<&sub_7FF7C3EE7D30>]                                                    |
00007FF7C3EE8706 | 4C:8D45 C0                       | lea r8,qword ptr ss:[rbp-40]                                                                 | [rbp-40]:&"tcp.SrcPort == "
00007FF7C3EE870A | BA 2B000000                      | mov edx,2B                                                                                   | 2B:'+'
00007FF7C3EE870F | E8 ECDD0100                      | call <windivert.core::result::unwrap_failed::h70751bb42e9051bd>                              |
00007FF7C3EE8714 | E9 84000000                      | jmp windivert.7FF7C3EE879D                                                                   |
00007FF7C3EE8719 | 48:8945 30                       | mov qword ptr ss:[rbp+30],rax                                                                |
00007FF7C3EE871D | 48:894D 28                       | mov qword ptr ss:[rbp+28],rcx                                                                |
00007FF7C3EE8721 | 48:8B45 D0                       | mov rax,qword ptr ss:[rbp-30]                                                                |
00007FF7C3EE8725 | 48:8945 38                       | mov qword ptr ss:[rbp+38],rax                                                                | [rbp+38]:std::thread::spawnhook::ChildSpawnHooks::run+17C
00007FF7C3EE8729 | 48:8D0D 60FE0100                 | lea rcx,qword ptr ds:[<anon.70de80080aa0578d8e2c0b1b642816f1.8.llvm.9175985875024411532>]    | 00007FF7C3F08590:"internal error: entered unreachable code"
00007FF7C3EE8730 | 4C:8D05 29FF0100                 | lea r8,qword ptr ds:[<anon.70de80080aa0578d8e2c0b1b642816f1.11.llvm.9175985875024411532>]    | 00007FF7C3F08660:&"C:\\Users\\jozef\\.rustup\\toolchains\\stable-x86_64-pc-windows-msvc\\lib/rustlib/src/rust\\library\\std\\src\\sync\\mpmc\\mod.rs"
00007FF7C3EE8737 | BA 28000000                      | mov edx,28                                                                                   | 28:'('
00007FF7C3EE873C | E8 3FDB0100                      | call <windivert.core::panicking::panic::h0cc6c70cb61d6977>                                   |
00007FF7C3EE8741 | EB 5A                            | jmp windivert.7FF7C3EE879D                                                                   |
00007FF7C3EE8743 | 0F1085 80000000                  | movups xmm0,xmmword ptr ss:[rbp+80]                                                          |
00007FF7C3EE874A | 0F108D 90000000                  | movups xmm1,xmmword ptr ss:[rbp+90]                                                          |
00007FF7C3EE8751 | 0F294D D0                        | movaps xmmword ptr ss:[rbp-30],xmm1                                                          |
00007FF7C3EE8755 | 0F2945 C0                        | movaps xmmword ptr ss:[rbp-40],xmm0                                                          |
00007FF7C3EE8759 | 48:8D05 68FA0100                 | lea rax,qword ptr ds:[7FF7C3F081C8]                                                          | rax:&"tcp.SrcPort == ", 00007FF7C3F081C8:&"src\\main.rs"
00007FF7C3EE8760 | 48:894424 20                     | mov qword ptr ss:[rsp+20],rax                                                                |
00007FF7C3EE8765 | 48:8D0D E4F60100                 | lea rcx,qword ptr ds:[7FF7C3F07E50]                                                          | 00007FF7C3F07E50:"called `Result::unwrap()` on an `Err` value"
00007FF7C3EE876C | 4C:8D0D BDF60100                 | lea r9,qword ptr ds:[7FF7C3F07E30]                                                           |
00007FF7C3EE8773 | 4C:8D45 C0                       | lea r8,qword ptr ss:[rbp-40]                                                                 | [rbp-40]:&"tcp.SrcPort == "
00007FF7C3EE8777 | BA 2B000000                      | mov edx,2B                                                                                   | 2B:'+'
00007FF7C3EE877C | E8 7FDD0100                      | call <windivert.core::result::unwrap_failed::h70751bb42e9051bd>                              |
00007FF7C3EE8781 | EB 1A                            | jmp windivert.7FF7C3EE879D                                                                   |
00007FF7C3EE8783 | 45:31E4                          | xor r12d,r12d                                                                                |
00007FF7C3EE8786 | EB 03                            | jmp windivert.7FF7C3EE878B                                                                   |
00007FF7C3EE8788 | 4D:89FE                          | mov r14,r15                                                                                  |
00007FF7C3EE878B | 4C:8D05 96F90100                 | lea r8,qword ptr ds:[7FF7C3F08128]                                                           | 00007FF7C3F08128:&"C:\\Users\\jozef\\.rustup\\toolchains\\stable-x86_64-pc-windows-msvc\\lib/rustlib/src/rust\\library\\alloc\\src\\slice.rs"
00007FF7C3EE8792 | 4C:89E1                          | mov rcx,r12                                                                                  |
00007FF7C3EE8795 | 4C:89F2                          | mov rdx,r14                                                                                  |
00007FF7C3EE8798 | E8 B6D80100                      | call <windivert.alloc::raw_vec::handle_error::h5d55154af761dff4>                             |
00007FF7C3EE879D | 0F0B                             | ud2                                                                                          |
00007FF7C3EE879F | 90                               | nop                                                                                          |
00007FF7C3EE87A0 | 48:895424 10                     | mov qword ptr ss:[rsp+10],rdx                                                                |
00007FF7C3EE87A5 | 55                               | push rbp                                                                                     |
00007FF7C3EE87A6 | 41:57                            | push r15                                                                                     |
00007FF7C3EE87A8 | 41:56                            | push r14                                                                                     |
00007FF7C3EE87AA | 41:55                            | push r13                                                                                     |
00007FF7C3EE87AC | 41:54                            | push r12                                                                                     |
00007FF7C3EE87AE | 56                               | push rsi                                                                                     |
00007FF7C3EE87AF | 57                               | push rdi                                                                                     |
00007FF7C3EE87B0 | 53                               | push rbx                                                                                     |
00007FF7C3EE87B1 | 48:83EC 28                       | sub rsp,28                                                                                   |
00007FF7C3EE87B5 | 48:8DAA 80000000                 | lea rbp,qword ptr ds:[rdx+80]                                                                |
00007FF7C3EE87BC | 48:8B4D 68                       | mov rcx,qword ptr ss:[rbp+68]                                                                |
00007FF7C3EE87C0 | 48:8B01                          | mov rax,qword ptr ds:[rcx]                                                                   | rax:&"tcp.SrcPort == "
00007FF7C3EE87C3 | 48:83C1 08                       | add rcx,8                                                                                    |
00007FF7C3EE87C7 | 48:85C0                          | test rax,rax                                                                                 | rax:&"tcp.SrcPort == "
00007FF7C3EE87CA | 74 0C                            | je windivert.7FF7C3EE87D8                                                                    |
00007FF7C3EE87CC | 83F8 01                          | cmp eax,1                                                                                    |
00007FF7C3EE87CF | 75 6B                            | jne windivert.7FF7C3EE883C                                                                   |
00007FF7C3EE87D1 | E8 AAE7FFFF                      | call <windivert.std::sync::mpmc::counter::Sender$LT$C$GT$::release::h556aa944d0fa04c6>       |
00007FF7C3EE87D6 | EB 69                            | jmp windivert.7FF7C3EE8841                                                                   |
00007FF7C3EE87D8 | 48:8B31                          | mov rsi,qword ptr ds:[rcx]                                                                   |
00007FF7C3EE87DB | F048:FF8E 00020000               | lock dec qword ptr ds:[rsi+200]                                                              |
00007FF7C3EE87E3 | 75 5C                            | jne windivert.7FF7C3EE8841                                                                   |
00007FF7C3EE87E5 | 48:8B86 80000000                 | mov rax,qword ptr ds:[rsi+80]                                                                | rax:&"tcp.SrcPort == "
00007FF7C3EE87EC | 48:8B8E 90010000                 | mov rcx,qword ptr ds:[rsi+190]                                                               |
00007FF7C3EE87F3 | 666666662E:0F1F8400 00000000     | nop word ptr ds:[rax+rax],ax                                                                 |
00007FF7C3EE8800 | 48:89C2                          | mov rdx,rax                                                                                  | rax:&"tcp.SrcPort == "
00007FF7C3EE8803 | 48:09CA                          | or rdx,rcx                                                                                   |
00007FF7C3EE8806 | F048:0FB196 80000000             | lock cmpxchg qword ptr ds:[rsi+80],rdx                                                       |
00007FF7C3EE880F | 75 EF                            | jne windivert.7FF7C3EE8800                                                                   |
00007FF7C3EE8811 | 48:8586 90010000                 | test qword ptr ds:[rsi+190],rax                                                              | rax:&"tcp.SrcPort == "
00007FF7C3EE8818 | 75 0C                            | jne windivert.7FF7C3EE8826                                                                   |
00007FF7C3EE881A | 48:8D8E 40010000                 | lea rcx,qword ptr ds:[rsi+140]                                                               |
00007FF7C3EE8821 | E8 CAB2FFFF                      | call <windivert.std::sync::mpmc::waker::SyncWaker::disconnect::h6ad45fdb3df37a47 (.llvm.9322 |
00007FF7C3EE8826 | B0 01                            | mov al,1                                                                                     |
00007FF7C3EE8828 | 8686 10020000                    | xchg byte ptr ds:[rsi+210],al                                                                |
00007FF7C3EE882E | 84C0                             | test al,al                                                                                   |
00007FF7C3EE8830 | 74 0F                            | je windivert.7FF7C3EE8841                                                                    |
00007FF7C3EE8832 | 48:89F1                          | mov rcx,rsi                                                                                  |
00007FF7C3EE8835 | E8 E6EDFFFF                      | call <windivert.core::ptr::drop_in_place$LT$alloc..boxed..Box$LT$std..sync..mpmc..counter..C |
00007FF7C3EE883A | EB 05                            | jmp windivert.7FF7C3EE8841                                                                   |
00007FF7C3EE883C | E8 8FE8FFFF                      | call <windivert.std::sync::mpmc::counter::Sender$LT$C$GT$::release::h9ff499d21cc3324b>       |
00007FF7C3EE8841 | 90                               | nop                                                                                          |
00007FF7C3EE8842 | 48:83C4 28                       | add rsp,28                                                                                   |
00007FF7C3EE8846 | 5B                               | pop rbx                                                                                      |
00007FF7C3EE8847 | 5F                               | pop rdi                                                                                      |
00007FF7C3EE8848 | 5E                               | pop rsi                                                                                      |
00007FF7C3EE8849 | 41:5C                            | pop r12                                                                                      |
00007FF7C3EE884B | 41:5D                            | pop r13                                                                                      |
00007FF7C3EE884D | 41:5E                            | pop r14                                                                                      |
00007FF7C3EE884F | 41:5F                            | pop r15                                                                                      |
00007FF7C3EE8851 | 5D                               | pop rbp                                                                                      |
00007FF7C3EE8852 | C3                               | ret                                                                                          |

source

peanalyse -i calling-conventions.exe --entry
Architecture: Pe64
AddressOfEntryPoint (RVA): 0x000168A0
ImageBase:                0x140000000
EntryPoint (VA):          0x1400168A0
peanalyse -i calling-conventions.exe --disassemble-from-addr=0x1400016B0
0x1400016EA: mov        dword ptr [rsp + 0x38], eax
0x1400016EE: mov        ecx, 1
0x1400016F3: mov        edx, 2
0x1400016F8: mov        r8d, 3
0x1400016FE: mov        r9d, 4
0x140001704: mov        dword ptr [rsp + 0x20], 5
0x14000170C: mov        dword ptr [rsp + 0x28], 6
0x140001714: mov        dword ptr [rsp + 0x30], 7
0x14000171C: call       0x1400012c0

Windows x64 calling convention:

  • Registers: RCX, RDX, R8, R9 for the first 4 parameters.
  • Stack: parameters 5, 6, 7 go on the stack at offsets from RSP.
0x14000188F: mov        dword ptr [rsp + 0x44], eax
0x140001893: mov        dword ptr [rsp + 0x48], 1
0x14000189B: mov        dword ptr [rsp + 0x4c], 2
0x1400018A3: mov        dword ptr [rsp + 0x50], 3
0x1400018AB: mov        dword ptr [rsp + 0x54], 4
0x1400018B3: mov        dword ptr [rsp + 0x58], 5
0x1400018BB: mov        dword ptr [rsp + 0x5c], 6
0x1400018C3: mov        dword ptr [rsp + 0x60], 7
0x1400018CB: mov        dword ptr [rsp + 0x64], 8
0x1400018D3: mov        rax, qword ptr [rsp + 0x48]
0x1400018D8: mov        qword ptr [rsp + 0x1a8], rax
0x1400018E0: mov        rax, qword ptr [rsp + 0x50]
0x1400018E5: mov        qword ptr [rsp + 0x1b0], rax
0x1400018ED: mov        rax, qword ptr [rsp + 0x58]
0x1400018F2: mov        qword ptr [rsp + 0x1b8], rax
0x1400018FA: mov        rax, qword ptr [rsp + 0x60]
0x1400018FF: mov        qword ptr [rsp + 0x1c0], rax
0x140001907: lea        rcx, [rsp + 0x1a8]
0x14000190F: call       0x1400011b0

On x86-64 Windows (MSVC calling convention):

  • If the struct fits in 1–2 registers (≤16 bytes), it is passed in registers.
  • If the struct is larger than 16 bytes, it is passed by reference: the caller allocates space on the stack and passes a pointer.
  • The callee then reads fields via that pointer.
  • BigStruct is 32 bytes, so rust will pass a pointer to struct rather than copying all fields into registers. -- lea rcx, [rsp + ...] or mov rcx, &struct_on_stack before the call.

This program generates a random creature variant and prints its name using a precomputed lookup table. The Rust enum is transmuted from a random byte, and a match on the enum is replaced by a table-based string lookup in release mode.

source

call rand::rngs::thread::rng
mov rsi, rax
mov [rbp+local_20], rax

Initializes ThreadRng and stores its pointer in rsi and a local variable.

mov rcx, [rsi + 0x150]
cmp rcx, 0x40
jc SHORT LAB_BUFFER_OK

Loads the RNG buffer index and checks if it needs a refill.

lea r8, [rax + 0x10]
add rax, 0x110
mov rcx, [rsi + 0x148]
test rcx, rcx
jle SHORT LAB_REPLENISH_FALLBACK
add rcx, -0x100
mov [rsi + 0x148], rcx
mov rcx, rax
mov edx, 0x6
call rand_chacha::guts::refill_wide
jmp SHORT LAB_CONTINUE
LAB_REPLENISH_FALLBACK:
mov rcx, rax
mov rdx, r8
call FUN_140001050

Refills the ChaCha RNG buffer if exhausted. Fallback path for insufficient buffer, calls internal RNG helper.

lea rcx, [DAT_STRING_OFFSET_TABLE]
movsxd rdx, [rcx + rax*4]
add rdx, rcx
lea rcx, [DAT_STRING_PTR_TABLE]
mov rax, [rcx + rax*8]
mov [rbp + local_30], rdx
mov [rbp + local_28], rax

Maps the enum variant to a string pointer using precomputed offset and pointer tables.

[rcx + rax*4]

  • The offset table uses 32-bit entries (4 bytes each).
  • rax holds the random enum variant (0–31).
  • Multiplying rax by 4 gives the byte offset for the correct entry.
  • MOVSXD rdx, [rcx + rax*4] loads the 32-bit offset for the variant and sign-extends it to 64-bit.
  • This offset is relative to the base of the string table, so adding rdx + rcx produces the absolute string address.

[rcx + rax*8]

  • The pointer table uses 64-bit entries (8 bytes each).
  • Again, rax is the variant index.
  • Multiplying by 8 gives the byte offset of the correct pointer.
  • MOV rax, [rcx + rax*8] loads the full 64-bit pointer directly, no sign-extension needed.
lea rax, [rbp + local_30]
mov [rbp + local_40], rax
lea rax, [LAB_140001030]
mov [rbp + local_38], rax
lea rax, [DAT_CONST_1]
mov [rbp + local_70], rax
mov [rbp + local_68], 2
mov [rbp + local_50], 0
lea rax, [rbp + local_40]
mov [rbp + local_60], rax
mov [rbp + local_58], 1
lea rcx, [rbp + local_70]
call std::io::stdio::_print

Prepares arguments and calls _print to output the creature name.

mov rax, [rbp + local_20]
dec [rax]
jz SHORT LAB_DROP
add rsp, 0x88
pop rsi
pop rbp
ret
mov rax, [rbp + local_20]

Loads the pointer to the ThreadRng instance, which is stored in local_20.

dec [rax]

Decrements the reference count of the ThreadRng. ThreadRng is behind an Rc (reference-counted smart pointer).

jz SHORT LAB_DROP

LAB_DROP:
lea rcx, [rbp + local_20]
call alloc::rc::Rc<T,A>::drop_slow

If the reference count reached zero, jump to drop_slow to free the memory. If not zero, skip and just clean the stack.

add rsp, 0x88; pop rsi; pop rbp; ret

Standard stack cleanup and return from main if the RNG instance is still alive (ref count > 0).

This exercise tauri app template.

source

tauri::plugin::Builder<R,C>::new _ZN5tauri6plugin20Builder$LT$R$C$C$GT$3new

140096e10 e8 5b 4d 4f 00 CALL std::hash::random::impl$0::new::KEYS::constant
140096e15 49 89 c6        MOV R14,RAX
140096e18 80 78 10 01     CMP byte ptr [RAX+0x10],0x1
  • Part of HashMap/FxHasher initialization.
  • Returns a pointer (RAX → R14) to the random seed/keys used internally by the plugin builder.
140096e22 49 8b 06        MOV RAX,qword ptr [R14]
140096e25 49 8b 56 08     MOV RDX,qword ptr [R14+0x8]
140096e29 48 8d 48 01     LEA RCX,[RAX+1]
140096e2d 49 89 0e        MOV qword ptr [R14],RCX
  • Increments an internal counter stored in the random::KEYS structure.
  • Likely used to ensure unique identifiers for each plugin instance.

_ZN83_$LT$tauri_runtime_wry..Wry$LT$T$GT$$u20$_<>::run

1400fc4a0 MOV RSI, qword ptr [RCX + 0x50]
1400fc4a4 INC.LOCK qword ptr [RSI]
1400fc4a8 JLE LAB_1400fc4c8
  • Loads a pointer from the object (RCX points to self).
  • Atomically increments the value pointed to by that pointer.
  • Jumps if less than or equal to zero (JLE) to LAB_1400fc4c8.
1400fc4aa MOV RDI, qword ptr [RCX + 0x18]
1400fc4ae INC.LOCK qword ptr [RDI]
1400fc4b2 JLE LAB_1400fc4c8

1400fc4b4 MOV RBX, qword ptr [RCX + 0x48]
1400fc4b8 INC.LOCK qword ptr [RBX]
1400fc4bc JLE LAB_1400fc4c8

1400fc4be MOV RAX, qword ptr [RCX + 0x58]
1400fc4c2 INC.LOCK qword ptr [RAX]
1400fc4c6 JG LAB_1400fc4ca
  • Each load gets a pointer from the struct and performs an atomic increment.
  • If any of these increments result in <= 0, the code jumps to a UD2 instruction (illegal instruction) at LAB_1400fc4c8.
  • The last increment uses JG (jump if greater) to continue normal execution.

Misc

C:\Program Files (x86)\Windows Kits\10\Include\10.0.26100.0\um

ntdll.LdrGetProcedureAddressForCaller

  • Internal loader function that resolves function pointers in DLLs.
  • Equivalent to GetProcAddress, but with extra security / caller tracking.
  • Used during import table processing or when dynamic function lookups occur.

ntdll.RtlDeleteElementGenericTableAvlEx

  • Deletes an element from an AVL-based generic table.
  • Windows often uses these tables internally to track loaded modules, TLS slots, or runtime resources.
  • Seeing this in a loader trace usually indicates cleanup or deallocation during module setup or teardown.

kernelbase.GetApplicationRestartSettings

  • Retrieves settings related to Windows application restart / recovery.
  • Called internally during process initialization to see if the OS wants to auto-restart a crashed application.

ntdll.RtlEncodeRemotePointer

  • Obfuscates or encodes pointers that may be shared across processes or stored in global tables.
  • Prevents accidental or malicious misuse of raw pointers (security measure).
  • Usually happens after resolving function addresses or storing thread-local data.

ntdll.RtlAnsiStringToUnicodeString

  • Converts an ANSI string to a Unicode (UTF-16) string.
  • Used during DLL loading or manifest/registry string parsing, because many Windows APIs expect Unicode internally.

ntdll.RtlAcquireSRWLockExclusive

  • Acquires a Slim Reader/Writer lock exclusively.
  • Prevents multiple threads from modifying shared resources at the same time.
  • Often used in runtime and loader code for: -- AVL tables -- Loader metadata -- Heap or TLS structures

ntdll.RtlUTF8ToUnicode

  • Converts a UTF-8 string to Unicode (UTF-16).

ntdll.TpCallbackMayRunLong

  • Part of Windows Thread Pool (Tp) API.
  • Called internally when a thread pool callback might take a long time to execute.
  • The runtime uses this to decide whether to inject additional threads or adjust scheduling.

RtlInsertElementGenericTableFullAvl

  • Inserts an element into a generic AVL tree in memory.
  • The “FullAvl” version handles both insertion and balancing automatically.

ntdll.RtlRaiseStatus

  • Raises a Windows NTSTATUS exception.
  • Converts a status code (like an error or system signal) into an exception that can be caught by SEH handlers.

ntdll.RtlUserThreadStart

  • Entry point for new user-mode threads.
  • Windows sets up a thread so that when it begins execution, it runs RtlUserThreadStart.
  • Responsible for: -- Setting up thread-local storage (TLS) -- Calling your thread function (LPTHREAD_START_ROUTINE) -- Handling structured exception handling (SEH) for the thread

kernel32.BaseThreadInitThunk

  • Called by the OS when a thread starts.
  • Sets up the thread environment before calling RtlUserThreadStart.
  • Handles: -- Register initialization -- Stack setup -- Exception frame setup

ntdll.NtReleaseWorkerFactoryWorker ntdll.RtlGetReturnAddressHijackTarget ntdll.ZwWaitForWorkViaWorkerFactory ntdll.NtWaitForSingleObject

LdrpInitialize LdrpInitializeProcess LdtpInitializeThread TestAlert NtContinue

ntdll.NtMapViewOfSection

NTSYSAPI NTSTATUS ZwMapViewOfSection(
  [in]                HANDLE          SectionHandle,
  [in]                HANDLE          ProcessHandle,
  [in, out]           PVOID           *BaseAddress,
  [in]                ULONG_PTR       ZeroBits,
  [in]                SIZE_T          CommitSize,
  [in, out, optional] PLARGE_INTEGER  SectionOffset,
  [in, out]           PSIZE_T         ViewSize,
  [in]                SECTION_INHERIT InheritDisposition,
  [in]                ULONG           AllocationType,
  [in]                ULONG           Win32Protect
);

Maps a view of a section into the virtual address space of a subject process.

ntdll.LdrGetDllHandleByMapping

Given a mapped memory region, tries to resolve if it corresponds to a loaded DLL.

Helps the loader avoid re-loading the same module.

ntdll.RtlDeactivateActivationContextUnsafeFast

Cleans up activation contexts (side-by-side assemblies, manifests, COM contexts).

You see this around DLL load/unload sequences.

"UnsafeFast" = lightweight version without full safety checks.

ntdll.LdrGetDllHandleEx

Higher-level helper for finding a DLL handle by name or characteristics.

Often used before LdrLoadDll.

ntdll.LdrLoadDll

Main function to load a DLL (after checking handles/mappings).

Calls NtMapViewOfSection internally if the DLL isn’t already mapped.

Also processes imports, TLS callbacks, and entrypoints (DllMain).

ntdll.RtlFindClearBitsAndSet

A low-level runtime routine that manipulates a bitmap (finds a sequence of 0s, flips them to 1s).

Used internally by the loader and memory manager to track free/used slots (e.g., TLS slots, heap allocations).

ntdll.EtwEventWriteNoRegistration

Event Tracing for Windows (ETW).

Writes events even if no provider is registered.

Usually system bookkeeping — not critical to program flow, but shows the loader/system is logging activity.

ntdll.LdrInitializeThunk

Runs when a new thread starts (especially the first thread of a process). Final loader setup: initializes loader state, processes TLS, resolves imports. Then jumps to program’s real entrypoint (e.g., main, WinMain, or DllMain for DLL entry).

What Happens When You Double-Click an Executable in Windows

1. User Action and Shell Event

  • The user double-clicks the .exe file icon in Windows Explorer.
  • Windows Explorer interprets this as a request to “open” the file using the default verb.
  • Internally, Explorer calls the ShellExecuteEx API to handle the action:

Registry

Computer\HKEY_CLASSES_ROOT\exefile
FriendlyTypeName @%SystemRoot%\System32\shell32.dll,-10156

Api

ShellExecuteEx(&sei);
typedef struct _SHELLEXECUTEINFOA {
  DWORD     cbSize;
  ULONG     fMask;
  HWND      hwnd;
  LPCSTR    lpVerb;
  LPCSTR    lpFile;
  LPCSTR    lpParameters;
  LPCSTR    lpDirectory;
  int       nShow;
  HINSTANCE hInstApp;
  void      *lpIDList;
  LPCSTR    lpClass;
  HKEY      hkeyClass;
  DWORD     dwHotKey;
  union {
    HANDLE hIcon;
    HANDLE hMonitor;
  } DUMMYUNIONNAME;
  HANDLE    hProcess;
} SHELLEXECUTEINFOA, *LPSHELLEXECUTEINFOA;

EditFlags

EditFlags for exefile

38 07 00 00
3	0x08	FTA_NoEdit	Cannot rename in Explorer
4	0x10	FTA_NoRemove	Cannot delete
5	0x20	FTA_NoNewVerb	Hidden from “New” menu
8	0x100	FTA_NoEditDesc	Cannot edit description
9	0x200	FTA_NoEditIcon	Cannot edit icon
10	0x400	FTA_NoEditDflt	Cannot edit default verb