<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Himanshu</title>
    <description>The latest articles on DEV Community by Himanshu (@himanshup601).</description>
    <link>https://dev.to/himanshup601</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3363715%2F3171a7cc-51dd-4c67-b5a1-6e477435fe13.jpeg</url>
      <title>DEV Community: Himanshu</title>
      <link>https://dev.to/himanshup601</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/himanshup601"/>
    <language>en</language>
    <item>
      <title>From PEB to WinExec: Manual Shellcode Execution Without Imports on Windows x64</title>
      <dc:creator>Himanshu</dc:creator>
      <pubDate>Fri, 18 Jul 2025 19:23:03 +0000</pubDate>
      <link>https://dev.to/himanshup601/from-peb-to-winexec-manual-shellcode-execution-without-imports-on-windows-x64-5ebc</link>
      <guid>https://dev.to/himanshup601/from-peb-to-winexec-manual-shellcode-execution-without-imports-on-windows-x64-5ebc</guid>
      <description>&lt;h2&gt;
  
  
  Table of Contents
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;What's this about?&lt;/li&gt;
&lt;li&gt;Who's this for?&lt;/li&gt;
&lt;li&gt;Must Know Concepts (Before You Dive In)&lt;/li&gt;
&lt;li&gt;Why It Matters in Shellcoding?&lt;/li&gt;
&lt;li&gt;Windows x64 Calling Convention&lt;/li&gt;
&lt;li&gt;
Understanding Stack Alignment in x64 (Why 16 Byte Matters?)
What Are We Going to Perform?
&lt;/li&gt;
&lt;li&gt;Accessing PEB (Process Environment Block)&lt;/li&gt;
&lt;li&gt;Walking LDR to Locate kernel32.dll&lt;/li&gt;
&lt;li&gt;Getting into Export Table&lt;/li&gt;
&lt;li&gt;Getting Address of WinExec()&lt;/li&gt;
&lt;li&gt;Executing WinExec&lt;/li&gt;
&lt;li&gt;Complete Code&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Whats this about?
&lt;/h2&gt;

&lt;p&gt;In this blog, we’ll walk through crafting shellcode that locates and calls &lt;code&gt;WinExec("calc.exe", 1)&lt;/code&gt; &lt;strong&gt;entirely without relying on imported functions&lt;/strong&gt;. Instead, we’ll manually resolve &lt;code&gt;kernel32.dll&lt;/code&gt; and locate &lt;code&gt;WinExec&lt;/code&gt; by navigating the process's memory structures.&lt;/p&gt;

&lt;p&gt;This technique mirrors real-world malware behavior and is widely used in shellcode payloads, and CTF challenges. We’ll break down each part of the code so you understand &lt;strong&gt;how it works and why it works&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Who's this for?
&lt;/h2&gt;

&lt;p&gt;This post is intended for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Intermediate to advanced developers learning x64 assembly&lt;/li&gt;
&lt;li&gt;CTF participants working with custom shellcode&lt;/li&gt;
&lt;li&gt;Anyone curious about how to access Windows API functions manually&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You don’t need to be an expert in reverse engineering, but a basic understanding of registers, memory layout, and the PE file structure will help a lot.&lt;/p&gt;

&lt;h2&gt;
  
  
  Must Know Concepts (Before You Dive In)
&lt;/h2&gt;

&lt;p&gt;In shellcoding and low-level assembly (especially x86 and x86_64), the terms byte, word, double word, and quad word (qword) describe the size of data being operated on. These sizes map directly to registers and instructions, and understanding them is critical when crafting shellcode.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Term&lt;/th&gt;
&lt;th&gt;Size&lt;/th&gt;
&lt;th&gt;Bits&lt;/th&gt;
&lt;th&gt;Used in Registers Like&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Byte&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;1 byte&lt;/td&gt;
&lt;td&gt;8&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;AL&lt;/code&gt;, &lt;code&gt;BL&lt;/code&gt;, &lt;code&gt;CL&lt;/code&gt;, &lt;code&gt;DL&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Word&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;2 bytes&lt;/td&gt;
&lt;td&gt;16&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;AX&lt;/code&gt;, &lt;code&gt;BX&lt;/code&gt;, &lt;code&gt;CX&lt;/code&gt;, &lt;code&gt;DX&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Dword&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;4 bytes&lt;/td&gt;
&lt;td&gt;32&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;EAX&lt;/code&gt;, &lt;code&gt;EBX&lt;/code&gt;, &lt;code&gt;ECX&lt;/code&gt;, &lt;code&gt;EDX&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Qword&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;8 bytes&lt;/td&gt;
&lt;td&gt;64&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;RAX&lt;/code&gt;, &lt;code&gt;RBX&lt;/code&gt;, &lt;code&gt;RCX&lt;/code&gt;, &lt;code&gt;RDX&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Register&lt;/th&gt;
&lt;th&gt;Bits&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;RAX&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;64&lt;/td&gt;
&lt;td&gt;Quad word&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;EAX&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;32&lt;/td&gt;
&lt;td&gt;Lower 32 bits of RAX&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;AX&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;16&lt;/td&gt;
&lt;td&gt;Lower 16 bits of EAX&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;AH&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;8&lt;/td&gt;
&lt;td&gt;High byte of AX&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;AL&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;8&lt;/td&gt;
&lt;td&gt;Low byte of AX&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Why It Matters in Shellcoding?
&lt;/h2&gt;

