taskmgr多开补丁

来源:互联网 发布:网络联合电视台 编辑:程序博客网 时间:2024/05/21 08:44
       本来想写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代码及简陋过程分析如下:

0100538E  /$  8BFF          MOV EDI,EDI01005390  |.  55            PUSH EBP01005391  |.  8BEC          MOV EBP,ESP01005393  |.  81EC 10040000 SUB ESP,41001005399  |.  A1 94540101   MOV EAX,DWORD PTR DS:[1015494]0100539E  |.  53            PUSH EBX0100539F  |.  56            PUSH ESI010053A0  |.  8B75 08       MOV ESI,DWORD PTR SS:[EBP+8]010053A3  |.  57            PUSH EDI010053A4  |.  33FF          XOR EDI,EDI010053A6  |.  47            INC EDI010053A7  |.  33DB          XOR EBX,EBX010053A9  |.  68 4C1B0001   PUSH taskmgr.01001B4C                    ; /MsgName = "TaskbarCreated"010053AE  |.  8945 FC       MOV DWORD PTR SS:[EBP-4],EAX             ; |010053B1  |.  89B5 28FCFFFF MOV DWORD PTR SS:[EBP-3D8],ESI           ; |010053B7  |.  8935 285E0101 MOV DWORD PTR DS:[1015E28],ESI           ; |010053BD  |.  89BD 2CFCFFFF MOV DWORD PTR SS:[EBP-3D4],EDI           ; |010053C3  |.  899D 20FCFFFF MOV DWORD PTR SS:[EBP-3E0],EBX           ; |定义一个新的窗口消息,保证整个系统中是唯一的010053C9  |.  FF15 A0120001 CALL DWORD PTR DS:[<&USER32.RegisterWind>; \RegisterWindowMessageW010053CF  |.  68 C0140001   PUSH taskmgr.010014C0                    ; /MutexName = "NTShell Taskman Startup Mutex"010053D4  |.  57            PUSH EDI                                 ; |InitialOwner => TRUE010053D5  |.  53            PUSH EBX                                 ; |pSecurity => NULL010053D6  |.  A3 105E0101   MOV DWORD PTR DS:[1015E10],EAX           ; |创建一个互斥体,如果存在则GetLastError为 ERROR_ALREADY_EXISTS (0x0B7)010053DB  |.  FF15 2C110001 CALL DWORD PTR DS:[<&KERNEL32.CreateMute>; \CreateMutexW010053E1  |.  3BC3          CMP EAX,EBX010053E3  |.  A3 145E0101   MOV DWORD PTR DS:[1015E14],EAX010053E8  |.  BF 10270000   MOV EDI,2710010053ED  |.  74 1A         JE SHORT taskmgr.01005409010053EF  |.  FF15 84110001 CALL DWORD PTR DS:[<&KERNEL32.GetLastErr>; [GetLastError010053F5  |.  3D B7000000   CMP EAX,0B7010053FA  |.  75 0D         JNZ SHORT taskmgr.01005409               ;  如果不存在互斥体,跳转010053FC  |.  57            PUSH EDI                                 ; /Timeout => 10000. ms010053FD  |.  FF35 145E0101 PUSH DWORD PTR DS:[1015E14]              ; |有互斥体存在,等待10000ms,使其他taskmgr可以显示窗口,事实证明这个10000ms还是太短了01005403  |.  FF15 40110001 CALL DWORD PTR DS:[<&KERNEL32.WaitForSin>; \WaitForSingleObject01005409  |>  68 985E0101   PUSH taskmgr.01015E98                    ; /Arg3 = 01015E980100540E  |.  68 945E0101   PUSH taskmgr.01015E94                    ; |Arg2 = 01015E9401005413  |.  68 905E0101   PUSH taskmgr.01015E90                    ; |Arg1 = 01015E9001005418  |.  E8 ACE9FFFF   CALL taskmgr.01003DC9                    ; \taskmgr.01003DC90100541D  |.  391D 905E0101 CMP DWORD PTR DS:[1015E90],EBX01005423  |.  74 12         JE SHORT taskmgr.0100543701005425  |.  68 9C5E0101   PUSH taskmgr.01015E9C0100542A  |.  FF15 30110001 CALL DWORD PTR DS:[<&KERNEL32.GetCurrent>; [GetCurrentProcessId01005430  |.  50            PUSH EAX01005431  |.  FF15 34110001 CALL DWORD PTR DS:[<&KERNEL32.ProcessIdT>;  kernel32.ProcessIdToSessionId01005437  |>  68 04010000   PUSH 104                                 ; /Count = 104 (260.)0100543C  |.  8D85 30FCFFFF LEA EAX,DWORD PTR SS:[EBP-3D0]           ; |01005442  |.  50            PUSH EAX                                 ; |Buffer01005443  |.  68 13270000   PUSH 2713                                ; |RsrcID = STRING "Windows 任务管理器"01005448  |.  56            PUSH ESI                                 ; |hInst01005449  |.  8B35 BC130001 MOV ESI,DWORD PTR DS:[<&USER32.LoadStrin>; |USER32.LoadStringW0100544F  |.  FFD6          CALL ESI                                 ; \LoadStringW01005451  |.  85C0          TEST EAX,EAX01005453  |.  74 6A         JE SHORT taskmgr.010054BF01005455  |.  8D85 30FCFFFF LEA EAX,DWORD PTR SS:[EBP-3D0]0100545B  |.  50            PUSH EAX                                 ; /Title0100545C  |.  68 02800000   PUSH 8002                                ; |Class = 800201005461  |.  FF15 9C120001 CALL DWORD PTR DS:[<&USER32.FindWindowW>>; \FindWindowW01005467  |.  3BC3          CMP EAX,EBX                              ;  查找窗口类为0x8002的窗口,用spy++可以知道#32770 (Dialog)正是taskmgr的窗口类01005469  |.  8985 14FCFFFF MOV DWORD PTR SS:[EBP-3EC],EAX           ;  所以这里是检测获取另一个窗口的窗口HWND0100546F  |.  74 4E         JE SHORT taskmgr.010054BF                ;  关键点:如果找到窗体则激活那个窗体,将退出本进程(只要这里一直jmp就可以实现多开了)01005471  |.  8D8D 1CFCFFFF LEA ECX,DWORD PTR SS:[EBP-3E4]01005477  |.  51            PUSH ECX                                 ; /pProcessID01005478  |.  50            PUSH EAX                                 ; |hWnd01005479  |.  899D 1CFCFFFF MOV DWORD PTR SS:[EBP-3E4],EBX           ; |0100547F  |.  FF15 98120001 CALL DWORD PTR DS:[<&USER32.GetWindowThr>; \GetWindowThreadProcessId01005485  |.  FFB5 1CFCFFFF PUSH DWORD PTR SS:[EBP-3E4]0100548B  |.  FF15 94120001 CALL DWORD PTR DS:[<&USER32.AllowSetFore>;  USER32.AllowSetForegroundWindow01005491  |.  8D85 18FCFFFF LEA EAX,DWORD PTR SS:[EBP-3E8]01005497  |.  50            PUSH EAX                                 ; /pResult01005498  |.  57            PUSH EDI                                 ; |Timeout01005499  |.  6A 02         PUSH 2                                   ; |Flags = SMTO_NORMAL|SMTO_ABORTIFHUNG0100549B  |.  53            PUSH EBX                                 ; |lParam0100549C  |.  53            PUSH EBX                                 ; |wParam0100549D  |.  BF 0B040000   MOV EDI,40B                              ; |010054A2  |.  57            PUSH EDI                                 ; |Message => WM_USER+11.010054A3  |.  FFB5 14FCFFFF PUSH DWORD PTR SS:[EBP-3EC]              ; |hWnd010054A9  |.  FF15 90120001 CALL DWORD PTR DS:[<&USER32.SendMessageT>; \SendMessageTimeoutW010054AF  |.  85C0          TEST EAX,EAX010054B1  |.  74 0C         JE SHORT taskmgr.010054BF010054B3  |.  39BD 18FCFFFF CMP DWORD PTR SS:[EBP-3E8],EDI010054B9  |.  0F84 FB020000 JE taskmgr.010057BA                      ;  已存在taskmgr则跳去释放互斥体,然后退出010054BF  |>  8D85 24FCFFFF LEA EAX,DWORD PTR SS:[EBP-3DC]           ;  跳到这里是说明可以生成一个taskmgr界面了
在OD里面将

JE SHORT 010054BF

改成

JMP SHORT 010054BF

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

#include <windows.h>BYTE buf[] = "\x89\x85\x14\xFC\xFF\xFF\x74\x4E";void MyFunc(){STARTUPINFO sInfo; PROCESS_INFORMATION pInfo;  BYTE RemoteMemory[8];DWORD wBytes;ZeroMemory( &sInfo, sizeof(sInfo) ); sInfo.cb = sizeof(sInfo); sInfo.dwFlags = STARTF_USESHOWWINDOW; sInfo.wShowWindow = SW_SHOWNORMAL; ZeroMemory( &pInfo, sizeof(pInfo) ); if( CreateProcess( NULL,    TEXT("taskmgr.exe"),  NULL,  NULL,  FALSE,  CREATE_SUSPENDED,  // 线程启动后在入口暂停NULL,  NULL,  &sInfo,  &pInfo )             )  {// 读取 0x01005469开始的8个数据,包括要修改的0x0100546F处1Byteif (ReadProcessMemory(pInfo.hProcess, (LPVOID)0x01005469, RemoteMemory, 8, &wBytes)){// 多读取的数据为了判断是不是我们要修改的数据,如果不是则不修改,// 这样就不需要判断是什么系统了if (memcmp(RemoteMemory, buf, 8) == 0){RemoteMemory[6] = '\xEB'; // RemoteMemory[6] = '\x74'; je 修改成 0xEB jmp WriteProcessMemory(pInfo.hProcess, (LPVOID)0x01005469, RemoteMemory, 8, &wBytes); //写入修改后的数据ResumeThread(pInfo.hThread); // 程序继续运行}else{// 留着这个进程没作用,直接关了吧TerminateProcess(pInfo.hProcess, 0);}}CloseHandle( pInfo.hProcess ); CloseHandle( pInfo.hThread ); } }

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

#include <windows.h>BYTE buf[] = "\x89\x85\x14\xFC\xFF\xFF\x74\x4E";BYTE BreakPoint[] = "\x8D\x85\x24\xFC\xFF\xFF\x50\x68";typedef void (WINAPI * PDebugSetProcessKillOnExit)(BOOL);void MyFunc(){STARTUPINFO sInfo; PROCESS_INFORMATION pInfo;  DEBUG_EVENT debug;CONTEXT context;BYTE RemoteMemory[16];DWORD wBytes;BOOL flags = TRUE;ZeroMemory( &sInfo, sizeof(sInfo) ); sInfo.cb = sizeof(sInfo); sInfo.dwFlags = STARTF_USESHOWWINDOW; sInfo.wShowWindow = SW_SHOWNORMAL; ZeroMemory( &pInfo, sizeof(pInfo) ); if( CreateProcess( NULL,    TEXT("taskmgr.exe"),  NULL,  NULL,  FALSE,  DEBUG_ONLY_THIS_PROCESS, NULL,  NULL,  &sInfo,  &pInfo )             )  {  // 在调试器退出的时候,被调试程序不会退出HMODULE hmodule = LoadLibrary(TEXT("kernel32.dll"));PDebugSetProcessKillOnExit DebugSetProcessKillOnExit = (PDebugSetProcessKillOnExit)GetProcAddress(hmodule, "DebugSetProcessKillOnExit");if ( DebugSetProcessKillOnExit != NULL ){DebugSetProcessKillOnExit(FALSE);}ZeroMemory(&context, sizeof(context));context.ContextFlags = CONTEXT_FULL | CONTEXT_DEBUG_REGISTERS;// 等待运行到断点处while(flags){WaitForDebugEvent( &debug , INFINITE );switch(debug.dwDebugEventCode){case CREATE_PROCESS_DEBUG_EVENT: // 启动调试事件if (ReadProcessMemory(pInfo.hProcess, (LPVOID)0x01005469, RemoteMemory, 8, &wBytes)){if (memcmp(RemoteMemory, buf, 8) == 0){// 跳过检测窗口,下断点RemoteMemory[6] = '\xEB';WriteProcessMemory(pInfo.hProcess, (LPVOID)0x01005469, RemoteMemory, 8, &wBytes);WriteProcessMemory(pInfo.hProcess, (LPVOID)0x010054BF, "\xCC", 1, &wBytes);}}else{flags = FALSE;TerminateProcess(pInfo.hProcess, 0);}break;case EXCEPTION_DEBUG_EVENT: // 异常发生,捕获int 3断点就可以了if ( debug.u.Exception.ExceptionRecord.ExceptionCode == EXCEPTION_BREAKPOINT ){if ((DWORD)debug.u.Exception.ExceptionRecord.ExceptionAddress == 0x010054BF ){// 将数据改回去WriteProcessMemory(pInfo.hProcess, (LPVOID)0x01005469, buf, 8, &wBytes);WriteProcessMemory(pInfo.hProcess, (LPVOID)0x010054BF, BreakPoint, 4, &wBytes);// 将EIP往回退1byteif (GetThreadContext(pInfo.hThread, &context)){context.Eip -= 1;SetThreadContext(pInfo.hThread, &context);}flags = FALSE; // 退出循环}}break;}if (!ContinueDebugEvent(debug.dwProcessId, debug.dwThreadId, DBG_CONTINUE )){// continue errorTerminateProcess(pInfo.hProcess, 0);ExitProcess(0);}}FreeLibrary(hmodule);CloseHandle( pInfo.hProcess ); CloseHandle( pInfo.hThread ); } }

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

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

原创粉丝点击