taskmgr多开补丁
来源:互联网 发布:网络联合电视台 编辑:程序博客网 时间:2024/05/21 08:44
本来想写xxx游戏多开补丁的,后来想想算了,这个游戏有违道德,so 选择一个微软自己的东西搞搞理论就好了。
可是像上面的代码可能在某些程序里面有问题,原因是程序这样的修改是永久性的,不管程序运行多久,地址0x0100546F的数据永远都变成0xEB,如果程序自校验的就会被发现的,那么再跳转过后,就需要把这个代码改回去的,不过修改回去的方法可没有先前改的简单了,需要用到调试运行设置断点来修改,不细说了,代码如下
经常用任务管理器的人都知道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,还有的可能是驱动级的保护……这个技术实在太多了,想修改那些代码实现多开也是可以的,有矛必有盾嘛。
太累了,还是搞个无图无真相吧。
- taskmgr多开补丁
- taskmgr多开补丁
- taskmgr
- 自定义的TaskMgr
- Ext.TaskMgr.start
- taskmgr任务管理器
- 补丁
- 补丁
- 解决regedit taskmgr不能启动
- 控制taskmgr CPU记录曲线
- 各种开源程序补丁地址
- Create dump via taskmgr in XP
- ExtJs Ext.TaskMgr定时刷新数据源
- ExtJs Ext.TaskMgr定时刷新数据源
- 魔兽争霸3冰封王座1.24e 多开联机补丁 信息发布与收集点
- 魔兽争霸3冰封王座1.24e 双开/多开联机补丁 备用信息发布点
- 生成单个/多个补丁,打补丁用法
- 给开源社区发了第一个补丁,很遗憾,补丁有fatal problem
- struts2学习笔记
- FFMpeg分析2:AVInputFormat和AVOutputFormat
- FFMpeg分析2:AVInputFormat和AVOutputFormat
- Comet:基于 HTTP 长连接的“服务器推”技术
- FFMpeg分析3:AVFormatContext和AVIContext、FLVContext等XXXContext
- taskmgr多开补丁
- ViewGroup_caidan
- FMpeg分析4:AVStream
- FMpeg分析5:AVCodecContext和AVCodec
- php验证码无错版(无刷新更换验证码)
- MDK 分散加载文件分析
- FMpeg分析6:AVPicture、AVFrame和AVPacket
- 用FFMPEG SDK进行视频转码压缩时解决音视频不同步问题的方法(转) PTS DTS
- 如何强制ffmpeg编码时输出一个关键帧