我爲什麼做外掛

我只有兩天,一天用來聽許巍,一天用來幹別的。
今年沒去outing,也很少給自己放假,積到年末就剩下了很多。這兩天給自己放羊,計劃 寫點技術文章。起牀後打開電腦,順手放些音樂,是許巍的《每一刻都是嶄新的》,不料上了癮,又把《在別處》、《那一年》以及05年的北京演唱會折騰來,就 這麼聽了一整天。許巍的音樂,什麼歌都一個調調,可它就有一種力量能讓人沉迷進去,然後什麼也幹不了。今天起來學了乖,許巍還是想聽的,爲了不至於沉迷進 去,我找了另外一首歌換着聽,也是我很喜歡的,很絕,特頹廢,叫《Suicide is Painless》。
瘋狂的玩着Diablo II的時候,我一個人在北京忙着拿學位。本來打算好畢業後就離開北京,離開這個我已經呆了8年的城市,一個偶然的原因讓我又留了下來,多待了半年。那半年 陪着我的除了工作加班,就只有《時光.漫步》和逆向工程做Maphack。從小學玩街機開始,我玩過很多遊戲,用過的遊戲作弊軟件數不清,但我從來沒想到 有一天我會自己做外掛。Diablo是我非常喜歡的一款遊戲,從第一代開始,Diablo、HellFire、Diablo II、 Diablo II LOD(毀滅之王)都玩過,但上Closed server是很後來的事,已是09的後期。經歷過09時代的暗黑玩家都知道,那時Maphack是標準配備,差不多人人都用,很多私服甚至把它做爲唯一 允許使用的外掛。我自然也用,從最初的單純使用,後來學會自己改配置文件,再後來開始看一些源代碼。
萬衆期待的1.10補丁發佈以後,我和很多玩家一樣等着新的Maphack出來。由於在此之前Maphack的作者鼠標墊(MousePad)在1.10 補丁beta 2發佈後第一時間就推出了相應的Maphack版本(即Maphack 5.1s),大家都認爲針對1.10正式版的Maphack也會很快。不料等了一週沒任何動靜。這時候有人(jhj)做了個只能開地圖的簡易版 maphack。又過了一週還是沒動靜,我有點兒等得不耐煩,在一天上班的路上,我琢磨着這個事,突然有了想法,想自己也做一個。我自然不想做簡易版,這 個已經有人做過了,再做沒意思。鼠標墊老兄倒是公佈過一份maphack的早期版本的源代碼(maphack 4.6),不過相對於最新版本來說功能太少,在此基礎上再實現新功能工作量還是挺大的,而我只想做個臨時版。想來想去,覺得比較簡單的做法是在最新的 Maphack程序上改出一個能給1.10用的版本。這麼做有幾個問題要想清楚,一個主要的困難在於數據結構可能改變。比如,在1.10中小場景的數據表 示如下:
struct DrlgLevel {
    DrlgMisc 
*pDrlgMisc; //+00
    DWORD nLevelNo; //+04
    DWORD _1[3];
    D2Seed seed; 
//+14
    DWORD _2[5];
    DrlgRoom2 
*pRoom2First; //+30
    DWORD _3[126];
    DrlgLevel 
*pLevelNext; //+22c
};

在1.11中變成這樣:
struct DrlgLevel { //sizeof(DrlgLevel) = 0x230
    DWORD _1[5];
    DWORD nLevelNo; 
//+14
    DWORD _1a[120];
    D2Seed seed; 
//+1f8
    DWORD _2[1];
    DrlgRoom2 
*pRoom2First; //+204
    DrlgMisc *pDrlgMisc; //+208
    DWORD _3[8];
    DrlgLevel 
*pLevelNext; //+22c
};

