Search code examples
c++assemblyx86calling-convention

Thunking __stdcall function with stack adjustment


I'd like to thunk (by adjusting the stack) __stdcall function. For example a caller think is has a pointer to a callback function with the following prototype:

int Func(int a);

I'd like to write a thunk (that will be passed as a callback) that adjust the call to the following function prototype:

int Func(char* ptr, int a);

I know that when my thunk will be called that stack layout is:

------------------
|       a        |
------------------
| return address | <-- Top of the stack
------------------

I'd like to adjust the stuck to:

------------------
|       a        |
------------------
------------------
|       ptr      |
------------------
| return address | <-- Top of the stack
------------------

and then do a relative jump to relevant function (this way when the called function return the stack is balanced)

Here is my final thunk that works (of course it has to be packed and dynamically loaded to executable memory), Kudo to Jester for helping with assembly hex code for needed instructions !

struct Thunk
{
    BYTE    m_popRet;
    BYTE    m_pushPtr;          
    DWORD   m_ptr;         
    BYTE    m_pushRet;         
    BYTE    m_jmp;          
    DWORD   m_relProc;      
    BOOL Init(DWORD_PTR proc, void* ptr)
    {
        m_popRet  = 0x58;       
        m_pushPtr = 0x68; 
        m_ptr     = PtrToUlong(ptr);
        m_pushRet = 0x50;
        m_jmp     = 0xE9;
        m_relProc = DWORD((INT_PTR)proc - ((INT_PTR)this + sizeof Thunk));
        return TRUE;
    }
}

Solution

  • Since you described the stack layout, not sure what you have a problem with. Anyway, if you want to use JMP your code could look like:

    pop eax  ; 58             return address
    push ptr ; 68 xx xx xx xx
    push eax ; 50             put return address back
    jmp proc ; E9 xx xx xx xx
    

    Note that this will change stack alignment, so if you are in an environment where that matters, you will have to adjust the code. A somewhat more civilized version could be:

    push edx     ; 52             align stack
    push [esp+8] ; FF 74 24 08    "a"
    push ptr     ; 68 xx xx xx xx
    call proc    ; E9 xx xx xx xx
    pop edx      ; 5A
    ret 4        ; C2 04 00