家电维修班,手机维修班,电脑维修班,电工班,焊工班,液晶电视维修班,电动工具维修班、电动车摩托车维修班、网络营销培训、网站设计培训、淘宝培训---全国招生 家电维修班,手机维修班,电脑维修班,电工班,焊工班,液晶电视维修班,电动工具维修班、电动车摩托车维修班、网络营销培训、网站设计培训、淘宝培训---全国招生
首 页·您想咨询招生情况,请联系我啊·您想咨询招生情况,请联系我啊
当前位置:湖南阳光电子技术学校文章资讯技术园地电脑维修技术
招生办公室电话:0731-85569651 0731-85579057 全国免费电话:0731-85579057

“变速齿轮”再研究

减小字体 增大字体 作者:佚名  来源:本站整理  发布时间:2010-07-28 00:16:43
提起“变速齿轮”(以下简称“齿轮”)这个软件,大家应该都知道吧,该软件号称
是全球第一款能改变游戏速度的程序。我起初用时觉得很神奇,久而久之就不禁思考其实现原理了,但苦于个人水平有限,始终不得其解,成了长驻于脑中挥散不去的大问号。

  偶然一天在BBS上看到了一篇名为《“变速齿轮”研究手记》(以下简称《手记》)的文章,我如获至宝,耐着性子把文章看完了,但之后还是有很多地方不解,不过还是有了比较模糊的认识:原来齿轮是通过截获游戏程序对时间相关函数的调用并修改返回结果实现的呀。

  为了彻彻底底地弄清齿轮的原理,我这次打算豁出去了。考虑到《手记》的作者从是研究的“齿轮”的反汇编代码的,那我也照样从反汇编代码开始。不过自认为汇编功底不够,又从图书馆借了几本关于Windows底层机制和386汇编的书,在经过差不多两周的“修行”之后,自我感觉有点好啦,哈哈,我也有点要迫不及待地把“齿轮”大卸八块了!

  在动手之前,我又把《手记》看了一遍,这次可就清楚多了:通过调用门跳到Ring0级代码段,修改各系统时间相关函数的前8个字节为jmp指令,转跳到“齿轮”映射到2G之上的代码,达到截获对各系统时间相关函数的调用的目的。但同时我的疑惑也更明确了:
  1.“齿轮”怎样建立指向自己映射到2G以上内存的代码的调用门描述符的;
  2.“齿轮”怎样将自己的代码映射到2G以上线性地址的;
  3.映射到2G之上的代码是怎样做到在代码基址更改的情况仍能正确运行的

  带着这样的疑问,我正式开始了对“齿轮”反汇编代码的分析。工具嘛,不用说当
然是Softice for Windows98、W32Dasm,OK,出发啦!

  我的“齿轮”版本是0.221 for win98和winme的,内含有两个文件(变速齿轮.exe
和Hook.dll)。先看看Hook.dll里面有些什么,用W32Dasm将Hook.dll反汇编,看看它的输出函数:

 __@@A">?ghWnd@@3PAUHWND__@@A
 ?gnHotKey1@@3KA
 ?gnHotKey2@@3KA
 ?gnHotKey3@@3KA
 ?gnHotKey4@@3KA
 ?nHook@@3HA
 __@@@Z">?SetHook@@YAHPAUHWND__@@@Z
 ?UnHook@@YAHXZ

  看函数名好象该dll只是安装钩子捕获变速热键的,与我的研究目的没太大的关系, 跳过去!
  再看看变速齿轮.exe的导入函数,timeGetTim、GetTickCount等时间相关的函数都
在里面。嘿,还有CreateFileMappingA和MapViewOfFileEx,看来“齿轮”是用这两个函
数创建映射文件的。以下列出几个关键的导入函数:

 Hook.?gnHotKey1@@3KA
 Hook.?gnHotKey2@@3KA
 Hook.?gnHotKey3@@3KA
 Hook.?gnHotKey4@@3KA
 __@@@Z">Hook.?SetHook@@YAHPAUHWND__@@@Z
 KERNEL32.CreateFileMappingA
 KERNEL32.GetModuleFileNameA
 KERNEL32.GetModuleHandleA
 KERNEL32.GetTickCount
 KERNEL32.MapViewOfFileEx
 KERNEL32.QueryPerformanceCounte
 USER32.KillTimer
 USER32.SendMessageA
 USER32.SetTimer
 WINMM.timeGetTime
 WINMM.timeSetEvent

  既然“齿轮”截获了timeGetTime,那我就跟踪timeGetTime函数的执行情况。

  我先写了个Win32 APP (以下简称APP),当左击客户区时会调用timeGetTime并将返回的结果输出至客户区。运行这个程序,打开“齿轮”,改变当前速度。

  Ctrl + D 呼出Softice,bpx timeGetTime ,退出,再左击APP客户区,Softice跳出。哈,果然timeGetTime函数的首指令成了jmp 8xxx 002A ,好F8继续执行,进入了“ 齿轮”映射到2G线性地址之上的代码。一路F8下去,发现接着“齿轮”把timeGetTime 首指令恢复,并再次调用timeGetTime,这样就得到了timeGetTime的正确结果,保存结果。“齿轮”再把timeGetTime首指令又改为jmp 8xxx 002A 。接下来都猜得到“齿轮”要干什么了!没错,将得到的返回值修改后返回至调用timeGetTime的程序APP。

  我仔细分析了一下,“齿轮”修改返回值的公式如下:
  倍数*(返回值-第一次调用timeGetTime的返回值)
