[筆記] 多開破解

因為論壇有人在問...就去查了一下...

rf: 多開限制突破

1. Findwindow突破

bp FindWindowW,運行程序斷下來,執行到返回,來到下面
004F0E5C    8BF4            mov esi,esp
004F0E5E    68 B8466A00     push FindWind.006A46B8                 ; UNICODE "FindWindow"
004F0E63    6A 00           push 0
004F0E65    FF15 28EE6F00   call dword ptr ds:[<&USER32.FindWindow>; USER32.FindWindowW
004F0E6B    3BF4            cmp esi,esp
004F0E6D    E8 280FFFFF     call FindWind.004E1D9A
004F0E72    8945 C8         mov dword ptr ss:[ebp-38],eax
004F0E75    837D C8 00      cmp dword ptr ss:[ebp-38],0
004F0E79    74 32           je short FindWind.004F0EAD
004F0E7B    6A 00           push 0
004F0E7D    6A 00           push 0
004F0E7F    68 9C466A00     push FindWind.006A469C
004F0E84    E8 86DBFEFF     call FindWind.004DEA0F
004F0E89    8BF4            mov esi,esp
004F0E8B    8B45 C8         mov eax,dword ptr ss:[ebp-38]
004F0E8E    50              push eax
004F0E8F    FF15 E8EC6F00   call dword ptr ds:[<&USER32.SetForegro>; USER32.SetForegroundWindow
004F0E95    3BF4            cmp esi,esp
004F0E97    E8 FE0EFFFF     call FindWind.004E1D9A
004F0E9C    8BF4            mov esi,esp
004F0E9E    6A 00           push 0
004F0EA0    FF15 74E96F00   call dword ptr ds:[<&KERNEL32.ExitProc>; kernel32.ExitProcess
004F0EA6    3BF4            cmp esi,esp
004F0EA8    E8 ED0EFFFF     call FindWind.004E1D9A
004F0EAD    68 B8466A00     push FindWind.006A46B8                 ; UNICODE "FindWindow"
004F0EB2    8B4D EC         mov ecx,dword ptr ss:[ebp-14]
004F0EB5    E8 F3DDFEFF     call FindWind.004DECAD

首先FindWindowW判斷窗口是否存在(是否為NULL),下面有個je short FindWind.004F0EAD,存在就繼續向下執行,可以看到繼續向下的話,有個kernel32.ExitProcess了,所以我們直接將je改為jmp就可以。測試下可以多開了。也可以寫程序直接SetWindowText將窗口標題改掉。


2. EnumWindows突破

bp EnumWindows,運行程序斷下來,執行到返回
004F0F9C    8BF4            mov esi,esp
004F0F9E    6A 00           push 0
004F0FA0    68 679C4D00     push EnumWind.004D9C67
004F0FA5    FF15 34EE6F00   call dword ptr ds:[<&USER32.EnumWindow>; USER32.EnumWindows

我們知道EnumWindows有個回調函數,call上面壓棧的參數地址應該就是回調函數地址,我們ctrl+g轉到看下,是個jmp,那就繼續轉,下面來到的地方就是回調函數了
004F0940    55              push ebp
004F0941    8BEC            mov ebp,esp
004F0943    81EC CC020000   sub esp,2CC
004F0949    53              push ebx
004F094A    56              push esi
004F094B    57              push edi
004F094C    8DBD 34FDFFFF   lea edi,dword ptr ss:[ebp-2CC]
004F0952    B9 B3000000     mov ecx,0B3
004F0957    B8 CCCCCCCC     mov eax,CCCCCCCC
004F095C    F3:AB           rep stos dword ptr es:[edi]
004F095E    A1 48526F00     mov eax,dword ptr ds:[6F5248]
004F0963    33C5            xor eax,ebp
004F0965    8945 FC         mov dword ptr ss:[ebp-4],eax
004F0968    33C0            xor eax,eax
004F096A    66:8985 F8FDFFF>mov word ptr ss:[ebp-208],ax
004F0971    68 FE010000     push 1FE
004F0976    6A 00           push 0
004F0978    8D85 FAFDFFFF   lea eax,dword ptr ss:[ebp-206]
004F097E    50              push eax
004F097F    E8 2B40FFFF     call EnumWind.004E49AF
004F0984    83C4 0C         add esp,0C
004F0987    8BF4            mov esi,esp
004F0989    68 00010000     push 100
004F098E    8D85 F8FDFFFF   lea eax,dword ptr ss:[ebp-208]
004F0994    50              push eax
004F0995    8B4D 08         mov ecx,dword ptr ss:[ebp+8]
004F0998    51              push ecx
004F0999    FF15 30EE6F00   call dword ptr ds:[<&USER32.GetWindowT>; USER32.GetWindowTextW
004F099F    3BF4            cmp esi,esp
004F09A1    E8 F413FFFF     call EnumWind.004E1D9A
004F09A6    8D85 F8FDFFFF   lea eax,dword ptr ss:[ebp-208]
004F09AC    50              push eax
004F09AD    68 38436A00     push EnumWind.006A4338                 ; UNICODE "EnumWindows"
004F09B2    E8 00A7FEFF     call EnumWind.004DB0B7
004F09B7    83C4 08         add esp,8
004F09BA    85C0            test eax,eax
004F09BC    75 32           jnz short EnumWind.004F09F0
004F09BE    6A 00           push 0
004F09C0    6A 00           push 0
004F09C2    68 1C436A00     push EnumWind.006A431C
004F09C7    E8 4DE0FEFF     call EnumWind.004DEA19
004F09CC    8BF4            mov esi,esp
004F09CE    8B45 08         mov eax,dword ptr ss:[ebp+8]
004F09D1    50              push eax
004F09D2    FF15 ECEC6F00   call dword ptr ds:[<&USER32.SetForegro>; USER32.SetForegroundWindow
004F09D8    3BF4            cmp esi,esp
004F09DA    E8 BB13FFFF     call EnumWind.004E1D9A
004F09DF    8BF4            mov esi,esp
004F09E1    6A 00           push 0
004F09E3    FF15 78E96F00   call dword ptr ds:[<&KERNEL32.ExitProc>; kernel32.ExitProcess
004F09E9    3BF4            cmp esi,esp
004F09EB    E8 AA13FFFF     call EnumWind.004E1D9A
004F09F0    B8 01000000     mov eax,1
004F09F5    52              push edx
004F09F6    8BCD            mov ecx,ebp
004F09F8    50              push eax
004F09F9    8D15 280A4F00   lea edx,dword ptr ds:[4F0A28]
004F09FF    E8 E1D2FEFF     call EnumWind.004DDCE5
004F0A04    58              pop eax
004F0A05    5A              pop edx
004F0A06    5F              pop edi
004F0A07    5E              pop esi
004F0A08    5B              pop ebx
004F0A09    8B4D FC         mov ecx,dword ptr ss:[ebp-4]
004F0A0C    33CD            xor ecx,ebp
004F0A0E    E8 3BF6FEFF     call EnumWind.004E004E
004F0A13    81C4 CC020000   add esp,2CC
004F0A19    3BEC            cmp ebp,esp
004F0A1B    E8 7A13FFFF     call EnumWind.004E1D9A
004F0A20    8BE5            mov esp,ebp
004F0A22    5D              pop ebp
004F0A23    C2 0800         retn 8

向下拉看到GetWindowTextW了吧,回調函數中傳進來的窗口句柄,通過GetWindowTextW獲取窗口標題,然後比較,來判斷是否結束實例 所以將004F09BC 75 32 jnz short EnumWind.004F09F0這一行的jnz改為jmp就可以了,保存修改,運行試下,可以多開了。 牽扯到通過窗口標題來防止多開的都可以SetWindowText將窗口標題改掉來突破多開。


3. 互斥對象突破

同樣bp CreateMutexW,運行程序斷下來,執行到返回
004F0E5E    68 B8466A00     push 互斥體單.006A46B8
004F0E63    6A 00           push 0
004F0E65    6A 00           push 0
004F0E67    FF15 74E96F00   call dword ptr ds:[<&KERNEL32.CreateMu>; kernel32.CreateMutexW
004F0E6D    3BF4            cmp esi,esp
004F0E6F    E8 300FFFFF     call 互斥體單.004E1DA4
004F0E74    A3 C46E6F00     mov dword ptr ds:[6F6EC4],eax
004F0E79    8BF4            mov esi,esp
004F0E7B    FF15 78E96F00   call dword ptr ds:[<&KERNEL32.GetLastE>; ntdll.RtlGetLastWin32Error
004F0E81    3BF4            cmp esi,esp
004F0E83    E8 1C0FFFFF     call 互斥體單.004E1DA4
004F0E88    3D B7000000     cmp eax,0B7
004F0E8D    75 1F           jnz short 互斥體單.004F0EAE

調用GetLastError返回值與0xB7比較,0xB7是ERROR_ALREADY_EXISTS錯誤代碼,然後不相等就調走,所以將跳轉改為JMP,保存測試,成功多開。


4. 共享節法突破

思路是,共享節中的某個數據用來判斷是否運行過實例,我們可以捕捉訪問該段的代碼。 OD載入ALT+M顯示內存,這裡可以看到許多段,選中Shared段右鍵在訪問上設置中斷,對整個內存塊設置該類型斷點,這個斷點是一次性斷點,當所在段被讀取或執行時就中斷,中斷髮生後,斷點將被刪除。F9運行程序來到下面
004F0E5C    833D 00407000 0>CMP DWORD PTR DS:[704000],0  
004F0E63    75 0E           JNZ SHORT 共享節單.004F0E73  

轉到004F0E73這個地址我們看到有ExitProcess,可以斷定這兩句代碼就是拿出共享段中得某個數據與0比較來判斷是否有實例運行,我們將其JNZ NOP掉,讓其永遠不會跳轉,保存修改,成功多開。


rf: war3多開的實現

好孩子不怎麼玩遊戲,就拿這個練下手了,看郁的教程裝了個熱血,那個直接SetWindowText然後將遊戲換個目錄就可以多開。
先運行一個Frozen Throne.exe,然後再運行一個提示「魔獸爭霸資料片:冰封王座已經運行」,OD載入bp MessageBoxA下斷,執行後ait+f9返回用戶代碼
004010AE  |.  6A 00         PUSH 0                                   ; /Style = MB_OK|MB_APPLMODAL
004010B0  |.  8D4C24 40     LEA ECX,DWORD PTR SS:[ESP+40]            ; |
004010B4  |.  50            PUSH EAX                                 ; |Title
004010B5  |.  51            PUSH ECX                                 ; |Text
004010B6  |.  6A 00         PUSH 0                                   ; |hOwner = NULL
004010B8  |.  FF15 34714000 CALL DWORD PTR DS:[<&USER32.MessageBoxA>>; \MessageBoxA
004010BE  |.  8B5424 10     MOV EDX,DWORD PTR SS:[ESP+10]
004010C2  |.  52            PUSH EDX                                 ; /hObject
004010C3  |.  FF15 58704000 CALL DWORD PTR DS:[<&KERNEL32.CloseHandl>; \CloseHandle

看到CloseHandle沒,應該是使用的創建互斥對象來防多開的,向上找,看到了GetLastError了
0040103C  |.  FFD5          CALL EBP                                 ; [GetLastError  
0040103E  |.  3D B7000000   CMP EAX,0B7  
00401043  |.  75 1A         JNZ SHORT Frozen_T.0040105F  

果斷JNZ改為JMP,上面看到使用的是CreateEvent。保存修改,運行下,不行,又出來錯誤提示「請核實您的冰封王座光盤已在光盤驅動器中,然後點擊重試」,OD載入修改好後的Frozen Throne.exe,發現是創建了個進程,Frozen Throne.exe就相當於個loader,那我們直接分析war3.exe吧

先運行一個war3.exe,然後再運行一個提示「warcraft III was unable to initialize」,od載入bp MessageBoxA,F9運行,斷下,ALT+F9返回用戶代碼,彈出那個窗口了,所在的是GAME.DLL這個模塊,在附近沒有發現可以跳過這個CALL的地方,按CTRL+F9執行到返回,往上拉可以看到「warcraft III was unable to initialize「這個字符串了,CTRL+F9繼續執行到返回
6F00974A    85C0            TEST EAX,EAX  
6F00974C    74 0F           JE SHORT Game.6F00975D  
6F00974E    E8 ED270000     CALL Game.6F00BF40  
6F009753    33C9            XOR ECX,ECX  
6F009755    E8 66D1FFFF     CALL Game.6F0068C0                       ;返回到這個CALL  
6F00975A    33C0            XOR EAX,EAX  
6F00975C    C3              RETN  
6F00975D    B9 9881886F     MOV ECX,Game.6F888198                    ; ASCII "Warcraft III Game Application"  

在這個CALL的上面看到了個跳轉,改為強制跳轉試下,保存修改,成功多開


留言

本月最夯