一、前言
《冠軍足球經理》系列作為一款拟真度極高的足球經營類遊戲,赢得過無數贊譽,而CM4可以說是這個傳奇的起點。但是在遊戲安裝過程中,當使用者輸入完序列号之後,程式并不會對使用者的輸入進行真僞判斷,隻有等到安裝完畢,進入遊戲之後,通過遊戲是否正常顯示才能夠得知。而如果遇到使用者不小心輸入錯誤的情況,那麼隻能解除安裝遊戲重新安裝,這就會造成很大的麻煩。
為解決這個問題,這次的研究會以兩篇文章的篇幅通過兩種方式對這個遊戲進行逆向分析,一種是采用常見的“爆破”手段,也就是本文所讨論的方法;而另一種則是編寫出CM4的注冊碼生成器,這會在下一篇文章中進行讨論。後者需要依據反彙編代碼分析出遊戲的驗證機制,這可以說是任何逆向研究的最終目标,也是本次研究的最終目标。

圖1 CM4遊戲封面
二、嘗試在沒有序列号的前提下安裝并進入遊戲
CM4這款遊戲在遊戲安裝的過程中,會要求使用者輸入序列号,這個序列号由數字加字母組成,一共16位,每4位為一組。
圖2 CM4安裝程式的序列号輸入界面
而在本研究的過程中,我嘗試将序列号輸入為“0123456789ABCDEF”,每一位輸入不同的字元,這樣便于後面的逆向跟蹤。這種方式往往也運用于緩沖區溢出的檢測(可見《反病毒攻防研究第003篇:簡單程式漏洞的利用》)。當遊戲安裝完畢後,進入遊戲。程式會先進行序列号的驗證,如果之前的序列号輸入錯誤,那麼就會出現錯誤提示對話框。
圖3 進入遊戲之前提示的錯誤資訊
這裡當我們單擊“确定”之後,依然能夠進入遊戲,但是遊戲卻無法正常顯示,在我的電腦中,凡是出現文字的部分,均會以亂碼顯示。雖然說對于老玩家而言,依然可以通過各個按鈕的位置來确定每個按鈕的功能,但是依然會造成很大的麻煩,是以在此很有必要對這一問題進行逆向研究。
圖4 進入遊戲中的亂碼顯示
三、尋找軟體的CDKEY檢查對話框位置
一般來說,想要找到軟體的驗證語句的位置,則需要運用動态或者靜态反彙編工具,得到它的反彙編代碼,分析該軟體的運作機理,一步一步跟蹤執行,直至彈出如圖3所示的“CDKEY檢查”對話框。這個對話框一定是由一個CALL語句調用出來的,那麼這個CALL語句必然包含了相應的驗證機制,就有必要進入這個CALL語句,進一步分析。
對于這次的研究對象——CM4來說同樣如此,根據慣例,我們有必要先對這款軟體進行查殼的操作,這是一切逆向工作的起始,畢竟有殼的軟體是必須要進行脫殼之後才能進一步分析的。這裡我使用的是PEiD:
圖5 對CM4進行查殼操作
根據查殼的結果可以看到,本軟體是采用Microsoft Visual C++ 8.0編寫的Debug版本,并沒有加殼,那麼接下來就可以按照上述思想開始分析了。直接單步運作進行檢查,很快就可以定位到調用錯誤提示對話框的CALL語句,其相對位址為0x0041495C(當然真正調用MessageBox()語句的 CALL還在這個CALL的内部)。
圖6 找到CDKEY檢查的CALL
按F7進入這個CALL之後,繼續單步執行,來到相對位址為0x00411E3C位置處的語句,由于經過上一步(test eax,eax)的驗證後ZF标志位為1(兩個eax的值相等),于是跳轉實作,會直接跳轉到0x00411F26的位置。
圖7 跳轉至對話框的語句
經過觀察可以發現,所跳轉到的0x00411F26的位置就是調用MessageBox()函數的位置,而它也正是“CDKEY檢查”對話框。
圖8 對話框調用函數位置
分析至此,就可以采取相應的手段來避開這個對話框,使遊戲正常運作。
四、采取“爆破”方式來正常進入遊戲
“爆破”最常用的方式是修改關鍵跳,對于本軟體來說,就是上面分析出來的相對位址為0x00411E3C位置(圖7)處的“je00411F26”(相等則跳轉)語句。正是由于這個跳轉實作,使得CDKEY檢查對話框(圖3)彈出。依據這個就可以進行修改了。
在此情況下通常有兩種方式可以達到目的。一種是可以考慮改變條件跳轉語句的條件。可以将je修改為jnz(不等于0則跳轉),這樣程式可以順序執行下去,而不會跳轉到錯誤提示視窗。
圖9 修改跳轉語句的條件
另一種是可以直接将跳轉語句删除,用nop予以取代,也可以達到避免産生跳轉的效果。(注意:将反彙編代碼修改為nop并不是對所有程式都有效,其目的隻是避免跳轉,進而繼續下一條語句執行。具體情況需要具體分析)。
圖10 nop掉跳轉語句
采用上述任何一種方式修改之後,進入遊戲,可以發現錯誤提示視窗不再顯示,并且遊戲中的文字也正常了。
圖11 修改後進入遊戲
當然,“爆破”的手段五花八門,可供修改的位置以及方式多種多樣,在此也就不再贅述。但是有一點在此需要強調,在一般的軟體逆向分析中,有一種去除NAG視窗的方式是把MessageBox()函數的第一個參數(在反彙編代碼中是第四個參數)的值修改為一個無意義的值,比如1,這樣就會導緻消息視窗建立失敗,進而也就不會顯示MessageBox了。
圖12 修改MessageBox的hWnd參數的值
但是在本軟體中,采用這種方式雖然能夠去除錯誤視窗,但是進入遊戲後依舊顯示亂碼(如圖4所示),可見,此時雖然不再提示CDKEY檢查錯誤對話框,但是驗證依舊失敗,說明驗證流程已經執行了。是以在本程式中,僅僅修改hWnd這個參數是無法達到目的的。
五、進一步分析CM4序列号驗證機理
采取“爆破”手段雖然能夠解決問題,但是卻修改了程式的源代碼,是以并不是高明的手段。而類似于這種軟體的逆向分析的最高目标,就是通過分析其序列号的驗證機制,進而編寫出序列号生成器,這樣不會破壞程式的原始代碼,也對程式有了比較深刻的了解。當然關于序列号驗證算法的逆向分析與序列号生成器的程式編寫,會放到下一篇文章中讨論,這裡隻是去尋找驗證機制的反彙編代碼位置。
首先可以肯定的是,序列号驗證子產品的入口代碼一定是一個CALL語句,而且它必然在判斷是否執行錯誤提示視窗代碼(圖7)的上方(可能在上方很遠處)。對于本程式來說,這個CALL的傳回值儲存在eax中,而這個eax正好就在彈出“CDKEY檢查”視窗反彙編代碼的正上方:
圖13 序列号驗證傳回值判斷
一般來說,序列号的驗證就是通過一系列的算法對序列号進行檢驗,驗證結束以後,接下來的語句就可以通過傳回值,也就是儲存在eax中的值的情況進行判斷,以決定程式接下來的走向。有些不一樣的是,本程式并不是對eax中的内容直接進行判斷,而是将[ebp-19d]中的值經填充後再賦給eax進行驗證,那麼有理由相信,用于驗證的CALL語句的真正傳回值會儲存在[ebp-19d]中,它才是最為關鍵的位置。逆向分析時就需要時刻留意這個位置的值如何發生變化。換算成相對位址,也就是0x0012FCEB。
不斷向上回溯查找可以發現,整個流程中會出現非常多的CALL,但是不必每一個CALL都要跟進檢視,隻要留意該CALL語句執行完畢後是否改變了0x0012FCEB位置的值即可。可以緊盯資料視窗中的0x0012FCEB位置,看其究竟是受到哪個CALL的影響由斷點“CC”變成了非零值(關于斷點“CC”的說明,可檢視《技術面試問題彙總第001篇:獵豹移動反病毒工程師part1》中問題1末尾處的補充知識)。按照這種思想,很快就可以找到關鍵CALL:
圖14 影響傳回值的關鍵CALL
相對位址為0x0041DB3的CALL語句執行後,其傳回值賦給了[ebp-19d],将該位置的值由CC變成了00。
圖15 資料視窗中檢視0x0012FCEB
這樣一來,接下來的工作就是進入相對位址為0x0041DB3的CALL語句中進行分析了。對于這個CALL内部原理的分析,我會放在下一篇文章中。