2012年7月18日 星期三

OllyDBG基礎教程:曹操傳(二)

要學好修改EXE,首先要看的懂裡面的代碼意義,也就是組合語言,學這個要有耐心,不懂可以發問。

先解釋部份曹操傳常用指令的意義。

cmp a,b 比較a與b

mov a,b 把b的值移入a,使a=b

retn 返回調用的程序

nop 無作用

(解釋:ultraedit打開編輯exe文件時你看到90,等同於組合語言語句nop)

call 調用副程式

je 或jz 若相等則跳

jne或jnz 若不相等則跳

jmp 無條件跳

jb 若小於則跳

ja 若大於則跳

jg 若大於則跳

jge 若大於等於則跳

jl 若小於則跳

jle 若小於等於則跳

pop 出棧

push 壓棧

ADD  加法. 

INC  加 1. 

SUB  減法. 

DEC  減 1. 

IMUL  整數乘法. 

DIV  無符號除法. 

IDIV  整數除法. 


eax,ecx,edx,ebx,esp,ebp,esi,edi 這幾個都是32位元暫存器,用來存放數值。但是除了eax,ecx,edx,ebx,其他的不能亂用,否則容易出錯。
這是EAX、ECX、EDX、EBX暫存器的格式,以EAX來說明:
EAX
 
AX
  
AH
AL

假設EAX=01234567,則AX=4567,AH=45,AL=67

以下是曹操傳"獲取連擊概率"代碼的範例解說:

00405CE6  /$  55            push    ebp
將ebp壓入堆棧

00405CE7  |.  8BEC          mov     ebp, esp
將esp的值移入ebp

00405CE9  |.  83EC 0C       sub     esp, 0C
esp = esp - 0C (0C是十六進位,也就是12。這行是為了空出三個暫存空間。每個空間小大為4,三個就是12。之後會用[ebp-n]來表示這些位置。前面的mov ebp,esp也是這個用意。)

00405CEC  |.  894D F4       mov     dword ptr [ebp-C], ecx
將ecx值移入第三個暫存空間[ebp-C],用[]引號括起來的,代表內存裡的值。例如ebp=23FFF0,[ebp-C]就是內存23FFE4裡的值。而這裡的ecx則儲存著"攻擊資訊"的內存位置。

00405CEF  |.  8B45 F4       mov     eax, dword ptr [ebp-C]
將[ebp-C]值移入eax。

00405CF2  |.  8B48 0C       mov     ecx, dword ptr [eax+C]
將[eax+C]值移入ecx,此時的[eax+C]存放著"攻擊方武將"的內存位置。

00405CF5  |.  E8 37990300   call    0043F631
調用0043F631副程式。這又是另一個副程式,按回車可以進入查看,按 - 號即可返回。這個副程式是獲取武將ecx的爆發力,也就是攻擊方武將的爆發力。

00405CFA  |.  8945 F8       mov     dword ptr [ebp-8], eax
將eax移入[ebp-8],也就是第二個暫存位置。而這個eax則存放著攻擊方武將的爆發力。

00405CFD  |.  8B4D F4       mov     ecx, dword ptr [ebp-C]
將[ebp-C]值移入ecx。這[ebp-C]值存放著攻擊資訊的內存位置,還記得吧?

00405D00  |.  33D2          xor     edx, edx
將edx清為0。

00405D02  |.  8A51 01       mov     dl, byte ptr [ecx+1]  
將[ecx+1]值移入dl (dl是edx的一部份,上面有解釋到),此時的[ecx+1]值存放著被攻擊方的武將編號。

00405D05  |.  8BCA          mov     ecx, edx  
將edx值移入ecx。

00405D07  |.  6BC9 24       imul    ecx, ecx, 24  
將ecx乘與24,並將結果存進ecx。這個24代表戰場武將資訊裡,每個武將資料的間隔。

00405D0A  |.  81C1 502C4B00 add     ecx, 004B2C50  
將ecx加上4B2C50。這個4B2C50是戰場武將內存的第一個武將位置。而ECX存放著"被攻擊方武將編號 * 24",加上4B2C50後,就是被攻擊方武將的內存位置。

00405D10  |.  E8 1C990300   call    0043F631  
調用43F631副程式,獲取武將ecx的爆發力,也就是獲取被攻擊方武將的爆發力。

