Thunk : 将一段机器码对应的字节保存在一个连续内存结构里, 然后将其指针强制转换成函数. 即用作函数来执行,通常用来将对象的成员函数作为回调函数.

#include "stdafx.h"
#include <Windows.h> namespace pri{ typedef unsigned char u1byte;
typedef unsigned short u2byte;
typedef unsigned long u4byte;
typedef void* pvoid; #define GETBYTE(b, n) ((u1byte)(b >> ((n - 1)* 8) & 0x 000000FF)) class Thunk
{
public:
Thunk()
{
m_pThis = (Thunk*)VirtualAlloc(nullptr, sizeof(Thunk),
MEM_COMMIT, PAGE_EXECUTE_READWRITE);
} ~Thunk()
{
if (m_pThis) {
VirtualFree(m_pThis, 0, MEM_RELEASE);
}
} public:
void* ThisCall(void* pThis, u4byte addr)
{
/*
__asm {
mov exc,pThis;
call Addr;
}
*/
m_pThis->m_thisCall.Mov = 0xB9; // mov exc,pThis;
m_pThis->m_thisCall.This = (u4byte)pThis;
m_pThis->m_thisCall.Jmp = 0xE9; // call Addr;
m_pThis->m_thisCall.Addr = addr - (u4byte)(&(m_pThis->m_thisCall)) -
sizeof(BYTECODE_THISCALL); FlushInstructionCache(GetCurrentProcess(), &(m_pThis->m_stdCall),
sizeof(BYTECODE_THISCALL));
return &(m_pThis->m_thisCall);
} void* StdCall(void* pThis, u4byte addr)
{
/*
__asm{
push dword ptr [esp];
mov dword ptr [esp+4],pThis;
call Addr;
}
*/
m_pThis->m_stdCall.Push[0] = 0xFF; // push dword ptr [esp];
m_pThis->m_stdCall.Push[1] = 0x34;
m_pThis->m_stdCall.Push[2] = 0x24;
m_pThis->m_stdCall.Mov = 0x042444c7; // mov dword ptr [esp+4],pThis;
m_pThis->m_stdCall.This = (u4byte)pThis;
m_pThis->m_stdCall.Jmp = 0xE9; // call Addr;
m_pThis->m_stdCall.Addr = addr - (u4byte)(&(m_pThis->m_stdCall)) -
sizeof(BYTECODE_STDCALL);
FlushInstructionCache(GetCurrentProcess(), &(m_pThis->m_stdCall),
sizeof(BYTECODE_STDCALL));
return &(m_pThis->m_stdCall);
} template<typename T>
static u4byte GetMemberAddr(T funcName)
{
union {
T From;
u4byte To;
} union_cast;
union_cast.From = funcName;
return union_cast.To;
} #pragma pack(push, 1)
struct BYTECODE_THISCALL
{
u1byte Mov; // 0xB0
u4byte This; // this
u1byte Jmp; // 0xE9
u4byte Addr; // addr
}; struct BYTECODE_STDCALL
{
u1byte Push[3];
u4byte Mov;
u4byte This;
u1byte Jmp;
u4byte Addr;
}; #pragma pack (pop)
BYTECODE_THISCALL m_thisCall;
BYTECODE_STDCALL m_stdCall;
Thunk* m_pThis;
};
} class A
{
public:
A() {} ~A() {} // __thiscall调用约定 [12/28/2014]
// 将this指针存入ecx寄存器进行参数传递
void __thiscall fun1(HWND hwnd, UINT msg, UINT_PTR id, DWORD time)
{
hwnd = 0;
msg = 1;
id = 2;
time = 3;
m_index = 100;
} // Win32API函数调用约定 [12/28/2014]
// 将this指针压入栈进行参数传递
void __stdcall fun2(HWND hwnd, UINT msg, UINT_PTR id, DWORD time)
{
hwnd = 0;
msg = 1;
id = 2;
time = 3;
m_index = 100;
} // c++默认为__thiscall调用约定 [12/28/2014]
void fun3(HWND hwnd, UINT msg, UINT_PTR id, DWORD time)
{
hwnd = 0;
msg = 1;
id = 2;
time = 3;
m_index = 100;
} private:
int m_index;
}; int _tmain(int argc, _TCHAR* argv[])
{
A* pa = new A();
pa->fun1(0, 1, 2, 3);
pa->fun2(0, 1, 2, 3);
pa->fun3(0, 1, 2, 3); pri::Thunk thunk;
void* thisAddr = thunk.ThisCall(pa, pri::Thunk::GetMemberAddr(&A::fun1));
void* stdAddr = thunk.StdCall(pa, pri::Thunk::GetMemberAddr(&A::fun2)); // 这里是非成员函数调用,只能为__stdcall [12/28/2014]
//typedef void(__thiscall* ThisCall)(HWND, UINT, UINT_PTR, DWORD);
typedef void(__stdcall* StdCall)(HWND, UINT, UINT_PTR, DWORD);
StdCall pv0 = (StdCall)thisAddr;
StdCall pv1 = (StdCall)stdAddr;
pv0(0, 1, 2, 3);
pv1(0, 1, 2, 3); // 执行成员函数回调 [12/28/2014]
UINT_PTR id0 = SetTimer(nullptr, 100, 1000, (TIMERPROC)pv0);
UINT_PTR id1 = SetTimer(nullptr, 101, 1000, (TIMERPROC)pv1); MSG msg;
int itemp;
while ( (itemp = GetMessage(&msg, NULL,NULL,NULL))&& (itemp!=0) && (-1 != itemp))
{
if (msg.message == WM_TIMER)
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
} system("pause"); return 0;
}