修改后的返回值=---------------------------------------------------+上一次修改后的返回值
  100000
  公式中“上次修改后的返回值”是自己猜测的未经证实,仅供参考。

  代码分析已经进行一部分了,可我之前的疑问仍未解决,“齿轮”是怎么将代码映
射的?又是怎么得到修改代码的权限的?

  既然“齿轮”中调用了CreateFileMappingA,我想其安装调用门,映射代码的初始化部分应该就在调用该函数代码的附近。好,沿着这个思路,呼出Softice,在CreateF ileMappingA处设置断点,将“齿轮”关闭后再运行。Softice跳出,停在了CreateFile MappingA处,F11回到“齿轮”的代码。看到了“齿轮”调用CreateFileMappingA的形式如下:

  CreateFileMappingA(FF,0,4,0,10000,0);
  可见“齿轮”创建了长度为0x10000的映射文件,继续,“齿轮”接着又调用MapViewOfFileEx,调用形式如下:
  MapViewOfFileEx(EDX,2,0,0,0,EAX);
  //EDX为CreateFileMappingA返回的映射文件句柄
  //EAX为申请映射代码的基址,第一次调用时EAX为0x8000 0000

  这里就是关键了,“齿轮”要将映射文件映射至基址为0x8000 0000 的内存空间中,可并不见得Windows就真的允许其映射呀?果然,“齿轮”在在调用之后判断返回值是否有效,无效则将上次申请的基址加上0x1000,再次调用MapViewOfFileEx,一直循环到成功为止,再将返回的地址保存。

  接下来“齿轮”将原“齿轮”exe中的截获API的代码逐字节拷贝到映射区域去。至此,“齿轮”已经将关键代码映射到2G以上线性地址中了。

  我再F8,哈哈,和熟悉的SGDT指令打了个照面。“齿轮”保存全局描述符表线性基 址,再用SLDT指令保存局部描述符表索引,计算出LDT基址。接着呢“齿轮”在局部描述表中创建了一个特权等级为0的代码段指向需要利用Ring0特权修改代码的“齿轮”自己的代码,并把局部描述表中索引为2的调用门指向的地址改为“齿轮”映射到高于2G的代码。

  然后“齿轮”依次调用各时间相关的API,保存其返回值留做计算返回时结果用。
“齿轮”又依次调用映射到高于2G的代码修改各API的首指令。到了这里,“齿轮”的初始化部分就结束了,只等着还蒙在鼓里的游戏上钩啦,哈哈!

  结束代码只不过是作些恢复工作罢了,仅仅是初始化代码的逆过程,所以就不再赘述(其实是我自己懒得看了,^_^!).
  至此,我对“齿轮”的加速原理已有大致的了解,深刻感受到“齿轮”代码的精巧, 所以觉得有必要将"齿轮"中所运用到的一些技巧作一个总结:

1.基址无关代码的编写
  姑且以上面一句话作标题,^_^。看了“齿轮”的初始化代码,知道其映射代码的基址差不多是随机的,那么“齿轮”是怎么保证映射后的代码能正常运行的呢?如果 代码是完全顺序执行的倒没什么问题,但如果要调用自己映射代码中的子程序呢?呵呵,就只有运行时计算出子程序的入口地址并调用了,不过还是要先得到映射代码所在的地址才行。“齿轮”简单地用两条指令就得到当前正在执行的指令的地址,具体如下(地址为假设的):

  0:0 call 5
  0:5 pop esi

  现在esi中的值就是5了,哈哈!

  这里的call用的是近调用,整条指令为E800000000,即为调用下一条指令.所进行的操作只不过是把下一条指令的地址入栈而已.再pop将返回地址(即pop指令本身的地址)取出.