&lt;p&gt;Shellcode is highly size-conscious. Each instruction must:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Fit within strict size constraints.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Use correct data sizes to avoid buffer overflows or misalignment.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Align with syscall conventions (e.g., arguments in rdi, rsi, etc., are 64-bit for x86_64).&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Example:&lt;/p&gt;

&lt;p&gt;1.Moving Imediate Data:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;mov al, 0x41       ; Move 1 byte to AL
mov ax, 0x4142     ; Move 2 bytes to AX
mov eax, 0x41424344 ; Move 4 bytes to EAX
mov rax, 0x4142434445464748 ; Move 8 bytes to RAX
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;2.Stack Operations (ESP/RSP):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;push eax   ; pushes a dword (4 bytes)
push rax   ; pushes a qword (8 bytes)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Windows x64 Calling Convention
&lt;/h2&gt;

&lt;p&gt;The Windows x64 Calling Convention (used in 64-bit Windows) defines how functions receive parameters, return values, and manage the stack. It’s crucial for shellcoding, reverse engineering, and writing assembly that interacts with Windows APIs.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Aspect&lt;/th&gt;
&lt;th&gt;Rule/Usage&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Register Arguments&lt;/td&gt;
&lt;td&gt;First &lt;strong&gt;4&lt;/strong&gt; arguments: &lt;code&gt;RCX&lt;/code&gt;, &lt;code&gt;RDX&lt;/code&gt;, &lt;code&gt;R8&lt;/code&gt;, &lt;code&gt;R9&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Return Value&lt;/td&gt;
&lt;td&gt;Returned in &lt;code&gt;RAX&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Shadow Space&lt;/td&gt;
&lt;td&gt;32 bytes (4×8 bytes) must be reserved by the &lt;strong&gt;caller&lt;/strong&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Stack Alignment&lt;/td&gt;
&lt;td&gt;Stack (&lt;code&gt;RSP&lt;/code&gt;) must be &lt;strong&gt;16-byte aligned before &lt;code&gt;call&lt;/code&gt;&lt;/strong&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Rest of Arguments&lt;/td&gt;
&lt;td&gt;Passed on the &lt;strong&gt;stack&lt;/strong&gt; (right to left)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Caller-saved regs&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;RAX&lt;/code&gt;, &lt;code&gt;RCX&lt;/code&gt;, &lt;code&gt;RDX&lt;/code&gt;, &lt;code&gt;R8–R11&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Callee-saved regs&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;RBX&lt;/code&gt;, &lt;code&gt;RBP&lt;/code&gt;, &lt;code&gt;RDI&lt;/code&gt;, &lt;code&gt;RSI&lt;/code&gt;, &lt;code&gt;R12–R15&lt;/code&gt;, &lt;code&gt;RSP&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Param Position&lt;/th&gt;
&lt;th&gt;Register&lt;/th&gt;
&lt;th&gt;Notes&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1st argument&lt;/td&gt;
&lt;td&gt;&lt;code&gt;RCX&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2nd argument&lt;/td&gt;
&lt;td&gt;&lt;code&gt;RDX&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3rd argument&lt;/td&gt;
&lt;td&gt;&lt;code&gt;R8&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4th argument&lt;/td&gt;
&lt;td&gt;&lt;code&gt;R9&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5th+ arguments&lt;/td&gt;
&lt;td&gt;Stack&lt;/td&gt;
&lt;td&gt;Right to left order (like C)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;example :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;MessageBoxA(NULL, "Hi", "Title", MB_OK);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Assembly(simplified) :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;mov rcx, 0          ; HWND hWnd = NULL
mov rdx, str_hi     ; LPCSTR lpText
mov r8, str_title   ; LPCSTR lpCaption
mov r9d, 0x0        ; UINT uType = MB_OK
sub rsp, 0x28       ; shadow space + align
call MessageBoxA
add rsp, 0x28
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Understanding Stack Alignment in x64 (Why 16 Byte Matters?)
&lt;/h2&gt;

&lt;h4&gt;
  
  
  What Is 16-Byte Alignment?
&lt;/h4&gt;

