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. Sublime themes/ lint themes setup

    [Sublime 3 Setup for ES6 / Babel] https://www.youtube.com/watch?v=L8nmOqyyJLA [config oceanic next t ...

  2. 2DToolkit官方文档中文版打地鼠教程

    初始设置 创建一个Unity项目,并导入2D Toolkit插件. 导入完成后,在Project窗口会显示TK2DROOT文件夹(后续版本文件夹名称或许会有变动). 导入素材游戏,你可以从这里下载.下 ...

  3. C#连接sqlserver数据库

    // 混合登录 写法1:Data Source=myServerAddress;Initial Catalog=myDataBase;User Id=myUsername;Password=myPas ...

  4. WTL版本ACEdit控件,改写自MFC版,附带源码

    自动完成是个很酷也很实用的功能,比如在浏览器地址栏输入几个字母,相关的记录就会在下拉框中陈列出来. 最近在做公司产品UI部分的改善,原版本是MFC做的,我决定用WTL,于是就遇到自动完成控件的问题.遍 ...

  5. zabbix 监控mysql主从

    这里记录了,每次都百度查询多次. zabbix默认包含mysql监控 其中包含 mysql的基本状态监控 MySQL主从监控需要结合自定义 1)目前项目需求 只对 Slave_IO_Running . ...

  6. mysql备份并自动压缩命令

    #! /bin/bash mysqldump -uroot -p'password' databasename | gzip > /home/backup/database_`date +%Y% ...

  7. asp 操作 json

    <% Dim sc4Json Sub InitScriptControl Set sc4Json =Server.CreateObject("MSScriptControl.Scrip ...

  8. cmd 下登陆ftp及相关操作

    cmd 下登陆ftp及相关操作 2011-08-09 20:34:28|  分类: 小技巧|字号 订阅 一.举例 假设FTP地址为“ 61.129.83.39”(大家试验的时候不要以这个FTP去试,应 ...

  9. cPanel 安装方法

    . 如何安装cPanel/WHM? 答:安装过程较长,建议使用screen或nohupscreen: yum -y install screen perl screen -S cpanel cd /h ...

  10. Android软件盘InputMethodManager

    调用下面代码:(第一次调用显示,再次调用则隐藏,如此反复),this指activity InputMethodManager imm = (InputMethodManager)this.getSys ...