这里想说的是:代码中的关键点为用指令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; 

}

c++ THUNK技术的更多相关文章

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

    我们知道ATL(活动模板库)是一套很小巧高效的COM开发库,它本身的核心文件其实没几个,COM相关的(主要是atlbase.h, atlcom.h),另外还有一个窗口相关的(atlwin.h), 所以 ...

  2. C++中的Thunk技术 / 非静态类成员函数作为回调函数 的实现方法

    原文:https://blog.twofei.com/616/ 用我的理解通俗地解释一下什么是C++中的Thunk技术吧! Thunk技术就是申请一段可执行的内存, 并通过手动构造CPU指令的形式来生 ...

  3. thunk技术

    Thunk : 将一段机器码对应的字节保存在一个连续内存结构里, 然后将其指针强制转换成函数. 即用作函数来执行,通常用来将对象的成员函数作为回调函数. #include "stdafx.h ...

  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. nyoj 17

    // nyoj 17        代码如上,用的是dp,总的来说就是对一个字符串 从末尾开始比较,设定一个数组,存放每个单调字串的最大长度,最后比较... //要注意的就是里面if语句对于每次字符比 ...

  2. H1标签使用的七大注意事项

    H1标签使用的七大注意事项: 1 每个页面都应该有H1标签,H1标签是每个网页不可缺少的要素. 2 使用H1标签的内容应该简洁明了; 3 H1标签要尽量出现在源文件代码的开头的部分,这样可以让访问者和 ...

  3. CSS简要内容

    1. 简介 用于布局与美化网页(颜色,字体) CSS语言是一种标记语言,不需编译,可直接由浏览器执行 大小写不敏感 CSS定义由选择符.属性.属性取值组成 格式:selector{property:v ...

  4. Visual Studio 2013如何破解(密钥激活)

    其实有个方法最简单,就是点击“帮助”,选择注册产品,点击打开页面右下边的“使用秘钥注册产品”,输入上述秘钥即可.   在输入密钥界面,输入密钥“BWG7X-J98B3-W34RT-33B3R-JVYW ...

  5. web项目环境搭建(2):整合SpringMVC+velocity

    velocity是一个基于java的模板引擎.velocity应用于web开发时,前端设计人员可以只关注页面的显示效果,而java程序人员只关注业务逻辑代码.velocity将java代码从web页面 ...

  6. 武汉科技大学ACM :1003: A+B for Input-Output Practice (III)

    Problem Description Your task is to Calculate a + b. Input Input contains multiple test cases. Each ...

  7. 函数递归时,递归次数到900多时,就是抛出异常exception RuntimeError('maximum recursion depth exceeded',)

    import subprocess import multiprocessing import urllib import sys import os import pymongo import si ...

  8. Jquery中$.get(),$.post(),$.ajax(),$.getJSON()的用法总结【转载】

    详细解读Jquery各Ajax函数:$.get(),$.post(),$.ajax(),$.getJSON() 一,$.get(url,[data],[callback]) 说明:url为请求地址,d ...

  9. [转] JS运算符 &&和|| 及其优先级

    第一.&& (逻辑与)运算,看一个简单的例子: var a = 1 && 2 && 3; var b = 0 && 1 &&am ...

  10. office2003万能密钥

    保证有效 OFFICE 2003 :  GWH28-DGCMP-P6RC4-6J4MT-3HFDY