2.修改调用门,生成jmp指令,修改代码
  这些都是高度依赖于CPU的操作,技巧性也很强,主要是钻了操作系统的漏洞。比如“齿轮”就是用SGDT,SLDT获得全局和局部描述符表基址来安装调用门,通过访问调用门来获取RING0权限作一些平时不为系统所允许的操作;而CIH病毒是用SIDT获得中断描述符表基址安装中断门然后出发软中断获取RING0权限的,原理都是一样的。这些在水木上讨论过很多遍,大家都很熟悉,所以也就不敢班门弄斧,写到此为止。

3.64K代码编写
  由调用CreateFileMappingA函数参数可知“齿轮”只映射10000(64K)大小的区域,所以其映射在2G之上的代码和数据决不能大于64K。我想作者之所以选择64K为映射区域的大小,可能是与调用子程序或数据时容易计算地址有关。在映射代码的任意一处得到当前指令地址之后将其低16位置0即可得到映射代码的基地址,再加上子程序入口或数据的偏移即可求得其绝对地址。
 
我的评论:

  一句话:佩服“齿轮”的作者王荣先生。

  “齿轮”的代码表现他对windows运行机制的深刻理解以及深厚的汇编功底还有丰富的想象力。对我来说“齿轮”仿佛就是一件精美的艺术品,每个细处都很值得玩味一 番,所以我才在看过“齿轮”代码之后有了把我的分析过程用笔写下来的冲动。但同时 我又不得不承认“齿轮”的功能的实现是依靠其高度技巧化的代码实现的,换句话说就 是这种的方法局限性实在是太大了。不就是截获API嘛,用的着这么麻烦吗?

  为了证实自己的想法,我在Codeguru上直接找了个HOOK API 的代码,该代码是通过安装WH_CBT类型全局钩子在所有被插入DLL的进程中修改进程PE映像的输入节达到截获API的(这种方法在《windows核心编程》中有详细说明)。把代码稍做修改,就能工作了(在星际争霸下试过,可以改变游戏速度)。尽管只在98下试过,但我觉得肯定也能在2000下用,因为代码中只用了一两句汇编指令,而且整个程序都是在RING3下运行的,没有作出什么出轨的举动。当然这种方法也有缺点,就是对用Loadlibrary加载WINMM.dll再用GetProcAddress获取timeGetTime地址的API调用不起作用(原因在《windows核心编程》中有说明)。

  我打算在将测试用程序稍稍完善后再公布源代码,届时欢迎大家下载。
 
我的感谢:
  在我彻底弄清“齿轮”的代码之后,已经是第三天的上午了,无奈自己才疏学浅,全不像《手记》的作者只花了一个晚上就弄清楚,我可是花了一个上午、两个下午、两个晚上才结束了战斗,实在是惭愧呀。

  自己之所以能自得其乐地坚持了两天多,是与寝室兄弟小强的支持分不开的。穷 困潦倒的我在这几天不知道总共抽了他多少支烟,无以为报,只有在这里说一声谢谢了!另外还要感谢sunlie非常地阅读本文,指出了原文中的错误并提出了非常宝贵的意见!

   后要说的就是个人水平有限,文中难免出现错误,欢迎大家讨论!^_^

附A:
  使用工具:Softice for Windows98,W32Dasm,VisualC++ 6.0
  操作系统:Window98 2nd
  分析目标:变速齿轮 for 98me 版本:0.221
  参考书籍或文章:
    80x86汇编语言程序设计教程 杨季文等编著 清华大学出版社
    windows剖析--初始化篇及内核篇清华大学出版社
    虚拟设备驱动程序开发
    intel 32位系统软件编程
    80x86指令参考手册
    《“变速齿轮”研究手记》