&lt;p&gt;In 64-bit Windows (and Linux), the stack pointer (RSP) must be aligned to a 16-byte (0x10) boundary before calling a function. This is required by the x64 calling convention.&lt;/p&gt;

&lt;h4&gt;
  
  
  Meaning:
&lt;/h4&gt;

&lt;p&gt;The value in the RSP register should always be divisible by 16 (RSP % 16 == 0) when a call instruction is made.&lt;/p&gt;

&lt;h4&gt;
  
  
  Why Is This Important?
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Misalignment may cause crashes, performance penalties, or incorrect behavior.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Windows functions and syscalls may fail silently or crash if the stack is misaligned.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Example of Aligned Stack:&lt;br&gt;
Let's say RSP = 0x00000000001FFFD0 — that's 16-byte aligned.&lt;/p&gt;

&lt;p&gt;If you do:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;call SomeFunction
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then internally, the call pushes the return address (8 bytes), making RSP:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;RSP = RSP - 8 = 0x00000000001FFFC8
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now RSP is NOT aligned (RSP % 16 == 8) during the function execution.&lt;/p&gt;

&lt;h4&gt;
  
  
  Correcting This: Stack Alignment Before call
&lt;/h4&gt;

&lt;p&gt;To maintain alignment inside the called function, you need to adjust before the call:&lt;/p&gt;

&lt;h4&gt;
  
  
  Rule of Thumb:
&lt;/h4&gt;

&lt;p&gt;Ensure RSP is 16-byte aligned BEFORE a call, so that after call (which pushes return address), it becomes misaligned by 8 bytes, which is what's expected inside the function.&lt;/p&gt;

&lt;h4&gt;
  
  
  Example in Shellcode (Manual Stack Setup)
&lt;/h4&gt;

