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的,所以盡量以原版曹操傳來測試。

沒有留言:

張貼留言