thunk技术的更多相关文章

  1. 理解ATL中的一些汇编代码(通过Thunk技术来调用类成员函数)

    我们知道ATL(活动模板库)是一套很小巧高效的COM开发库,它本身的核心文件其实没几个,COM相关的(主要是atlbase.h, atlcom.h),另外还有一个窗口相关的(atlwin.h), 所以 ...

  2. c++ THUNK技术

    这里想说的是:代码中的关键点为用指令jmp pFunc跳转到你想要运行的函数pFunc. 指令"jmp xxxx"占5个字节,代码中用了个一字节对齐的结构体struct Thunk ...

  3. C++中的Thunk技术 / 非静态类成员函数作为回调函数 的实现方法

    原文:https://blog.twofei.com/616/ 用我的理解通俗地解释一下什么是C++中的Thunk技术吧! Thunk技术就是申请一段可执行的内存, 并通过手动构造CPU指令的形式来生 ...

  4. C++函数调用的反汇编过程及Thunk应用

    x86汇编基础知识 1. 汇编常用寄存器 esp,(Extended stack pointer)栈顶指针.因为x86的栈内存是向下扩展的,因此当push入栈时,esp–.pop出栈时,esp++.e ...

  5. Java多态与C++中多态的实现

    大牛的文章,值得拜读http://www.ibm.com/developerworks/cn/java/j-lo-polymorph/ 粘贴过来好多图片丢失了 /(ㄒoㄒ)/~~ 众所周知,多态是面向 ...

  6. Delphi对象变成Windows控件的前世今生(关键是设置句柄和回调函数)goodx

    ----------------------------------------------------------------------第一步,准备工作:预定义一个全局Win控件变量,以及一个精简 ...

  7. duilib底层机制剖析:窗体类与窗体句柄的关联

    转载请说明原出处,谢谢~~ 看到群里朋友有人讨论WTL中的thunk技术,让我联想到了duilib的类似技术.这些技术都是为了解决c++封装的窗体类与窗体句柄的关联问题. 这里是三篇关于thunk技术 ...

  8. [转]《深度探索C++对象模型》读书笔记[二]

    3.3 Data Member的存取1.   不管什么情况,每一个static data member只有一个实体,放在程序的data segment之中,每次程序取用static member,不管 ...

  9. 【高级】C++中虚函数机制的实现原理

    多态是C++中的一个重要特性,而虚函数却是实现多态的基石.所谓多态,就是基类的引用或者指针可以根据其实际指向的子类类型而表现出不同的功能.这篇文章讨论这种功能的实现原理,注意这里并不以某个具体的编译器 ...

随机推荐

  1. ffmpeg编译

    CFLAGS=-g ./configure --enable-opengl  --disable-yasm  --enable-shared --enable-pic

  2. MBProgressHUD详解

    1,MBProgressHUD常用属性和用法Demo - (void)testMBProgressHUD { NSLog(@"test MBProgressHUD "); /* 要 ...

  3. sort 排序详解

    http://www.qdfuns.com/notes/17398/c56832f62b3271e79671f77dcdd2c058.html. http://www.qdfuns.com/notes ...

  4. 委托的BeginInvoke和EndInvoke方法

    .NET Framework 允许异步调用任何方法,为了实现异步调用目标,需要定义与被调用方法具有相同签名的委托.公共语言运行时会自动使用适当的签名为该委托定义 BeginInvoke 和 EndIn ...

  5. 关于const *和 * const

    int main() { ; ; int const *p = &i; p = &j; *p = ; //错误,*p的值被const修饰,为只读变量,不可更改 int * const ...

  6. android通过代码判断手机是否root

    只要/system/bin/su./system/xbin/su这两个文件中有一个存在,就表明已经具有ROOT权限,如果两个都不存在,则不具有ROOT权限. // 判断是否具有ROOT权限 publi ...

  7. leetcode21

    Merge two sorted linked lists and return it as a new list. The new list should be made by splicing t ...

  8. ERROR 1406 : Data too long for column 解决办法

    解决办法: 在my.ini里找到 sql-mode=”STRICT_TRANS_TABLES,NO_AUTO_Create_USER,NO_ENGINE_SUBSTITUTION” 把其中的STRIC ...

  9. YII2 小部件(widgets)

    小部件基本上在views中使用,在视图中可调用 yii\base\Widget::widget() 方法使用小部件. 该方法使用 配置 数组初始化小部件并返回小部件渲染后的结果. 例如如下代码插入一个 ...

  10. hdu_5044_Tree(树链剖分)

    题目连接:http://acm.hdu.edu.cn/showproblem.php?pid=5044 题意:给一棵树,在点和边上操作 题解:树链剖分,剖完后用树状数组维护即可,因为只有加减操作,连树 ...