如 你所見,數據還是那些數據,但是相對位置變了。在有maphack源代碼的情況下,這是一個簡單的問題,只要在頭文件中重新定義一下DrlgLevel結 構再編譯一下就行了。問題是我沒有源代碼,只能在現有maphack程序上改,只要maphack用到的遊戲內部數據結構中的一個改了,這個想法就完蛋。 但是仔細想了一下,我覺得這點不會有問題,因爲最新的Maphack是for 1.10 beta 2的,beta 2是正式版發佈之前的最後一個beta版,一般來說軟件開發在beta階段主要任務是改bug,程序框架和主要的數據結構不應該有什麼變化,最後的 beta版改動就更小了。另外一個問題當然是必須找出maphack所有的patch點和引用的內部函數在1.10中的相應地址,這些共有100多個,數 量看起來是挺嚇人,不過不存在技術問題。一個有利的條件是通過研究maphack 4.6的源代碼和反彙編maphack 5.1s程序,我知道這些patch點和引用的內部函數地址在內存中的位置是連續的,這大大有利於二進制級別的修正。總之經過一番分析,我覺得在最新程序 的基礎上改應該是可行的。事實證明我的想法也沒有錯,除了有一點不至於導致程序崩潰的數據結構有所改變外,其他的基本沒什麼問題。大約花了一週時間,我把 100多個地址找齊了,做出第一個版本。又做了一些測試、改bug,把它穩定了下來。
剛開始的時候我的想法很簡單,只是想在真正的Maphack 發佈之前給大家一個可用的東西,不至於摸黑。我也把它當成一個玩具,順便玩玩逆向工程,並不打算得到什麼回報,因此我只把它放到了我當時所在私服的BBS (ZIXIA)上。但是什麼東西一到網絡上,事情就不歸你控制,於是很快就有人把它放到公衆網上,再過不久又被老外發現,又到了國外網站。老外很熱心,甚 至給它建了個技術支持網站。老外一知道,不可避免地原作者也會知道,終於在Maphack的支持論壇上引起了軒然大波。很多老鼠墊(MousePad)的 粉絲們破口大罵,說這是ripoff,是trojan,還有的說我沒有給鼠標墊credit。鼠標墊本人也很不滿,主要理由是這個東西已經被我改過,不能 算他的作品(出什麼問題不該歸他負責),應該換個名字,至少maphack加載時顯示的這句話應該改掉:
<Maphack>: Mousepad's Diablo II Maphack v1.10 (v5.1s) installed.

不過從事後來看,鼠標墊對此不滿還有另外一個原因:他其實早就把新版本升級好了,遲遲不發佈是打算拿Maphack賣錢,那當時正忙於做防盜版功能。我這 麼半道一橫槓子插進來,正好擋了人家的財道!其實直到現在我對鼠標墊本人還是挺尊重的,這位老兄在D2 hacking上做了很多原創性貢獻,逆向工程的本領沒的說,C程序也是寫的無比精巧,絕對是世界一流的黑客。要是事先知道他打算賣錢,我是肯定不會弄出 這麼個東西的。
名字的問題其實我在發佈前也有考慮。首先,正因爲我尊重鼠標墊老兄,所以從一開始我就打算給他credit,否則早就把名字改了。再者,我做的工作也就是 修正一下內存地址(雖然比較多),絕大部分的代碼還是他的,我當然不認爲這是我的軟件。最後,我只是想做一個臨時的替代品,也沒想搞出多大動靜,因此起什 麼名字本來就是無所謂的。不過事後看起來,比較合適的做法還是應該改改那句話,成這樣:
<Maphack>: Mousepad's Diablo II Maphack v1.10 (v5.1s) sting edited version installed.

