这个是我找的一段代码:<br>“齿轮”关键代码完全注释<br> 一、初始化部分(从"齿轮"调用CreateFileMappingA函数开始分析)<br> 0167:00401B0E PUSH 00<br> 0167:00401B10 PUSH 00010000<br> 0167:00401B15 PUSH 00<br> 0167:00401B17 PUSH 04<br> 0167:00401B19 PUSH 00<br> 0167:00401B1B PUSH FF<br> 0167:00401B1D CALL [KERNEL32!CreateFileMappingA]<br> ;调用CreateFileMappingA<br> ; 调用形式如右:CreateFileMappingA(FF,0,4,0,10000,0)<br> 0167:00401B23 MOV ECX,[EBP-30]<br> 0167:00401B26 MOV [ECX+00000368],EAX<br> 0167:00401B2C MOV DWORD PTR [EBP-14],80000000<br> 0167:00401B33 JMP 00401B41<br> 0167:00401B35 MOV EDX,[EBP-14]<br> 0167:00401B38 ADD EDX,00010000<br> ;申请基址加0x10000<br> 0167:00401B3E MOV [EBP-14],EDX<br> 0167:00401B41 MOV EAX,[EBP-14]<br> 0167:00401B44 PUSH EAX ;映射文件基址<br> 0167:00401B45 PUSH 00 ;映射的字节数<br> 0167:00401B47 PUSH 00 ;文件偏移低32位<br> 0167:00401B49 PUSH 00 ;文件偏移高32位<br> 0167:00401B4B PUSH 02 ;访问模式<br> 0167:00401B4D MOV ECX,[EBP-30]<br> 0167:00401B50 MOV EDX,[ECX+00000368]<br> 0167:00401B56 PUSH EDX<br> ;CreateFileMappingA返回的映射文件句柄<br> 0167:00401B57 CALL [KERNEL32!MapViewOfFileEx]<br> ; 调用形式如右:MapViewOfFileEx(EDX,2,0,0,0,EAX)<br> 0167:00401B5D MOV ECX,[EBP-30]<br> ;[EBP-30]为即将映射到2G之上<br> 0167:00401B60 MOV [ECX+0000036C],EAX<br> ; 的代码的数据域的起始地址<br> 0167:00401B66 MOV EDX,[EBP-30]<br> 0167:00401B69 CMP DWORD PTR [EDX+0000036C],00<br> ;检查MapViewOfFileEx<br> 0167:00401B70 JZ 00401B74<br> ;返回值,若为0则继续调<br> 0167:00401B72 JMP 00401B76 ;调用MapViewOfFileEx<br> 0167:00401B74 JMP 00401B35 ;直至成功为止<br> 0167:00401B76 MOV EAX,[EBP-30]<br> 0167:00401B79 MOV ECX,[EAX+0000036C]<br> 0167:00401B7F MOV [EBP-08],ECX<br> ;映射文件起始地址存入[EBP-08]<br> 0167:00401B82 CALL [WINMM!timeGetTime]<br> 0167:00401B88 MOV [EBP-14],EAX<br> ;将初次调用timeGetTime<br> 0167:00401BA0 MOV ECX,[EBP-08]<br> ;的返回值保存到[EBP-14]<br> 0167:00401BA3 MOV EDX,[EBP-14]<br> ;以及映射文件基址+FF30处<br> 0167:00401BA6 MOV [ECX+0000FF30],EDX<br> ...省略的代码类似的保存调用初次GetTickCount,QueryPerformanceCounter的返回值<br> <br> 0167:00401BED MOV DWORD PTR [EBP-14],00000000<br> 0167:00401BF4 MOV EDX,[EBP-30]<br> 0167:00401BF7 MOV EAX,[EDX+0000036C]<br> 0167:00401BFD MOV ECX,[EBP-14]<br> 0167:00401C00 MOV BYTE PTR [ECX+EAX+0000F000],9A<br> ;9a为远调用的指令码<br> 0167:00401C08 MOV EDX,[EBP-14]<br> 0167:00401C0B ADD EDX,01<br> 0167:00401C0E MOV [EBP-14],EDX<br> 0167:00401C11 MOV EAX,[EBP-14]<br> 0167:00401C14 ADD EAX,04<br> 0167:00401C17 MOV [EBP-14],EAX<br> 0167:00401C1A MOV ECX,[EBP-30]<br> 0167:00401C1D MOV EDX,[ECX+0000036C]<br> 0167:00401C23 MOV EAX,[EBP-14]<br> 0167:00401C26 MOV BYTE PTR [EAX+EDX+0000F000],14<br> ;14为调用门描述符的索引<br> 0167:00401C2E MOV ECX,[EBP-14]<br> 0167:00401C31 ADD ECX,01<br> 0167:00401C34 MOV [EBP-14],ECX<br> 0167:00401C37 MOV EDX,[EBP-30]<br> 0167:00401C3A MOV EAX,[EDX+0000036C]<br> 0167:00401C40 MOV ECX,[EBP-14]<br> 0167:00401C43 MOV BYTE PTR [ECX+EAX+0000F000],00<br> ;CALL指令其他部分<br> 0167:00401C4B MOV EDX,[EBP-14]<br> 0167:00401C4E ADD EDX,01<br> 0167:00401C51 MOV [EBP-14],EDX<br> 0167:00401C54 MOV EAX,[EBP-30]<br> 0167:00401C57 MOV ECX,[EAX+0000036C]<br> 0167:00401C5D MOV EDX,[EBP-14]<br> 0167:00401C60 MOV BYTE PTR [EDX+ECX+0000F000],C2<br> 0167:00401C68 MOV EAX,[EBP-14]<br> 0167:00401C6B ADD EAX,01<br> 0167:00401C6E MOV [EBP-14],EAX<br> 0167:00401C71 MOV ECX,[EBP-30]<br> 0167:00401C74 MOV EDX,[ECX+0000036C]<br> 0167:00401C7A MOV EAX,[EBP-14]<br> 0167:00401C7D MOV BYTE PTR [EAX+EDX+0000F000],00<br> 0167:00401C85 MOV ECX,[EBP-14]<br> 0167:00401C88 ADD ECX,01<br> 0167:00401C8B MOV [EBP-14],ECX<br> 0167:00401C8E MOV EDX,[EBP-30]<br> 0167:00401C91 MOV EAX,[EDX+0000036C]<br> 0167:00401C97 MOV ECX,[EBP-14]<br> 0167:00401C9A MOV BYTE PTR [ECX+EAX+0000F000],00<br> 0167:00401CA2 MOV EDX,[EBP-14]<br> ;以上代码为在映射代码偏移F000处写入指令CALL 0014:0000<br> 0167:00401CA5 ADD EDX,01<br> ;指令 A91400C20000共6个字节<br> 0167:00401CA8 MOV [EBP-14],EDX ;<br> 0167:00401CAB MOV ESI,0040213B<br> ;要复制的代码的起始地址<br> 0167:00401CB0 MOV EDI,[EBP-08]<br> ;要复制代码的目标地址(映射区域中)<br> 0167:00401CB3 MOV ECX,00402688<br> ;402688为要复制的代码的末地址<br> 0167:00401CB8 SUB ECX,ESI<br> 0167:00401CBA REPZ MOVSB ;将代码全部复制到映射区域<br> 0167:00401CBC SGDT FWORD PTR [EBP-1C] ;这句开始就很关键了<br> 0167:00401CC0 LEA EAX,[EBP-001C]<br> 0167:00401CC6 MOV EAX,[EAX+02] ;取GDT线性基址 <br> 0167:00401CC9 XOR EBX,EBX <br> 0167:00401CCB SLDT BX ;取LDT在GDT中的偏移 <br> 0167:00401CCE AND BX,-08 <br> 0167:00401CD2 ADD EAX,EBX <br> 0167:00401CD4 MOV ECX,[EAX+02] <br> 0167:00401CD7 SHL ECX,08 <br> 0167:00401CDA MOV CL,[EAX+07] <br> 0167:00401CDD ROR ECX,08 ;以上计算出LDT线性基址 <br> 0167:00401CE0 MOV [EBP-0C],ECX ;保存 <br> 0167:00401CE3 MOV EAX,[EBP-30] <br> 0167:00401CE6 MOV ECX,[EBP-0C] <br> 0167:00401CE9 MOV [EAX+00000370],ECX <br> 0167:00401CEF MOV EDX,[EBP-30] <br> 0167:00401CF2 MOV EAX,[EDX+0000036C] <br> 0167:00401CF8 MOV ECX,[EBP-0C] <br> 0167:00401CFB MOV [EAX+0000FE00],ECX<br> ;将LDT线性基址保存至映射代码中 <br> 0167:00401D01 MOV AX,CS<br> ;得到当前代码段描述符号 <br> 0167:00401D04 AND AX,FFF8 <br> 0167:00401D08 MOV [EBP-10],AX <br> 0167:00401D0C MOV EDX,[EBP-10] <br> 0167:00401D0F AND EDX,0000FFFF<br> ;EDX为代码段描述符在LDT中的偏移量<br> 0167:00401D15 MOV EAX,[EBP-30]<br> 0167:00401D18 MOV ECX,[EAX+00000370] ;ECX此时为LDT线性基址 0167:00401D1E MOV EAX,[EBP-30]<br> 0167:00401D21 MOV EAX,[EAX+00000370] <br>;EAX此时为LDT线性基址 <br><br> 0167:00401D27 MOV ESI,[EDX+ECX] <br> 0167:00401D2A MOV [EAX+08],ESI <br> 0167:00401D2D MOV ECX,[EDX+ECX+04]<br> ;以上将当前代码段描述符复制到 <br> 0167:00401D31 MOV [EAX+0C],ECX ;LDT第1项 <br> 0167:00401D34 MOV EDX,[EBP-30] <br> 0167:00401D37 MOV EAX,[EDX+00000370] <br> 0167:00401D3D MOV CL,[EAX+0D] <br> 0167:00401D40 AND CL,9F <br> 0167:00401D43 MOV EDX,[EBP-30] <br> 0167:00401D46 MOV EAX,[EDX+00000370] <br> 0167:00401D4C MOV [EAX+0D],CL<br> ;以上修改LDT第1项的DPL为0,则当由调用门转到该段代码时即获得RING0权限 <br> 0167:00401D4F MOV EAX,[EBP-0C] <br> 0167:00401D52 ADD EAX,10 ;获得LDT中索引为2的调用门地址 <br> 0167:00401D55 MOV EBX,0040213B <br> 0167:00401D5A MOV [EAX],EBX <br> 0167:00401D5C MOV [EAX+04],EBX <br> 0167:00401D5F MOV WORD PTR [EAX+02],000C <br> 0167:00401D65 MOV WORD PTR [EAX+04],EC00 ;调用门修改完毕 <br> 0167:00401D6B MOV ECX,[EBP-08] <br> 0167:00401D6E MOV EDX,[WINMM!timeGetTime] <br> 0167:00401D74 MOV [ECX+0000FEE0]<br><br>;EDX;保存timeGetTime入口地址<br> ...省略部分依次保存GetTickCount,GetMessageTime,timeSetEvent,SetTimer,<br> timeGetSystemTime,QueryPerformanceCounter入口地址 <br> 0167:00401DD2 MOV ECX,[EBP-08] <br> 0167:00401DD5 MOV EAX,[WINMM!timeGetTime] <br> 0167:00401DDA MOV EBX,[EAX] <br> 0167:00401DDC MOV [ECX+0000FE40],EBX <br> 0167:00401DE2 MOV EBX,[EAX+04] <br> 0167:00401DE5 MOV [ECX+0000FE44],EBX<br> ;保存timeGetTime函数前8个字节指令<br> ...省略部分依次保存GetTickCount,GetMessageTime,timeSetEvent,<br> timeGetSystemTime , QueryPerformanceCounter前8个字节指令 <br> 0167:00401E6D MOV BYTE PTR [ECX+0000FE90],E9 <br> 0167:00401E74 MOV EAX,00402165 <br> 0167:00401E79 SUB EAX,0040213B<br> ;EAX为截获代码在映射代码中的偏移 <br> 0167:00401E7E ADD EAX,ECX ;计算出截获代码的线性入口地址 <br> 0167:00401E80 SUB EAX,[WINMM!timeGetTime] <br> 0167:00401E86 SUB EAX,05 ;JMP指令总长5个字节 <br> 0167:00401E89 MOV [ECX+0000FE91],EAX<br> ;计算生成从timeGetTime跳到截获代码的JMP指令并保存<br> <br> ...省略部分依次计算并生成GetTickCount,GetMessageTime,timeSetEvent,<br> timeGetSystemTime , QueryPerformanceCounter跳到截获代码的JMP指令<br> 并保存 <br> <br> 0167:00401F58 CLI ;关闭中断,谨防修改代码时发生意外 <br> 0167:00401F59 MOV EAX,004021F3 ; <br> 0167:00401F5E SUB EAX,0040213B;计算子程序在映射代码中的偏移 <br> 0167:00401F63 ADD EAX,[EBP-08] ;EAX=8xxx 00B8 <br> 0167:00401F66 PUSH EAX ;传入参数EAX为修改timeGetTime代码的<br> ;子程序入口地址 <br> 0167:00401F67 MOV EAX,[EBP-08] ;调用8xxx 0000 <br> 0167:00401F6A CALL EAX ;返回时timeGetTime首指令被更改<br> <br> ...省略部分依次修改GetTickCount,GetMessageTime,timeSetEvent,<br> timeGetSystemTime , QueryPerformanceCounter函数的首指令 <br> <br> 0167:00401FF SETI ;设置中断,初始化代码结束<br> 二、截获时间函数部分(以timeGetTime为例子,代码以跟踪顺序列出)<br> timeGetTime<br> JMP 832A 002A<br> ;这是timeGetTime被修改后的首指令 <br> 0167:832A 002A CLI<br> ;此时[esp]=40BF2C,即游戏程序中调用timeGetTime函数的下一条指令<br> ...(6个)各寄存器分别入栈 且MOV EBP,ESP <br> 0167:832A 0033 CALL 832A 0038<br> ;将当前EIP入栈(即下一条指令的地址) <br> 0167:832A 0038 POP EDI ;取出当前指令地址 <br> XOR DI , DI<br> MOV ESI , EDI<br> ;将64K内存首地址赋给ESI<br> ;此时ESI=EDI=832A 0000<br> ADD ESI , 0040 2102 <br> SUB ESI , 0040 213B ;求出映射代码首地址 <br> PUSH ESI <br> 0167:832A 004B CALL EDI ;ESI为传进的参数<br> ;返回时已经将timeGetTime代码还原 <br> 0167:832A 004D CALL 832A 0052 ; <br> 0167:832A 0052 POP EDI<br> XOR DI ,DI ;故技重施 <br> CALL [EDI + 0000FEED];调用原timeGetTime函数<br> SUB EAX,[EDI + 0000 FF30]<br> ;减去第一次调用timeGetTime的结果<br> MUL DWORD PTR [EDI+0000 FE30]<br> ;乘以用户所指定的倍数<br> MOV EBX ,00100000<br> DIV EBX<br> ;除以常数100000<br> ADD EAX ,[EDI+ 0000FE20] <br> MOV EAX,004021F3 <br> SUB EAX,0040213B <br> ADD EAX,EDI<br> ;以上指令为修改timeGetTime函数返回值 <br> PUSH EAX<br> ;EAX为传进的参数 <br> CALL EDI<br> ;返回时又将timeGetTime首指令换成JMP<br> ...恢复各寄存器的值,EAX中为修改后的返回值 <br> RET ;此时[ESP]=40BF2C,执行RET将返回到游戏中去<br> ; <br> 0167:832A 0000 CALL 832A 0005 <br> 0167:832A 0005 POP EDI <br> XOR DI ,DI ;老套了撒^_^<br> MOV ESI ,[EDI+0000 FE00]<br> ;此地址保存着LDT的线性基址<br> MOV EAX,[ESP+04] <br> MOV [ESI +10],AX <br> SHR EAX,10 <br> MOV [ESI+16],AX<br> ;以上代码将LDT中索引为2的调用门描述符的偏移改为传入的参数<br> ... <br> MOV EAX,0000 0F00 <br> CALL EAX<br> ;调用子程序修改timeGetTime代码<br> 0167:832A 0027 RET 4<br> ;弹出参数,返回<br> ; <br> 0167:832A F000 CALL 0014:00000000<br> RET 0<br> ; <br> 000C:832A 0097 CALL 832A 009C <br> 000C:832A 009C POP EDI<br> MOV EAX,[EDI+0000 FE40] <br> MOV EBX,[EDI+0000 FEE0] <br> MOV [EBX],EAX <br> MOV EAX,[EDI+0000 FE44] <br> MOV [EBX+04],EAX <br> RETF<br> 注:EDI+0000 FE40起前8个字节为原timeGetTime函数的指令<br> EDI+0000 FEE0保存着timeGetTime函数的入口地址<br> 以上即恢复timeGetTime前8个字节的代码<br> ; <br> 000C:832A 00B8 CALL 832A 00BD <br> 000C:832A 00BD POP EDI<br> XOR DI ,DI<br> ... <br> MOV EAX,[EDI+0000 FE90] <br> MOV EBX,[EDI+0000 FEE0] <br> MOV [EBX],EAX <br> MOV EAX,[EDI+0000FE94] <br> MOV [EBX+04],EAX <br> RETF<br><br> 注:EDI+0000 FE90 起前8个字节保存着JMP 832A 002A 指令<br> 是由“齿轮”初始化部分代码计算出来的,以上代码将JMP 832A 002A<br> 写入timeGetTime函数<br>--<br>这段代码是汇编的!