zoukankan      html  css  js  c++  java
  • 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 

    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() 

       *pC=new C; 

       pC->Init(C::Fun1); 
       pC->function(); //1 

       pC->Init(C::Fun2); 
        
       pC->function();//2 
        
       //请注意,上面调用同一个函数,第一个运行的是C::Fun1,第二个却运行的是C::Fun2 
       //这充分说明实现了多态性! 
        return 0; 

  • 相关阅读:
    span里设置高度
    Tensorflow2.0语法
    Python-OpenCV中的filter2D()函数
    解决安装tensorflow等速度慢,超时
    keras绘图之pydot和graphviz的导入( pydot` failed to call GraphViz)
    天天向上
    time库
    PythonDraw及turtle库
    TempComvert及-eval的用法
    百分号字符串拼接
  • 原文地址:https://www.cnblogs.com/zfyouxi/p/4009449.html
Copyright © 2011-2022 走看看