1. 程式人生 > >逆向工程第002篇:打造自己的仙劍奇俠

逆向工程第002篇:打造自己的仙劍奇俠

        眾所周知,在國產RPG遊戲裡面,《仙劍奇俠傳》是永恆的經典。釋出近二十年以來,依舊話題不斷。但是鮮有人對其進行逆向分析,只是聽說多年之前曾有人為了探究其是否有隱藏劇情,從而採取了某種逆向分析的手段。在此,我依舊以通過分析其存檔檔案的方式,從最簡單的修改金錢出發,以主角李逍遙為研究物件,逆向追蹤物品、人物狀態以及法術的相對地址標誌位,以無限制使用“酒神”為最終目標,從而實現打造自己的仙劍奇俠的目的。

圖1  《仙劍奇俠傳》遊戲封面

一、觀察遊戲目錄中的檔案資訊

        《仙劍奇俠傳》遊戲目錄中包含有兩個資料夾以及35個檔案。兩個資料夾分別用於儲存遊戲說明檔案(網頁版)以及遊戲音樂。剩下的35個檔案,包含有6個AVI格式的視訊檔案,即遊戲中的所有片頭片尾及過場動畫。包含6個以RPG為副檔名的存檔檔案,以0至5作為檔名,對應於遊戲中的5個存檔位置,其中0.RPG檔案可能僅作備份之用,因此實際可用的存檔檔案為1.RPG、2.RPG、3.RPG、4.RPG以及5.RPG。只有在遊戲中儲存過進度,這五個存檔檔案才會依次出現,否則遊戲資料夾中初始只有0.RPG。而存檔檔案也是本文重點分析的物件。然後,還有14個MKF格式的檔案,1個ICO(圖示)檔案,4個DLL(動態連結庫)檔案,1個INI(配置)檔案,1個DAT(資料)檔案,1個MSG檔案以及1個EXE(可執行)檔案,因為這些檔案不對我們的修改產生影響,因此不作深入討論。但是需要注意的是,M.msg檔案儲存有遊戲中的所有旁白以及對話資訊,可通過修改這個檔案的內容來達到修改遊戲對話及旁白的目的。而Word.dat檔案儲存有遊戲中所有的物品及法術等文字資訊,稍後會用到這個檔案的內容。

圖2  《仙劍奇俠傳》遊戲目錄

二、修改遊戲金錢

        遊戲金錢的修改可以說是一切的根本,是我們逆向研究的起點。通過對金錢的修改,可以在遊戲中的商店(武器鋪、雜貨鋪及藥鋪等)隨意購買任何物品,同時也可以無限制使用“乾坤一擲”。但由於遊戲初始的金錢數為0,不好搜尋,幸運的是很快苗人首領就給了我們500金錢。十進位制的500等於十六進位制的1F4,由於是小端顯示,因此在遊戲存檔檔案的十六進位制程式碼中應該是以F401的方式顯示的,通過這個就可以迅速定位。經過測試可以知道在相對地址0x00028至0x0002b這四個位元組就是遊戲中金錢的標誌位。由於遊戲中只能顯示六位有效的金錢數字,而如果超出六位,要麼會只保留低六位顯示,要麼就是徹底不顯示。因此將金錢修改為999999即十六進位制的F423F(小端顯示為3F420F)就足夠了。

圖3  金錢標誌位

三、逆向追蹤並修改物品

        一般來說,RPG遊戲會有眾多的各式各樣的物品,那麼我們的工作就是找到這些物品在遊戲中的編號以及相對地址。如果能夠找到,那麼就無需在遊戲中購買物品,金錢的作用也就僅僅是使用“銅錢鏢”以及“乾坤一擲”了。遊戲初始我們身上是沒有任何物品的,但是在李逍遙自己的房間可以找到止血草、淨衣符、木鞋以及皮帽,這就已經足夠了。在取得物品前後分別存檔,用檔案二進位制程式碼比較軟體對這兩個存檔進行比較,那麼就可以找到物品的標誌位。它起始於相對地址為0x006c0的位置,以六個位元組為一個單元表示一樣物品(這點比較特殊,一般別的標誌位都是以兩個位元組為一個單元)。在這六個位元組中,前兩個位元組是物品的編號,第三個位元組是物品的數量,之後再用三個位元組的00作為填充對齊之用。

圖4  物品標誌位

        通過分析可以得知,止血草的編號為63(十六進位制),淨衣符為40,木鞋為ec,皮帽為c9。有理由相信,遊戲中的所有物品都是以某種順序排列的,編號也是依次排列下來的。所以在此需要分析之前提到過的Word.dat檔案。