00405D15  |.  8945 FC       mov     dword ptr [ebp-4], eax  
將eax移入[ebp-4],也就是第一個暫存位置。而這個eax則存放著被攻擊方武將的爆發力。

00405D18  |.  8B45 FC       mov     eax, dword ptr [ebp-4]  
將[ebp-4]移入eax。基本上這行是多餘的,曹操傳裡常常有這種多餘的代碼,可以空出來寫其他東西。

00405D1B  |.  6BC0 03       imul    eax, eax, 3  
將eax * 3,並存入eax。

00405D1E  |.  3945 F8       cmp     dword ptr [ebp-8], eax  
比較[ebp-8]和eax,[ebp-8]存放著攻擊方武將的爆發力。

00405D21  |.  72 04         jb      short 00405D27  
若[ebp-8] < eax,則跳轉到00405D27。也就是攻擊方武將爆發力 < 被攻擊方武將爆發力 * 3 ,則跳轉,否則繼續下一行。

00405D23  |.  B0 64         mov     al, 64
將64這個值移入al,這個al就代表著"連擊機率。也就是攻擊方武將爆發力 > 被攻擊方武將爆發力 * 3 ,則連擊機率為100%

00405D25  |.  EB 3E         jmp     short 00405D65  
無條件跳轉到00405D65

00405D27  |>  8B4D FC       mov     ecx, dword ptr [ebp-4]  
將[ebp-4]值移入ecx。這行是從405D21跳轉過來的。而[ebp-4]存放著被攻擊方武將的爆發力。

00405D2A  |.  D1E1          shl     ecx, 1  
將ecx * 2。(shl就是乘與2的次方。例如shl  ecx, 2,就是ecx * 4)

00405D2C  |.  394D F8       cmp     dword ptr [ebp-8], ecx  
比較[ebp-8]值與ecx。[ebp-8]值存放著攻擊方武將的爆發力。

00405D2F  |.  72 17         jb      short 00405D48  
如果[ebp-8] < ecx則跳轉到00405D48。也就是攻擊方武將爆發力 < 被攻擊方武將爆發力 * 2 ,則跳轉,否則繼續下一行。

00405D31  |.  8B55 FC       mov     edx, dword ptr [ebp-4]  
將[ebp-4]移入edx。[ebp-4]存放著被攻擊方武將的爆發力。

00405D34  |.  D1E2          shl     edx, 1  
將edx * 2。

00405D36  |.  8B45 F8       mov     eax, dword ptr [ebp-8]  
將[ebp-8]移入eax。[ebp-8]值存放著攻擊方武將的爆發力。

00405D39  |.  2BC2          sub     eax, edx  
將eax減去edx。

00405D3B  |.  6BC0 50       imul    eax, eax, 50  
將eax乘與50,並存入eax

00405D3E  |.  33D2          xor     edx, edx  
將edx清為0

00405D40  |.  F775 FC       div     dword ptr [ebp-4]  
將eax除與[ebp-4]。div這個指令固定是以eax來除,商數存於eax,餘數存於edx,所以使用前要先將edx清為0。

00405D43  |.  83C0 14       add     eax, 14  
將eax加上14。這個就是連擊機率。
上面幾行總結,就是在"攻擊方武將爆發力 > 被攻擊方武將爆發力 * 2"的情況下,機率公式為:
(攻擊方武將的爆發力 - 被攻擊方武將的爆發力 * 2) * 80 / 被攻擊方武將的爆發力 + 20

00405D46  |.  EB 1D         jmp     short 00405D65  
無條件跳轉到00405D65  

00405D48  |>  8B45 F8       mov     eax, dword ptr [ebp-8]  
將[ebp-8]值移入eax。[ebp-8]存放什麼不需要解釋了吧?  這行是從00405D2F 跳轉來的。

00405D4B  |.  3B45 FC       cmp     eax, dword ptr [ebp-4]  
比較eax和[ebp-4]。[ebp-4]存放著...??自己想。

00405D4E  |.  72 13         jb      short 00405D63  
如果eax < [ebp-4],則跳轉到00405D63。也就是攻擊方武將爆發力 < 被攻擊方武將爆發力,則跳轉,否則繼續下一行。

00405D50  |.  8B45 F8       mov     eax, dword ptr [ebp-8]  
將[ebp-8]移入eax

00405D53  |.  2B45 FC       sub     eax, dword ptr [ebp-4]  
將eax減去[ebp-4]

