# x64 Return Address Spoofing

## Introduction

AntiVirus or EDR solutions determine if an activity is malicious based on behavioural thresholds. If a process's activity crosses this threshold, it gets categorized as suspicious or outrightly malicious and is probably terminated. The threshold, however, is different for all processes. Trusted processes, like system services, have a higher threshold as opposed to the process of a never-seen or unsigned executable. There are various activities that are monitored to identify suspicious activities. Typically, one such activity is the execution of suspicious APIs from unbacked memory regions. For instance, if a shellcode that has been loaded into the memory starts executing WinAPIs like "InternetConnectA", "HttpOpenRequestA", or "HttpSendRequestA", etc., the process can be categorized as malicious with certainty.

To determine the memory location from which a WinAPI is called, one just needs to look at its return address. This is the address from which the program will continue execution after returning from the WinAPI. By modifying the return address, we can make it look like the function is being called from a different location. This technique is called as "**Return Address Spoofing**". While this technique is not new or perfect and can be detected as it breaks the call stack chain, it is a fundamental technique to build upon. There are various blogs and great resources on this technique, and going through them inspired me to develop a POC that works with all WinAPIs.

The code for this project can be found on my [GitHub](https://github.com/HulkOperator/Spoof-RetAddr).

## Let's begin!

First, let's see how the call stack would look like when a shellcode from unbacked memory executes a MessageBox.&#x20;

```c

#include <Windows.h>
#include <stdio.h>

unsigned char shellcode[] = { 0x57,0x48,0x89,0xe7,0x48,0x83,0xe4,0xf0,0x48,0x83,0xec,0x20,0xe8,0x0f,0x01,0x00,0x00,0x48,0x89,0xfc,0x5f,0xc3,0x66,0x2e,0x0f,0x1f,0x84,0x00,0x00,0x00,0x00,0x00,0x65,0x48,0x8b,0x04,0x25,0x60,0x00,0x00,0x00,0x48,0x8b,0x40,0x18,0x41,0x89,0xca,0x4c,0x8b,0x58,0x20,0x4d,0x89,0xd9,0x66,0x0f,0x1f,0x84,0x00,0x00,0x00,0x00,0x00,0x49,0x8b,0x41,0x50,0x31,0xc9,0x4c,0x8d,0x40,0x02,0x0f,0xb7,0x00,0x66,0x85,0xc0,0x74,0x20,0x66,0x0f,0x1f,0x44,0x00,0x00,0x89,0xca,0x0f,0xb7,0xc0,0x49,0x83,0xc0,0x02,0xc1,0xe2,0x04,0x01,0xd0,0x01,0xc1,0x41,0x0f,0xb7,0x40,0xfe,0x66,0x85,0xc0,0x75,0xe6,0x41,0x39,0xca,0x74,0x09,0x4d,0x8b,0x09,0x4d,0x39,0xcb,0x75,0xc1,0xc3,0x49,0x8b,0x41,0x20,0xc3,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x57,0x56,0x53,0x48,0x63,0x41,0x3c,0x8b,0xbc,0x01,0x88,0x00,0x00,0x00,0x48,0x01,0xcf,0x44,0x8b,0x4f,0x20,0x8b,0x5f,0x14,0x49,0x01,0xc9,0x85,0xdb,0x74,0x51,0x49,0x89,0xcb,0x89,0xd6,0x45,0x31,0xd2,0x66,0x0f,0x1f,0x84,0x00,0x00,0x00,0x00,0x00,0x41,0x8b,0x01,0x31,0xc9,0x4c,0x01,0xd8,0x4c,0x8d,0x40,0x01,0x0f,0xbe,0x00,0x84,0xc0,0x74,0x1c,0x0f,0x1f,0x44,0x00,0x00,0x89,0xca,0xc1,0xe2,0x04,0x01,0xd0,0x01,0xc1,0x4c,0x89,0xc0,0x49,0x83,0xc0,0x01,0x0f,0xbe,0x00,0x84,0xc0,0x75,0xe9,0x39,0xce,0x74,0x11,0x49,0x83,0xc2,0x01,0x49,0x83,0xc1,0x04,0x4c,0x39,0xd3,0x75,0xc0,0x5b,0x5e,0x5f,0xc3,0x8b,0x57,0x24,0x4b,0x8d,0x0c,0x53,0x8b,0x47,0x1c,0x5b,0x5e,0x0f,0xb7,0x14,0x11,0x5f,0x49,0x8d,0x14,0x93,0x8b,0x04,0x02,0x4c,0x01,0xd8,0xc3,0x48,0xb8,0x75,0x73,0x65,0x72,0x33,0x32,0x2e,0x64,0x48,0x83,0xec,0x38,0x48,0x89,0x44,0x24,0x25,0xb8,0x6c,0x6c,0x00,0x00,0x66,0x89,0x44,0x24,0x2d,0xc6,0x44,0x24,0x2f,0x00,0xc7,0x44,0x24,0x20,0x74,0x65,0x73,0x74,0xc6,0x44,0x24,0x24,0x00,0x65,0x48,0x8b,0x04,0x25,0x60,0x00,0x00,0x00,0x48,0x8b,0x40,0x18,0x4c,0x8b,0x50,0x20,0x4d,0x89,0xd1,0x0f,0x1f,0x44,0x00,0x00,0x49,0x8b,0x41,0x50,0x4c,0x8d,0x40,0x02,0x0f,0xb7,0x00,0x66,0x85,0xc0,0x74,0x2a,0x31,0xc9,0x66,0x0f,0x1f,0x44,0x00,0x00,0x89,0xca,0x0f,0xb7,0xc0,0x49,0x83,0xc0,0x02,0xc1,0xe2,0x04,0x01,0xd0,0x01,0xc1,0x41,0x0f,0xb7,0x40,0xfe,0x66,0x85,0xc0,0x75,0xe6,0x81,0xf9,0x00,0x27,0x9b,0x77,0x74,0x3f,0x4d,0x8b,0x09,0x4d,0x39,0xca,0x75,0xbe,0x4c,0x89,0xd9,0xba,0x86,0x45,0x6a,0xef,0xe8,0xd9,0xfe,0xff,0xff,0x48,0x8d,0x4c,0x24,0x25,0xff,0xd0,0xba,0x7f,0x30,0x7b,0xb4,0x48,0x89,0xc1,0xe8,0xc5,0xfe,0xff,0xff,0x48,0x8d,0x54,0x24,0x20,0x45,0x31,0xc9,0x31,0xc9,0x49,0x89,0xd0,0xff,0xd0,0x31,0xc0,0x48,0x83,0xc4,0x38,0xc3,0x4d,0x8b,0x59,0x20,0xeb,0xc3,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 };


int main() {

	UINT64 pAddr;
	HANDLE hThread;

	pAddr = VirtualAlloc(NULL, sizeof(shellcode), MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
	memcpy(pAddr, shellcode, sizeof(shellcode));
	hThread = CreateThread(NULL, 0x00, pAddr, NULL, 0x00, NULL);
	WaitForSingleObject(hThread, INFINITE);

}
```

<div align="left"><figure><img src="https://1334214017-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FGdM1jIOKw0EWSCHRMsql%2Fuploads%2Fp6oBq28Ij9MJv2A6hIc8%2FShellcode_MessageBox.jpg?alt=media&#x26;token=d5a52080-052b-4649-8bb5-d75cad88c8e4" alt=""><figcaption><p>System Informer - Thread Information</p></figcaption></figure></div>

As we can see, the originating call is from an unbacked memory region.

Let's take a look at how the below code looks inside a debugger.

```c
#include <Windows.h>
#include <stdio.h>

int main() {

	MessageBoxA(NULL, "TEST", "TEST", MB_OK);

}
```

<div align="left"><figure><img src="https://1334214017-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FGdM1jIOKw0EWSCHRMsql%2Fuploads%2FnQUoKjzndgcO7ZU2hByr%2FMainReturnAddress.png?alt=media&#x26;token=bb4bb446-974f-4b42-a951-da37361adcfa" alt=""><figcaption><p>x64dbg - MessageBoxA</p></figcaption></figure></div>

The breakpoint is set at the first instruction of **MessageBoxA**. Since this API is called within the "main()" function, we can see its return address at the top of the stack. Our objective will be to modify this value to an address within a trusted DLL, such as KERNEL32.DLL. This will make it look as if MessageBoxA is being called from KERNEL32.DLL. When the MessageBoxA API returns, the execution will be directed at the address in KERNEL32.DLL, and the instructions at this address will be executed.

The return address needs to be selected in such a way that the corresponding instructions redirect execution flow back to us, or else the program will crash. Such instructions are usually referred to as gadgets. We will use the following gadget in our program `jmp QWORD PTR [rbx]`.

The address of our liking is selected and its pointer is placed into the "rbx" register. When the gadget in KERNEL32.DLL gets executed, the control flow will be directed back to the address stored in "rbx", giving us the control.&#x20;

You can alternatively use any DLL which contains these instructions. Here is a simple Python script to check if a DLL can be used.

```py
with open("C:\\Windows\\System32\\kernel32.dll", 'rb') as binfile:
    bindata = binfile.read()
    for i in range(0, len(bindata)-1):
        if (bindata[i] == 0xff and bindata[i+1] == 0x23):
            print("[#] This DLL Works")
            break
```

## Implementation

Now that we have an idea of what to do let's start with the implementation.

### C Program

The following function retrieves the memory location of our gadget from a loaded DLL.&#x20;

<div align="left"><figure><img src="https://1334214017-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FGdM1jIOKw0EWSCHRMsql%2Fuploads%2FkVcSkE9yN8E7a8u1gEbx%2FFindGadget.png?alt=media&#x26;token=51318d11-7a56-4596-8bed-b69cf3673e37" alt=""><figcaption><p>Function To Find The Gadget</p></figcaption></figure></div>

We will store all the required arguments inside a structure which is defined as follows&#x20;

<div align="left"><figure><img src="https://1334214017-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FGdM1jIOKw0EWSCHRMsql%2Fuploads%2FWRpfQOXSoIdEcu4W4Nkl%2FStack_Config.png?alt=media&#x26;token=7945529b-f8f7-4cec-907b-5021794b68c3" alt=""><figcaption></figcaption></figure></div>

* "pRopGadget" will hold the address of our gadget
* "pTarget" will contain the address of the function which needs to be called. e.g. MessageBoxA, VirtualAlloc, etc.
* "dwNumberOfArgs" to specify the number of arguments our target function needs. e.g. 4 for MessageBoxA
* "pEbx" to hold the address of our liking when the gadget is executed
* "pArgs" pointer to the arguments of our target function

We will use a function to initialize this structure and the required arguments for our target function.&#x20;

<div align="left"><figure><img src="https://1334214017-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FGdM1jIOKw0EWSCHRMsql%2Fuploads%2FElv5EARQt4QWS7tzFgts%2FSetupConfig.png?alt=media&#x26;token=a68ccc7b-4a75-4f09-a9cd-03aea1a7f644" alt=""><figcaption><p>Function To Initialize STACK_CONFIG structure</p></figcaption></figure></div>

This function configures four as the minimum number of arguments, and if the number of arguments is odd, it is incremented by one. This is done to avoid complex steps in our assembly code to make sure that the stack will be aligned.

Before proceeding to the assembly section, let's understand the Windows x64 calling convention and the stack alignment requirement.

Windows x64 uses the `fastcall` calling convention. In the `fastcall` calling convention, the first four arguments for a function are stored in registers in the following order: `rcx`, `rdx`, `r8`, and `r9`. Any additional arguments are pushed to the stack from right to left. i.e. the 5th argument will be at the top of the stack, and the last argument will be at the bottom. If there are an odd number of arguments, an additional padding of 8 bytes is adjusted to maintain the stack alignment.&#x20;

Additionally, a 32-bit space must be reserved on the stack before calling the function, known as the shadow space. This space is used by the callee to store the first four arguments from the registers. Windows also requires the stack to be 16-byte aligned before a function is called. Basically, the value in `rsp` must be divisible by 16.

We will define a prototype for our `Spoof` function, which will be coded in assembly. This function will take the pointer to our config structure as a parameter and will be responsible for spoofing the return address.

<div align="left"><figure><img src="https://1334214017-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FGdM1jIOKw0EWSCHRMsql%2Fuploads%2F87TXEkINtyd3WTD8Fo3b%2FSpoof_Prototype.png?alt=media&#x26;token=7590b384-c2a3-4368-8362-a2bc3d56edce" alt=""><figcaption></figcaption></figure></div>

### Spoof Assembly Code

This is where we get our hands dirty and work directly with assembly. This part is necessary as we want granular control over the stack and the register values.

To get started with coding in assembly, check out [g3tsyst3m's](https://g3tsyst3m.github.io/) "x64 Assembly" series.

#### **Assembly Code**

Firstly, we will store the return address within our "main" function inside the `rdi` register. We would like to continue execution from this address after our shenanigans are completed. Once the `pop` instruction is executed, our stack will be in an aligned state, and we need to maintain that. The next set of instructions configure the first four arguments in the registers. If our target function has more than four arguments, the number of arguments to be placed on the stack is stored in the `r12` register.

<div align="left"><figure><img src="https://1334214017-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FGdM1jIOKw0EWSCHRMsql%2Fuploads%2FJzW3XmgwJbyukIFhljWF%2FSpoof_1.png?alt=media&#x26;token=250b6afe-5444-44cc-a56c-58b088cda45f" alt=""><figcaption><p>Assembly Code</p></figcaption></figure></div>

We now have to store the additional arguments on the stack. Which will be accomplished by using a loop. First, space is created on the stack by subtracting the `rsp` value. As we have ensured that the number of arguments is even, the stack will still be aligned.

<div align="left"><figure><img src="https://1334214017-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FGdM1jIOKw0EWSCHRMsql%2Fuploads%2FCpVYJff4Eggk2swshyvZ%2FSpoof_2.png?alt=media&#x26;token=79b9e464-a881-4994-8c70-e0d278d98475" alt=""><figcaption><p>Assembly Code</p></figcaption></figure></div>

Now that our stack is ready, we have to do the following steps:

* Allocate Shadow Space
* Push the gadget's address to the stack, which will act as the return address
* Configure `rbx`
* Jump to the target function

<div align="left"><figure><img src="https://1334214017-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FGdM1jIOKw0EWSCHRMsql%2Fuploads%2Fhv8ZG3P4tDLPaUFq0whi%2FSpoof_3.png?alt=media&#x26;token=a969ac77-6878-400a-a549-3c10c8cb1ae4" alt=""><figcaption><p>Assembly Code</p></figcaption></figure></div>

The final section is the `cleanup`, which will revert the stack back to its original state and return to our "main" function.

<figure><img src="https://1334214017-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FGdM1jIOKw0EWSCHRMsql%2Fuploads%2FPvIsj4dnFKWdEagC8C9x%2FSpoof_4.png?alt=media&#x26;token=86ad2309-a22b-4ebc-a267-21864289b689" alt=""><figcaption></figcaption></figure>

### Example

Let's see an example of executing a shellcode using this technique.&#x20;

<div align="left"><figure><img src="https://1334214017-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FGdM1jIOKw0EWSCHRMsql%2Fuploads%2F1fJ1yFldzgSk5mRDwYgG%2FExample_Code.png?alt=media&#x26;token=736e3fe9-4286-420d-9466-e6854aa587dc" alt=""><figcaption><p>Code To Execute Shellcode By Spoofing Return Addresses</p></figcaption></figure></div>

<div align="left"><figure><img src="https://1334214017-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FGdM1jIOKw0EWSCHRMsql%2Fuploads%2F7lFoibp3AQBklFa2reJn%2FMessageBox.png?alt=media&#x26;token=640f92ed-136b-4494-9089-7f2828b9281d" alt=""><figcaption><p>Shellcode Popping a Message Box</p></figcaption></figure></div>

We can see that our Shellcode has been successfully executed. Let's analyse this inside a debugger.

**Breakpoint at `VirtualAlloc`**

<div align="left"><figure><img src="https://1334214017-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FGdM1jIOKw0EWSCHRMsql%2Fuploads%2FHNSFI3E7wmShw2YcnsO0%2FVirtualAlloc.png?alt=media&#x26;token=9acc4679-8c37-4149-ba43-6093a5fb2739" alt=""><figcaption><p>Return Address at VirtualAlloc</p></figcaption></figure></div>

**Breakpoint at `CreateThread`**

<div align="left"><figure><img src="https://1334214017-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FGdM1jIOKw0EWSCHRMsql%2Fuploads%2FqMeatea3l7ame6evJMSM%2FCreateThread.png?alt=media&#x26;token=0b3bc4cd-91e5-4049-b043-77bf238184c8" alt=""><figcaption><p>Return Address at CreateThread</p></figcaption></figure></div>

**Breakpoint at `WaitForSingleObject`**

<div align="left"><figure><img src="https://1334214017-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FGdM1jIOKw0EWSCHRMsql%2Fuploads%2FI0Q8Vud7ezT9jcnJoZ2M%2FWaitForSingleObject.png?alt=media&#x26;token=39c7ee69-e5c9-4d39-b0c9-50c2d82e1594" alt=""><figcaption><p>Return Address at WaitForSingleObject</p></figcaption></figure></div>

## References

* <https://sabotagesec.com/the-stack-series-return-address-spoofing-on-x64/>
* <https://g3tsyst3m.github.io/shellcoding/assembly/debugging/x64-Assembly-&-Shellcoding-101/>