圖5 Word.dat檔案(部分內容)

        可見遊戲物品中排在第一位的是“觀音符”,而“淨衣符”排在第四位,那麼依照順序可以得知,“觀音符”的編號為3d,以此可以類推到編號為126(十六進位制)的最後一樣物品,也就是蘆葦漂。這些物品包括恢復類物品、劇情類物品以及武器防具等。至此所有物品的編號以及標誌位都已經推斷出,現在就可以通過修改獲得任意物品了。


表1  《仙劍奇俠傳》所有物品編號列表

四、逆向追蹤並修改人物狀態

        在遊戲中的人物狀態介面中共有九項內容,它們分別是:Exp(經驗值)、修行、體力、真氣、武術、靈力、防禦、身法以及吉運。由於Exp以及修行的修改沒有意義,故不予論述。

圖6  人物狀態介面

        體力的修改比較簡單,可以直接搜尋96(十六進位制,李逍遙的初始體力值),之後對搜尋出來的結果分別修改,然後進入遊戲以進行檢視。這裡至少會搜尋出兩個正確的結果,即當前的體力值以及體力的最大值。於是可以知道:

        李逍遙的體力最大值標誌位的相對地址為0x00250以及0x00251,

        李逍遙當前的體力值標誌位的相對地址為0x00268以及0x00269。

        同理可以檢索到:

        李逍遙的真氣最大值標誌位的相對地址為0x0025c以及0x0025d,

        李逍遙當前的真氣值標誌位的相對地址為0x00274以及0x00275。

圖7  李逍遙的體力與真氣值標誌位

        這裡需要特別說明的是,在李逍遙每一項體力或者真氣標誌位的後面都還有十個位元組的資料,這些資料代表的是其他五位遊戲中的可控人物的初始體力或者真氣值。舉個例子來說,遊戲第二個可控出場人物是趙靈兒,那麼她的這四項數值就是緊緊跟在李逍遙四項數值的後面。例如0x00252以及0x00253,這兩個位元組是趙靈兒的初始體力值上限,也就是十六進位制的00f0,即十進位制的240。以此類推,這裡不再贅述。那麼我們就可以對所有登場人物的體力值以及真氣值進行修改,但是最大值不能超過十進位制的999,即十六進位制的03e7。

        之後的五種狀態屬性比較特殊,基本不能通過直接搜尋獲得相對地址。比如搜尋武術屬性,李逍遙的初始值為十進位制的35,即十六進位制的23,可是即便將所有的搜尋結果進行改動,遊戲中李逍遙的武術值依舊無法改變,那麼可以得知遊戲中是以其他的數值來取代該項資料的。為了進行修改,可以首先修改出一定數量的金蠶王,通過在遊戲中使用金蠶王來使李逍遙不斷升級,那麼這五個狀態屬性也就會隨之改變。將改變前的存檔與改變後的存檔用二進位制程式碼對比軟體進行對比,就可以鎖定這些狀態屬性的位置了。於是便得到:

        李逍遙武術屬性標誌位的相對地址為0x002c8以及0x002c9;

        李逍遙靈力屬性標誌位的相對地址為0x002d4以及0x002d5;

        李逍遙防禦屬性標誌位的相對地址為0x002e0以及0x002e1;

        李逍遙身法屬性標誌位的相對地址為0x002ec以及0x002ed;

        李逍遙吉運屬性標誌位的相對地址為0x002f8以及0x002f9。

圖8  李逍遙的五種狀態屬性標誌位

        同理,李逍遙每種屬性後面的五個位元組分別對應於遊戲中五個可控人物的屬性值,此處也不再論述。

        以武術屬性為例,遊戲中顯示的值為35,而實際搜尋出來的值為33。之所以會出現這樣的情況,我認為是因為遊戲中李逍遙在沒有任何裝備的前提下會有一個基礎屬性值,而進行裝備之後的實際屬性值則是遊戲中顯示的值,這裡為35。遊戲初始,李逍遙裝備了武術加2的木劍,李逍遙的基礎武術值33加上木劍的加成,得到35。那麼可以得知,我們搜尋出來的這五項屬性值就是人物的基礎屬性值,它們的實際在遊戲中的屬性值還需加上相應的裝備的加成。也正是因為這個原因,才會出現開始時搜不到屬性值的情況。

五、逆向追蹤並修改法術

        其實法術的逆向追蹤與修改的原理與之前的物品逆向的方法相同,同樣要配合Word.dat檔案進行。通過該檔案可以得知各項法術的編號,因為法術是緊挨著物品依次排列下來的。而通過對比的手段則可以定位法術的相對地址。


表2  《仙劍奇俠傳》所有法術編號列表

        李逍遙最初只有“氣療術”這一招法術,在山神廟師從酒劍仙又可以學會“御劍術”,那麼通過山神廟劇情前後的存檔檔案對比,搜尋代表“氣療術”的0128(十六進位制)以及代表“御劍術”的0159(十六進位制)就可以鎖定法術的相對地址,即0x0037c以及0x0037d為李逍遙第一個法術的位置,間隔十個位元組,來到0x00388以及0x00389的位置,即為李逍遙第二個法術的位置(若沒有法術則顯示0000)。依此類推,每隔十個位元組就是李逍遙下一個法術的位置。而同樣地,李逍遙每兩個法術之間,是其他可控人物的法術標誌位,這裡也不再進行討論。

圖9  李逍遙法術標誌位

        經過以上分析,就可以實現人物法術的修改,可以在遊戲初期就擁有高級別的法術,但是“酒神”法術卻比較特殊,需要另外詳加論述。

六、通過修改達到無限制使用酒神的目的

        在《仙劍奇俠傳》遊戲中,“酒神”作為終極法術,威力極大,因此在遊戲中只能夠使用九次。而之所以在這裡研究“酒神”,是因為需要之前的成果,需要調出物品“酒”以及法術“酒神”。因此我將修改“酒神”的使用限制作為本篇研究的最終目標。

        一般來說,在編寫這樣的程式時,無非是設立一個標誌位,從0到9開始計數,每用一次“酒神”,標誌位自加1,直至標誌位達到9的時候,令“酒神”不能使用。或者反過來,從9開始計數,每次自減1,直至標誌位為0。

        經過實際研究,當“酒神”使用九次之後,李逍遙的法術標誌位中本來屬於“酒神”的位置被重新置為了0。而將“酒神”再次修改出來之後,進入遊戲也只能再僅僅使用一次便顯示法術已經用盡。當然確實可以每用完一次再修改一次,再用一次再修改一次的方法來達到無限次使用“酒神”的目的,但是這種笨拙的方法顯然是我們不希望使用的,還是必須找到“酒神”的計數器才可以。可惜的是,存檔檔案中所有的09似乎並不是我們要找的標誌位,也許使用了其它數字予以取代。那麼只能通過對比存檔檔案之間的不同,採用“暴力”的方式來進行定位。

        我取得了李逍遙在同一個野外場景中,“酒神”分別還能使用九次、八次、七次直到已經用盡的十份存檔檔案,這裡的“酒神”不斷用盡的過程也是在這一場景中,免得不同場景之間增加其它的不同的標誌位。對比還能使用九次以及還能使用一次的兩個存檔檔案,將不同之處進行分組,以組為單位,對“酒神”還能使用一次的存檔進行修改。若某組修改之後進入遊戲,“酒神”只能使用一次,說明要尋找的標誌位不在這個組之中。反之則可定位到這個組之中,那麼下一步就是對這個組中每個不同的位元組分別進行修改,每修改完一處就進入遊戲進行檢視,直至定位到某一個或兩個位元組處,就是“酒神”計數器的位置。這裡我找到的位置是0x02a60以及0x02a61。在我的系統中,這個值初始為76a8(小端顯示),每用一次“酒神”,這個值就會自增1,直至用完九次,這個值變為7ea8,“酒神”便無法使用。

圖10  “酒神”計數器標誌位

        在“酒神”還能使用一次以及用盡時,計數器位置的數值是完全一樣的,而不同的是在“酒神”用盡的存檔中,酒神法術的位置會被清空。所以之前在“酒神”用盡時,通過修改法術標誌位將法術調出來,由於計數器標誌位沒有更改,因此遊戲會認為只剩下一次“酒神”法術,所以每次修改完只能使用一次。因此只需把這個標誌位兩個位元組的資料全部修改為00即可。經過測試發現,修改完之後,使用“酒神”不再改變這個標誌位的數值,那麼這個標誌位的數值永遠無法達到7ea8,於是我們的目的也就達到,“酒神”可以無限制地使用了。但是需要注意的是,必須要有充足的“酒”作為供應才可以。

七、總結

        經過對《仙劍奇俠傳》存檔檔案的分析可見,遊戲中的某些可見資料(如之前的人物狀態屬性值)在逆向的過程中不見得能夠出現,它可能是幾個數字之和形成的,所以需要採用多種方式進行查詢。而“暴力查詢法”需要多次的檔案對比(如查詢“酒神”計數標誌位),這也是最後的選擇,畢竟“暴力查詢法”非常耗費時間與精力。

        至此,我們的目的已經達到,能夠任意在仙劍的世界馳騁。逆向工程的第二個成功的嘗試,也為以後的逆向工作積累了非常寶貴的經驗。