&lt;p&gt;Imagine you're writing shellcode and want to call a function (e.g., WinExec):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sub rsp, 0x28      ; Allocate space &amp;amp; align
call WinExec
add rsp, 0x28      ; Clean up the stack
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Why 0x28 (40 bytes)? Because:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;32 bytes (shadow space, required by Microsoft x64 calling convention)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;+8 bytes to fix alignment (so after call, it's back to aligned)&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;What Happens If Misaligned?&lt;br&gt;
If you do:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sub rsp, 8
call SomeFunc
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And RSP was already aligned, now RSP % 16 == 8 BEFORE the call, so during the function, it becomes %16 == 0 (aligned).&lt;/p&gt;

&lt;p&gt;That violates the convention. Stack alignment is off inside the function. This can crash on systems using movaps, call printf, etc.&lt;/p&gt;

&lt;p&gt;Visual Summary:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Step&lt;/th&gt;
&lt;th&gt;RSP Value&lt;/th&gt;
&lt;th&gt;RSP % 16&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Initial&lt;/td&gt;
&lt;td&gt;&lt;code&gt;0x...D0&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sub rsp, 0x28&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;0x...A8&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;8&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;call&lt;/code&gt; (push ret)&lt;/td&gt;
&lt;td&gt;&lt;code&gt;0x...A0&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;0 aligned during function&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h4&gt;
  
  
  In Shellcoding
&lt;/h4&gt;

&lt;p&gt;When writing shellcode:&lt;/p&gt;

&lt;p&gt;Always ensure 16-byte alignment before calling any function.&lt;/p&gt;

&lt;p&gt;When doing syscall, alignment is usually less critical, but still good practice.&lt;/p&gt;

&lt;p&gt;Avoiding stack misalignment helps with compatibility, especially on Windows Defender-protected or DEP-enabled systems.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Are We Going to Perform?
&lt;/h2&gt;

&lt;p&gt;We're going to manually invoke WinExec("calc.exe", SW_SHOWNORMAL)on a 64-bit Windows system without using imports, by resolving &lt;code&gt;WinExec&lt;/code&gt; manually.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;#include &amp;lt;windows.h&amp;gt;

int main() {
    // Launch calculator
    WinExec("calc.exe", SW_SHOWNORMAL);
    return 0;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;On Linux, you’d resolve syscalls. On Windows, this means manually resolving &lt;code&gt;WinExec&lt;/code&gt; from the export table of &lt;code&gt;kernel32.dll&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;This can be achieved by :&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Step&lt;/th&gt;
&lt;th&gt;Purpose&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;Access PEB via &lt;code&gt;gs:[0x60]&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;Walk loader data to find &lt;code&gt;kernel32.dll&lt;/code&gt; base&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;Locate Export Directory&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;Search for &lt;code&gt;"WinExec"&lt;/code&gt; in Export Names&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;Get function address via Ordinal and Address table&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;td&gt;Push &lt;code&gt;calc.exe&lt;/code&gt; and call &lt;code&gt;WinExec&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Accessing PEB (Process Environment Block)
&lt;/h2&gt;

&lt;p&gt;To access the PEB (Process Environment Block), we first need to access the TEB (Thread Environment Block), because the TEB structure contains a pointer to the PEB:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;typedef struct _TEB64 {
    NT_TIB64 NtTib;                        // 0x0000
    PVOID EnvironmentPointer;             // 0x0038
    CLIENT_ID64 ClientId;                 // 0x0040
    PVOID ActiveRpcHandle;                // 0x0050
    PVOID ThreadLocalStoragePointer;      // 0x0058
    PPEB64 ProcessEnvironmentBlock;       // 0x0060
    ULONG LastErrorValue;                 // 0x0068
    ULONG CountOfOwnedCriticalSections;   // 0x006C
    PVOID CsrClientThread;                // 0x0070
    PVOID Win32ThreadInfo;                // 0x0078
    ULONG User32Reserved[26];            // 0x0080
    ULONG UserReserved[5];               // 0x00E8
    PVOID WOW32Reserved;                 // 0x0100
    ULONG CurrentLocale;                 // 0x0108
    ULONG FpSoftwareStatusRegister;      // 0x010C
    PVOID SystemReserved1[54];           // 0x0110
    LONG ExceptionCode;                  // 0x02C0
    PVOID ActivationContextStackPointer; // 0x02C8
    BYTE SpareBytes1[24];                // 0x02D0
    PVOID TxFsContext;                   // 0x02E8
    GDI_TEB_BATCH64 GdiTebBatch;         // 0x02F0
    CLIENT_ID64 RealClientId;            // 0x04D8
    PVOID GdiCachedProcessHandle;        // 0x04E8
    ULONG GdiClientPID;                  // 0x04F0
    ULONG GdiClientTID;                  // 0x04F4
    PVOID GdiThreadLocalInfo;            // 0x04F8
    ULONGLONG Win32ClientInfo[62];       // 0x0500
    PVOID glDispatchTable[233];          // 0x06F0
    ULONGLONG glReserved1[29];           // 0x10D8
    PVOID glReserved2;                   // 0x1168
    PVOID glSectionInfo;                 // 0x1170
    PVOID glSection;                     // 0x1178
    PVOID glTable;                       // 0x1180
    PVOID glCurrentRC;                   // 0x1188
    PVOID glContext;                     // 0x1190
    ULONG LastStatusValue;              // 0x1198
    UNICODE_STRING StaticUnicodeString; // 0x11A0
    WCHAR StaticUnicodeBuffer[261];     // 0x11B0
    PVOID DeallocationStack;            // 0x13C8
    PVOID TlsSlots[64];                 // 0x13D0
    LIST_ENTRY TlsLinks;                // 0x15D0
    PVOID Vdm;                          // 0x15E0
    PVOID ReservedForNtRpc;             // 0x15E8
    PVOID DbgSsReserved[2];             // 0x15F0
    ULONG HardErrorMode;                // 0x1600
    // ... additional fields follow
} TEB64, *PTEB64;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;From the above structure, we can see that the PEB is located at offset 0x60 in the TEB.&lt;/p&gt;

&lt;h4&gt;
  
  
  How Do We Access the TEB?
&lt;/h4&gt;

&lt;p&gt;On Windows x64, the &lt;code&gt;TEB&lt;/code&gt; is accessible via the &lt;code&gt;GS&lt;/code&gt; segment register. Here's how it looks in assembly:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;xor rcx , rcx
mov rbx , gs:[rcx+0x00] //TEB
mov rbx , gs:[rcx+0x60] //PEB
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can also simplify this if you’re directly interested in the &lt;code&gt;PEB&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;xor rcx , rcx
mov rbx , gs:[rcx + 0x60] //PEB
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Walking ldr to Locate kernel32.dll
&lt;/h2&gt;

&lt;p&gt;To locate &lt;code&gt;kernel32.dll&lt;/code&gt;, we need to understand the structure of LIST_ENTRY, which is a doubly linked list used by Windows to track loaded modules:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;typedef struct _LIST_ENTRY {
    struct _LIST_ENTRY *Flink; // Forward link
    struct _LIST_ENTRY *Blink; // Backward link
} LIST_ENTRY, *PLIST_ENTRY;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each module loaded by the process such as &lt;code&gt;ntdll.dll&lt;/code&gt;, &lt;code&gt;kernel32.dll&lt;/code&gt;, &lt;code&gt;user32.dll&lt;/code&gt;, and others are part of this linked list.&lt;/p&gt;

&lt;h4&gt;
  
  
  All DLLs(modules) loaded by the process has a sequence like:
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;ntdll.dll&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;kernel32.dll&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;user32.dll&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;any other dependent/shared libraries&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Our 2nd module is &lt;code&gt;kernel32.dll&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;To access this module we need to access &lt;code&gt;InMemoryOrderModuleList&lt;/code&gt; , but the default module is 0 so we need to &lt;code&gt;flink&lt;/code&gt; in order to traverse forward to &lt;code&gt;kernel32.dll&lt;/code&gt; .&lt;/p&gt;

&lt;p&gt;&lt;code&gt;InMemoryOrderModuleList&lt;/code&gt; can  be access via these chain:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;InMemoryOrderModuleList &amp;lt;- ldr &amp;lt;- PEB &amp;lt;- TEB
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We've already accessed the PEB. Now let’s look at the PEB structure to locate Ldr:&lt;/p&gt;

&lt;h4&gt;
  
  
  PEB64 Structure:
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;typedef struct _PEB {
    BYTE   InheritedAddressSpace;         // 0x000
    BYTE   ReadImageFileExecOptions;      // 0x001
    BYTE   BeingDebugged;                 // 0x002
    BYTE   BitField;                      // 0x003
    ULONG  Padding0;                      // 0x004 (alignment padding)

    PVOID  Mutant;                        // 0x008
    PVOID  ImageBaseAddress;              // 0x010 -&amp;gt; Base address of the main module
    PVOID  Ldr;                           // 0x018 -&amp;gt; Pointer to PEB_LDR_DATA
    // ... you said stop here
} PEB, *PPEB;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The offset of &lt;code&gt;ldr&lt;/code&gt; is 0x018.&lt;/p&gt;

&lt;p&gt;calculation:&lt;/p&gt;

&lt;p&gt;offset = 1 * 4 + 4 + 8(pointer size in 64 bit) * 2 = 24 // 0x018&lt;/p&gt;

&lt;p&gt;####ldr structure :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; typedef struct _PEB_LDR_DATA {
    ULONG      Length;                      // 0x00
    BOOLEAN    Initialized;                 // 0x04
    BYTE       Reserved1[3];                // 0x05 - padding
    PVOID      SsHandle;                    // 0x08
    LIST_ENTRY InLoadOrderModuleList;       // 0x10
    LIST_ENTRY InMemoryOrderModuleList;     // 0x20
    LIST_ENTRY InInitializationOrderModuleList; // 0x30
    // ... More fields exist but usually not needed
} PEB_LDR_DATA, *PPEB_LDR_DATA;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;LIST_ENTRY being doubly link list containing two pointer has size 16 , so the offset of &lt;code&gt;InMemoryOrderModuleList&lt;/code&gt; can be calculated as :&lt;/p&gt;

&lt;p&gt;offset = 4 + 1 + 3 + 8 + 16 = 32 //0x20&lt;/p&gt;

&lt;p&gt;conclusion :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;ldr&lt;/code&gt; is at 0x18&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;InMemoryOrderModuleList&lt;/code&gt; is at 0x20&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;which can be interpreted as :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;mov rbx , [rbx + 0x18]  ;ldr
mov rbx , [rbx + 0x20]  ;InMemoryOrderModuleList
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;now we are currently at 0th module of process, to traverse to &lt;code&gt;kernel32.dll&lt;/code&gt; we need &lt;code&gt;flink&lt;/code&gt; in this way:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;InMemoryOrderModuleList.flink.flink //kernel32.dll
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;which looks like :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;mov rbx , [rbx] 
mov rbx , [rbx]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But for now, we are just pointing to the &lt;code&gt;kernel32.dll&lt;/code&gt; module specifically its &lt;code&gt;InLoadOrderLinks&lt;/code&gt; (the first entry in the module list). To proceed further, we need the module's base address, which can be accessed via the &lt;code&gt;DllBase&lt;/code&gt; field contained in the module structure we are currently referencing.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;typedef struct _LDR_DATA_TABLE_ENTRY {
    LIST_ENTRY InLoadOrderLinks;           // +0x00
    LIST_ENTRY InMemoryOrderLinks;         // +0x10
    LIST_ENTRY InInitializationOrderLinks; // +0x20
    PVOID      DllBase;                    // +0x30 ← This is the base address
    ...
} LDR_DATA_TABLE_ENTRY, *PLDR_DATA_TABLE_ENTRY;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To access &lt;code&gt;DllBase&lt;/code&gt;, we need to jump +0x20 (32 bytes) from the current offset.&lt;/p&gt;

