ImageVerifierCode 换一换
格式:DOCX , 页数:12 ,大小:18.23KB ,
资源ID:22994723      下载积分:3 金币
快捷下载
登录下载
邮箱/手机:
温馨提示:
快捷下载时,用户名和密码都是您填写的邮箱或者手机号,方便查询和重复下载(系统自动生成)。 如填写123,账号就是123,密码也是123。
特别说明:
请自助下载,系统不会自动发送文件的哦; 如果您已付费,想二次下载,请登录后访问:我的下载记录
支付方式: 支付宝    微信支付   
验证码:   换一换

加入VIP,免费下载
 

温馨提示:由于个人手机设置不同,如果发现不能下载,请复制以下地址【https://www.bdocx.com/down/22994723.html】到电脑端继续下载(重复下载不扣费)。

已注册用户请登录:
账号:
密码:
验证码:   换一换
  忘记密码?
三方登录: 微信登录   QQ登录  

下载须知

1: 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。
2: 试题试卷类文档,如果标题没有明确说明有答案则都视为没有答案,请知晓。
3: 文件的所有权益归上传用户所有。
4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
5. 本站仅提供交流平台,并不能对任何下载内容负责。
6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

版权提示 | 免责声明

本文(回调函数封装Thunk技术及反汇编技术.docx)为本站会员(b****1)主动上传,冰豆网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。 若此文所含内容侵犯了您的版权或隐私,请立即通知冰豆网(发送邮件至service@bdocx.com或直接QQ联系客服),我们立即给予删除!

回调函数封装Thunk技术及反汇编技术.docx

1、回调函数封装Thunk技术及反汇编技术回调函数封装之Thunk技术将回调函数封装在类内(笔记)回调函数的引入/导入头文件#include ZThunk.hclass CTimerprivate:/ 此对像必须声时为类的数据成员或者全局对像,以保证它的生命周期ZThunk m_thunk; public:/安装定时器void Set()/计算回调函数地址void* pAddr=m_thunk.Callback(this,&CTimer:TimerProc,ZThunk:thisCALL);/安装计时器SetTimer(NULL,1,1000,(TIMERPROC)pAddr); /定时器回调函数

2、,完全被封装成类成员函数!void TimerProc(HWND hWnd, DWORD dwMsg , WPARAM wPa, LPARAM lPa)/ to do something;下划线部分SetTimer(NULL,1,1000,(TIMERPROC)pAddr);原型UINT_PTR SetTimer( HWND hWnd,UINT_PTR nIDEvent,UINT uElapse,TIMERPROC lpTimerFunc);、/详细参考可见MSDN当定时时间到以后,系统会自动跳转至lpTimerFunc,执行对应的代码,一般称之为回调函数。但是,若想将函数定义为类的成员函数,

3、必须保证存在this指针(成员函数的默认参数,指向当前的对象)或将该函数定义为static函数(static函数是类的函数,因此不存在this指针)。综上,解决方案如下:方法一:将回调函数定义为类的static函数:static函数不存在this指针,因此不能访问非static成员函数(非static成员函数内部需要this指针)以及非static成员变量。因此,该方法有一定的限制,不能对对象的状态做相应的更改。代码如下:class CTimerpublic:/typedef VOID (CALLBACK* TIMERPROC)(HWND, UINT, UINT, DWORD);/安装定时器v

4、oid Set()/计算回调函数地址void* pAddr=m_thunk.Callback(this,&CTimer:TimerProc,ZThunk:thisCALL);/安装计时器SetTimer(NULL,1,1000,(TIMERPROC)pAddr); /定时器回调函数,完全被封装成类成员函数!static void TimerProc(HWND hWnd, DWORD dwMsg , WPARAM wPa, LPARAM lPa)/ to do something;方法二:利用Thunk技术Thunk技术是利用嵌入一组动态ASM(汇编)指令,传递this指针,同时跳转至Timer

5、Proc。下面反汇编一段简单程序:C+源程序:#include using namespace std;class test1public:int b;char a;char c3;void func1()a = a;couta b)return a;elsereturn b;int main()int a = 0; int b = 1; int c = 2;a = Compare(a, b, b);coutaendl;test1 t1;t1.func1();return 0;/main函数部分的反汇编代码int main()/利用保存调main函数的的ebp寄存器004015D0 55 pu

