taskmgr多开补丁

本来想写xxx游戏多开补丁的,后来想想算了,这个游戏有违道德,so 选择一个微软自己的东西搞搞理论就好了。

     经常用任务管理器的人都知道taskmgr默认是只能开一个的,除非电脑非常卡的时候可以开很多个,就像xxx游戏在运行一个客户端以后,迅速的再双击,又可以再运行一个差不多原理(这个跟多线程安全差不多)。

      程序只能运行一个实例的方法有很多,理论就不讲了,直接开场taskmgr的方法。

      首先,这个taskmgr是XP SP3系统上面的。其他自己研究。

      用OD加载直接代码就是Call   xxxxx  然后 jmp  xxxx,如果逆向多的话,这个就很清楚了,至少是VS05以上的C/C++编译器(好像这个多开跟编译器没多大关系吧...)

      继续跟下去,大家都很清楚:对于VC编译器入口还是不管是_tmain还是_tWinMain都是在调用了GetCommandLine以后有很多个push  push xxx之后的;exit、ExitProcess之前的那个函数就是了。所以我假设你已经找到WinMain函数地址 0x0100538E。

       WinMain代码及简陋过程分析如下:

[cpp]  view plain copy
  1. 0100538E  /$  8BFF          MOV EDI,EDI  
  2. 01005390  |.  55            PUSH EBP  
  3. 01005391  |.  8BEC          MOV EBP,ESP  
  4. 01005393  |.  81EC 10040000 SUB ESP,410  
  5. 01005399  |.  A1 94540101   MOV EAX,DWORD PTR DS:[1015494]  
  6. 0100539E  |.  53            PUSH EBX  
  7. 0100539F  |.  56            PUSH ESI  
  8. 010053A0  |.  8B75 08       MOV ESI,DWORD PTR SS:[EBP+8]  
  9. 010053A3  |.  57            PUSH EDI  
  10. 010053A4  |.  33FF          XOR EDI,EDI  
  11. 010053A6  |.  47            INC EDI  
  12. 010053A7  |.  33DB          XOR EBX,EBX  
  13. 010053A9  |.  68 4C1B0001   PUSH taskmgr.01001B4C                    ; /MsgName = "TaskbarCreated"  
  14. 010053AE  |.  8945 FC       MOV DWORD PTR SS:[EBP-4],EAX             ; |  
  15. 010053B1  |.  89B5 28FCFFFF MOV DWORD PTR SS:[EBP-3D8],ESI           ; |  
  16. 010053B7  |.  8935 285E0101 MOV DWORD PTR DS:[1015E28],ESI           ; |  
  17. 010053BD  |.  89BD 2CFCFFFF MOV DWORD PTR SS:[EBP-3D4],EDI           ; |  
  18. 010053C3  |.  899D 20FCFFFF MOV DWORD PTR SS:[EBP-3E0],EBX           ; |定义一个新的窗口消息,保证整个系统中是唯一的  
  19. 010053C9  |.  FF15 A0120001 CALL DWORD PTR DS:[<&USER32.RegisterWind>; \RegisterWindowMessageW  
  20. 010053CF  |.  68 C0140001   PUSH taskmgr.010014C0                    ; /MutexName = "NTShell Taskman Startup Mutex"  
  21. 010053D4  |.  57            PUSH EDI                                 ; |InitialOwner => TRUE  
  22. 010053D5  |.  53            PUSH EBX                                 ; |pSecurity => NULL  
  23. 010053D6  |.  A3 105E0101   MOV DWORD PTR DS:[1015E10],EAX           ; |创建一个互斥体,如果存在则GetLastError为 ERROR_ALREADY_EXISTS (0x0B7)  
  24. 010053DB  |.  FF15 2C110001 CALL DWORD PTR DS:[<&KERNEL32.CreateMute>; \CreateMutexW  
  25. 010053E1  |.  3BC3          CMP EAX,EBX  
  26. 010053E3  |.  A3 145E0101   MOV DWORD PTR DS:[1015E14],EAX  
  27. 010053E8  |.  BF 10270000   MOV EDI,2710  
  28. 010053ED  |.  74 1A         JE SHORT taskmgr.01005409  
  29. 010053EF  |.  FF15 84110001 CALL DWORD PTR DS:[<&KERNEL32.GetLastErr>; [GetLastError  
  30. 010053F5  |.  3D B7000000   CMP EAX,0B7  
  31. 010053FA  |.  75 0D         JNZ SHORT taskmgr.01005409               ;  如果不存在互斥体,跳转  
  32. 010053FC  |.  57            PUSH EDI                                 ; /Timeout => 10000. ms  
  33. 010053FD  |.  FF35 145E0101 PUSH DWORD PTR DS:[1015E14]              ; |有互斥体存在,等待10000ms,使其他taskmgr可以显示窗口,事实证明这个10000ms还是太短了  
  34. 01005403  |.  FF15 40110001 CALL DWORD PTR DS:[<&KERNEL32.WaitForSin>; \WaitForSingleObject  
  35. 01005409  |>  68 985E0101   PUSH taskmgr.01015E98                    ; /Arg3 = 01015E98  
  36. 0100540E  |.  68 945E0101   PUSH taskmgr.01015E94                    ; |Arg2 = 01015E94  
  37. 01005413  |.  68 905E0101   PUSH taskmgr.01015E90                    ; |Arg1 = 01015E90  
  38. 01005418  |.  E8 ACE9FFFF   CALL taskmgr.01003DC9                    ; \taskmgr.01003DC9  
  39. 0100541D  |.  391D 905E0101 CMP DWORD PTR DS:[1015E90],EBX  
  40. 01005423  |.  74 12         JE SHORT taskmgr.01005437  
  41. 01005425  |.  68 9C5E0101   PUSH taskmgr.01015E9C  
  42. 0100542A  |.  FF15 30110001 CALL DWORD PTR DS:[<&KERNEL32.GetCurrent>; [GetCurrentProcessId  
  43. 01005430  |.  50            PUSH EAX  
  44. 01005431  |.  FF15 34110001 CALL DWORD PTR DS:[<&KERNEL32.ProcessIdT>;  kernel32.ProcessIdToSessionId  
  45. 01005437  |>  68 04010000   PUSH 104                                 ; /Count = 104 (260.)  
  46. 0100543C  |.  8D85 30FCFFFF LEA EAX,DWORD PTR SS:[EBP-3D0]           ; |  
  47. 01005442  |.  50            PUSH EAX                                 ; |Buffer  
  48. 01005443  |.  68 13270000   PUSH 2713                                ; |RsrcID = STRING "Windows 任务管理器"  
  49. 01005448  |.  56            PUSH ESI                                 ; |hInst  
  50. 01005449  |.  8B35 BC130001 MOV ESI,DWORD PTR DS:[<&USER32.LoadStrin>; |USER32.LoadStringW  
  51. 0100544F  |.  FFD6          CALL ESI                                 ; \LoadStringW  
  52. 01005451  |.  85C0          TEST EAX,EAX  
  53. 01005453  |.  74 6A         JE SHORT taskmgr.010054BF  
  54. 01005455  |.  8D85 30FCFFFF LEA EAX,DWORD PTR SS:[EBP-3D0]  
  55. 0100545B  |.  50            PUSH EAX                                 ; /Title  
  56. 0100545C  |.  68 02800000   PUSH 8002                                ; |Class = 8002  
  57. 01005461  |.  FF15 9C120001 CALL DWORD PTR DS:[<&USER32.FindWindowW>>; \FindWindowW  
  58. 01005467  |.  3BC3          CMP EAX,EBX                              ;  查找窗口类为0x8002的窗口,用spy++可以知道#32770 (Dialog)正是taskmgr的窗口类  
  59. 01005469  |.  8985 14FCFFFF MOV DWORD PTR SS:[EBP-3EC],EAX           ;  所以这里是检测获取另一个窗口的窗口HWND  
  60. 0100546F  |.  74 4E         JE SHORT taskmgr.010054BF                ;  关键点:如果找到窗体则激活那个窗体,将退出本进程(只要这里一直jmp就可以实现多开了)  
  61. 01005471  |.  8D8D 1CFCFFFF LEA ECX,DWORD PTR SS:[EBP-3E4]  
  62. 01005477  |.  51            PUSH ECX                                 ; /pProcessID  
  63. 01005478  |.  50            PUSH EAX                                 ; |hWnd  
  64. 01005479  |.  899D 1CFCFFFF MOV DWORD PTR SS:[EBP-3E4],EBX           ; |  
  65. 0100547F  |.  FF15 98120001 CALL DWORD PTR DS:[<&USER32.GetWindowThr>; \GetWindowThreadProcessId  
  66. 01005485  |.  FFB5 1CFCFFFF PUSH DWORD PTR SS:[EBP-3E4]  
  67. 0100548B  |.  FF15 94120001 CALL DWORD PTR DS:[<&USER32.AllowSetFore>;  USER32.AllowSetForegroundWindow  
  68. 01005491  |.  8D85 18FCFFFF LEA EAX,DWORD PTR SS:[EBP-3E8]  
  69. 01005497  |.  50            PUSH EAX                                 ; /pResult  
  70. 01005498  |.  57            PUSH EDI                                 ; |Timeout  
  71. 01005499  |.  6A 02         PUSH 2                                   ; |Flags = SMTO_NORMAL|SMTO_ABORTIFHUNG  
  72. 0100549B  |.  53            PUSH EBX                                 ; |lParam  
  73. 0100549C  |.  53            PUSH EBX                                 ; |wParam  
  74. 0100549D  |.  BF 0B040000   MOV EDI,40B                              ; |  
  75. 010054A2  |.  57            PUSH EDI                                 ; |Message => WM_USER+11.  
  76. 010054A3  |.  FFB5 14FCFFFF PUSH DWORD PTR SS:[EBP-3EC]              ; |hWnd  
  77. 010054A9  |.  FF15 90120001 CALL DWORD PTR DS:[<&USER32.SendMessageT>; \SendMessageTimeoutW  
  78. 010054AF  |.  85C0          TEST EAX,EAX  
  79. 010054B1  |.  74 0C         JE SHORT taskmgr.010054BF  
  80. 010054B3  |.  39BD 18FCFFFF CMP DWORD PTR SS:[EBP-3E8],EDI  
  81. 010054B9  |.  0F84 FB020000 JE taskmgr.010057BA                      ;  已存在taskmgr则跳去释放互斥体,然后退出  
  82. 010054BF  |>  8D85 24FCFFFF LEA EAX,DWORD PTR SS:[EBP-3DC]           ;  跳到这里是说明可以生成一个taskmgr界面了  
在OD里面将

JE SHORT 010054BF

改成

JMP SHORT 010054BF

会发现只是 地址0x0100546F的0x74变成了0xEB,所以多开补丁如下:

[cpp]  view plain copy
  1. #include <windows.h>  
  2.   
  3. BYTE buf[] = "\x89\x85\x14\xFC\xFF\xFF\x74\x4E";  
  4.   
  5. void MyFunc()  
  6. {  
  7.     STARTUPINFO sInfo;   
  8.     PROCESS_INFORMATION pInfo;    
  9.     BYTE RemoteMemory[8];  
  10.     DWORD wBytes;  
  11.   
  12.     ZeroMemory( &sInfo, sizeof(sInfo) );   
  13.     sInfo.cb = sizeof(sInfo);   
  14.     sInfo.dwFlags = STARTF_USESHOWWINDOW;   
  15.     sInfo.wShowWindow = SW_SHOWNORMAL;   
  16.     ZeroMemory( &pInfo, sizeof(pInfo) );   
  17.   
  18.     if( CreateProcess( NULL,      
  19.         TEXT("taskmgr.exe"),    
  20.         NULL,    
  21.         NULL,    
  22.         FALSE,    
  23.         CREATE_SUSPENDED,  // 线程启动后在入口暂停  
  24.         NULL,    
  25.         NULL,    
  26.         &sInfo,    
  27.         &pInfo )               
  28.         )    
  29.     {  
  30.         // 读取 0x01005469开始的8个数据,包括要修改的0x0100546F处1Byte  
  31.         if (ReadProcessMemory(pInfo.hProcess, (LPVOID)0x01005469, RemoteMemory, 8, &wBytes))  
  32.         {  
  33.             // 多读取的数据为了判断是不是我们要修改的数据,如果不是则不修改,  
  34.             // 这样就不需要判断是什么系统了  
  35.             if (memcmp(RemoteMemory, buf, 8) == 0)  
  36.             {  
  37.                 RemoteMemory[6] = '\xEB'// RemoteMemory[6] = '\x74'; je 修改成 0xEB jmp   
  38.                 WriteProcessMemory(pInfo.hProcess, (LPVOID)0x01005469, RemoteMemory, 8, &wBytes); //写入修改后的数据  
  39.                 ResumeThread(pInfo.hThread); // 程序继续运行  
  40.             }  
  41.             else  
  42.             {  
  43.                 // 留着这个进程没作用,直接关了吧  
  44.                 TerminateProcess(pInfo.hProcess, 0);  
  45.             }  
  46.         }  
  47.         CloseHandle( pInfo.hProcess );   
  48.         CloseHandle( pInfo.hThread );   
  49.     }   
  50. }  

       可是像上面的代码可能在某些程序里面有问题,原因是程序这样的修改是永久性的,不管程序运行多久,地址0x0100546F的数据永远都变成0xEB,如果程序自校验的就会被发现的,那么再跳转过后,就需要把这个代码改回去的,不过修改回去的方法可没有先前改的简单了,需要用到调试运行设置断点来修改,不细说了,代码如下

[cpp]  view plain copy
  1. #include <windows.h>  
  2.   
  3. BYTE buf[] = "\x89\x85\x14\xFC\xFF\xFF\x74\x4E";  
  4. BYTE BreakPoint[] = "\x8D\x85\x24\xFC\xFF\xFF\x50\x68";  
  5.   
  6. typedef void (WINAPI * PDebugSetProcessKillOnExit)(BOOL);  
  7.   
  8. void MyFunc()  
  9. {  
  10.     STARTUPINFO sInfo;   
  11.     PROCESS_INFORMATION pInfo;    
  12.     DEBUG_EVENT debug;  
  13.     CONTEXT context;  
  14.   
  15.     BYTE RemoteMemory[16];  
  16.     DWORD wBytes;  
  17.     BOOL flags = TRUE;  
  18.   
  19.     ZeroMemory( &sInfo, sizeof(sInfo) );   
  20.     sInfo.cb = sizeof(sInfo);   
  21.     sInfo.dwFlags = STARTF_USESHOWWINDOW;   
  22.     sInfo.wShowWindow = SW_SHOWNORMAL;   
  23.     ZeroMemory( &pInfo, sizeof(pInfo) );   
  24.   
  25.     if( CreateProcess( NULL,      
  26.         TEXT("taskmgr.exe"),    
  27.         NULL,    
  28.         NULL,    
  29.         FALSE,    
  30.         DEBUG_ONLY_THIS_PROCESS,   
  31.         NULL,    
  32.         NULL,    
  33.         &sInfo,    
  34.         &pInfo )               
  35.         )    
  36.     {    
  37.         // 在调试器退出的时候,被调试程序不会退出  
  38.         HMODULE hmodule = LoadLibrary(TEXT("kernel32.dll"));  
  39.         PDebugSetProcessKillOnExit DebugSetProcessKillOnExit =   
  40.             (PDebugSetProcessKillOnExit)GetProcAddress(hmodule, "DebugSetProcessKillOnExit");  
  41.         if ( DebugSetProcessKillOnExit != NULL )  
  42.         {  
  43.             DebugSetProcessKillOnExit(FALSE);  
  44.         }  
  45.           
  46.         ZeroMemory(&context, sizeof(context));  
  47.         context.ContextFlags = CONTEXT_FULL | CONTEXT_DEBUG_REGISTERS;  
  48.         // 等待运行到断点处  
  49.         while(flags)  
  50.         {  
  51.             WaitForDebugEvent( &debug , INFINITE );  
  52.             switch(debug.dwDebugEventCode)  
  53.             {  
  54.                 case CREATE_PROCESS_DEBUG_EVENT: // 启动调试事件  
  55.                     if (ReadProcessMemory(pInfo.hProcess, (LPVOID)0x01005469, RemoteMemory, 8, &wBytes))  
  56.                     {  
  57.                         if (memcmp(RemoteMemory, buf, 8) == 0)  
  58.                         {  
  59.                             // 跳过检测窗口,下断点  
  60.                             RemoteMemory[6] = '\xEB';  
  61.                             WriteProcessMemory(pInfo.hProcess, (LPVOID)0x01005469, RemoteMemory, 8, &wBytes);  
  62.                             WriteProcessMemory(pInfo.hProcess, (LPVOID)0x010054BF, "\xCC", 1, &wBytes);  
  63.                         }  
  64.                     }  
  65.                     else  
  66.                     {  
  67.                         flags = FALSE;  
  68.                         TerminateProcess(pInfo.hProcess, 0);  
  69.                     }  
  70.                     break;  
  71.                 case EXCEPTION_DEBUG_EVENT: // 异常发生,捕获int 3断点就可以了  
  72.                     if ( debug.u.Exception.ExceptionRecord.ExceptionCode == EXCEPTION_BREAKPOINT )  
  73.                     {  
  74.                         if ((DWORD)debug.u.Exception.ExceptionRecord.ExceptionAddress == 0x010054BF )  
  75.                         {  
  76.                             // 将数据改回去  
  77.                             WriteProcessMemory(pInfo.hProcess, (LPVOID)0x01005469, buf, 8, &wBytes);  
  78.                             WriteProcessMemory(pInfo.hProcess, (LPVOID)0x010054BF, BreakPoint, 4, &wBytes);  
  79.                               
  80.                             // 将EIP往回退1byte  
  81.                             if (GetThreadContext(pInfo.hThread, &context))  
  82.                             {  
  83.                                 context.Eip -= 1;  
  84.                                 SetThreadContext(pInfo.hThread, &context);  
  85.                             }  
  86.                             flags = FALSE; // 退出循环  
  87.                         }                         
  88.                     }  
  89.                     break;  
  90.             }  
  91.               
  92.             if (!ContinueDebugEvent(debug.dwProcessId, debug.dwThreadId, DBG_CONTINUE ))  
  93.             {  
  94.                 // continue error  
  95.                 TerminateProcess(pInfo.hProcess, 0);  
  96.                 ExitProcess(0);  
  97.             }  
  98.         }  
  99.   
  100.         FreeLibrary(hmodule);  
  101.         CloseHandle( pInfo.hProcess );   
  102.         CloseHandle( pInfo.hThread );   
  103.     }   
  104. }  

       程序还有可能是用调试的方法加载的自身,还有可能HOOK掉了几个关键的API,还有的可能是驱动级的保护……这个技术实在太多了,想修改那些代码实现多开也是可以的,有矛必有盾嘛。

      太累了,还是搞个无图无真相吧。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值