thunk技术
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技术的更多相关文章
- 理解ATL中的一些汇编代码(通过Thunk技术来调用类成员函数)
我们知道ATL(活动模板库)是一套很小巧高效的COM开发库,它本身的核心文件其实没几个,COM相关的(主要是atlbase.h, atlcom.h),另外还有一个窗口相关的(atlwin.h), 所以 ...
- c++ THUNK技术
这里想说的是:代码中的关键点为用指令jmp pFunc跳转到你想要运行的函数pFunc. 指令"jmp xxxx"占5个字节,代码中用了个一字节对齐的结构体struct Thunk ...
- C++中的Thunk技术 / 非静态类成员函数作为回调函数 的实现方法
原文:https://blog.twofei.com/616/ 用我的理解通俗地解释一下什么是C++中的Thunk技术吧! Thunk技术就是申请一段可执行的内存, 并通过手动构造CPU指令的形式来生 ...
- C++函数调用的反汇编过程及Thunk应用
x86汇编基础知识 1. 汇编常用寄存器 esp,(Extended stack pointer)栈顶指针.因为x86的栈内存是向下扩展的,因此当push入栈时,esp–.pop出栈时,esp++.e ...
- Java多态与C++中多态的实现
大牛的文章,值得拜读http://www.ibm.com/developerworks/cn/java/j-lo-polymorph/ 粘贴过来好多图片丢失了 /(ㄒoㄒ)/~~ 众所周知,多态是面向 ...
- Delphi对象变成Windows控件的前世今生(关键是设置句柄和回调函数)goodx
----------------------------------------------------------------------第一步,准备工作:预定义一个全局Win控件变量,以及一个精简 ...
- duilib底层机制剖析:窗体类与窗体句柄的关联
转载请说明原出处,谢谢~~ 看到群里朋友有人讨论WTL中的thunk技术,让我联想到了duilib的类似技术.这些技术都是为了解决c++封装的窗体类与窗体句柄的关联问题. 这里是三篇关于thunk技术 ...
- [转]《深度探索C++对象模型》读书笔记[二]
3.3 Data Member的存取1. 不管什么情况,每一个static data member只有一个实体,放在程序的data segment之中,每次程序取用static member,不管 ...
- 【高级】C++中虚函数机制的实现原理
多态是C++中的一个重要特性,而虚函数却是实现多态的基石.所谓多态,就是基类的引用或者指针可以根据其实际指向的子类类型而表现出不同的功能.这篇文章讨论这种功能的实现原理,注意这里并不以某个具体的编译器 ...
随机推荐
- WCF、Web API、WCF REST、Web Service的区别
Difference between WCF and Web API and WCF REST and Web Service The .Net framework has a number of ...
- C++中构造函数或析构函数定义为private
转自:http://www.blogjava.net/fhtdy2004/archive/2009/05/30/278971.html 很多情况下要求当前的程序中只有一个object.例如一个程序只有 ...
- drupal7 安装百度编辑器Ueditor及后续使用
参考文章:drupal7安装百度编辑器ueditor 一.下载 1.需要下载安装的模块: 1.1.wysiwyg 1.2.ueditor 1.3Libraries 下载后安装在\sites\all\m ...
- sql随机
想从MySQL数据库中随机取一条或者N条记录时,最好把RAND()生成随机数放在JOIN子查询中以提高效率. SELECT id FROM table ORDER BY RAND() LIMIT n; ...
- jQuery中的方法
jQuery中的方法来操作HTML标签中的属性 attr(name) 获取当前对象的指定的属性的值 attr(key,value) 给当前对象设置属性值 attr(properties) 一 ...
- TODO:小程序的使用体验
TODO:小程序的使用体验 2017.01.09小程序如期而至,话说十年前的今天2007.01.09是第一代iPhone发布日期. 清晨朋友圈发了一张小程序的截图,很多朋友问用什么版本的微信才有小程序 ...
- android常用工具类
import android.content.Context; import android.net.ConnectivityManager; import android.net.NetworkIn ...
- ios可变数组的所有操作
#pragma mark 创建数组c NSMutableArray * array =[[NSMutableArray alloc] initWithObjects:@"a",@& ...
- android log 学习
一,Bug出现了, 需要“干掉”它 bug一听挺吓人的,但是只要你懂了,android里的bug是很好解决的,因为android里提供了LOG机制,具体的底层代码,以后在来分析,只要你会看bug, a ...
- TD配置安装方式
TD服务器搭建及配置指南 第一:安装前的环境准备 系统需安装IIS作为web服务器(停止IIS的smtp服务). 选择SQL Server2000作为数据库.Win2003需安装SP3. 以管理员登陆 ...