Open Advanced Windows Exploitation
  • Introduction
    • Welcome
      • Subscribe
      • Contents
      • Intended Audience
      • Required Software and Tools
      • Thank You and Support
  • Custom Shellcode
    • 64-bit Architecture
      • 64-bit Enhancements
      • Calling Conventions
    • Shellcode Workflow
      • Visual Studio Code
      • Netwide Assembler
      • Windbg Preview
      • Workflow
    • Writing Shellcode
      • NULL-Free Position-Independent Shellcode
      • Finding kernel32.dll
      • Resolving Symbols
      • Finding VMAs
      • MessageBox Shellcode
      • Avoiding NULL
      • GetLastError
    • Reverse Shell
      • Exercise
      • Solution
  • Exploit Mitigations
    • Understanding the Battlefield
      • Memory Corruption
      • Vulnerability Primitives
      • Overview of Mitigations
    • Our Old Foes
      • DEP
      • ASLR
  • Memory Management
    • Memory Basics
      • Pages
      • Shared Memory
    • Memory Management
      • The Stack
      • The Heap
        • Heap Grooming and Overflow
        • Virtual Functions in C++
        • The Heap Continued
        • Kernel Mode Heap
      • Managed Memory
  • The Kernel
    • Kernel Basics
      • Kernel Structures
      • Kernel Debugging Options
      • Navigating the Kernel
      • Analysing the Kernel
    • Access Tokens
      • Access Token Basics
      • Token Theft
  • Drivers
    • Driver Basics
      • Implementing a Driver
      • Reversing Our Driver
      • A Basic User Mode Application
  • First Kernel Exploit
    • A Kernel Exploit
      • CVE 2020-17382
      • IDA Free
      • Writing A Basic Fuzzer
      • Controlling RIP
      • Meet SMEP
      • ROP to the Rescue
      • kASLR
      • Priv Esc Shellcode
    • Exploit Code
  • References
    • References
Powered by GitBook
On this page
  1. Custom Shellcode
  2. Writing Shellcode

GetLastError

GetLastError() in the Win32 API retrieves the error code for the last operation, aiding in diagnosing and handling errors in Windows programming.

Sometimes when we are calling Win32 APIs from shellcode we need to understand why the function has not carried out the tasks we expected. The Win32 APIs have a really useful function called GetLastError. We can make this one of the first functions we resolve and use it later in subsequent assembly code.

Resolving the function is the same as any other:

call_getprocaddress_getlasterror:
    mov [rbp-0x28], rbx             ; [RBP-0x28] = Kernel32 base address
    mov rcx, [rbp-0x28]             ; RCX = hModule = Kernel32 base address
    mov rax, 0x726f7272             ;
    push rax                        ;
    mov rax, 0x457473614c746547     ;
    push rax                        ;
    mov rdx, rsp                    ; RDX = lpProcName = GetLastError  
    sub rsp, 0x2c                   ; Allocate stack space for the function call 
                                    ; (+ alignment)
    call [rbp-0x18]                 ; CALL GetProcAddress
    add rsp, 0x2c                   ; Clean up allocated space
    add rsp, 0x10                   ; Clean up GetLastError on stack
    mov [rbp-0x8], rax              ; [RBP-0x8] = *GetLastError

Now, if we are not seeing the results we expect from Win32 APIs, we can call GetLastError and the error code will be in rax after the call:

sub rsp, 0x2c                   ; Allocate stack space for the function call (+         
                                ; alignment)
call [rbp-0x8]                  ; Call GetLastError
int3                            ; Break to examine error in rax

Once your shellcode is working as intended you can remove the GetLastError code.

Example

The following example uses a the WinHttp APIs to download some malicious shellcode, with the intention of injectiing it in to memory (this could be a basic stager):

The flow on the left shows the order in which the calls should be made. The flow on the right shows what happens if we forget to call WinHttpReceiveResponse.

WinHttpQueryDataAvailable will return 0 instead of the number of bytes in the shellcode. This is because it has failed. If we find this during debugging our mistake might not be that obvious.

During the different calls the HINTERNET handle is used to track the request. If we use the GetLastError call imediately after our mistake we can get an insight in to why it failed.

The 12019 error is the ERROR_INTERNET_INCORRECT_HANDLE_STATE, which should help us diagnose the problem.

PreviousAvoiding NULLNextReverse Shell

Last updated 1 year ago

Using GetLastError