




版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1、PS:昨天回家搭车时听了About变速齿轮的工作原理的探讨,感觉有点奇怪,于是上网查了下,貌似最有说服力就是这篇,关于利用驱动通过Ring0进行访问I/O,我感觉采用这种方法的可能性不大,因为没下载变速齿轮,无法得知他是否采用这种方法。(用了呢种方案出错率非一般的大,一错了,随时死机。) -我是传说中的分割线- 变速齿轮工作原理解密 绝大部分游戏里面即时都会用到使用的定时器,变速齿轮之所欲可以给游戏加速,就是改变了定时器的性质。 有两种办法可以改变系统定时器。 1)API代码注入,通过注入自己的代码,使得API跳转到自己的代码处运行 计时API函数有GETTICKCOUNT和TIMEGETTI
2、ME,它是windows系统函数,如果可以找到他们的未知,修改成对自己有利的形式,就达到了加速的目的。 下面以GETTICKCOUNT为例进行分析:原本的GETTICKCOUNT汇编: kernel32!gettickcountmovgs,bffcaea18 moveax,gs:00000000 subedx,edx movgs,dx ret 变速齿轮修改后的GETTICKCOUNT汇编: kernel32!gettickcount 这里是关键->jmp840500d9(840500d9并不是绝对的) addeax,al addecx+00000000,ah subedx,edx mov
3、gs,dx ret 可以看出变速齿轮修改了gettickcount的代码,当游戏和程序使用gettickcount时就会自动跳转到840500d9处执行。 再看?40500d9处的代码汇编: 840500d9:CLI pushebp movebp,esp pushebx pushec pushedx pushesi pushedi call840500e7 840500e7:popedi xordi,di movesi,edi addesi,00402051 subesi,00401f0b pushesi calledi call84050101 84050101:popedi xordi,d
4、i calledi+0000fef0 call84050110 84050110:subeax,edi+0000ff30 muldword,ptredi+0000ff30 movebx,00100000 divebx addeax,edi+0000fe20 pusheax moveax,00402072 subeax,00401f08 addeax,edi pusheax calledi popeax popedi popesi popedx popecx popebx popebp sil ret 以上正是变速齿轮变速的核心所在。(GETTICKCOUNT返回的是EAX的值你可以对EAX进行
5、跟踪) 下面说一下变速齿轮挂接API的方法:首先变速齿轮在MMF区(WIN9X/ME)申请一块内存,把上面的代码从程序中移到该内存。使用修改描述符的方法从应用程序级跳到核心级,修改GETTICKCOUNT开头的代码使之指向申请的内存的首地址实现挂接。 这是普遍采用的一种方式。 2)还有一种方式。从驱动级修改。 在win95/98时代,我们是可以直接操作IO端口的,winNT以后,包括2000,XP系统,当我们试图操作IO端口,改变硬件设置的时候,系统会拒绝或者引起冲突。事实上在386以后的CPU上,用户程序都是运行在保护模式下,用户对IO端口对设备的访问都要经过操作系统的管理和监督。用户程序是
6、无法直接对设备操作的。 那么在window下,要访问设备怎么办?windows提供了2中办法: 第一,通过修改EFLAGS寄存器中的特权级别(IOPL)实现 第二,任务状态段(TSS)中的IO许可映射BIt位 WindowsNT下,只使用了2种等级的特权级,0特权级和3特权级。用户程序运行在3特权级,设备驱动和系统内核运行在0特权级。只有系统内核程序和设备驱动才被允许直接操作IO端口。所有的用户程序在访问IO端口前,都需要得到设备驱动的准入,低信任级别的程序是无法访问的。 IObit映射就是为了使得那些低信任级别的程序能够访问设备IO而设置的。 在NT系统下,直接操作IO端口就有两种方式,一是
7、,编写设备驱动,运行在0特权级直接操作IO设备端口。另外一种可行的办法就是修改IObit映射。 我们建议采用第一种办法,通过工作在0特权级的驱动访问IO端口。 这里有写好的设备驱动,PortTalk.sys,并提供了对外的接口,下面是用c语言写的,通过这个驱动对IO访问的一个例子: #include #include #include void_cdeclmain(void unsignedcharvalue; printf("IoExampleforPortTalkV2.0nCopyright2001CraigPeacockn" OpenPortTalk(; outpor
8、tb(0x378,0xFF; value=inportb(0x378; printf("Valuereturned=0x%02Xn",value; outp(0x378,0xAA; value=inp(0x378; printf("Valuereturned=0x%02Xn",value; ClosePortTalk(; 变速齿轮原理 (转 通过调用门跳到Ring0级代码段,修改各系统时间相关函数的前8个字节为jmp指令,转跳到“齿轮”映射到2G之上的代码,达到截获对各系统时间相关函数的调用的目的。但同时我的疑惑也更明确了: 1.“齿轮”怎样建立指向自己
9、映射到2G以上内存的代码的调用门描述符的; 2.“齿轮”怎样将自己的代码映射到2G以上线性地址的; 3.映射到2G之上的代码是怎样做到在代码基址更改的情况仍能正确运行的 带着这样的疑问,我正式开始了对“齿轮”反汇编代码的分析。工具嘛,不用说当 然是Softice for Windows98、W32Dasm,OK,出发啦! 我的“齿轮”版本是0.221 for win98和winme的,内含有两个文件(变速齿轮.exe 和Hook.dll)。先看看Hook.dll里面有些什么,用W32Dasm将Hook.dll反汇编,看看它的输出函数: ?ghWnd3PAUHWND_A ?gnHotKey13K
10、A ?gnHotKey23KA ?gnHotKey33KA ?gnHotKey43KA ?nHook3HA ?SetHookYAHPAUHWND_Z ?UnHookYAHXZ 看函数名好象该dll只是安装钩子捕获变速热键的,与我的研究目的没太大的关系, 跳过去! 再看看变速齿轮.exe的导入函数,timeGetTim、GetTickCount等时间相关的函数都 在里面。嘿,还有CreateFileMappingA和MapViewOfFileEx,看来“齿轮” 是用这两个函 数创建映射文件的。以下列出几个关键的导入函数: Hook.?gnHotKey13KA Hook.?gnHotKey23KA
11、 Hook.?gnHotKey33KA Hook.?gnHotKey43KA Hook.?SetHookYAHPAUHWND_Z KERNEL32.CreateFileMappingA KERNEL32.GetModuleFileNameA KERNEL32.GetModuleHandleA KERNEL32.GetTickCount KERNEL32.MapViewOfFileEx KERNEL32.QueryPerformanceCounte USER32.KillTimer USER32.SendMessageA USER32.SetTimer WINMM.timeGetTime WIN
12、MM.timeSetEvent 既然“齿轮”截获了timeGetTime,那我就跟踪timeGetTime函数的执行情况。 我先写了个Win32 APP (以下简称APP),当左击客户区时会调用timeGetTime并将返回的结果输出至客户区。运行这个程序,打开“齿轮”,改变当前速度。 Ctrl + D 呼出Softice,bpx timeGetTime ,退出,再左击APP客户区,Softice跳 出。哈,果然timeGetTime函数的首指令成了jmp 8xxx 002A ,好F8继续执行,进入了“ 齿轮”映射到2G线性地址之上的代码。一路F8下去,发现接着“齿轮”把timeGetTime
13、 首指令恢复,并再次调用timeGetTime,这样就得到了timeGetTime的正确结果,保存结果。“齿轮”再把timeGetTime首指令又改为jmp 8xxx 002A 。接下来都猜得到“齿轮”要干什么了!没错,将得到的返回值修改后返回至调用timeGetTime的程序APP。 我仔细分析了一下,“齿轮”修改返回值的公式如下: 倍数*(返回值-第一次调用timeGetTime的返回值) 修改后的返回值=-+上一次修改后的返回值 100000 公式中“上次修改后的返回值”是自己猜测的未经证实,仅供参考。 代码分析已经进行一部分了,可我之前的疑问仍未解决,“齿轮”是怎么将代码映 射的?又是
14、怎么得到修改代码的权限的? 既然“齿轮”中调用了CreateFileMappingA,我想其安装调用门,映射代码的初始 化部分应该就在调用该函数代码的附近。好,沿着这个思路,呼出Softice,在CreateF ileMappingA处设置断点,将“齿轮”关闭后再运行。Softice跳出,停在了CreateFile MappingA处,F11回到“齿轮”的代码。看到了“齿轮”调用CreateFileMappingA的形式 如下: CreateFileMappingA(FF,0,4,0,10000,0; 可见“齿轮”创建了长度为0x10000的映射文件,继续,“齿轮”接着又调用 MapViewO
15、fFileEx,调用形式如下: MapViewOfFileEx(EDX,2,0,0,0,EAX; /EDX为CreateFileMappingA返回的映射文件句柄 /EAX为申请映射代码的基址,第一次调用时EAX为0x8000 0000 这里就是关键了,“齿轮”要将映射文件映射至基 址为0x8000 0000 的内存空间中,可并不见得Windows就真的允许其映射呀?果然,“齿轮”在在调用之后判断返回值是否有效,无效则将上次申请的基址加上0x1000,再次调用MapViewOfFileEx,一直循环到成功为止,再将返回的地址保存。 接下来“齿轮”将原“齿轮”exe中的截获API的代码逐字节拷贝
16、到映射区域去。至 此,“齿轮”已经将关键代码映射到2G以上线性地址中了。 我再F8,哈哈,和熟悉的SGDT指令打了个照面。“齿轮”保存全局描述符表线性基 址,再用SLDT指令保存局部描述符表索引,计算出LDT基址。接着呢“齿轮”在局部描述表中创建了一个特权等级为0的代码段指向需要利用Ring0特权修改代码的“齿轮”自己的代码,并把局部描述表中索引为2的调用门指向的地址改为“齿轮”映射到高于2G的代码。 然后“齿轮”依次调用各时间相关的API,保存其返回值留做计算返回时结果用。 “齿轮”又依次调用映射到高于2G的代码修改各API的首指令。到了这里,“齿轮”的初 始化部分就结束了,只等着还蒙在鼓里
17、的游戏上钩啦,哈哈! 结束代码只不过是作些恢复工作罢了,仅仅是初始化代码的逆过程,所以就不再 赘述(其实是我自己懒得看了,_!. 至此,我对“齿轮”的加速原理已有大致的了解,深刻感受到“齿轮”代码的精巧, 所以觉得有必要将"齿轮"中所运用到的一些技巧作一个总结: 1.基址无关代码的编写 姑且以上面一句话作标题,_。看了“齿轮”的初始化代码,知道其映射代码 的基址差不多是随机的,那么“齿轮”是怎么保证映射后的代码能正常运行的呢?如果 代码是完全顺序执行的倒没什么问题,但如果要调用自己映射代码中的子程序呢?呵呵,就只有运行时计算出子程序的入口地址并调用了,不过还是要先得到映射代
18、码所在的地址才行。“齿轮”简单地用两条指令就得到当前正在执行的指令的地址,具体如下(地址为假设的): 0:0 call 5 0:5 pop esi 现在esi中的值就是5了,哈哈! 这里的call用的是近调用,整条指令为E800000000,即为调用下一条指令.所进行 的操作只不过是把下一条指令的地址入栈而已.再pop将返回地址(即pop指令本身的地址取出. 2.修改调用门,生成jmp指令,修改代码 这些都是高度依赖于CPU的操作,技巧性也很强,主要是钻了操作系统的漏洞。比如“齿轮”就是用SGDT,SLDT获得全局和局部描述符表基址来安装调用门,通过访问调用门来获取RING0权限作一些平时不为
19、系统所允许的操作;而CIH病毒是用SIDT获得中 断描述符表基址安装中断门然后出发软中断获取RING0权限的,原理都是一样的。这些在水木上讨论过很多遍,大家都很熟悉,所以也就不敢班门弄斧,写到此为止。 3.64K代码编写 由调用CreateFileMappingA函数参数可知“齿轮”只映射10000(64K)大小的 区域,所以其映射在2G之上的代码和数据决不能大于64K。我想作者之所以选择64K为映射区域的大小,可能是与调用子程序或数据时容易计算地址有关。在映射代码的任意一处得到当前指令地址之后将其低16位置0即可得到映射代码的基地址,再加上子程序入口或数据的偏移即可求得其绝对地址。 我的评论
20、: 一句话:佩服“齿轮”的作者王荣先生。 “齿轮”的代码表现他对windows运行机制的深刻理解以及深厚的汇编功底还有丰 富的想象力。对我来说“齿轮”仿佛就是一件精美的艺术品,每个细处都很值得玩味一 番,所以我才在看过“齿轮”代码之后有了把我的分析过程用笔写下来的冲动。但同时 我又不得不承认“齿轮”的功能的实现是依靠其高度技巧化的代码实现的,换句话说就 是这种的方法局限性实在是太大了。不就是截获API嘛,用的着这么麻烦吗? 为了证实自己的想法,我在Codeguru上直接找了个HOOK API 的代码,该代码是通过安装WH_CBT类型全局钩子在所有入DLL的进程中修改进程PE映像的输入节达到截获
21、API的(这种方法在windows核心编程中有详细说明)。把代码稍做修改,就能工作了(在星际争霸下试过,可以改变游戏速度)。尽管只在98下试过,但我觉得肯定也能在2000下用,因为代码中只用了一两句汇编指令,而且整个程序都是在RING3下运行的,没有作出什么出轨的举动。当然这种方法也有缺点,就是对用Loadlibrary加载WINMM.dll再用GetProcAddress获取timeGetTime地址的API调用不起作用(原因在windows核心编程中有说明)。 我打算在将测试用程序稍稍完善后再公布源代码,届时欢迎大家下载。 我的感谢: 在我彻底弄清“齿轮”的代码之后,已经是第三天的上午了,
22、无奈自己才疏学浅, 全不像手记的作者只花了一个晚上就弄清楚,我可是花了一个上午、两个下午、两个晚上才结束了战斗,实在是惭愧呀。 自己之所以能自得其乐地坚持了两天多,是与寝室兄弟小强的支持分不开的。穷 困潦倒的我在这几天不知道总共抽了他多少支烟,无以为报,只有在这里说一声谢谢了!另外还要感谢sunlie非常地阅读本文,指出了原文中的错误并提出了非常宝贵的意见! 最后要说的就是个人水平有限,文中难免出现错误 ,欢迎大家讨论!_ 附A: 使用工具:Softice for Windows98,W32Dasm,VisualC+ 6.0 操作系统:Window98 2nd 分析目标:变速齿轮 for 98
23、me 版本:0.221 参考书籍或文章: 80x86汇编语言程序设计教程 杨季文等编著 清华大学出版社 windows剖析-初始化篇及内核篇 清华大学出版社 虚拟设备驱动程序开发 intel 32位系统软件编程 80x86指令参考手册 “变速齿轮”研究手记 0167:00401CE0 MOV EBP-0C,ECX ;保存 0167:00401CE3 MOV EAX,EBP-30 0167:00401CE6 MOV ECX,EBP-0C 0167:00401CE9 MOV EAX+00000370,ECX 0167:00401CEF MOV EDX,EBP-30 0167:00401CF2 MO
24、V EAX,EDX+0000036C 0167:00401CF8 MOV ECX,EBP-0C 0167:00401CFB MOV EAX+0000FE00,ECX ;将LDT线性基址保存至映射代码中 0167:00401D01 MOV AX,CS ;得到当前代码段描述符号 0167:00401D04 AND AX,FFF8 0167:00401D08 MOV EBP-10,AX 0167:00401D0C MOV EDX,EBP-10 0167:00401D0F AND EDX,0000FFFF ;EDX为代码段描述符在LDT中的偏移量 0167:00401D15 MOV EAX,EBP-3
25、0 0167:00401D18 MOV ECX,EAX+00000370 ;ECX此时为LDT线性基址 0167:00401D1E MOV EAX,EBP-30 0167:00401D21 MOV EAX,EAX+00000370 ;EAX此时为LDT线性基址 0167:00401D27 MOV ESI,EDX+ECX 0167:00401D2A MOV EAX+08,ESI 0167:00401D2D MOV ECX,EDX+ECX+04 ;以上将当前代码段描述符复制到 0167:00401D31 MOV EAX+0C,ECX ;LDT第1项 0167:00401D34 MOV EDX,EB
26、P-30 0167:00401D37 MOV EAX,EDX+00000370 0167:00401D3D MOV CL,EAX+0D 0167:00401D40 AND CL,9F 0167:00401D43 MOV EDX,EBP-30 0167:00401D46 MOV EAX,EDX+00000370 0167:00401D4C MOV EAX+0D,CL ;以上修改LDT第1项的DPL为0,则当由调用门转到该段代码时即获得RING0权限 0167:00401D4F MOV EAX,EBP-0C 0167:00401D52 ADD EAX,10 ;获得LDT中索引为2的调用门地址 01
27、67:00401D55 MOV EBX,0040213B 0167:00401D5A MOV EAX,EBX 0167:00401D5C MOV EAX+04,EBX 0167:00401D5F MOV WORD PTR EAX+02,000C 0167:00401D65 MOV WORD PTR EAX+04,EC00 ;调用门修改完毕 0167:00401D6B MOV ECX,EBP-08 0167:00401D6E MOV EDX,WINMM!timeGetTime 0167:00401D74 MOV ECX+0000FEE0 ;EDX;保存timeGetTime入口地址 .省略部分依
28、次保存GetTickCount,GetMessageTime,timeSetEvent,SetTimer, timeGetSystemTime,QueryPerformanceCounter入口地址 0167:00401DD2 MOV ECX,EBP-08 0167:00401DD5 MOV EAX,WINMM!timeGetTime 0167:00401DDA MOV EBX,EAX 0167:00401DDC MOV ECX+0000FE40,EBX 0167:00401DE2 MOV EBX,EAX+04 0167:00401DE5 MOV ECX+0000FE44,EBX ;保存tim
29、eGetTime函数前8个字节指令 .省略部分依次保存GetTickCount,GetMessageTime,timeSetEvent, timeGetSystemTime , QueryPerformanceCounter前8个字节指令 0167:00401E6D MOV BYTE PTR ECX+0000FE90,E9 0167:00401E74 MOV EAX,00402165 0167:00401E79 SUB EAX,0040213B ;EAX为截获代码在映射代码中的偏移 0167:00401E7E ADD EAX,ECX ;计算出截获代码的线性入口地址 0167:00401E80
30、SUB EAX,WINMM!timeGetTime 0167:00401E86 SUB EAX,05 ;JMP指令总长5个字节 0167:00401E89 MOV ECX+0000FE91,EAX ;计算生成从timeGetTime跳到截获代码的JMP指令并保存 .省略部分依次计算并生成GetTickCount,GetMessageTime,timeSetEvent, timeGetSystemTime , QueryPerformanceCounter跳到截获代码的JMP指令 并保存 0167:00401F58 CLI ;关闭中断,谨防修改代码时发生意外 0167:00401F59 MOV
31、EAX,004021F3 ; 0167:00401F5E SUB EAX,0040213B;计算子程序在映射代码中的偏移 0167:00401F63 ADD EAX,EBP-08 ;EAX=8xxx 00B8 0167:00401F66 PUSH EAX ;传入参数EAX为修改timeGetTime代码的 ;子程序入口地址 0167:00401F67 MOV EAX,EBP-08 ;调用8xxx 0000 0167:00401F6A CALL EAX ;返回时timeGetTime首指令被更改 .省略部分依次修改GetTickCount,GetMessageTime,timeSetEvent,
32、 timeGetSystemTime , QueryPerformanceCounter函数的首指令 0167:00401FF SETI ;设置中断,初始化代码结束 二、截获时间函数部分(以timeGetTime为例子,代码以跟踪顺序列出) timeGetTime JMP 832A 002A ;这是timeGetTime被修改后的首指令 0167:832A 002A CLI ;此时esp=40BF2C,即游戏程序中调用timeGetTime函数的下一条指令 .(6个)各寄存器分别入栈 且MOV EBP,ESP 0167:832A 0033 CALL 832A 0038 ;将当前EIP入栈(即下
33、一条指令的地址) 0167:832A 0038 POP EDI ;取出当前指令地址 XOR DI , DI MOV ESI , EDI ;将64K内存首地址赋给ESI ;此时ESI=EDI=832A 0000 ADD ESI , 0040 2102 SUB ESI , 0040 213B ;求出映射代码首地址 PUSH ESI 0167:832A 004B CALL EDI ;ESI为传进的参数 ;返回时已经将timeGetTime代码还原 0167:832A 004D CALL 832A 0052 ; 0167:832A 0052 POP EDI XOR DI ,DI ;故技重施 CALL
34、EDI + 0000FEED;调用原timeGetTime函数 SUB EAX,EDI + 0000 FF30 ;减去第一次调用timeGetTime的结果 MUL DWORD PTR EDI+0000 FE30 ;乘以用户所指定的倍数 MOV EBX ,00100000 DIV EBX ;除以常数100000 ADD EAX ,EDI+ 0000FE20 MOV EAX,004021F3 SUB EAX,0040213B ADD EAX,EDI ;以上指令为修改timeGetTime函数返回值 PUSH EAX ;EAX为传进的参数 CALL EDI ;返回时又将timeGetTime首指令
35、换成JMP .恢复各寄存器的值,EAX中为修改后的返回值 RET ;此时ESP=40BF2C,执行RET将返回到游戏中去 ; 0167:832A 0000 CALL 832A 0005 0167:832A 0005 POP EDI XOR DI ,DI ;老套了撒_ MOV ESI ,EDI+0000 FE00 ;此地址保存着LDT的线性基址 MOV EAX,ESP+04 MOV ESI +10,AX SHR EAX,10 MOV ESI+16,AX ;以上代码将LDT中索引为2的调用门描述符的偏移改为传入的参数 . MOV EAX,0000 0F00 CALL EAX ;调用子程序修改tim
36、eGetTime代码 0167:832A 0027 RET 4 ;弹出参数,返回 ; 0167:832A F000 CALL 0014:00000000 RET 0 ; 000C:832A 0097 CALL 832A 009C 000C:832A 009C POP EDI MOV EAX,EDI+0000 FE40 MOV EBX,EDI+0000 FEE0 MOV EBX,EAX MOV EAX,EDI+0000 FE44 MOV EBX+04,EAX RETF 注:EDI+0000 FE40起前8个字节为原timeGetTime函数的指令 EDI+0000 FEE0保存着timeGetT
37、ime函数的入口地址 以上即恢复timeGetTime前8个字节的代码 ; 000C:832A 00B8 CALL 832A 00BD 000C:832A 00BD POP EDI XOR DI ,DI . MOV EAX,EDI+0000 FE90 MOV EBX,EDI+0000 FEE0 MOV EBX,EAX MOV EAX,EDI+0000FE94 MOV EBX+04,EAX RETF 注:EDI+0000 FE90 起前8个字节保存着JMP 832A 002A 指令 是由“齿轮”初始化部分代码计算出来的,以上代码将JMP 832A 002A 写入timeGetTime函数 附B:
38、 “齿轮”关键代码完全注释 一、初始化部分(从"齿轮"调用CreateFileMappingA函数开始分析 0167:00401B0E PUSH 00 0167:00401B10 PUSH 00010000 0167:00401B15 PUSH 00 0167:00401B17 PUSH 04 0167:00401B19 PUSH 00 0167:00401B1B PUSH FF 0167:00401B1D CALL KERNEL32!CreateFileMappingA ;调用CreateFileMappingA ; 调用形式如右:CreateFileMappingA(F
39、F,0,4,0,10000,0 0167:00401B23 MOV ECX,EBP-30 0167:00401B26 MOV ECX+00000368,EAX 0167:00401B2C MOV DWORD PTR EBP-14,80000000 0167:00401B33 JMP 00401B41 0167:00401B35 MOV EDX,EBP-14 0167:00401B38 ADD EDX,00010000 ;申请基址加0x10000 0167:00401B3E MOV EBP-14,EDX 0167:00401B41 MOV EAX,EBP-14 0167:00401B44 PUS
40、H EAX ;映射文件基址 0167:00401B45 PUSH 00 ;映射的字节数 0167:00401B47 PUSH 00 ;文件偏移低32位 0167:00401B49 PUSH 00 ;文件偏移高32位 0167:00401B4B PUSH 02 ;访问模式 0167:00401B4D MOV ECX,EBP-30 0167:00401B50 MOV EDX,ECX+00000368 0167:00401B56 PUSH EDX ;CreateFileMappingA返回的映射文件句柄 0167:00401B57 CALL KERNEL32!MapViewOfFileEx ; 调用
41、形式如右:MapViewOfFileEx(EDX,2,0,0,0,EAX 0167:00401B5D MOV ECX,EBP-30 ;EBP-30为即将映射到2G之上 0167:00401B60 MOV ECX+0000036C,EAX ; 的代码的数据域的起始地址 0167:00401B66 MOV EDX,EBP-30 0167:00401B69 CMP DWORD PTR EDX+0000036C,00 ;检查MapViewOfFileEx 0167:00401B70 JZ 00401B74 ;返回值,若为0则继续调 0167:00401B72 JMP 00401B76 ;调用MapVi
42、ewOfFileEx 0167:00401B74 JMP 00401B35 ;直至成功为止 0167:00401B76 MOV EAX,EBP-30 0167:00401B79 MOV ECX,EAX+0000036C 0167:00401B7F MOV EBP-08,ECX ;映射文件起始地址存入EBP-08 0167:00401B82 CALL WINMM!timeGetTime 0167:00401B88 MOV EBP-14,EAX ;将初次调用timeGetTime 0167:00401BA0 MOV ECX,EBP-08 ;的返回值保存到EBP-14 0167:00401BA3 M
43、OV EDX,EBP-14 ;以及映射文件基址+FF30处 0167:00401BA6 MOV ECX+0000FF30,EDX .省略的代码类似的保存调用初次GetTickCount,QueryPerformanceCounter的返回值 0167:00401BED MOV DWORD PTR EBP-14, 00000000 0167:00401BF4 MOV EDX,EBP-30 0167:00401BF7 MOV EAX,EDX+0000036C 0167:00401BFD MOV ECX,EBP-14 0167:00401C00 MOV BYTE PTR ECX+EAX+0000F0
44、00,9A ;9a为远调用的指令码 0167:00401C08 MOV EDX,EBP-14 0167:00401C0B ADD EDX,01 0167:00401C0E MOV EBP-14,EDX 0167:00401C11 MOV EAX,EBP-14 0167:00401C14 ADD EAX,04 0167:00401C17 MOV EBP-14,EAX 0167:00401C1A MOV ECX,EBP-30 0167:00401C1D MOV EDX,ECX+0000036C 0167:00401C23 MOV EAX,EBP-14 0167:00401C26 MOV BYTE PTR EAX+EDX+0000F000,14 ;14为调用门描述符的索引 0167:00401C2E MOV ECX,EBP-14 0167:00401C31 ADD ECX,01 0167:00401C34 MOV EBP-14,ECX 0167:00401C37 MOV EDX,EBP-30 0167:0040
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 技工语文考试题目及答案
- 2025年高职调研考试试题及答案
- 模拟互动面试题目及答案
- 财务内勤考试试题及答案
- 就业合作协议8篇
- 2025年精神科常见疾病诊断与治疗测试答案及解析
- 房屋拆迁的赔偿协议书模板5篇
- 2025年体育招教试题及答案
- 2025年生态文明环境保护知识竞赛试题库及答案
- 中专学生模拟面试题及答案
- 2025年学校少先队知识应知应会题库(含答案)
- 核桃肽粉生产技术规程(征求意见稿)编制说明
- 《储能技术》课件-3.各种类型的蓄能技术
- (2025)企业首席质量官培训考核试题(附含答案)
- 工业厂区场地平整建设方案
- 2024年丽水市莲都区事业单位招聘真题
- 锂电池pack工厂安全培训课件
- (2025秋新版)青岛版科学三年级上册全册教案
- 跨境电商合规管理操作手册
- 住院病人防止走失课件
- DB31∕T 1545-2025 卫生健康数据分类分级要求
评论
0/150
提交评论