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.
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.textsection 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.
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
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.
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)
- w64devkit or MinGW-w64 (GCC cross-compiler)
- Visual Studio (for building Extract.c and Hasher.c, or use GCC)
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"Build the extraction tool and run it against the compiled shellcode:
gcc tools/Extract.c -o Extract.exe
Extract.exe shellcode.exe calc.binBuild the hash tool and generate defines for new modules or APIs:
gcc tools/Hasher.c -o Hasher.exe
Hasher.exe kernel32.dll
Hasher.exe WinExecCopy the output defines into include/shellcode.h.
To resolve additional APIs, follow these steps:
-
Generate the hash with
Hasher.exe:Hasher.exe LoadLibraryA → #define HAPI_LOADLIBRARYA (0x...) Hasher.exe MessageBoxA → #define HAPI_MESSAGEBOXA (0x...) -
Add the define to
include/shellcode.h -
Create a typedef for the target function signature in
src/shellcode.c -
Resolve and call it in
Main():pLoadLibraryA = LdrFunctionAddress(Kernel32, HAPI_LOADLIBRARYA); User32 = pLoadLibraryA(User32String); pMessageBoxA = LdrFunctionAddress(User32, HAPI_MESSAGEBOXA); pMessageBoxA(NULL, TextString, TitleString, 0);
- MalDev Academy — Syllabus and methodology
- C5pider — Challenge Author at MalDev Academy, original shellcode template, and
Native.hstructures (Stardust)
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.
Xec (@Xec0xCC)
See LICENSE for details.

