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++中的一个重要特性,而虚函数却是实现多态的基石.所谓多态,就是基类的引用或者指针可以根据其实际指向的子类类型而表现出不同的功能.这篇文章讨论这种功能的实现原理,注意这里并不以某个具体的编译器 ...
随机推荐
- POJ 1704 Georgia and Bob(阶梯博弈+证明)
POJ 1704 题目链接 关于阶梯博弈有如下定理: 将所有奇数阶梯看作n堆石头,做Nim,将石头从奇数堆移动到偶数堆看作取走石头,同样地,异或值不为0(利己态)时,先手必胜. 定理证明看此博:htt ...
- hdu_5876_Sparse Graph(补图BFS)
题目链接:hdu_5876_Sparse Graph 附上叉姐的题解: 1009 Sparse Graph [by ftiasch] 题意:n 个点的无向完全图中删除 m 条边,问点 s 到其他点的最 ...
- Udemy - Angular 2 - The Complete Guide 笔记
1. install > npm install -g angular-cli 2. create app > ng new first-app 3. build app > cd ...
- java方法的多态性理解
1.什么是java的多态 浏览了别人博客中的一些介绍多态的文章,发现大家的描述有点不一样,主要区别在于是否把方法的重写算做多态.一种我比较认同的说法如下: 多态分为两种 a. 编译时多态:方法的重载: ...
- nefu 1191 平行宇宙 (bfs)
Description 小k是时空贸易者,他经常在两个平行宇宙之间往来经商,现在他要从S点到达E点,问最少需要多长时间.(已知小k在同一个宇宙中只能向上下左右四个方向移动,每次移动需要1个单位时间,且 ...
- 防暴力破解 Fail2Ban之python
fai2ban的介绍 fail2ban可以监视你的系统日志,然后匹配日志的错误信息(正则式匹配)执行相应的屏蔽动作(一般情况下是调用防火墙屏蔽),如:当有人在试探你的SSH.SMTP.FTP密码,只要 ...
- Sharepoint 的定制 - 代码附加内容编辑器
//来源:http://www.cnblogs.com/codingcow/articles/69143.html Sharepoint是一种非常新而且很有用的技术. 现在微软把基本的功能集成到了Wi ...
- jqgird 实践
$.jgrid.defaults.styleUI="Bootstrap"; $("#table_list_2").jqGrid({ multiselect: t ...
- Saltstack 服务器基本安装
Salt介绍 Salt是一个基础平台管理工具 Salt是一个配置管理系统,能够维护预定义状态的远程节点 Salt是一个分布式远程执行系统,用来在远程节点上执行命令和查询数据 Salt核心功能 使命令发 ...
- 2.Perl 多线程:Threads(线程返回值)
use warnings; use strict; use threads; sub TEST{ print "Hello, World!\n"; 'a'/); } #返回列表方法 ...