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. hdu_5881_Tea(xjb猜)

    题目链接:hdu_5881_Tea 题意: 有一壶水, 体积在 L 和 R 之间, 有两个杯子, 你要把水倒到两个杯子里面, 使得杯子水体积几乎相同(体积的差值小于等于1), 并且使得壶里剩下水体积不 ...

  2. 浙江大学 pat 题解---58

    1058. A+B in Hogwarts (20) 时间限制 50 ms 内存限制 32000 kB 代码长度限制 16000 B 判题程序 Standard 作者 CHEN, Yue If you ...

  3. 使用NGUI实现拖拽功能(拼图小游戏)

    上一次用UGUI实现了拼图小游戏,这次,我们来用NGUI来实现 实现原理 NGUI中提供了拖拽的基类UIDragDropItem,所以我们要做的就是在要拖拽的图片上加一个继承于该类的脚本,并实现其中的 ...

  4. 显示进度条tqdm

    http://www.open-open.com/lib/view/open1451794925808.html

  5. PHP ServerPush (推送) 技术

    用来代替ajax的请求 转自:http://blog.163.com/bailin_li/blog/static/17449017920124811524364/ 需求: 我想做个会员站内通知的功能. ...

  6. 网页 JavaScript

    今天,我主要学习了JavaScript的部分内容. JavaScript在html中的位置主要有三个地方:head里面.body里面.</html>之后,我们一般写在</html&g ...

  7. cookie和session的区别(搜狐笔试考到的一个题目)

    一.cookie机制和session机制的区别***************************************************************************** ...

  8. 《Windows驱动开发技术详解》之驱动程序调用驱动程序——通过设备指针调用其他驱动程序

    本节介绍“手动”构造各个IRP,然后将IRP传递到相应驱动程序的派遣函数里. 获得设备指针 每个内核中的句柄都会和一个内核对象的指针联系起来.ZwCreateFile内核函数可以通过设备名打开设备句柄 ...

  9. 《C++ Primer》之面向对象编程(二)

    构造函数和复制控制 每个派生类对象由派生类中定义的(非 static)成员加上一个或多个基类子对象构成,当我们构造.复制.赋值和撤销一个派生类对象时,也会构造.复制.赋值和撤销这些基类子对象. 构造函 ...

  10. Ajax应用-Ajax传输JSON数据实例

    ———————————————————— <script type="text/javascript">            var client;          ...