Skip to content

xec412/PebWalker

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

3 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

PebWalker

Custom position-independent shellcode that resolves Windows APIs at runtime through PEB walking and export table parsing, without relying on GetModuleHandle or GetProcAddress.

Built as a learning exercise while studying the MalDev Academy syllabus.

Overview

PebWalker demonstrates the core building blocks of position-independent code (PIC) development for Windows x64:

  • PEB Walking — Traverses the Process Environment Block to locate loaded modules (DLLs) in memory without any API calls
  • Export Table Parsing — Manually parses PE export directories to resolve function addresses, replacing GetProcAddress
  • Modified djb2 Hashing — Uses a customized djb2 hash algorithm with a non-standard seed and multiplier to resolve API and module names at runtime, avoiding plaintext strings in the binary
  • Stack-Based Strings — All strings are constructed on the stack as character arrays to prevent them from being placed in .rdata, ensuring they survive .text section extraction
  • x64 Calling Convention Compliance — Includes an assembly stub (Start) that enforces 16-byte stack alignment and allocates shadow space before executing the main logic

As a proof of concept, the shellcode spawns calc.exe via WinExec. The same technique and structure can be extended to resolve any Windows API.

Screenshots

Shellcode Execution

Shellcode executing calc.exe

Shellcode Extraction

Extracting .text section

Project Structure

PebWalker/
├── include/
│   ├── shellcode.h    # Hash defines, macros, and function prototypes
│   └── Native.h       # Windows internal structure definitions (PEB, LDR, PE headers)
├── src/
│   └── shellcode.c    # Main shellcode source (Start stub, PEB walking, export parsing, hash function)
├── tools/
│   ├── Extract.c      # PE parser that extracts raw shellcode from the .text section
│   └── Hasher.c       # Standalone hash generation tool for computing API/module hashes
├── docs/
│   └── screenshots/
├── README.md
└── LICENSE

Technical Details

Hash Algorithm

A modified djb2 implementation with custom parameters to avoid signature detection:

Parameter Standard djb2 This Implementation
Seed 5381 5785
Multiplier 33 (<< 5) 129 (<< 7)

The hash function handles both ANSI strings (null-terminated, used for function names) and UNICODE strings (length-delimited, used for module names from PEB) within a single implementation. All comparisons are case-insensitive.

Shellcode Flow

Start (asm)
  │  Stack alignment (16-byte) + shadow space (0x20)
  ▼
Main()
  │
  ├─ LdrModulePeb(HMODULE_KERNEL32)
  │    Walks: TEB → PEB → Ldr → InLoadOrderModuleList
  │    Compares each module's BaseDllName hash
  │    Returns: kernel32.dll base address
  │
  ├─ LdrFunctionAddress(kernel32, HAPI_WINEXEC)
  │    Parses: DOS Header → NT Header → Export Directory
  │    Iterates: AddressOfNames → hash compare → AddressOfOrdinals → AddressOfFunctions
  │    Returns: WinExec function pointer
  │
  └─ WinExec("calc.exe", SW_SHOW)

Building

Prerequisites

  • w64devkit or MinGW-w64 (GCC cross-compiler)
  • Visual Studio (for building Extract.c and Hasher.c, or use GCC)

Compile Shellcode

gcc src/shellcode.c -o shellcode.exe -Iinclude -masm=intel -Os -fno-asynchronous-unwind-tables -fno-ident -falign-functions=1 -fno-align-jumps -fno-align-loops -fno-align-labels -s -nostdlib -e Start "-Wl,--file-alignment,16" "-Wl,--section-alignment,16"

Extract Raw Shellcode

Build the extraction tool and run it against the compiled shellcode:

gcc tools/Extract.c -o Extract.exe
Extract.exe shellcode.exe calc.bin

Generate Hashes

Build the hash tool and generate defines for new modules or APIs:

gcc tools/Hasher.c -o Hasher.exe
Hasher.exe kernel32.dll
Hasher.exe WinExec

Copy the output defines into include/shellcode.h.

Extending

To resolve additional APIs, follow these steps:

  1. Generate the hash with Hasher.exe:

    Hasher.exe LoadLibraryA    →  #define HAPI_LOADLIBRARYA  (0x...)
    Hasher.exe MessageBoxA     →  #define HAPI_MESSAGEBOXA   (0x...)
    
  2. Add the define to include/shellcode.h

  3. Create a typedef for the target function signature in src/shellcode.c

  4. Resolve and call it in Main():

    pLoadLibraryA = LdrFunctionAddress(Kernel32, HAPI_LOADLIBRARYA);
    User32 = pLoadLibraryA(User32String);
    pMessageBoxA = LdrFunctionAddress(User32, HAPI_MESSAGEBOXA);
    pMessageBoxA(NULL, TextString, TitleString, 0);

Acknowledgements

  • MalDev Academy — Syllabus and methodology
  • C5pider — Challenge Author at MalDev Academy, original shellcode template, and Native.h structures (Stardust)

Disclaimer

This project is developed strictly for educational and research purposes. It is intended to demonstrate low-level Windows internals and position-independent code techniques as part of the MalDev Academy syllabus. The author does not condone the use of these techniques for unauthorized access or malicious activity. Use responsibly and only in environments you own or have explicit permission to test in.

Author

Xec (@Xec0xCC)

License

See LICENSE for details.

About

Custom position-independent calc.exe shellcode using PEB walking, export table parsing, and modified djb2 hashing. Educational PoC.

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages