最美情侣中文字幕电影,在线麻豆精品传媒,在线网站高清黄,久久黄色视频

歡迎光臨散文網(wǎng) 會(huì)員登陸 & 注冊(cè)

口袋妖怪綠寶石——數(shù)據(jù)提取與代碼分析(8-反作弊機(jī)制:校驗(yàn)碼與數(shù)據(jù)打亂)

2022-08-22 16:40 作者:圍巾胖頭魚(yú)  | 我要投稿

說(shuō)在前面:

????前兩期專欄介紹了原版綠寶石游戲反作弊機(jī)制的兩種方法:指針跳動(dòng)和數(shù)據(jù)加密。本期專欄繼續(xù)介紹綠寶石游戲中其他的反作弊機(jī)制:校驗(yàn)碼與數(shù)據(jù)打亂。

首寵修改

????在綠寶石系列游戲中,對(duì)隊(duì)伍首位精靈(簡(jiǎn)稱“首寵”)進(jìn)行修改的金手指也是網(wǎng)上各種發(fā)布的金手指中的一大類,無(wú)論是修改技能、等級(jí)、道具、性格,還是修改個(gè)體值、努力值、親密度、特性,甚至是修改閃光,基本上都是以首寵為準(zhǔn)。接下來(lái)我們會(huì)看到,原版綠寶石把針對(duì)首寵修改的反作弊機(jī)制做得十分復(fù)雜,不僅對(duì)數(shù)據(jù)進(jìn)行了加密,還通過(guò)校驗(yàn)碼和數(shù)據(jù)打亂的方式進(jìn)一步增加反作弊的力度。

????先來(lái)看看原版綠寶石中的隊(duì)伍首位精靈信息在什么地方:

隊(duì)伍精靈信息

????符號(hào)表中的gPlayerParty就是游戲中主角隊(duì)伍里的精靈信息,轉(zhuǎn)到它的定義:

gPlayerParty的定義

????從定義中可以看到,隊(duì)伍信息gPlayerParty是一個(gè)大小為6的數(shù)組(PARTY_SIZE是6),類型是結(jié)構(gòu)體struct Pokemon,再轉(zhuǎn)到這個(gè)結(jié)構(gòu)體的定義:

結(jié)構(gòu)體Pokemon的定義

????結(jié)構(gòu)體struct Pokemon里面,開(kāi)頭是一個(gè)類型為struct BoxPokemon的變量;它的含義是存儲(chǔ)在電腦倉(cāng)庫(kù)內(nèi)的精靈信息;換句話說(shuō),從第121行開(kāi)始向下的這些變量,它們會(huì)出現(xiàn)在描述隊(duì)伍精靈的信息里面,而不會(huì)出現(xiàn)在描述電腦倉(cāng)庫(kù)內(nèi)的精靈信息里,我們馬上就能看到什么樣的信息會(huì)滿足這樣的條件。

????上圖的右半邊是struct BoxPokemon的定義,里面有很多可以被金手指修改的屬性:

  • personality,精靈性格

  • otId,精靈主人的訓(xùn)練師ID

  • nickname,精靈昵稱

  • otName,精靈主人的名稱

????而在第111行定義了一個(gè)聯(lián)合體變量union secure,這個(gè)變量需要好好解釋一下。在解釋之前,這里把之前的一期專欄(究極綠寶石5.3——科普向,什么是金手指(七))的圖借用一下:

精靈數(shù)據(jù)表(來(lái)自之前的專欄)

????究極綠寶石作為綠寶石系列游戲的改版,在描述隊(duì)伍精靈的信息上只做了一些小的改動(dòng),大體的框架還是和原版綠寶石相同的。有一處小的改動(dòng)在相對(duì)地址1E處,由于原版綠寶石所處的第三世代還沒(méi)有隱藏特性(另一種說(shuō)法叫“夢(mèng)特性”)這個(gè)設(shè)定,所以在原版綠寶石中就沒(méi)有“是否是隱藏特性”這個(gè)變量。

????這個(gè)表格和上面的結(jié)構(gòu)體定義對(duì)比一下,可以發(fā)現(xiàn)表格中綠色的部分就是struct?BoxPokemon的范圍,也就是“非面板值”,除此之外就是下面的藍(lán)色部分“面板值”。在該圖片出現(xiàn)的專欄中提到過(guò):

圖中綠色的區(qū)域是非面板值,藍(lán)色的區(qū)域是面板值,也就是說(shuō)藍(lán)色區(qū)域中的變量取值是由綠色區(qū)域中的變量取值用游戲程序計(jì)算得到的。反映在游戲中,就是說(shuō)如果使用金手指修改面板值(藍(lán)色區(qū)域)的變量,那么將這只精靈放回電腦、在精靈中心回復(fù)、與訓(xùn)練師對(duì)戰(zhàn)時(shí),藍(lán)色區(qū)域的變量會(huì)根據(jù)綠色區(qū)域的變量重新計(jì)算,因此修改藍(lán)色區(qū)域變量的金手指實(shí)際上是起不到作用的。

????之所以放入電腦倉(cāng)庫(kù)中的精靈會(huì)像在精靈中心回復(fù)過(guò)一樣,就是因?yàn)殡娔X倉(cāng)庫(kù)只會(huì)保留非面板值,也就是struct?BoxPokemon的信息,后面的信息(面板值)都是從倉(cāng)庫(kù)中拿到隊(duì)伍里面那一刻計(jì)算出來(lái)的。

????不過(guò),在上面的非面板值中,還有好多信息(種族、道具等)沒(méi)有在struct?BoxPokemon的定義中看到,同時(shí)那個(gè)神秘的聯(lián)合體變量secure還沒(méi)有解釋,它是做什么的呢?

精靈信息的存儲(chǔ)方式:聯(lián)合體變量

????C語(yǔ)言中的關(guān)鍵字union用于定義聯(lián)合體變量,在該關(guān)鍵字包含的范圍內(nèi),所有變量共用同一塊空間,仔細(xì)看struct?BoxPokemon中聯(lián)合體變量的定義:

聯(lián)合體變量secure

????這個(gè)聯(lián)合體變量的名字叫secure,除了它的字面意思“安全”,現(xiàn)在還不清楚它有什么實(shí)際意義。這里面定義的兩個(gè)變量raw和substructs,按照聯(lián)合體的語(yǔ)法,是要共用同一塊空間的,其中raw是一個(gè)數(shù)組,而substruct又是一個(gè)聯(lián)合體類型的變量,也就是說(shuō),union PokemonSubstruct這個(gè)聯(lián)合體中定義的所有變量也要共用同一塊空間。

????共用一塊空間的意思是說(shuō),如果在程序中修改了raw變量的內(nèi)容,substructs的內(nèi)容也會(huì)改變,有點(diǎn)像是同一個(gè)位置的數(shù)據(jù)擁有兩個(gè)名字,通過(guò)哪個(gè)名字修改它都可以。

????不知道讀者們看到這里會(huì)不會(huì)有些迷糊,似乎只看到一個(gè)聯(lián)合體套著一個(gè)聯(lián)合體,也不知道這些聯(lián)合體是做什么的。要看懂接下來(lái)的內(nèi)容,請(qǐng)務(wù)必保持清醒的頭腦!

????再來(lái)到union PokemonSubstruct的定義處:

聯(lián)合體PokemonSubstruct的定義

????這個(gè)聯(lián)合體共定義了5個(gè)成員變量,前四個(gè)就是這個(gè)聯(lián)合體的名字加上0,1,2,3共四個(gè)編號(hào)的后綴,最后一個(gè)也是叫做raw的數(shù)組,和上面的secure變量類似。這5個(gè)變量共用一塊空間,也就是說(shuō),如果修改了其中一個(gè)變量,比如說(shuō)type3的內(nèi)容,那么其他的4個(gè)變量?jī)?nèi)容也會(huì)被一并修改。

????Substruct的含義是“子結(jié)構(gòu)體”,下面就用這個(gè)名稱來(lái)稱呼這個(gè)名字很長(zhǎng)的結(jié)構(gòu)體。

????最后來(lái)看這些以數(shù)字為結(jié)尾的子結(jié)構(gòu)體的定義:

子結(jié)構(gòu)體0,1,2,3的定義

????直到此時(shí),我們才看到了熟悉的精靈信息:種族、道具、經(jīng)驗(yàn)值、親密度在子結(jié)構(gòu)體0;技能和技能PP數(shù)在子結(jié)構(gòu)體1;努力值和選美值在子結(jié)構(gòu)體2;遇到精靈的信息、個(gè)體值、特性和緞帶在子結(jié)構(gòu)體3。

????這些信息才是我們?cè)谏厦婺菑埦`數(shù)據(jù)表格中看到的信息。原本它們應(yīng)該按照順序依次出現(xiàn)在BoxPokemon這個(gè)結(jié)構(gòu)體中,可是原版綠寶石做了一些很奇怪的“包裝”,讓事情一下子變得復(fù)雜了起來(lái)?,F(xiàn)在讓我們從最底層的這些子結(jié)構(gòu)體開(kāi)始,一步一步推測(cè)上層的“包裝”是做什么用的?;氐絇okemonSubstruct聯(lián)合體的定義:

聯(lián)合體PokemonSubstruct的定義(上面的圖搬下來(lái))

????這個(gè)被稱作“子結(jié)構(gòu)體”的聯(lián)合體,實(shí)際上是代表了4種子結(jié)構(gòu)體中的任意一個(gè),最下面的raw變量起到的是申請(qǐng)空間的作用,為此我們可以看看NUM_SUBSTRUCT_BYTES這個(gè)宏定義,這個(gè)宏的名稱字面意思是“子結(jié)構(gòu)體所需字節(jié)數(shù)”:

子結(jié)構(gòu)體所需字節(jié)數(shù)

????子結(jié)構(gòu)體所需字節(jié)數(shù),是所有子結(jié)構(gòu)體中最大的那一個(gè)所占的字節(jié)數(shù)(盡管在這里,所有的子結(jié)構(gòu)體是一樣大的),這就是上面那些注釋想要表達(dá)的含義。這樣一來(lái),PokemonSubstruct聯(lián)合體就有了足夠的空間可以存下任何一種子結(jié)構(gòu)體,在它看來(lái),這4種子結(jié)構(gòu)體就沒(méi)有區(qū)別了,它們都是占據(jù)了一塊空間的變量,和數(shù)組raw沒(méi)有區(qū)別。

????在往上層,回到BoxPokemon結(jié)構(gòu)體中secure聯(lián)合體的定義:

聯(lián)合體變量secure(上面的圖搬下來(lái))

????secure聯(lián)合體占據(jù)了4個(gè)子結(jié)構(gòu)體的空間(注意substruct后面的[4],說(shuō)明這是個(gè)數(shù)組)。

????現(xiàn)在可以做個(gè)結(jié)論了:存儲(chǔ)在倉(cāng)庫(kù)中的精靈信息BoxPokemon,除了少部分(如性格、昵稱等)信息按照正常的方式作為結(jié)構(gòu)體成員變量存儲(chǔ)之外,其他的信息被分割成了4塊內(nèi)容(子結(jié)構(gòu)體),保存在secure聯(lián)合體中。secure聯(lián)合體只是分配好了用于存儲(chǔ)4個(gè)子結(jié)構(gòu)體的空間,但對(duì)于其中的子結(jié)構(gòu)體不做區(qū)分。

????所有的這一切,都是為了數(shù)據(jù)打亂這個(gè)反作弊機(jī)制做準(zhǔn)備工作。

從精靈信息的接口中分析反作弊機(jī)制

????綠寶石的源代碼項(xiàng)目把精靈信息設(shè)計(jì)得這么復(fù)雜,真正在程序中要用的時(shí)候,訪問(wèn)某個(gè)成員變量不會(huì)很麻煩嗎?為此,需要介紹一下“接口”的概念。

????接口(Interface)是程序開(kāi)發(fā)的常用術(shù)語(yǔ),放在綠寶石ROM這個(gè)語(yǔ)境下,接口可以理解為一種函數(shù)(這里就不提接口的專業(yè)化定義了),它可以提供一種對(duì)數(shù)據(jù)對(duì)象操作功能,讓使用者可以不必關(guān)心被操作對(duì)象的細(xì)節(jié)。本期專欄提到的接口是對(duì)精靈信息進(jìn)行操作的函數(shù),這里的操作包括讀操作和寫(xiě)操作。

????用一個(gè)直觀的例子來(lái)解釋,就像家里的下水道壞了需要維修,此時(shí)維修師傅的電話就是一個(gè)接口,利用這個(gè)接口,你可以把師傅請(qǐng)來(lái)修好下水道,但是下水道究竟是怎么修好的你可能并不知道,或者并不關(guān)心。

????在綠寶石的源代碼項(xiàng)目中,有兩個(gè)函數(shù)體現(xiàn)的就是接口的功能:GetMonData和SetMonData。

????這種以Get或者Set開(kāi)頭的函數(shù)名稱具有典型的接口特點(diǎn):Get用于讀取數(shù)據(jù),Set用于寫(xiě)入數(shù)據(jù)。如果在源代碼項(xiàng)目中,“在文件中查找”:

? ? 可以找到接近一千個(gè)結(jié)果:

GetMonData的查找結(jié)果

????而且看它的用法,都是從某個(gè)隊(duì)伍中的精靈提取特定的信息,比如精靈種族(species)、性格(personality)之類。也就是說(shuō),對(duì)于游戲開(kāi)發(fā)者而言,只需要寫(xiě)好GetMonData這個(gè)函數(shù),就不需要再考慮復(fù)雜的精靈信息結(jié)構(gòu)體了,它作為一個(gè)接口能夠正常訪問(wèn)精靈信息就夠用了。

????不過(guò)對(duì)于想要了解精靈信息反作弊機(jī)制的我們來(lái)說(shuō),就得詳細(xì)地分析一下GetMonData這個(gè)函數(shù):

GetMonData函數(shù)

????????GetMonData函數(shù)的主體是一個(gè)switch結(jié)構(gòu),根據(jù)函數(shù)第二個(gè)參數(shù)field的不同,取出不同類型的數(shù)據(jù)。在上圖中可以看到,對(duì)于面板值而言,游戲程序沒(méi)有做任何加密,需要什么就直接返回什么。不過(guò),GetMonData僅對(duì)部分?jǐn)?shù)據(jù)直接返回結(jié)果,更多的信息還在它的default case里面:

GetBoxMonData函數(shù)

????與GetMonData對(duì)應(yīng)的結(jié)構(gòu)體是Pokemon,與GetBoxMonData對(duì)應(yīng)的結(jié)構(gòu)體是BoxPokemon。上圖展示的GetBoxMonData的前面若干行函數(shù),就是原版綠寶石對(duì)精靈信息采用的所有反作弊機(jī)制。

????其中,第3701~3704行的GetSubstruct對(duì)應(yīng)的是數(shù)據(jù)打亂,第3706行DecryptBoxMon函數(shù)對(duì)應(yīng)的是數(shù)據(jù)加密,第3708行CalculateBoxMonChecksum對(duì)應(yīng)的是校驗(yàn)碼。我們一個(gè)一個(gè)來(lái)說(shuō)。

數(shù)據(jù)打亂

????在第3693~3696行,四個(gè)子結(jié)構(gòu)體的變量各自定義了一個(gè),準(zhǔn)備利用GetSubstruct函數(shù)來(lái)獲得每一個(gè)子結(jié)構(gòu)體??梢钥吹剑珿etSubstruct函數(shù)的第二個(gè)參數(shù)是personality,也就是精靈性格值,它有什么用,需要到函數(shù)內(nèi)部去看:

GetSubstruct函數(shù)

????GetSubstruct函數(shù)返回值是一個(gè)子結(jié)構(gòu)體,函數(shù)主體仍然是一個(gè)switch代碼塊,條件是性格值對(duì)24取模的值,共有24種可能:從0到23。每個(gè)case用宏定義SUBSTRUCT_CASE來(lái)代替,這個(gè)宏定義有5個(gè)參數(shù),仔細(xì)一看不難發(fā)現(xiàn)規(guī)律,第一個(gè)參數(shù)從0到23依次枚舉下來(lái),而后4個(gè)參數(shù)則是遍歷了0,1,2,3這四個(gè)數(shù)的全排列。4個(gè)數(shù)的全排列恰好有24種可能性。

????來(lái)到宏定義SUBSTRUCT_CASE的定義:

????這里的宏定義是根據(jù)4個(gè)數(shù)字的某種排列取出對(duì)應(yīng)的子結(jié)構(gòu)體。現(xiàn)在可以舉個(gè)例子來(lái)說(shuō)明GetSubstruct的含義了:

????假設(shè)我們的一只精靈,它的性格值是0x0000001,對(duì)24取模之后結(jié)果是1,對(duì)應(yīng)的0,1,2,3的排列是0,1,3,2,如果我們想要取出這只精靈的子結(jié)構(gòu)體3,也就是取出PokemonSubstruct3(這里面存的是努力值、個(gè)體值、緞帶信息等)的信息,就需要到substruct的下標(biāo)2處去找,這里子結(jié)構(gòu)體的編號(hào)3,對(duì)應(yīng)到了聯(lián)合體的下標(biāo)2。

????頭腦還清醒的讀者應(yīng)該能理解數(shù)據(jù)打亂的含義了。之所以要把一部分精靈信息拆成4個(gè)大小相同的子結(jié)構(gòu)體,就是為了可以支持把它們的順序打亂(彼此可以相互替代),打亂的規(guī)則按照精靈的性格值來(lái)確定,是24種排列其中的一種。這樣一來(lái),類似精靈個(gè)體值這樣的數(shù)據(jù)就再也沒(méi)有一個(gè)固定的地址(用作金手指),因?yàn)樗推渌麛?shù)據(jù)被混在一起打亂了順序。

數(shù)據(jù)加密

????Decrypt的含義是解密,在取出精靈信息之前,需要先對(duì)被加密的精靈數(shù)據(jù)解密,然后才能取出正確的精靈信息。來(lái)到這個(gè)函數(shù):

DecryptBoxMon函數(shù)

????和上期專欄一樣,綠寶石ROM的加密方式就是簡(jiǎn)單的異或操作。使用的加密密鑰有兩個(gè),一個(gè)是精靈主人的訓(xùn)練師ID,另一個(gè)是精靈的性格值。這樣一來(lái),不同的精靈使用的加密密鑰幾乎不會(huì)相同(性格值共有40多億種可能性),給通過(guò)比對(duì)數(shù)據(jù)找金手指的方法帶來(lái)極大的困難。

校驗(yàn)碼

????哪怕你成功闖過(guò)了前兩關(guān),如果在校驗(yàn)碼檢測(cè)這一關(guān)沒(méi)有通過(guò),那么你修改的精靈就會(huì)變成蛋!

????校驗(yàn)碼常用于判斷一段數(shù)據(jù)是否被損壞,舉一個(gè)很簡(jiǎn)單的例子,比如有這么一段0/1序列的數(shù)據(jù):

????設(shè)計(jì)一個(gè)校驗(yàn)碼,把這8個(gè)數(shù)字加起來(lái)再對(duì)2取模(這是一種常見(jiàn)的設(shè)計(jì)校驗(yàn)碼的方法,因此校驗(yàn)碼有時(shí)也被稱作校驗(yàn)和),得到的結(jié)果是0,這個(gè)0就是這串0/1序列的校驗(yàn)碼。

????如果數(shù)據(jù)出錯(cuò)了,例如其中一個(gè)0變成了1:

????再計(jì)算一遍校驗(yàn)和,會(huì)發(fā)現(xiàn)計(jì)算出來(lái)的校驗(yàn)和是1,與正確的校驗(yàn)和0不同,這就說(shuō)明數(shù)據(jù)出錯(cuò)了。

????注意:如果校驗(yàn)碼錯(cuò)誤,能夠說(shuō)明數(shù)據(jù)一定出錯(cuò)了,但反之卻不一定成立。錯(cuò)誤的數(shù)據(jù)也有可能得到正確的校驗(yàn)和(比如上面的0/1序列有兩個(gè)0變成了1)。一個(gè)校驗(yàn)和能夠從多大程度上避免這種事情的發(fā)生,以及它本身占據(jù)的空間大小,是衡量校驗(yàn)和設(shè)計(jì)好壞的標(biāo)準(zhǔn)。

????從上面的代碼可以看出來(lái),綠寶石源代碼在提取精靈信息時(shí),如果發(fā)現(xiàn)校驗(yàn)碼(英文名checksum)不正確,就會(huì)把這只精靈變成“壞蛋”(isBadEgg)。不知道有多少綠寶石系列游戲的玩家,在使用首寵修改的金手指時(shí)會(huì)碰到這種情況:用了金手指之后,隊(duì)伍首位精靈就變成蛋了。

????計(jì)算校驗(yàn)碼的函數(shù)CalculateBoxMonChecksum如下:

CalculateBoxMonChecksum函數(shù)

????綠寶石源代碼計(jì)算校驗(yàn)碼的方式符合傳統(tǒng):校驗(yàn)和,就是把所有的數(shù)據(jù)都加起來(lái)。

破解精靈信息的反作弊機(jī)制

????有了前兩期專欄的知識(shí)基礎(chǔ),相信看到這里的讀者們對(duì)于怎樣用金手指破解這些反作弊機(jī)制已經(jīng)有了自己的想法。

????對(duì)于數(shù)據(jù)打亂,破解的方式就是固定好一種排列順序(比如按照上面給出的精靈數(shù)據(jù)表就很不錯(cuò));對(duì)于數(shù)據(jù)加密,破解的方式就是讓加密密鑰為0(針對(duì)異或加密),或者干脆讓程序跳過(guò)加密過(guò)程;對(duì)于校驗(yàn)碼,我們甚至都不需要知道校驗(yàn)碼是怎么計(jì)算的,只需要在判斷校驗(yàn)碼是不是正確的時(shí)候“動(dòng)一下手腳”就可以了。下面依次來(lái)說(shuō)。

破解數(shù)據(jù)打亂

????來(lái)看GetSubstruct的匯編代碼(怎樣找到GetSubstruct函數(shù)在ROM中的位置?還不熟悉的讀者們需要到前兩期專欄復(fù)習(xí)一下了):

GetSubstruct的匯編代碼

????除了函數(shù)開(kāi)頭熟悉的push指令,我們還可以看看匯編代碼是怎么實(shí)現(xiàn)C語(yǔ)言的switch結(jié)構(gòu)的。注意這4行:

????前三行是典型的從數(shù)組中取數(shù)據(jù)的匯編代碼寫(xiě)法(r1指向數(shù)組,r0作為下標(biāo));最后一行對(duì)pc寄存器賦值,pc寄存器永遠(yuǎn)指向當(dāng)前需要執(zhí)行的指令所在的地址,如果對(duì)pc寄存器進(jìn)行修改,就相當(dāng)于程序進(jìn)行了跳轉(zhuǎn)。而這種跳轉(zhuǎn)和一個(gè)數(shù)組密切相關(guān),說(shuō)明匯編代碼實(shí)現(xiàn)switch的方法就是把switch里各種case的跳轉(zhuǎn)地址保存在一個(gè)數(shù)組內(nèi),然后根據(jù)判斷條件的取值決定跳轉(zhuǎn)到哪個(gè)分支。

????既然我們需要把數(shù)據(jù)打亂的順序固定下來(lái),只需要讓下標(biāo)r0固定為0就可以了,這可以對(duì)0806a28c處的add r0, r0, r1動(dòng)一下手腳,改成

?這樣就相當(dāng)于總是從r1數(shù)組的下標(biāo)0處跳轉(zhuǎn),金手指是:

破解數(shù)據(jù)加密

????來(lái)看DecryptBoxMon的匯編代碼:

DecryptBoxMon的匯編代碼

????里面那兩行eor指令如此顯眼,一看就是異或加密操作。還有一個(gè)比較高級(jí)的指令stmia需要介紹一下。

????stmia是由stm命令加上兩個(gè)后綴i和a得到的,這條指令有兩個(gè)操作數(shù),指令的含義是將操作數(shù)2存入操作數(shù)1指向的地址中,并且還需要根據(jù)stm指令的后綴修改操作數(shù)1的值。具體來(lái)說(shuō):

????后綴i的含義是Increasement(增加),也就是stm指令在操作數(shù)1上加上一個(gè)值,由于stm只能存儲(chǔ)4字節(jié)的數(shù)據(jù),所以這個(gè)加上去的值只能是4。后綴a的含義是increasement After?(在存儲(chǔ)操作之后增加),也就是add操作在str之后。

????有了Increasement,就有Decreasement(減小),對(duì)應(yīng)后綴d;有了increasement After,就有increasement Before(在存儲(chǔ)操作之前增加),對(duì)應(yīng)后綴b。所以stm指令共有4個(gè)版本:stmia,stmib,stmda,stmdb。這里只舉一個(gè)stmdb的例子:

????注意str指令和對(duì)操作數(shù)1(r2)進(jìn)行加減指令的順序(對(duì)應(yīng)后綴b),以及add和sub(減法)指令(對(duì)應(yīng)后綴d)。

????另外,stm指令中操作數(shù)1后面跟的那個(gè)嘆號(hào)也不能省略,省略的話指令的含義就會(huì)發(fā)生變化。關(guān)于這條指令更具體的分析可以看口袋妖怪綠寶石——數(shù)據(jù)提取與代碼分析(5-THUMB匯編指令基礎(chǔ))給出的文檔。

????稍微跑題一下,現(xiàn)在回來(lái)。對(duì)于DecryptBoxMon函數(shù),有很多修改方案可以讓解密(加密)操作失效,這里作者給出一個(gè)跳轉(zhuǎn)指令的方案:

????這是在函數(shù)一開(kāi)始就跳轉(zhuǎn)到函數(shù)末尾,直接讓函數(shù)什么都不做就返回了(當(dāng)然必要的push和pop指令是不能跳過(guò)的)。為了能讓在線網(wǎng)站成功翻譯這條匯編指令,還是需要用到網(wǎng)站左下角的offset輸入框:

在線網(wǎng)站代碼轉(zhuǎn)換

????因?yàn)閎指令的操作數(shù)是相對(duì)地址,只有填入這條指令當(dāng)前所在的地址時(shí),才能進(jìn)行絕對(duì)地址的轉(zhuǎn)換。

????和解密函數(shù)DecryptBoxMon對(duì)應(yīng)的還有一個(gè)加密函數(shù)EncryptBoxMon,這一對(duì)函數(shù)都需要修改才能讓加解密的過(guò)程同時(shí)失效。這兩個(gè)函數(shù)的匯編代碼幾乎一模一樣(有興趣的讀者可以到VBA的反匯編器中去看)。所以,破解數(shù)據(jù)加密反作弊機(jī)制的金手指是:

破解校驗(yàn)碼

????判斷校驗(yàn)碼是否正確的代碼:

判斷校驗(yàn)碼是否正確

????如果能在這動(dòng)一下手腳,讓3708行的判斷條件永遠(yuǎn)不會(huì)成立,也就永遠(yuǎn)不會(huì)執(zhí)行括號(hào)內(nèi)的內(nèi)容(把精靈變成蛋),破解校驗(yàn)碼的目的就達(dá)到了。

????來(lái)到GetBoxMonData的匯編代碼中:

GetBoxMonData的匯編代碼

????如何快速在匯編代碼和C代碼中找到相似性?這件事考驗(yàn)的是一個(gè)人對(duì)兩種語(yǔ)言的熟練程度,以及閱讀代碼積累的經(jīng)驗(yàn)。例如上圖中,bl $0806a270這條函數(shù)調(diào)用語(yǔ)句出現(xiàn)了4次,能夠迅速發(fā)現(xiàn)這個(gè)特征就可以和下面的C代碼進(jìn)行對(duì)應(yīng):

4個(gè)相同的函數(shù)調(diào)用

????同樣是在GetBoxMonData的函數(shù)開(kāi)頭不久,同樣是連續(xù)調(diào)用4個(gè)相同的函數(shù),能找到這樣的相似性,就可以不必一條一條指令去分析、去對(duì)應(yīng)(這樣很累的?。?,而是快速定位到自己感興趣的代碼處。

????根據(jù)相似性,接下來(lái)C代碼還有對(duì)DecryptBoxMon和CalculateBoxMonChecksum的函數(shù)調(diào)用,因此在上面匯編代碼圖的最后,我們期待會(huì)看到接下來(lái)還有兩條bl指令,其中第二條就是我們關(guān)注的計(jì)算校驗(yàn)碼的函數(shù):

GetBoxMonData的匯編代碼(續(xù))

????在最后一次調(diào)用完GetSubstruct函數(shù)(0806a6be)后,果然下面出現(xiàn)了兩次bl指令,其中0806a6cc處的bl $08068c78就是對(duì)計(jì)算校驗(yàn)碼函數(shù)的調(diào)用。接下來(lái)的兩行先左移(lsl)后右移(lsr)的操作,在上次專欄講到過(guò),這是做一個(gè)類型強(qiáng)制轉(zhuǎn)換。再接下來(lái)的兩行:

????是典型的從結(jié)構(gòu)體中取數(shù)據(jù)的匯編代碼寫(xiě)法。r8的取值可以回到GetBoxMonData函數(shù)的開(kāi)頭去找,它存儲(chǔ)的是函數(shù)的第一個(gè)參數(shù)boxMon,然后在這個(gè)結(jié)構(gòu)體內(nèi)相對(duì)地址0x1c處取出一個(gè)成員變量放在r1中。其實(shí)不需要回到BoxPokemon結(jié)構(gòu)體去看0x1c處是什么成員變量,只需要對(duì)比一下C代碼就知道:

上面的圖搬下來(lái)繼續(xù)用……

????這個(gè)地方取出來(lái)的值是boxMon->checksum。如果不出意外,下一步應(yīng)該就是比較兩個(gè)數(shù)值(計(jì)算校驗(yàn)碼函數(shù)的返回值,和精靈信息中存儲(chǔ)的校驗(yàn)碼),果然:

????下面的beq指令,說(shuō)明如果r0和r1相等,就跳過(guò)一段代碼不執(zhí)行(注意0806a6da和跳轉(zhuǎn)到的地址0806a6f2之間還是有一段代碼的)。如果要破解校驗(yàn)碼的機(jī)制,我們就應(yīng)該讓這里的跳轉(zhuǎn)總是發(fā)生。這樣就有了兩種修改方案:

????兩種方案都能起到作用,讀者可以自己體會(huì)一下它們的區(qū)別和聯(lián)系。

????和GetBoxMonData對(duì)應(yīng)的,還有SetBoxMonData,可以通過(guò)VS Code文件查找來(lái)驗(yàn)證:調(diào)用CalculateBoxMonChecksum進(jìn)行校驗(yàn)碼判斷的只有這兩個(gè)函數(shù)(其他的調(diào)用不是為了判斷),這說(shuō)明破解校驗(yàn)碼和數(shù)據(jù)加密一樣,也得改兩處。如果采用上面的方案一,那么破解校驗(yàn)碼的金手指就是:

????總結(jié)一下,破解三個(gè)對(duì)隊(duì)伍精靈進(jìn)行修改的反作弊機(jī)制,需要下面5行金手指(答案不是唯一的):

????本期專欄介紹的內(nèi)容,說(shuō)實(shí)話,難度很大(希望不是因?yàn)樽髡哂邢薜谋磉_(dá)能力帶來(lái)的困惑)。但所謂“難者不會(huì),會(huì)者不難”,如果能充分理解里面涉及到的各種知識(shí),就會(huì)發(fā)現(xiàn)口袋妖怪綠寶石的反作弊機(jī)制也不過(guò)如此。它用了很難的數(shù)據(jù)加密算法了嗎?沒(méi)有。它的校驗(yàn)碼計(jì)算過(guò)程很復(fù)雜嗎?復(fù)不復(fù)雜根本不用管,反正破解它也不需要知道校驗(yàn)碼的計(jì)算細(xì)節(jié)。它的數(shù)據(jù)打亂機(jī)制看起來(lái)有點(diǎn)創(chuàng)意,破解起來(lái)困難嗎?還不是改一行匯編指令就可以……

????當(dāng)然,作者在這里把破解反作弊機(jī)制說(shuō)得這么輕松,完全是因?yàn)橛性创a項(xiàng)目這個(gè)堪稱上帝視角的資源。沒(méi)有它的幫助,破解這些反作弊機(jī)制的速度就會(huì)成百上千倍地放慢。因此,我還是由衷地感謝源代碼項(xiàng)目的作者們,TA們對(duì)開(kāi)源項(xiàng)目社區(qū)的貢獻(xiàn)是巨大的!

????再次感謝眾位讀者的支持,甚至都不指望能有多少讀者能看完作者的長(zhǎng)篇大論了……

一點(diǎn)可有可無(wú)的疑惑

????由于作者的上一系列專欄是介紹究極綠寶石系列金手指的,在當(dāng)時(shí)技術(shù)水平還沒(méi)達(dá)到現(xiàn)在寫(xiě)專欄的程度時(shí),只能按照最簡(jiǎn)單通用的方法去找金手指。奇怪的是,作為綠寶石改版的究極綠寶石,原版綠寶石中出現(xiàn)的反作弊機(jī)制(上上期、上期和本期),在究綠中一個(gè)都沒(méi)有。

????后來(lái),作者在VBA的反匯編器中查看究綠的匯編代碼時(shí)看到,究綠把這些破解反作弊機(jī)制的金手指已經(jīng)寫(xiě)到改版游戲的ROM里面去了(和這幾期作者給出的金手指不同,但是效果是一樣的)!難以想象,貼吧里不知道有多少吧友強(qiáng)調(diào):究極綠寶石是個(gè)反作弊機(jī)制很厲害的改版游戲!確實(shí),非法的精靈或者非法的技能會(huì)被刪除,努力值修改超過(guò)510,對(duì)戰(zhàn)會(huì)直接導(dǎo)致游戲重啟……但是,如果究綠選擇把原版綠寶石的這幾個(gè)反作弊機(jī)制保留下來(lái),分分鐘就可以讓網(wǎng)上流傳的絕大多數(shù)金手指瞬間失效。

????這樣一來(lái),作者就實(shí)在搞不清楚究綠制作組的成員們究竟是怎么想的了。

????你說(shuō)TA們到底是支持金手指呢(破解了原版綠寶石的反作弊機(jī)制)?還是反對(duì)金手指呢(自己新添加了一些反作弊機(jī)制)?這是作者在利用這些工具進(jìn)行分析時(shí),產(chǎn)生的一點(diǎn)可有可無(wú)的疑惑……

口袋妖怪綠寶石——數(shù)據(jù)提取與代碼分析(8-反作弊機(jī)制:校驗(yàn)碼與數(shù)據(jù)打亂)的評(píng)論 (共 條)

分享到微博請(qǐng)遵守國(guó)家法律
二手房| 红原县| 郸城县| 郧西县| 加查县| 曲靖市| 屯昌县| 霍山县| 拉萨市| 永福县| 九江市| 林口县| 循化| 绥滨县| 翁牛特旗| 同仁县| 宜章县| 金山区| 高清| 凭祥市| 巢湖市| 德阳市| 洪泽县| 金秀| 沙坪坝区| 淳安县| 城固县| 阳谷县| 阿克陶县| 义马市| 南涧| 安远县| 林芝县| 苍南县| 宜良县| 西畴县| 盘山县| 得荣县| 乳源| 垣曲县| 铜陵市|