Simple Thread Stack Spoofing in Assembly

A while ago I came across this technique for thread stack spoofing by Mariusz Banach. I wanted to see if I could replicate the technique using assembly (MASM), and so I set off to do just that. For those who aren’t aware of the technique, it can be demonstrated from C using the following code:

    
    void WINAPI MySleep(DWORD _dwMilliseconds)
{
    [...]
    auto overwrite = (PULONG_PTR)_AddressOfReturnAddress();
    const auto origReturnAddress = *overwrite;
    *overwrite = 0;

    [...]
    *overwrite = origReturnAddress;
}

It will get the address of the return address for the current function and overwrite that value with zero, then restore it with its original value before returning. This effectively hides stack frames for anything coming after the function MySleep in the above example and it makes the call stack appear as if it truncated at the point of MySleep. Looking at the C code, we can likely replicate this using assembly with minimal effort. But first, we should have some understanding about the stack on 64-bit Windows. Here’s a photo of what a standard function call looks like on 64-bit Windows.

64-bit Windows call stack

As you can see, at the start of a function the return address will be in the RSP register. This is the value returned by _AddressOfReturnAddress() in the previous C example from intrin.h. So now that we have our target address that we will be overwriting, we must also understand that any changes we make to the stack after the function starts will bring us farther away from the return address on the stack. It does not remain in the RSP register as your function continues to execute, so you must keep this distance in mind when you go to restore the return address value at the end of your assembly function. If we do not restore the return address with its original value properly, we will cause a crash of our program, so proper restoration is necessary. Actual implementations can vary, but a convenient approach would be to copy the value of RSP at the beginning of the function into a non-volatile register for restoration later, overwrite the value of RSP (return address at this time) with zero, then restore that value from the preservation register at the end. Let’s demonstrate an example of this. Let’s say that our assembly function will consume 40 bytes of stack space or 28 in hexadecimal. Here is how our example would look:

    
    .CODE

Spoof PROC
    mov r12, qword ptr [rsp]       ; Preserve the return address in r12
    mov qword ptr [rsp], 0         ; Overwrite return address with zero
    ...
    40 byte function
    ...
    mov qword ptr [rsp + 28h], r12 ; Restore the original value of the return address from r12 before returning
    ret
Spoof ENDP

END

And that’s it! A simple way to perform thread stack spoofing that you can incorporate into your functions written in assembly.

Scroll to Top