&lt;p&gt;This can be done using:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;mov r8 , [rbx+0x20]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;At this point, r8 contains the base address of &lt;code&gt;kernel32.dll&lt;/code&gt;.&lt;/p&gt;

&lt;h4&gt;
  
  
  Memory Walk Visualized:
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;GS:[0x00] → TEB
         +0x60 → PEB
                +0x18 → Ldr (PEB_LDR_DATA)
                       +0x20 → InMemoryOrderModuleList
                                  ↓ Flink
                        → kernel32.dll module entry
                                  +0x30 → DllBase

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Visualising the Memory Layout (TEB → PEB → LDR → Module → DllBase)
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;+--------------------------+
|       GS Segment         |
+--------------------------+
            ↓
+--------------------------+
|         TEB (at GS:[0])  |
|  +0x60 → PEB             |
+--------------------------+
            ↓
+--------------------------+
|           PEB            |
|  +0x18 → Ldr             |
+--------------------------+
            ↓
+--------------------------+
|      PEB_LDR_DATA        |
|  +0x20 → InMemoryOrderModuleList (LIST_ENTRY)  
+--------------------------+
            ↓
+--------------------------+
| LIST_ENTRY (1st module)  | → ntdll.dll
| LIST_ENTRY (2nd module)  | → kernel32.dll
+--------------------------+
            ↓
