How to thunk a function in x86 and x64? (Like std::bind in C++, but dynamic)

前端 未结 2 750
春和景丽
春和景丽 2021-01-06 03:00

How do I thunk an arbitrary function with an arbitrary (fixed) number of arguments, on x86 and x64?

(I don\'t need floating-point, SSE, or the like. The arguments ar

2条回答
  •  暖寄归人
    2021-01-06 03:32

    Here is a modification for thiscall functions

    The vbind() stub generator above is meant to be used for C++ member functions as well, although it is not clear how to proceed. Here's what I've come up with:

    // experimental x64 thiscall thunking
    class TestHook {
    public:
        typedef void (TestHook::*TMFP)();
    
        TestHook(DWORD num) 
        {
            m_context = num;
    
            union { void* (*func)(); TMFP method; } addr;
            addr.method = (TMFP)CBTHook_stub;
    
            // pass "this" as the first fixed argument
            void *args[] = { this };
            size_t thunk_size = vbind(addr.func, 4, m_thunk, 0, args, 1);
            ATLASSERT(thunk_size < sizeof(m_thunk));
    
            unsigned long old;
            VirtualProtect(m_thunk, thunk_size, PAGE_EXECUTE_READWRITE, &old);
            FlushInstructionCache(GetCurrentProcess(), m_thunk, thunk_size);
        }
    
        FARPROC GetThunk() const {    return (FARPROC)(void*)m_thunk; }
    
    protected:
        // test thiscall: one integer and two 8-byte arguments
        LRESULT CBTHook_stub(int nCode, WPARAM wParam, LPARAM lParam) 
        {
            ATLTRACE(_T("this=%p, code=%d, wp=%x, lp=%x, context=%x\n"), this, nCode, wParam, lParam, m_context);
            return lParam;
        }
    
        DWORD m_context;
        unsigned char m_thunk[1024]; // fixed; don't know size required apriori!
    };
    
    #ifndef _WIN64
    #error does not work for win32
    #endif
    void main(void)
    {
        TestHook tmp(0xDeadBeef);
    
        HOOKPROC proc = (HOOKPROC)tmp.GetThunk();
        ATLTRACE(_T("object %p return value=%d\n"), &tmp, proc(1, 2, 3));
    }
    

    I am not an assembly gury but this code correctly stubs into the member function for 64 bit code. There are some implicit assumptions (I'm not 100% sure if valid, please correct me if I'm wrong):

    1. in x64 (amd / microsoft VS) all function arguments are passed as 8 bytes long. So although vbind was just for pointer-type arguments, it is possible to thunk into other function prototypes (e.g. the HOOKPROC takes one integer and two __int64)

    2. "this" pointer is passed as the first stack argument in x64 instead of ECX. I used the bounded argument to pass "this" pointer and provide context to the C++ object

提交回复
热议问题