附B:
 “齿轮”关键代码完全注释
 一、初始化部分(从"齿轮"调用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(FF,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PUSH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]
  ; 调用形式如右: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 ;调用MapViewOfFileEx
  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MOV 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+0000F000],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:00401C3AMOV EAX,[EDX+0000036C]
 0167:00401C40MOV ECX,[EBP-14]
 0167:00401C43MOV BYTE PTR [ECX+EAX+0000F000],00
  ;CALL指令其他部分
 0167:00401C4BMOV EDX,[EBP-14]
 0167:00401C4EADD EDX,01
 0167:00401C51MOV [EBP-14],EDX
 0167:00401C54MOV EAX,[EBP-30]
 0167:00401C57MOV ECX,[EAX+0000036C]
 0167:00401C5DMOV EDX,[EBP-14]
 0167:00401C60MOV BYTE PTR [EDX+ECX+0000F000],C2
 0167:00401C68MOV EAX,[EBP-14]
 0167:00401C6BADD EAX,01
 0167:00401C6EMOV [EBP-14],EAX
 0167:00401C71MOV ECX,[EBP-30]
 0167:00401C74MOV EDX,[ECX+0000036C]
 0167:00401C7AMOV EAX,[EBP-14]
 0167:00401C7DMOV BYTE PTR [EAX+EDX+0000F000],00
 0167:00401C85MOV ECX,[EBP-14]
 0167:00401C88ADD ECX,01
 0167:00401C8BMOV [EBP-14],ECX
 0167:00401C8EMOV EDX,[EBP-30]
 0167:00401C91MOV EAX,[EDX+0000036C]
 0167:00401C97MOV ECX,[EBP-14]
 0167:00401C9AMOV BYTE PTR [ECX+EAX+0000F000],00
 0167:00401CA2MOV EDX,[EBP-14]
  ;以上代码为在映射代码偏移F000处写入指令CALL 0014:0000
 0167:00401CA5ADD EDX,01
  ;指令 A91400C20000共6个字节
 0167:00401CA8MOV [EBP-14],EDX ;
 0167:00401CABMOV ESI,0040213B
  ;要复制的代码的起始地址
 0167:00401CB0MOV EDI,[EBP-08]
  ;要复制代码的目标地址(映射区域中)
 0167:00401CB3MOV ECX,00402688
  ;402688为要复制的代码的末地址
 0167:00401CB8SUB ECX,ESI
 0167:00401CBAREPZMOVSB;将代码全部复制到映射区域
 0167:00401CBCSGDTFWORD PTR [EBP-1C];这句开始就很关键了
 0167:00401CC0LEA EAX,[EBP-001C]
 0167:00401CC6MOV EAX,[EAX+02];取GDT线性基址
 0167:00401CC9XOR EBX,EBX
 0167:00401CCBSLDTBX;取LDT在GDT中的偏移
 0167:00401CCEAND BX,-08
 0167:00401CD2ADD EAX,EBX
 0167:00401CD4MOV ECX,[EAX+02]
 0167:00401CD7SHL ECX,08
 0167:00401CDAMOV CL,[EAX+07]
 0167:00401CDDROR ECX,08 ;以上计算出LDT线性基址
 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MOV 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-30]
 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,[EBP-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的调用门地址
 0167: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入口地址
  ...省略部分依次保存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
 ;保存timeGetTime函数前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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 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,
  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入栈(即下一条指令的地址)
 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 [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首指令换成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
  ;调用子程序修改timeGetTime代码
 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保存着timeGetTime函数的入口地址
  以上即恢复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函数
  湖南省阳光电子技术学校常年开设:手机维修培训、家电维修培训、电工培训、电脑维修培训、焊工培训--面向全国火爆招生!网址:http://www.hnygpx.com 报名电话:0731-85579057)。安置就业。考试合格颁发全国通用权威证书。采用我校多年来独创的“模块教学法”,理论与实践相结合、原理+图纸+机器三位一体的教学模式,半天理论,半天实践,通俗易懂,确保无任何基础者也能全面掌握维修技能、成为同行业中的佼佼者。工作(一期不会,免费学会为止)。

Tags:变速齿轮 研究

作者:佚名
[]
电工培训学校 电动车维修学校 摩托车维修学校 摩托车维修培训 手机维修培训 家电维修培训 电脑维修培训 电动工具维修培训 液晶电视维修培训 安防监控培训 空调维修培训 网络营销培训 网站设计培训 淘宝网店培训 电器维修培训 家电维修学校 电工培训 焊工培训 电工学校 电工培训学校 电动车维修学校 摩托车维修学校 摩托车维修培训 手机维修培训 家电维修培训 电脑维修培训 电动工具维修培训 液晶电视维修培训 安防监控培训 空调维修培训 网络营销培训 网站设计培训 淘宝网店培训 电器维修培训 家电维修学校 电工培训 焊工培训 电工学校 电工培训学校 电动车维修学校 摩托车维修学校 摩托车维修培训 手机维修培训 家电维修培训 电脑维修培训 电动工具维修培训 液晶电视维修培训 安防监控培训 空调维修培训 网络营销培训 网站设计培训 淘宝网店培训 电器维修培训 家电维修学校 电工培训 焊工培训 电工学校 电工培训学校 电动车维修学校 摩托车维修学校 摩托车维修培训 手机维修培训 家电维修培训 电脑维修培训 电动工具维修培训 液晶电视维修培训 安防监控培训 空调维修培训 网络营销培训 网站设计培训 淘宝网店培训 电器维修培训 家电维修学校 电工培训 焊工培训 电工学校
中山市,固原市,银川市,玉树,海东,陇南市,酒泉市,张掖市,天水市,金昌市,兰州市,榆林市,延安市,渭南市,铜川市,阿里,山南,拉萨市,怒江,文山州,楚雄州,普洱市,昭通市,玉溪市,昆明市,毕节,铜仁,遵义市,贵阳市,甘孜州,资阳市,达州市,宜宾市,南充市,遂宁市,绵阳市,泸州市,自贡市,三亚市,崇左市,河池市,玉林市,钦州市,梧州市,柳州市,梅州市,肇庆市,湛江市,佛山市,珠海市,韶关市,湘西州,怀化市,郴州市,张家界市,邵阳市,株洲市,仙桃市,随州市,荆州市,荆门市,襄樊市,黄石市,驻马店市,信阳市,南阳市,漯河市,中卫市,石嘴山市,海西,海南藏州,黄南州,海北,甘南,庆阳市,平凉市,武威市,白银市,嘉峪关市,安康市,汉中市,咸阳市,宝鸡市,林芝,日喀则,昌都,迪庆,德宏,大理,西双版纳,红河州,临沧市,丽江市,保山市,曲靖市,黔东州,黔西州,安顺市,六盘水市,凉山州,阿坝州,雅安市,广安市,眉山市,内江市,广元市,德阳市,攀枝花市,成都市,海口市,来宾市,百色市,贵港市,北海市,桂林市,南宁市,云浮市,揭阳市,潮州市,清远市,阳江市,汕尾市,惠州市,茂名市,江门市,汕头市,深圳市,广州市,娄底市,永州市,益阳市,岳阳市,湘潭市,长沙市,恩施州,黄冈市,孝感市,鄂州市,十堰市,武汉市,周口市,商丘市,三门峡市,许昌市,焦作市,安阳市,鹤壁市,平顶山市,开封市,郑州市,聊城市,滨州市,德州市,莱芜市,日照市,泰安市,烟台市,潍坊市,东营市,淄博市,上饶市,济南市,抚州市,宜春市,赣州市,新余市,九江市,景德镇市,宁德市,南平市,泉州市,莆田市,厦门市,宣城市,亳州市,六安市,宿州市,黄山市,滁州市,安庆市,淮北市,马鞍山市,蚌埠市,芜湖市,合肥市,丽水市,舟山市,衢州市,金华市,湖州市,嘉兴市,宁波市,宿迁市,镇江市,盐城市,连云港市,苏州市,徐州市,南京市,绥化市,牡丹江市,佳木斯市,大庆市,鹤岗市,哈尔滨市,白城市,白山市,辽源市,吉林市,葫芦岛市,铁岭市,盘锦市,阜新市,锦州市,本溪市,鞍山市,沈阳市,锡林郭勒盟,通辽市,乌海市,吕梁市,忻州市,晋中市,晋城市,阳泉市,太原市,廊坊市,承德市,保定市,邯郸市,唐山市,宁夏,甘肃省,西藏,贵州省,重庆市,广西,湖南省,河南省,江西省,安徽省,江苏省,黑龙江省,辽宁省,山西省,天津市,四平市,内蒙古,吴忠市,果洛,西宁市,定西市,商洛市,西安市,那曲,黔南州,巴中市,乐山市,贺州市,防城港市,东莞市,河源市,常德市,衡阳市,咸宁市,宜昌市,濮阳市,新乡市,洛阳市,菏泽市,临沂市,威海市,济宁市,枣庄市,青岛市,吉安市,鹰潭市,萍乡市,南昌市,龙岩市,漳州市,三明市,福州市,池州市,巢湖市,阜阳市,铜陵市,淮南市,台州市,绍兴市,温州市,杭州市,泰州市,扬州市,淮安市,南通市,常州市,无锡市,大兴安岭,黑河市,七台河市,伊春市,双鸭山市,鸡西市,齐齐哈尔市,延边,松原市,通化市,长春市,朝阳市,辽阳市,营口市,丹东市,抚顺市,大连市,阿拉善盟,兴安盟,乌兰察布市,巴彦淖尔市,呼伦贝尔市,鄂尔多斯市,赤峰市,头市,呼和浩特市,临汾市,运城市,朔州市,长治市,大同市,衡水市,沧州市,张家口市,邢台市,秦皇岛市,石家庄市,青海省,陕西省,云南省,四川省,海南省,广东省,湖北省,山东省,福建省,浙江省,上海市,吉林省,河北省,北京市