+--------------------------+
|  LDR_DATA_TABLE_ENTRY    | ← We're here after two `.Flink` jumps
|  +0x30 → DllBase         | ← base of kernel32.dll
+--------------------------+

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Why Do We Need DllBase?
&lt;/h4&gt;

&lt;p&gt;We use &lt;code&gt;DllBase&lt;/code&gt; to manually parse the Export Table of &lt;code&gt;kernel32.dll&lt;/code&gt;, locate functions like &lt;code&gt;WinExec&lt;/code&gt;, and call them directly without relying on imports — crucial in shellcode and evasion techniques.&lt;/p&gt;

&lt;h2&gt;
  
  
  Getting into Export Table
&lt;/h2&gt;

&lt;p&gt;Our next step is to access the Export Table of &lt;code&gt;kernel32.dll&lt;/code&gt; in order to retrieve information about the &lt;code&gt;WinAPI&lt;/code&gt; functions it exports.&lt;/p&gt;

&lt;p&gt;To navigate to the Export Table, follow this pointer chain:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Export Table &amp;lt;- PE hdrs offset &amp;lt;- DOS Header
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Accessing the DOS Header
&lt;/h4&gt;

&lt;p&gt;We don’t need to do anything extra because:&lt;/p&gt;

&lt;p&gt;When a PE (Portable Executable) file like a DLL or EXE is loaded into memory:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;The DLL base address (also called ImageBase) points to the beginning of the loaded image in memory.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The DOS header (IMAGE_DOS_HEADER) starts exactly at that base address.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Memory Layout:
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;DLLBase
│
├─&amp;gt; 0x00: DOS Header ('MZ' = 0x5A4D)
│    └─&amp;gt; 0x3C: e_lfanew (DWORD) → offset to PE Header
│
├─&amp;gt; DLLBase + e_lfanew → PE Header ('PE\0\0')
│    └─&amp;gt; +0x18: Optional Header
│         └─&amp;gt; +0x70: DataDirectory[0] (Export Table RVA + Size)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  DOS Header structure :
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;typedef struct _IMAGE_DOS_HEADER {  // DOS .EXE header
    WORD   e_magic;      // Magic number: "MZ" (0x5A4D)
    WORD   e_cblp;       // Bytes on last page of file
    WORD   e_cp;         // Pages in file
    WORD   e_crlc;       // Relocations
    WORD   e_cparhdr;    // Size of header in paragraphs
    WORD   e_minalloc;   // Minimum extra paragraphs needed
    WORD   e_maxalloc;   // Maximum extra paragraphs needed
    WORD   e_ss;         // Initial (relative) SS value
    WORD   e_sp;         // Initial SP value
    WORD   e_csum;       // Checksum
    WORD   e_ip;         // Initial IP value
    WORD   e_cs;         // Initial (relative) CS value
    WORD   e_lfarlc;     // File address of relocation table
    WORD   e_ovno;       // Overlay number
    WORD   e_res[4];     // Reserved words
    WORD   e_oemid;      // OEM identifier (for e_oeminfo)
    WORD   e_oeminfo;    // OEM information; e_oemid specific
    WORD   e_res2[10];   // Reserved words
    LONG   e_lfanew;     // File address of new exe header (PE Header offset)
} IMAGE_DOS_HEADER, *PIMAGE_DOS_HEADER;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Actual picture with steps :
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fr3fyrg13st6sz2wky89e.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fr3fyrg13st6sz2wky89e.png" alt="DOS Header" width="800" height="726"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Accessing the Export Table
&lt;/h4&gt;

&lt;p&gt;Note:Every entry in the DOS Header is relative to the base of &lt;code&gt;kernel32.dll&lt;/code&gt;, i.e., it uses RVA (Relative Virtual Address).&lt;br&gt;
To convert an RVA to a VA (Virtual Address), add the base address of the module (&lt;code&gt;DllBase&lt;/code&gt;)&lt;/p&gt;
&lt;h4&gt;
  
  
  Step 1: Get PE Header Offset via &lt;code&gt;e_lfanew&lt;/code&gt;
