Thunk: thiscall, stdcall

Thunk:根据编译器的调用规范,在代码中人工设置函数调用方式。

作用:修改回调函数的参数,将类的成员函数设置为回调函数。

原理:


以窗口函数为例  LRESULT (CALLBACK* WNDPROC)(HWND, UINT, WPARAM, LPARAM);

stdcall的调用方式

push LPARAM
push WPARAM
push UINT
push HWND
call WNDPROC


要修改参数在call前加一句代码:mov dword ptr [esp+0x4],  value

现在用一个结构体保存机器码来替代 call 的代码

typedef struct _STDCALL_
{
    unsigned int  mov;     // mov dword ptr [esp + 4], value ;
    unsigned int  value;   // value
    unsigned char jmp;    // 0xE9
    unsigned int  addr;     // relative jmp
} STDCALL;

在可执行的内存中分配一段内存存放这个结构体,就可以把这个结构体当函数调用了,而且修改了第一个参数的值


类似的 thiscall 是将 this 指针放在了 ecx 寄存器,只要使用同样的方法就能将 thiscall 变成 stdcall

typedef struct _THISCALL_
{
    unsigned char mov;     // 0xB9
    unsigned int  obj;        // this pointer
    unsigned char jmp;     // 0xE9
    unsigned int  addr;      // relative jmp
} THISCALL;


封装好的类:

template<class T>
class Thunk
{
 typedef ::LRESULT (T::* WndProc)(::HWND, ::UINT, ::WPARAM, ::LPARAM);
public:
    Thunk()
    {
        m_thunk = (Thunk*)VirtualAlloc(NULL, sizeof (Thunk), MEM_COMMIT, PAGE_EXECUTE_READWRITE);
    }
    ~Thunk()
    {
        if (NULL != m_thunk) VirtualFree(m_thunk, 0, MEM_RELEASE);
    }
 template<typename R, typename U>
    R Thiscall(T* obj, U fn)
    {
        m_thunk->m_thiscall.mov  = 0xB9;
        m_thunk->m_thiscall.obj  = reinterpret_cast<unsigned int>(obj);
        m_thunk->m_thiscall.jmp  = 0xE9;
        m_thunk->m_thiscall.addr = union_cast<unsigned int>(fn) - (unsigned int)(&(m_thunk->m_thiscall)) - sizeof(THISCALL);
        FlushInstructionCache(GetCurrentProcess(), &(m_thunk->m_thiscall), sizeof(THISCALL));
        return (R)&(m_thunk->m_thiscall);
    }
 template<typename R, typename U>
    R Stdcall (T* obj, U fn)
    {
        m_thunk->m_stdcall.mov     = 0x042444C7;
        m_thunk->m_stdcall.obj     = reinterpret_cast<unsigned int>(obj);
        m_thunk->m_stdcall.jmp     = 0xE9;
        m_thunk->m_stdcall.addr    = union_cast<unsigned int>(fn) - (unsigned int)(&(m_thunk->m_stdcall)) - sizeof(STDCALL);
        FlushInstructionCache(GetCurrentProcess(), &(m_thunk->m_stdcall), sizeof(STDCALL));
        return (R)&(m_thunk->m_stdcall);
    }
private:
#pragma pack (push, 1)
    typedef struct _THISCALL_
    {
        unsigned char mov;     // 0xB9
        unsigned int  obj;    // this pointer
        unsigned char jmp;     // 0xE9
        unsigned int  addr;    // relative jmp
    } THISCALL;
    typedef struct _STDCALL_
    {
        unsigned int  mov;    // mov dword ptr [esp + 4], obj;
        unsigned int  obj;    // this pointer
        unsigned char jmp;     // 0xE9
        unsigned int  addr;    // relative jmp
    } STDCALL;
#pragma pack (pop)
    THISCALL m_thiscall;
    STDCALL  m_stdcall;
    Thunk* m_thunk;
};


转载于:https://my.oschina.net/u/174780/blog/363482

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值