標籤:
因為是第一次破解較大型的商業軟體,所以有必要記錄一下,另外UE的價格也實在太貴了。。。
第零步:準備
準備好破解常用軟體。我常用的工具有IDA(用於靜態分析)、Ollydbg(動態調試)、PEiD(用於查看可執行檔是否加殼)、W32Dasm(在一個網上教學視頻中看到的軟體,用於靜態搜尋軟體中的字串資源)、CheatEngine(多用於遊戲作弊,這裡用來動態搜尋進程中的字串)。
先對Uedit32.exe這個可執行檔進行初探,PEiD發現它沒有加殼,這也不出意料,這種軟體肯定是不屑於加殼的。
其次,需要瞭解一下UE的註冊/啟用機制:預設安裝後軟體處於未註冊/啟用狀態,此時可以試用30天,試用到期後,會彈出提示,必須註冊才可以使用;未到期時也可以點擊“協助”->“註冊”,此時看到的是UE的線上啟用對話方塊(如所示),填入許可證ID和密碼點擊“啟用”按鈕後將向UE的server發起HTTP互動,沒有正確的許可證ID和密碼時當然是不能被server check通過的。
還有另一種啟用方式--離線啟用,需要在禁用網卡的情況下點擊上面的“啟用”按鈕才會出現:
點擊“離線啟用”,在對話方塊中填入“許可證”、“密碼”、“驗證碼1”、“驗證碼2”後,點擊“啟用”按鈕,會彈出失敗資訊:
注意這個錯誤提示資訊“您輸入的代碼無效。您需要...”,本文所陳述的破解方式就從這個字串開始。
第一步,找到訪問出錯提示的指令和函數。
首先嘗試靜態尋找。使用W32dasm,尋找字串“您輸入的代碼無效。您需要...”,沒找到。
由此猜測UE的提示資訊可能使用動態載入的方式,在UE啟動時從某個檔案中讀取到記憶體中。據此嘗試使用CheatEngine附加後尋找,尋找成功:
繼續使用CheatEngine找出是什麼訪問了這個地址,找到這樣幾個指令:
我們只應該關注UE模組內的指令,因此這裡要關注中第一條指令。
嘗試對這條指令下斷點,發現程式被不停地斷下,可以猜測UE可能存在一個線程在不停地執行該處指令,另外觀察到每次斷下後堆棧都不相同,由此可見該處的指令可能位於一個底層函數內部,因此需要使用條件斷點,當寄存器EDI的值等於05A27B80時斷下。這時發現不會被反覆斷下了,並且再次嘗試啟用時斷到了這條指令。
然後需要開始一個痛苦的步驟:需要找到按下“啟用”按鈕時所調用的函數。注意查看右下的調用棧,由內向外依次嘗試對各個call下斷點(非條件斷點),每加一個斷點,嘗試讓UE運行,看是不是只是在點擊“啟用”按鈕時才被斷下,如果不是,刪除斷點,繼續在上一級函數下斷點。嘗試幾次後,找到了一個call:0099B170。
第二步,分析判斷驗證碼/註冊碼匹配的關鍵指令邏輯。
關掉CheatEngine,使用IDA對UE可執行檔進行反組譯碼,並找到函數0099B170。由於檔案較大,反組譯碼可能需要很久才能ready。
分析反組譯碼,發現下面指令是在判斷使用者是否輸入了許可證:
cmp dword ptr [eax-0Ch], 0jnz loc_99B2F9
並且後續所調用的這一段邏輯與輸入了許可證但驗證錯誤的情況下都會被執行:
.text:0099B8FF loc_99B8FF: ; CODE XREF: sub_99B170+783j.text:0099B8FF mov edx, [eax].text:0099B901 mov ecx, eax.text:0099B903 mov eax, [edx+0Ch].text:0099B906 call eax.text:0099B908 lea edi, [eax+10h].text:0099B90B mov [ebp+var_68], edi.text:0099B90E push 6D6Fh ; unsigned int.text:0099B913 mov byte ptr [ebp+var_4], 18h.text:0099B917 call [email protected]@[email protected]@[email protected] ; AfxFindStringResourceHandle(uint).text:0099B91C test eax, eax.text:0099B91E jz short loc_99B931.text:0099B920 push 6D6Fh ; lpWideCharStr.text:0099B925 push eax ; hModule.text:0099B926 lea ecx, [ebp+var_80].text:0099B929 call sub_4098F0.text:0099B92E mov ebx, [ebp+var_80].text:0099B931.text:0099B931 loc_99B931: ; CODE XREF: sub_99B170+7AEj.text:0099B931 push 6D70h ; unsigned int.text:0099B936 call [email protected]@[email protected]@[email protected] ; AfxFindStringResourceHandle(uint).text:0099B93B test eax, eax.text:0099B93D jz short loc_99B950.text:0099B93F push 6D70h ; lpWideCharStr.text:0099B944 push eax ; hModule.text:0099B945 lea ecx, [ebp+var_68]
由此猜測UE的驗證可能類似這樣的邏輯:
...ret = check(/*各種使用者的輸入*/)str_id = get_str_by_ret(ret);show_str(str_id)...
另外有幸看到前面有一段這樣的指令:
.text:0099B1C4 push 0 ; bEnable.text:0099B1C6 mov ecx, eax.text:0099B1C8 call [email protected]@@[email protected] ; CWnd::EnableWindow(int).text:0099B1CD
使用ollydbg嘗試修改.text:0099B1C4為push 1,發現啟用按鈕不再變灰,因此,猜測判斷註冊碼匹配與否的邏輯在上述兩段指令中間。
繼續分析ida的反組譯碼結果,發現中間有兩處調用atoi:
.text:0099B337 push ebx ; char *.text:0099B338 mov byte ptr [ebp+var_4], 4.text:0099B33C call _atoi.text:0099B341 add esp, 4.text:0099B344 push eax.text:0099B345 call sub_CCDA26.text:0099B34A mov edi, eax.text:0099B34C mov eax, [ebp+var_6C].text:0099B34F push 0C6h.text:0099B354 push eax ; char *.text:0099B355 call _atoi.text:0099B35A add esp, 4
ollydbg斷到這兩個地方,發現他們的入參分別的UE的驗證碼1和驗證碼2的字串,可見,判斷註冊碼匹配與否的邏輯在這兩個atoi後面。
繼續分析ida的反組譯碼結果,發現在兩個atoi後面有一個這樣的指令:
.text:0099B363 lea ecx, [edi-13h].text:0099B366 cmp ecx, 0Dh ; switch 14 cases.text:0099B369 ja loc_99B8B8 ; jumptable 0099B376 default case
感謝ida幫我們分析出這是一個switch case分支,猜測後面就是前面索要找的get_str_by_ret。
第三步,破解。
ollydbg嘗試修改執行cmp ecx, 0Dh前的ecx,最有可能正確的就是0,嘗試改為0,繼續運行,看到了彈出對話方塊,還可以試用30天。ollydbg脫離UE進程,停止調試,關閉UE,重新開啟,沒有再彈出試用到期的提示,破解成功。
總結
其實最後一步破解時,算是運氣比較好的,比較容易地找到了判斷邏輯,如果嘗試失敗了,可能要繼續找到真正的check函數了。
網上其實有很多破解補丁可以下載,甚至有破解版的UE(但這個20.00.0.1040版本的沒找到),正如剛開始所說的,本文的意義在於記錄分享而非炫耀。
可以進一步延伸:
1、我想UE的剩餘試用時間應該是寫在註冊表或者是某個檔案中,如果可以找到的話,就有可能把試用時間改為無限長;
2、可以挑戰一下線上註冊,完全不同的思路呢;
3、就本文的思路,還差一個破解補丁,在cmp ecx, 0Dh之前修改一下ecx的值,這個也應該比較容易,後續有時間再搞。
破解UltraEdit(Ver20.00.0.1040),無限試用