&lt;/h4&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;mov edx , [r8 + 0x3c] //RVA of PE Header
lea rdx , [rdx + r8]  //VA of PE Header
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Now we know that Export Table is at offset +0x88 from PE Header.&lt;/p&gt;
&lt;h4&gt;
  
  
  Step 2: Get RVA of Export Table from PE Header
&lt;/h4&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;xor rcx , rcx
mov cl , 0x88
mov edx , [rdx + rcx]  //RVA of Export Table
lea rdx , [rdx + r8]   //VA of Export Table
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h2&gt;
  
  
  Getting Address of WinExec
&lt;/h2&gt;

&lt;p&gt;Now that we've handled the complex part—parsing the PE headers and finding the export table—it's time to resolve the address of the &lt;code&gt;WinExec&lt;/code&gt; function, which is comparatively simpler.&lt;/p&gt;
&lt;h4&gt;
  
  
  Structure of Export Table
&lt;/h4&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;typedef struct _IMAGE_EXPORT_DIRECTORY {
    DWORD   Characteristics;         // 0x00 - Reserved, usually zero
    DWORD   TimeDateStamp;           // 0x04 - Timestamp of export table creation
    WORD    MajorVersion;            // 0x08 - Major version number
    WORD    MinorVersion;            // 0x0A - Minor version number
    DWORD   Name;                    // 0x0C - RVA of DLL name (ASCII string)
    DWORD   Base;                    // 0x10 - Starting ordinal number (usually 1)
    DWORD   NumberOfFunctions;       // 0x14 - Total number of function addresses
    DWORD   NumberOfNames;           // 0x18 - Number of named exports
    DWORD   AddressOfFunctions;      // 0x1C - RVA of DWORD array of function RVAs
    DWORD   AddressOfNames;          // 0x20 - RVA of DWORD array of function name RVAs
    DWORD   AddressOfNameOrdinals;   // 0x24 - RVA of WORD array of ordinals
} IMAGE_EXPORT_DIRECTORY;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h4&gt;
  
  
  Steps to Resolve WinExec Address
&lt;/h4&gt;

&lt;p&gt;1.Get the ordinal index of &lt;code&gt;WinExec&lt;/code&gt; via AddressOfNames (+0x20).&lt;br&gt;
2.Get the actual function index via AddressOfNameOrdinals (+0x24) using the ordinal index.&lt;br&gt;
3.Resolve the function's RVA via AddressOfFunctions (+0x1C) and add base to get VA.&lt;/p&gt;
&lt;h4&gt;
  
  
  Step 1: Finding the Function Name &lt;code&gt;WinExec&lt;/code&gt;
&lt;/h4&gt;

&lt;p&gt;Registers Used:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;rdx = base address of Export Table (i.e., pointer to IMAGE_EXPORT_DIRECTORY)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;r8 = DLL base address (e.g., base of &lt;code&gt;kernel32.dll&lt;/code&gt;)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;rsi = will point to array of function name RVAs (i.e., AddressOfNames)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;rcx = index counter for loop&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;rax/eax = temp register for reading name RVA and checking characters&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;mov esi, [rdx + 0x20]       ; Get RVA of AddressOfNames → esi
lea rsi, [rsi + r8]         ; Convert RVA to actual address → rsi = AddressOfNames[]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Loop through the names:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;xor rcx, rcx                ; Clear loop index
Find_next:
mov eax, [rsi + rcx * 4]    ; Get RVA of name at index rcx
add rax, r8                 ; Convert RVA to actual address → rax = &amp;amp;function_name
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Compare with &lt;code&gt;WinExec&lt;/code&gt; (manual byte match):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cmp dword [rax], 0x456e6957 ; Compare first 4 bytes → "WinE"
jnz next                    ; Not match? Go to next
cmp word [rax + 4], 0x6578  ; Compare next 2 bytes → "xe"
jnz next
cmp byte [rax + 6], 0x63    ; Compare last byte → "c"
jnz next
jmp found                   ; Match found → jump to found
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;"WinExec" = 'W' 'i' 'n' 'E' 'x' 'e' 'c'&lt;br&gt;
In little-endian:&lt;/p&gt;

&lt;p&gt;"WinE" → 0x456e6957&lt;/p&gt;

&lt;p&gt;"xe" → 0x6578&lt;/p&gt;

&lt;p&gt;'c' → 0x63&lt;/p&gt;

&lt;p&gt;If not matched:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;next:
inc rcx                     ; Try next function name
jmp Find_next              ; Loop
found:                      ;Got the Ordinal Index
; rcx now holds the index of "WinExec"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The above code loops through exported function names in a DLL and finds the one named &lt;code&gt;WinExec&lt;/code&gt;, character-by-character using binary comparison.&lt;/p&gt;

