c++ THUNK技术

这里想说的是:代码中的关键点为用指令jmp pFunc跳转到你想要运行的函数pFunc。

指令“jmp xxxx”占5个字节,代码中用了个一字节对齐的结构体struct Thunk ,

当然也能够用 unsigned char code[5]; 说还有一个关键点就是地址计算了,jmp xxxx指令用了相对跳转地址,

相对地址 = 要跳转函数的地址 - “jmp xxxx”指令的下一条指令的地址。

以下代码中的class C 仅仅有m_thunk一个数据成员,没有虚函数和在m_thunk前没有声明别的数据成员,

因此相对地址 = pFunc - [ (int)this + sizeof(struct Thunk) ]

如上所述,若有虚函数和在m_thunk前声明了别的数据成员,则相对地址的计算要做改动。

:)本来画个表会说得比較清楚,但本人嫌麻烦,就作罢了!

/////////////////////////////////////////////以下是所转的文章////////////////////////////////////////////////////////////////////////////////


实际上C++ 的THUNK技术是须要改变指令代码的,这里发一个贴说明之

// 此程序演示 执行时 改变 指令代码

//实质是 C++ 实现多态  的 THUNK 技术思想的简陋模拟

//在VC6.0 中编译通过。

#include <windows.h>

#include <iostream.h>

typedef void(*pFUN)();  //函数类型

#pragma pack(push,1) //强制编译器,使数据按字节边界对齐。

//默认情况下VC6.0是按4字节对齐,VC7.0按8字节对齐

//指令本不是按双字边界对齐的,所以必须使其按字节边界对齐,否则出错

// 以下是存储机器代码的结构

struct Thunk //有趣的是:这个结构不储存数据,而是储存指令。一个jmp跳转指令

{   //我们将改变这个结构,然后让程序运行此代码,此结构的运行将会改变程序的运行路径

BYTE    m_jmp; // 储存jmp指令的操作码

DWORD   m_adrr;      // 储存相对jmp指令的偏移地址(指令操作数)

};  //

#pragma pack(pop)//撤销数据按字节对齐,数据按双字对齐的主要目的是优化运行速度

class C

{

public:

Thunk    m_thunk;  //产生一个 Thunk 实例

void Init(pFUN pFun)

{

m_thunk.m_jmp = 0xe9;// 跳转指令的操作码是 0xe9 所以。。。

m_thunk.m_adrr = (int)pFun - ((int)this+sizeof(Thunk));

// JMP跳转是相对跳转,也就是说:它是跳转到的地址是: 当前指令地址(EIP)+相对操作数

// 相对操作数有符号的!

//当指令运行到Thunk 中指令的时候,我们须要跳转到pFun,而当前EIP指为(int)this+sizeof(Thunk)

//原因:在顺序运行指令时,EIP在运行一条指令后会自己主动增,这里当然增的是sizeof(Thunk)

//又因为没有virtual指针,所以 m_thunk的地址就是this指向地址,可是运行此指令后EIP会自己主动加,

//所以EIP内容为(int)this+sizeof(Thunk)

//所以 pFun=m_thunk.m_adrr+((int)this+sizeof(Thunk)),移项可得上式

FlushInstructionCache(GetCurrentProcess(),

&m_thunk, sizeof(m_thunk)); //强制刷新指令缓冲,

//目的是使指令CACHE与主存相一致

}

//实验的第一函数

void function()

{

// 初始化thunk

// 获得thunk代码地址

pFUN pFun = (pFUN)&(m_thunk);

// 调用StaticFun

pFun();

}

static void Fun1()

{

cout << "this is Fun1" << endl;

}

static void Fun2()

{

cout << "this is Fun2" << endl;

}

};

int main()

{

C *pC=new C;

pC->Init(C::Fun1);

pC->function(); //1

pC->Init(C::Fun2);

pC->function();//2

//请注意,上面调用同一个函数,第一个运行的是C::Fun1,第二个却运行的是C::Fun2

//这充分说明实现了多态性!

return 0;

}

时间: 2024-08-16 11:04:47

c++ THUNK技术的相关文章

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

我们知道ATL(活动模板库)是一套很小巧高效的COM开发库,它本身的核心文件其实没几个,COM相关的(主要是atlbase.h, atlcom.h),另外还有一个窗口相关的(atlwin.h), 所以拿来学习应该是很方便的.但是因为ATL的代码充满了模板和宏,内部还夹杂着汇编,所以如果没有比较丰富的C++模板和系统底层的知识,一般人会看得一头雾水. 下面我们主要分析一下ATL中的一些汇编代码. ATL中出现汇编代码主要是2处,一处是通过Thunk技术来调用类成员函数处理消息:还有一处是通过打开_