不管怎樣,這個事的結果是我落了個吃力不討好。最不爽的是那幫粉絲整天在那兒ripoff ripoff的罵,把我惹得火大,你們不是說我ripoff嗎,那我要配得上這個稱號,我得給它整個名副其實的ripoff,我要把Maphack 5.1s整個程序reverse過來,反彙編成C,在此基礎上再加一些功能,做一個和maphack競爭的軟件。
完全反彙編一個程序到C是一件很瘋狂的事情,一般情況下很難做到,我以前也從來沒做過,不要說做,連想都沒想過。不過火大歸火大,做事情還是要理性的,這 事兒到底可不可行,能不能幹,得好好分析分析。玩逆向工程,我覺得最重要的一點是大局觀一定要好,也就是說你有一個想法,到底可不可行,在技術上要能把握 住,事先就得想清楚。因爲逆向工 程隨便一個程序,面對的彙編代碼往往都是上百萬數量級的,就像大海撈針,如果沒事先想清楚,很容易一個猛子扎進去結果什麼都沒撈着,打擊是很大的。比較而 言正向程序設計上就要容易的多,要實現一個想法,你可以google別人的做法,你有很多基礎庫可以利用,你技術能力弱,寫的代碼也就是醜陋點兒,效率低 點兒,不至於做不出來。
在這個問題上,我覺得我有兩個有利條件。一是有maphack 4.6的源代碼,雖然最新版本在功能上增加了很多,但基本框架是沒變的。另一個有利條件是鼠標墊是C語言高手,代碼很精練,一句廢話都沒有,對於性能來說 這雖然很好,但是從逆向工程的角度看反而是缺點。最後,我花了兩週時間把它反匯編出來,又發出4個beta版本改bug。
這就是d2hackmap的由來。我之所以把它命名爲hackmap,主要有幾層含義,一是名字和maphack很像,大家一看就知道是什麼東西。事實上 不但名字像,功能上也完全兼容原來的程序。這是我的一大設計目標,用過maphack的人都知道它的配置文件是很複雜的,如果我另外搞一套,肯定會有非常 多的技術支持問題,會把我累死。而maphack的使用大家都早已熟悉,網上有很多論壇在討論它的使用,兼容maphack無疑能把我的技術支持工作量降 到最小(即使是這樣我還是收到了大量的郵件)。第二層含義是hackmap = hack maphack,也就是說hackmap是我hack了maphack得來的。第三層含義是惡搞鼠標墊一把,故意拿他開涮。
我玩D2最起勁的時候還是在09時期,1.10時期雖然也玩,但是已經很少了,1.11基本不玩。本來都沒打算做1.11的hackmap,因爲那時候我 已經知道warden不好對付,搞不好別人用了被BAN我又是吃力不討好,所以剛開始只做了一個相對安全點兒的只能開地圖的版本,沒花多少功夫。後來看到 很多人還是強烈希望想有一個全功能版本,就又做了一個,反正也只是體力勞動的問題。不過全功能版本的anti-warden我從一開始就沒打算做, maphack這種軟件和遊戲本身耦合的太緊密,要把自己隱藏起來工作量很大,即使做出來也是白做(除了掙點兒經驗值)。我認爲對抗到最後還是 warden會贏,因爲maphack(注意我只是說maphack類外掛)沒辦法對付warden的數據完整性檢查。想想maphack最基本的功能是 什麼?開地圖!如果你進入遊戲後5秒鐘內就把所有場景地圖都打開了,不是作弊就見鬼了。還有,如果你每次進入遊戲都直飛目的地,一點彎路都不帶繞的(D2 的場景地圖是隨機的),除了作弊還能是什麼。如果warden針對這些數據進行檢測,必死無疑。當然warden目前爲止還沒進化到這一步。
最後,我想說一句,人分三六九等,外掛也分善意的和惡意的。像maphack這種就是善意的,它的目標是幫助玩家更好的進行遊戲。甚至它還有一些防惡意外 掛的功能。比如有些惡意外掛利用遊戲程序的bug可以讓別的玩家掉線,maphack就可以避免這種情況,這相當於給遊戲改了bug。用d2loader 的玩家知道d2loader在過關時有bug,會導致遊戲退出,hackmap就改了這個bug。還有,迄今爲止我給hackmap做的比較費勁的一個功 能就是支持中文聊天(最早不是我做的)。D2的玩家都知道,D2遊戲本身不支持中文輸入,在遊戲中輸入的漢字都是亂碼,要交流只能用拼音,或者英文。 hackmap在1.15和1.16版本中增加了對中文輸入的支持,不過我一直覺得不夠滿意,沒能解決所有問題。其中的原因主要是因爲D2用到了三種字符 集:ANSI/MBCS,UNICODE和UTF-8:通常情況下用ANSI/MBCS,和多語言有關的部分用UNICODE,通過網絡傳輸時又轉換成 UTF-8,比如聊天信息(大致的情況是這樣的,具體的記不確切了)。這幾種字符集之間互相轉換,D2還有簡體中文和繁體中文兩種版本,錯綜複雜,在沒有源代碼的情況下很難把所有情況都照顧 到,所以在hackmap 2.0以後,我乾脆又把這一功能取消了。要徹底解決這個問題只能重新設計遊戲代碼。 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章