&lt;h4&gt;
  
  
  Step 2: Get Ordinal Index
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;mov esi, [rdx + 0x24]     ; offset 0x24 = AddressOfNameOrdinals RVA
add rsi, r8               ; convert RVA to VA → rsi = &amp;amp;NameOrdinals[0]
movzx ecx, word [rsi + rcx * 2]  ; get ordinal index for WinExec
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This gets the ordinal of the function &lt;code&gt;WinExec&lt;/code&gt; using the same index (rcx) used in the name array.&lt;/p&gt;

&lt;h4&gt;
  
  
  Step 3: Get Function Address
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;mov esi, [rdx + 0x1c]     ; offset 0x1C = AddressOfFunctions RVA
movsxd rsi, esi
add rsi, r8               ; convert RVA to VA → rsi = &amp;amp;FunctionAddresses[0]

mov eax, [rsi + rcx * 4]  ; get RVA of function using ordinal index
movsxd r9, eax
add r9, r8                ; r9 = actual address of WinExec
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, r9 contains the actual memory address of &lt;code&gt;WinExec()&lt;/code&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Executing WinExec()
&lt;/h2&gt;

&lt;p&gt;We now have the address of &lt;code&gt;WinExec&lt;/code&gt;, and it's time to execute it using proper calling convention.&lt;/p&gt;

&lt;h4&gt;
  
  
  1.Shadow Space Allocation
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sub rsp, 40
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Windows x64 calling convention requires 32 bytes of shadow space, plus alignment.&lt;/p&gt;

&lt;h4&gt;
  
  
  2.Pushing the String &lt;code&gt;calc.exe&lt;/code&gt;
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;push 0x6578652e   ; ".exe"
push 0x636c6163   ; "calc"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This results in the string "calc.exe" at rsp.&lt;/p&gt;

&lt;h4&gt;
  
  
  3.Setup Arguments for &lt;code&gt;WinExec&lt;/code&gt;
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;mov rcx, rsp
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Why:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;On Windows x64, the first argument to a function is passed in RCX.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;rcx = rsp now points to the string &lt;code&gt;calc.exe&lt;/code&gt; (first argument to WinExec).&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;xor rdx, rdx
inc rdx   ; SW_SHOWNORMAL
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Why:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Clears rdx and sets it to 1 → this is the second argument to WinExec, which expects:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;UINT uCmdShow = 1; // SW_SHOWNORMAL
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  4.Call WinExec
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;call r9
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Done! You've just launched &lt;code&gt;calc.exe&lt;/code&gt; using raw shellcode—no imports, no API stubs, just pure reverse engineering.&lt;/p&gt;

&lt;h2&gt;
  
  
  Complete Code:
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;section .text
    global _start
_start: 
        xor rcx , rcx
        mov rbx , gs:[rcx + 0x60]
        mov rbx , [rbx + 0x18]
        mov rbx , [rbx + 0x20]
        mov rbx , [rbx]
        mov rbx , [rbx]
        mov r8 , [rbx + 0x20]

        ; r8 = kernel32.dll

        mov edx , [r8 + 0x3c]
        lea rdx , [rdx + r8]
        xor ecx , ecx
        mov cl , 0x88
        mov edx , [rdx + rcx]
        lea rdx , [rdx + r8]
        mov esi , [rdx + 0x20]
        lea rsi , [rsi + r8]


        ;rdx = base of Exporttable
        xor rcx , rcx
        Find_next:
        mov eax , [rsi + rcx * 4]
        add rax , r8

        cmp dword  [rax] , 0x456e6957
        jnz next


        cmp word  [rax + 4] , 0x6578
        jnz next
        cmp byte  [rax + 6] , 0x63
        jnz next
        jmp found

        next:
        inc rcx
        jmp Find_next

        found:

        ;get ordinal table
        mov esi , [rdx + 0x24]
        add rsi , r8
        movzx ecx , word [rsi + rcx * 2]
        ;Get address of WinExec
        mov esi , [rdx + 0x1c]
        movsxd rsi , esi
        add rsi , r8
        mov eax, [rsi + rcx * 4]
        movsxd r9 , eax
        add r9 , r8

        ;r9 : addres of WinExec

        sub rsp , 40
        push 0x6578652e     ;'.exe'
        push 0x636c6163               ; 'calc'
        mov rcx , rsp
        xor rdx , rdx
        inc rdx
        call r9

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With the &lt;code&gt;kernel32.dll&lt;/code&gt; base address in hand, we're now ready to traverse the PE structure and uncover the Export Table — the key to resolving WinAPI functions at runtime.&lt;/p&gt;

</description>
      <category>assembly</category>
      <category>x64</category>
      <category>cybersecurity</category>
      <category>redteam</category>
    </item>
  </channel>
</rss>