compiler related

1. 词法分析 词法分析器根据词法规则识别出源程序中的各个记号(token),每个记号代表一类单词(lexeme).源程序中常见的记号可以归为几大类:关键字.标识符.字面量和特殊符号.词法分析器的输入是源程序,输出是识别的记号流.词法分析器的任务是把源文件的字符流转换成记号流.本质上它查看连续的字符然后把它们识别为“单词”. 2. 语法分析 语法分析器根据语法规则识别出记号流中的结构(短语.句子),并构造一棵能够正确反映该结构的语法树. 3. 语义分析 语义分析器根据语义规则对语法树中的语法单元

深入探索C++对象模型 读书笔记

第1章 关于对象 1.C++在布局以及存取时间上的主要的额外负担是由virtual引起的,包括: a.virtual function机制,引入vptr以及vtbl,支持一个有效率的"执行期绑定" b.virtual base class,用以实现"多次出现在继承体系中的base class,有一个单一而被共享的实例" c.多重继承下,派生类跟第二个以及后续基类之间的转换 2."指针的类型"会教导编译器如何解释某个特定地址中的内存内容以及其大小(

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

3.3 Data Member的存取1.   不管什么情况,每一个static data member只有一个实体,放在程序的data segment之中,每次程序取用static member,不管是通过operator::还是member selection operator,都会被内部转化为对该唯一extern实体的直接参考操作.每一个static member的存取以及与class的关联不会导致任何执行时间或空间上的额外负担.如果有两个classes,每一个都声明了一个static me

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

大牛的文章,值得拜读http://www.ibm.com/developerworks/cn/java/j-lo-polymorph/ 粘贴过来好多图片丢失了 /(ㄒoㄒ)/~~ 众所周知,多态是面向对象编程语言的重要特性,它允许基类的指针或引用指向派生类的对象,而在具体访问时实现方法的动态绑定.C++ 和 Java 作为当前最为流行的两种面向对象编程语言,其内部对于多态的支持到底是如何实现的呢,本文对此做了全面的介绍. 注意到在本文中,指针和引用会互换使用,它们仅是一个抽象概念,表示和另一个对

wtl学习总结

在windows平台,相比MFC,我更喜欢WTL,因其简洁漂亮.所以陆续花了一年的时间学习之,这里总结一下(在学习Wtl/Atl之前,最好是对WinApi编程有一定的了解). 安装 Wtl主页 http://sourceforge.net/projects/wtl/ ,整个库就是一堆.h文件,官方没有提供Installer,下载后解压到某个目录即可. 如果需要在VS中使用“工作导向”,可以点击Appwiz目录下的对应js文件来安装之.虽然没有直接对VS2010的支持,不过拿VS2008的改改即可

不同WINDOWS平台下磁盘逻辑扇区的直接读写

不同WINDOWS平台下磁盘逻辑扇区的直接读写 关键字:VWIN32.中断.DeviceIoControl 一.概述 在DOS操作系统下,通过BIOS的INT13.DOS的INT25(绝对读).INT26(绝对写)等功能调用实现对磁盘逻辑扇区或物理扇区的读写是很方便的,C语言中还有对应上述功能调用的函数:biosdisk.absread和abswrite等.但在WINDOWS操作系统下编写WIN32应用程序时却再也不能直接使用上述的中断调用或函数了.那么,在WINDOWS操作系统下能不能实现磁盘

移动网络接口设计

移动网络接口设计 摘要:移动设备面临着多样化和动态的网络选项,要想充分地使用这些选项要求知道应用程序的意图.移动网络接口是一个简单而强大的处理网络多样性的机制.应用程序为网络传输提供一个声明标签,并将系统匹配到最合适的网络.移动网络接口还可以推迟和重新排序传输的数据,提供应用程序互斥和排序约束机制. 关键词:移动网络;接口设计;数据传输 1引言 移动设备面临着一个多元.动态的网络选项.这些选项有各种各样的优点和缺点.因此,在所有情况下没有单一的"最佳选择",基础设施的多样性既是挑战,也

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

转载请说明原出处,谢谢~~ 看到群里朋友有人讨论WTL中的thunk技术,让我联想到了duilib的类似技术.这些技术都是为了解决c++封装的窗体类与窗体句柄的关联问题. 这里是三篇关于thunk技术的博客,不懂的朋友可以先看一下: WTL学习之旅(三)WTL中 Thunk技术本质(含代码) 深入剖析WTL-WTL框架窗口分析 (5) 学习下 WTL 的 thunk 我这里直接引用其他博客的一部分文字来说明窗体类与窗体句柄关联的重要性和相关的问题,然后说明一下duilib中的解决方法: ----