Post

Indirect Waffles - Shellcode Loader to Bypass EDRs

A shellcode loader that leverages advanced techniques such as HellHall's indirect syscalls, Early Bird APC injection, and more, to evade EDR detection and enhance payload delivery.

While preparing for CRTO 2 and learning from Maldev Academy, I wanted to put everything I had learned into practice. That’s when I created Indirect Waffles, a custom shellcode loader designed for EDR evasion and enhanced by many of the advanced techniques I’ve been studying.

Table of contents

  1. Demo
  2. Key Features
  3. Spoofing Binary Metadata
  4. Conclusion

Demo

Demo showcasing Indirect Waffles.

Key Features

  • Enumeration: Uses NtQuerySystemInformation to enumerate processes for PPID spoofing and NtOpenProcess syscall to obtain process handles.
  • Custom Dynamic HTTP/s Payload Staging
    • Check it out on my GitHub.
  • Shellcode Decryption: RC4 with runtime key brute-forcing.
  • Process Creation with NtCreateUserProcess and the following enhancements:
    • Suspended process creation for APC Injection.
    • Parent Process ID (PPID) spoofing.
    • Block DLL injection policy, preventing third-party DLLs (non-Microsoft signed) from being injected, mitigating some EDR hooking techniques.
  • Injection: Remote Mapped Injection via syscalls with RX (Read Execute) permissions for improved evasion from memory scanners.
  • Execution: Early Bird APC Injection using syscalls to queue the payload for execution before the target thread resumes execution.
  • Resumes process via NtResumeThread syscall.
  • Extra Enhancements:
    • Custom string literal obfuscation: Works on both normal and wide strings.
      • fc5156f67325c8e5433bf4fb4bcfa641.png
    • Compile-time IAT API hashing using MurmurHash to evade static API detection techniques.
    • HellHalls’ Indirect Syscall implementation with compile-time hashing via MurmurHash.
      • 93ee3d54f3f8cac2476da7ad12280d00.png
  • Anti-Debugging:
    • Checks the PEB flag for the IsDebugged flag to detect the presence of a debugger.
    • Anti-debug loop (30 seconds total):
      • 3-second sleep intervals using NtWaitForSingleObject.
      • API hammering to make the sleep appear more benign.
    • Uses QueryPerformanceCounter to measure total loop time; if it exceeds 35 seconds, it is likely being debugged.
  • Spoofed Binary Metadata:
    • .DLL: Spoofed as Notepad++’s libcurls.dll.
    • .EXE: Spoofed as Notepad++’s gup.exe.

Spoofing Binary Metadata

To make your malware less suspicious, you can spoof the malware’s metadata to resemble that of a legitimate, benign file.

  1. Add a new item to your project.
    • Right-click the project, select 'Add' > 'New Item'
    • 8228033a0bfb647f724f9802fe792b05.png
  2. Add a Resource (.rc) File.
    • Renaming the file is not necessary, but for this module, it will be renamed to metadata.rc.
    • b7386aebdea6a960a6a55c8cedef0787.png
  3. Exit Resource Viewer
    • When the file is added, Visual Studio will automatically open the file up in the resource viewer.
    • This is not required and therefore exit the resource reviewer by clicking the ‘X’.
    • a1c45eb1ae5e3e422ab4b85f14755b4d.png
  4. Edit Resource File
    • Right-click the resource file, and select 'Open With' > 'Source Code (Text) Editor’.
    • 8ddcafec1ab8a8817b9bc50bf8959b56.png
    • fbf4e5fc9aef297630ae1bf7ae16ab20.png
  5. Insert Metadata
    • Scroll down to the bottom of the file and insert the following contents.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
1 VERSIONINFO
FILEVERSION 112, 0, 5615, 88 // File version separated by commas
PRODUCTVERSION 1, 0, 0, 0
FILEFLAGSMASK 0x0L
#ifdef _DEBUG
   FILEFLAGS 0x1L
#else
   FILEFLAGS 0x0L
#endif
   FILEOS 0x0L
   FILETYPE 0x0L
   FILESUBTYPE 0x0L
BEGIN
   BLOCK "StringFileInfo"
   BEGIN
      BLOCK "040904B0"
      BEGIN
         // Modify the values below
         VALUE "CompanyName", "Google LLC."
         VALUE "FileDescription", "Google Chrome"
         VALUE "InternalName", "Chrome"
         VALUE "LegalCopyright", "Copyright 2023 Google LLC." 
         VALUE "OriginalFilename", "chrome.exe"
         VALUE "ProductName", "Google Chrome"
         VALUE "ProductVersion", "112.0.5615.86"
      END
   END
   BLOCK "VarFileInfo"
   BEGIN
      VALUE "Translation", 0x409, 1200
   END
END

6. The example above is from Chrome’s binary metadata, you can use this PowerShell script I created to extract the metadata from any file, DLLs included.

  • d1d738c91d8d3a7359e7b1ca719c4637.png
1
2
3
4
5
6
7
8
9
10
11
# Use the first argument as the file path
$path = $args[0]

# Get the file version information
$file = Get-Item $path
$versionInfo = $file.VersionInfo

# Iterate over all the properties of $versionInfo
foreach ($property in $versionInfo.PSObject.Properties) {
    Write-Output "VALUE `"$($property.Name)`", `"$($property.Value)`""
}

Conclusion

This project was incredibly useful for testing everything I’ve learned so far, but I think I can make a better and smaller loader.

My next goal is to take the lessons learned from this project and build a DLL payload loader inspired by NUL0x4C’s AtomLdr, focusing on leveraging DLL Sideloading to run the DLL payload. The plan is to use shellcode injection via Module Stomping and execute the payload through Fibers for thread callstack spoofing.

Stay tuned for updates!

Happy hacking! 😄

This post is licensed under CC BY 4.0 by the author.