简体   繁体   中英

How to bind this pointer to static member function using thunk in c++

I'm trying to create a thunk with C++ and Win32 API, that binds this pointer to static member function, so I can use that function as a callback.

Now, I have a working thunk for x64, it works by setting the value of r9 register (corresponds to 4th parameter of a function) to the address of this pointer.

But I'm having a problem with thunk for x86, I tried to setting the value of [esp+10h] (also corresponds to 4th parameter).

Here's the thunk:

#pragma pack(push, 1)
struct THUNK {
    DWORD mov;               // mov dword ptr[esp+10h], pThis
    DWORD pThis;
    BYTE  jmp;               // jmp relproc
    DWORD relproc;
}
#pragma pack(pop)

And here's the class that uses the thunk:

class foo {
    void callback_impl(int a, int b, int c) {
        ...
    }
    static void __stdcall callback(int a, int b, int c, foo *This) {
        This->callback_impl(a, b, c);
    }
public:
    THUNK *thunk;
    foo() {
        thunk = (THUNK*)VirtualAlloc(NULL, sizeof(THUNK), MEM_COMMIT, PAGE_EXECUTE_READWRITE);
        thunk->mov = 0x102444C7;
        thunk->pThis = (DWORD)this;
        thunk->jmp = 0xe9;
        thunk->relproc = DWORD((INT_PTR)&foo::callback - ((INT_PTR)thunk + sizeof(THUNK)));
        FlushInstructionCache(GetCurrentProcess(), this, sizeof(THUNK));
    }
    ~foo() {
        VirtualFree(thunk, sizeof(THUNK), MEM_DECOMMIT);
    }
};

And here's the callback user:

void callback_user(void(__stdcall *callback)(int, int, int)) {
    ...
}

// foo f;
// callback_user((void(__stdcall*)(int, int, int))f.thunk);

However, when I ran the program, it gave me the failure:

Run-Time Check Failure #0 - The value of ESP was not properly saved across a function call. This is usually a result of calling a function declared with one calling convention with a function pointer declared with a different calling convention.

How can I solve this problem?
Thanks.

This failure is caused by stdcall convention. Caller expects callee to clean up 3 arguments worth of stack while callee (your callback) cleans up 4 arguments causing esp to go to wrong location. Also you cannot just write to esp+10h because caller might be using it.

Now here is alternative idea: can't you just set ecx to this and call member function directly (provided it uses stdcall convention)?

UPDATE: Or you can put This as a first argument to your static member function so it closest to a stack top; thunk then can modify stack to make it look like a stdcall function call with 4 arguments. It will look something like

pop eax
push This
push eax
jmp func

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM