对类成员进行特殊操作(2) 发布者: 北斗龙 (进入北斗龙个人专栏) | |||||||
| |||||||
评价等级: |
| ![]() | |||||
2位用户为此文章评分,平均分为4.0 |
大家在看了文章1后以经对取得虚函数地址有所了解,但用它作回调函数还是有一点问题,因为要使成员函数正确运行,我们必须每次在调用这前传一个this给ecx(对应的成员函数中没有操作类成员除外,原因见(文章1)),作为回调函数,它可不给你这个机会,那怎么实现呢? 下面就是一种实现方法: 我们可以在数据段中开一个数组,在这个数组里存放一些特殊的数据,然后将这个数组的地址作为回调函数的地址,然后这个数组将被作为代码运行。那么这个数组对应的代码又做些什么呢?很简单的:将对象的地址传入ecx, 然后jmp到真正的回调函数。 下面是个例子: 主要部分也就是ThunkInit(ThunkData t, void *This, int VirFucID); 传入一个数组指针,一个对象的指针,一个对应第几个虚函数。然后这个函数将生成对应的可执行代码:将对象的地址传入ecx, 最后jmp到真正的回调函数。 其次,就是用数组的地址作为函数地址,调用对应的函数时,先执行数组里的代码,这样就保证了函数内部的this指针的正确性。 例3 class CCC { public: CCC() {m_data1=50;} ~CCC() {}; virtual void print1() { ::printf("m_data1=%dn", m_data1); } virtual void print2() { ::printf("m_data1+10=%dn", m_data1+10); } virtual void print3(int num) { ::printf("m_data1+%d=%dn", num, m_data1+num); } private: int m_data1; }; typedef unsigned char ThunkData[14]; void inline ThunkInit(ThunkData t, void *This, int VirFucID) { // begin ThunkInit t[0] = 0xB9; // mov ecx, *((long *)(t+1)) = (long) This; // this *((short int *)(t+5)) = 0x018B; // mov eax, [ecx] t[7] = 0x5; // add eax, *((long *)(t+8)) = VirFucID*4; // VirFucID*4 *((short int *)(t+12)) = 0x20FF; // jmp [eax] } // end ThunkInit void print5Times1(long fucAddr) { int i=5; while(i--) ((void (__stdcall *)(void))fucAddr)(); } void print5Times2(long fucAddr, int num) { int i=5; while(i--) ((void (__stdcall *)(int))fucAddr)(num); } void main() { CCC cc; ThunkData fucAddr; //不做回调函数 ThunkInit(fucAddr, &cc, 0); ((void (__stdcall *)(void))(long)fucAddr)(); ThunkInit(fucAddr, &cc, 1); ((void (__stdcall *)(void))(long)fucAddr)(); ThunkInit(fucAddr, &cc, 2); ((void (__stdcall *)(int))(long)fucAddr)(100); //做回调函数 ThunkInit(fucAddr, &cc, 0); print5Times1((long)fucAddr); ThunkInit(fucAddr, &cc, 1); print5Times1((long)fucAddr); ThunkInit(fucAddr, &cc, 2); print5Times2((long)fucAddr, 100); } 注意: 1. ((void (__stdcall *)(void))(long)fucAddr)();是将fucAddr的地址转换为long型,然后再将它转化为(void (__stdcall *)(void))类型函数(如有不明白,请找有关资料),最后调用此函数。 最后我想加几句题外话,这些例子都只是简单的用应,文章1中两个例子没有实际意义,旨在为例3做铺垫。至于有没有用,我也不知,只是我在一些程序中应用了而己,刚开始只是从其它原码中拿过来用,也不解其中的原理。但一次在图书管中看了<编程深入引导>>(中国水利水电出版社)后,由于它详细说明了类的实现,并附了对应的汇编源码,让我豁然开朗,经过几翻测试,终于弄懂了它的原理,觉得做法挺不错,也就写了上面这些,文笔较差,还不知能否让大家看懂。 不过这种做法有点费涩难懂,在附件中的工程DD,演示了“静态成员函数+对象的静态指针”做回调函数,不过在这里得注意一点,后面这种做法,整个类只能定义一个对象(因为对象的静态指针)。 |