文档章节

Thunk: thiscall, stdcall

扫地
 扫地
发布于 2015/01/04 14:38
字数 441
阅读 42
收藏 0

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;
};


© 著作权归作者所有

共有 人打赏支持
上一篇: NodeJS
下一篇: GCC 输入输出流
扫地
粉丝 0
博文 18
码字总数 12230
作品 0
成都
程序员
私信 提问
如何让C++类的成员函数作为回调函数

为什么类(class)的成员函数(member function)不能作为回调函数(callback function)? 首先来看看回调函数有怎样的特点。windows中,回调函都显式(explicit)使用CALLBACK修饰符(decorator)修饰...

LoveStones
2012/04/26
0
1
C/C++中函数调用规则(约定)__cdecl __stdcall __thiscall __vectorcall __fastcall

相关文献 stdcall https://msdn.microsoft.com/en-us/library/zxk0tw93.aspx C语言函数可变参数详解 - ranpanf的专栏 - 博客频道 - CSDN.NET http://blog.csdn.net/ranpanf/article/details/......

zray4u
2016/06/22
181
0
_cdecl、_stdcall、_fastcall和_thiscall整理

cdecl、stdcall、fastcall和thiscall整理 1._cdecl是C Declaration的缩写,表示C语言默认的函数调用方法:所有参数 从右到左依次入栈,这些参数由调用者清除,称为手动清栈(由调用者把参数弹...

西昆仑
2011/11/17
0
1
2016年4月5日:调用转换

cdecl fastcall与_stdcall,三者都是调用约定(Calling convention),它决定以下内容:1)函数参数的压栈顺序,2)由调用者还是被调用者把参数弹出栈,3)以及产生函数修饰名的方法。 1、stdcall...

maomao818
2016/04/05
18
0
带你玩转Visual Studio——调用约定__cdecl、__stdcall和__fastcall

有一定C++开发经验的人一定对"cdecl、stdcall、fastcall"肯定不陌生吧!但你真正理解了吗?是的,我曾在这采了无数个坑,栽了无数个跟头,终于忍无可忍要把它总结一下(虽然我已经有能力解决大...

spencer.luo
2017/12/25
0
0

没有更多内容

加载失败,请刷新页面

加载更多

AWS 为 Elasticsearch 推出开源发行版

AWS 近日宣布为 Elasticsearch 推出开源发行版 Open Distro for Elasticsearch。 Elasticsearch 是一个分布式、面向文档的搜索和分析引擎,它支持结构化和非结构化查询,并且不需要提前定义模...

linux-tao
21分钟前
5
0
spring cloud与spring boot版本对应关系

https://spring.io/projects/spring-cloud 看Release Train Greenwich |2.1.x |- Finchley |2.0.x Edgware |1.5.x Dalston |1.5.x...

Danni3
21分钟前
2
0
开源 java CMS - FreeCMS2.8 数据对象 guestbook

项目地址:http://www.freeteam.cn/ guestbook 在使用留言相关标签时,标签会封装guestbook供页面调用。 属性 说明 id id siteid 所属站点id memberid 留言会员id membername 留言会员名称 ...

freeteam
23分钟前
0
0
【java+selenium】网易云音乐刷累计听歌数

背景 应该是在去年的时候,刷知乎看到一个问题,大概是说怎么刷网易云音乐个人累计听歌数,然后有一个高赞回答,贴了一段js代码,直接在浏览器console执行就可以了。当时试了下,直接一下子刷...

卧颜沉默
25分钟前
2
0
开启阿里云linux下的pure-ftpd被动模式,解决flashfxp可连接但无法下载的问题

由于某个网站的备案出现问题,只能将网站临时迁到香港服务器,原服务器是阿里云的centos系统,ftp服务器是用的pure-ftpd,香港服务器由于历史原因装的是server 2008 32位,ftp软件用的是fla...

我退而结网
26分钟前
2
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部