00405D56  |.  6BC0 12       imul    eax, eax, 12  
將eax乘與12,並放入eax

00405D59  |.  33D2          xor     edx, edx  
將edx清零

00405D5B  |.  F775 FC       div     dword ptr [ebp-4]  
將eax除與[ebp-4]

00405D5E  |.  83C0 02       add     eax, 2  
將eax加2,這就是連擊機率。
上面幾行總結,就是在"攻擊方武將爆發力 > 被攻擊方武將爆發力"的情況下,機率公式為:
(攻擊方武將的爆發力 - 被攻擊方武將的爆發力) * 18 / 被攻擊方武將的爆發力 + 2

00405D61  |.  EB 02         jmp     short 00405D65  
無條件跳轉到00405D65  

00405D63  |>  B0 01         mov     al, 1  
將1移入al,這是"攻擊方武將爆發力 < 被攻擊方武將爆發力"情況下的機率。

00405D65  |>  8BE5          mov     esp, ebp  
將ebp移入esp

00405D67  |.  5D            pop     ebp  
將ebp從堆棧中取出

00405D68  \.  C3            retn  
返回調用的程序
最後這三行是曹操傳副程序的標準結尾。最後一行也有可能不一樣,以後再另外說明。



恭喜你很有耐心的看完了,也恭喜我終於打完了……
如果了解的人,不妨試著改變連擊公式吧!當然請記得備份……
ps.這是原版曹操傳的代碼,其他MOD可能有所不同,尤其是star175的,所以盡量以原版曹操傳來測試。

OllyDBG基礎教程:曹操傳(一)

一、安裝OllyICE
OllyICE是OllyDBG的整合版。首先下載OllyICE,將附件解壓縮到一個文件夾下,運行 OllyICE.exe 即可。

二、調試方法
點擊菜單「文件 -> 打開」(快捷鍵為 F3 ),選擇曹操傳主程序(以原版曹操傳Ekd5.exe為例),可看到如下畫面。

反匯編窗口:顯示程序的反匯編代碼。
寄存器窗口:顯示寄存器內容。
數據窗口:顯示內存或文件的內容。
堆棧窗口:顯示當前線程的堆棧。

調試中經常要用到的快捷鍵:
F9:運行。按下這個鍵如果沒有設置相應斷點的話,被調試的程序將直接開始運行。
F2:設置斷點,只要在光標定位的位置(上圖中反匯編窗口的淺藍色條)按F2鍵即可,再按一次F2鍵則會刪除斷點。
F8:單步步過。每按一次這個鍵執行一條反匯編窗口中的一條指令,遇到 CALL 等子程序不進入其代碼。
F7:單步步入。功能同單步步過(F8)類似,區別是遇到 CALL 等子程序時會進入其中,進入後首先會停留在子程序的第一條指令上。
Ctrl+G:跟隨到輸入的地址。
Ctrl+F:查找命令。
Ctrl+L:查找下一個,配合Ctrl+F使用。

三、修改代碼:
雙擊反匯編窗口中的代碼,在彈出的窗口中,輸入修改後的代碼。如下圖,將Push 2C改為Push 3D。


修改時可能會用到的快捷鍵:
Alt+Backspace:撤消選擇處修改。

三、儲存修改 (建議先備份Ekd5.exe,以免發生錯誤)
按住鼠標左鍵,選擇修改過的代碼後,點擊鼠標右鍵 -> 複製到可執行文件 -> 選擇,如下圖。


在接下來的畫面中,點擊鼠標右鍵 -> 保存文件 -> 儲存 -> 是,如下圖。



第一篇先講解到這裡,有興趣的人可以先試試:
假設要找"無反擊攻擊(2C)"的代碼位置,先單擊"反匯編窗口",按Home鍵,Ctrl+F尋找 Push 2C (無分小大寫)。
如果是停在 Call 407A09 附近,就是正確位置,否則 Ctrl+L 繼續搜尋。
然後在 Push 2C 這裡按下 F2 設定斷點,F9運行程序。
進入戰場後,攻擊敵人,當敵人要反擊時,就會停在這個代碼,接下來可以用F8F7F9試著繼續調試。
或是將Push 2C中的"2C"改為其他特效號,假如要和"麻痺攻擊(25)"合併,就將Push 2C改為Push 25,然後儲存。