6、sh ebp004015D1 8B EC mov ebp,esp/将栈顶指针下移54h字节,预留一段栈内存用于存储局部变量004015D3 83 EC 54 sub esp,54h/现场保护,将一系列寄存器入栈,程序结束后出栈004015D6 53 push ebx004015D7 56 push esi004015D8 57 push edi004015D9 8D 7D AC lea edi,ebp-54h004015DC B9 15 00 00 00 mov ecx,15h004015E1 B8 CC CC CC CC mov eax,0CCCCCCCCh004015E6 F3 AB re

7、p stos dword ptr ediint a = 0;/局部变量存在栈中004015E8 C7 45 FC 00 00 00 00 mov dword ptr ebp-4,0int b = 1;004015EF C7 45 F8 01 00 00 00 mov dword ptr ebp-8,1int c = 2;004015F6 C7 45 F4 02 00 00 00 mov dword ptr ebp-0Ch,2a = Compare(a, b, c);/调用函数,利用堆栈传参数:从右向左依次入栈:c、b、a004015FD 8B 45 F8 mov eax,dword ptr e

8、bp-0Ch00401600 50 push eax/c入栈00401601 8B 4D F8 mov ecx,dword ptr ebp-800401604 51 push ecx/b入栈00401605 8B 55 FC mov edx,dword ptr ebp-400401608 52 push edx/a入栈00401609 E8 9C FA FF FF call ILT+165(Compare) (004010aa)/见下0040160E 83 C4 0C add esp,0Ch /堆栈清理,将实参abc移除00401611 89 45 FC mov dword ptr ebp-4

9、,eaxcoutaendl;00401614 68 CD 10 40 00 push offset ILT+200(std:endl) (004010cd)00401619 8B 45 FC mov eax,dword ptr ebp-40040161C 50 push eax0040161D B9 90 BE 47 00 mov ecx,offset std:cout (0047be90)00401622 E8 DD FA FF FF call ILT+255(std:basic_ostreamchar,std:char_traits :operator) (00401104)0040162

10、7 8B C8 mov ecx,eax00401629 E8 C1 FB FF FF call ILT+490(std:basic_ostreamchar,std:char_traits :operator) (004011ef)test1 t1;t1.func1();0040162E 8D 4D EC lea ecx,ebp-14h/利用ecx传递this指针00401631 E8 50 FB FF FF call ILT+385(test1:func1) (00401186)return 0;00401636 33 C0 xor eax,eax/自身异或结果为0,利用eax传递main函数

11、的返回值00401638 5F pop edi00401639 5E pop esi0040163A 5B pop ebx0040163B 83 C4 54 add esp,54h/清理调用main函数时开辟的堆栈内存0040163E 3B EC cmp ebp,esp00401640 E8 7B F3 01 00 call _chkesp (004209c0)00401645 8B E5 mov esp,ebp00401647 5D pop ebp00401648 C3 retcall指令00401609 E8 9C FA FF FF call ILT+165(Compare) (00401

12、0aa)ILT+165(?CompareYAHHHHZ):004010AA E9 D1 04 00 00 jmp Compare (00401580)call指令做两件事:1) 将函数调用的返回地址,也就是下一条指令的内存地址入栈,此处是0x0040160E2) 直接跳转至004010AA执行,这是一条jmp跳转指令,目的地址如下:目的地址=源地址(EIP)+偏移量此处源地址是什么呢?是004010AA?此处的源地址应该是(004010AA+5),因为程序在执行的时候,首先需要读取指令,当该条指令(5字节指令:E9 D1 04 00 00)读完以后,EIP已经变为(004010AA+5),因此

13、:目的地址=(004010AA+5)+偏移量该条jmp指令中的E9为跳转指令的机器码,D1 04 00 00被解释为偏移量,根据高位存储在高地址区的原则,偏移量被解释为:0x000004D1,因此程序跳转至:(0x004010AA+5)+0x000004D1=0x00401580当根据 对象名.成员函数名 方式访问成员函数时,vc6采用寄存器ecx传递this指针的值,也就是如果需要传递this参数,只需要在函数调用之前,将this指针的值存入ecx寄存器即可。启发:函数调用的顺序是,先将实参入栈,然后再调用call指令,同时将返回地址入栈(此处由于是基于某个框架的,涉及到消息队列的处理,因此

14、返回地址尚未搞明白。暂时忽略吧)。根据定时器举例:SetTimer(NULL,1,1000,(TIMERPROC)pAddr); typedef VOID (CALLBACK* TIMERPROC)(HWND, UINT, UINT, DWORD);void TimerProc(HWND hWnd, DWORD dwMsg , WPARAM wPa, LPARAM lPa)当定时时间到了以后,系统会1)、首先将(HWND, UINT, UINT, DWORD)四个参数入栈,也就是在参数入栈的过程中,具体的执行函数是没有影响的;2)、参数入栈完毕以后,然后将函数转到(TIMERPROC)pAdd

15、r地址执行对应的函数。根据普通函数的启发,可以将汇编代码,此处说明c/c+的默认调用方式_cdecl情况:/ Encoded machine instruction Equivalent assembly languate notation/ - -/ B9 ? ? ? ? mov ecx, pthis ; Load ecx with this pointer/ E9 ? ? ? ? jmp target addr ; Jump to target message handler将代码的机器码(16进制)写入数组当中,然后将数组地址强制转换为TIMERPROC类型,(TIMERPROC)pAd

16、dr,系统会自动跳转至pAddr执行代码。利用ecx寄存器传递this指针参数,然后跳转至TimerProc函数处理,此时作为成员函数的TimerProc就已经有了对应的this指针参数。Thunk技术实现代码#ifndef _ZTHUNK#define _ZTHUNKclass ZThunk private:unsigned char m_ThiscallCode10;unsigned char m_StdcallCode16;ZThunk* m_pThunk;bool m_bDEP;public:ZThunk()/检查数据段执行代码保护是否存在 Data Execution Prevent

17、ion (DEP)m_bDEP = IsProcessorFeaturePresent(12/*PF_NX_ENABLED*/);/在当前进程的4GB虚拟地址空间内申请一段区域,用于赋予指定内存段可执行的属性,从而在数据段执行汇编代码if (m_bDEP)m_pThunk = (ZThunk*)VirtualAlloc(NULL, sizeof(ZThunk), MEM_COMMIT, PAGE_EXECUTE_READWRITE);elsem_pThunk = this;ZThunk()if (m_bDEP & m_pThunk)bool bSuccess = VirtualFree(m_p

18、Thunk, / Base address of blocksizeof(ZThunk), / Bytes of committed pagesMEM_RELEASE); / Decommit the pagesif (bSuccess) m_pThunk = NULL;enum CALLINGCONVENTIONSSTDCALL = 1,THISCALL= 2;public:template void* Callback(void* pThis,T MemberOffset,CALLINGCONVENTIONS CallingConvention = STDCALL)/ these code

19、s only use in stdcallif(CallingConvention = THISCALL)/ Encoded machine instruction Equivalent assembly languate notation/ - -/ B9 ? ? ? ? mov ecx, pthis ; Load ecx with this pointer/ E9 ? ? ? ? jmp target addr ; Jump to target message handlerchar Buf33=0;sprintf(Buf,%d,MemberOffset);unsigned long Jm

20、pAddr = (unsigned long) atol(Buf) - (unsigned long) &(m_pThunk-m_ThiscallCode0) - 10;m_pThunk-m_ThiscallCode0 = 0xB9;/mov ecx, pThis 指令机器码m_pThunk-m_ThiscallCode5 = 0xE9;/jmp xxxxxx 指令机器码*(unsigned long *) &(m_pThunk-m_ThiscallCode1) = (unsigned long) pThis;/this指针*(unsigned long *) &(m_pThunk-m_Thi

21、scallCode6) = JmpAddr;/偏移地址return (void*)(m_pThunk-m_ThiscallCode);/ these codes only use in thiscallelse if(CallingConvention = STDCALL)/ Encoded machine instruction Equivalent assembly languate notation/ - -/ FF 34 24 push dword ptr esp Save (or duplicate) ; the Return Addr into stack/ C7 44 24 04

22、 ? ? ? ? mov dword ptr esp+4, pthis ; Overwite the old ; Return Addr with this pointer/ E9 ? ? ? ? jmp target addr ; Jump to target message handlerchar Buf33=0;sprintf(Buf,%d,MemberOffset);unsigned long JmpAddr = (unsigned long) atol(Buf) - (unsigned long) &m_StdcallCode0 - 16;m_StdcallCode11 = 0xE9; *(unsigned long *) &m_StdcallCode 0) = 0x002434FF;*(unsigned long *) &m_StdcallCode 3) = 0x042444C7;*(unsigned long *) &m_StdcallCode 7) = (unsigned long) pThis;

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1