wordpress標(biāo)簽有問題百中搜優(yōu)化
1、C++游戲簡介
目前手機(jī)游戲直接用C++開發(fā)的已經(jīng)不多,使用C++開發(fā)的多是早期的基于cocos2dx的游戲,因此我們這里就以cocos2d-x為例講解C++游戲的分析與破解方法。
Cocos2d-x是一個移動端游戲開發(fā)框架,可以使用C++或者lua進(jìn)行開發(fā),也可以混合使用。在使用C++開發(fā)時,游戲主邏輯模塊默認(rèn)名字是“l(fā)ibgame.so”,跟其他的native模塊一樣,放在游戲的“l(fā)ib”目錄下。也就是Android手機(jī)上的“/data/app-lib/包名/”目錄,或者直接apk解包后的“l(fā)ib\armeabi-v7a”目錄,其中“armeabi-v7a”取決于當(dāng)前CPU架構(gòu)。
為了進(jìn)一步確定游戲引擎,可以把“l(fā)ibgame.so”載入IDA分析,搜索是否有包含“cocos2dx”字符串的函數(shù)名,如圖:
由于cocos2d-x引擎也支持lua,可以繼續(xù)搜索lua相關(guān)函數(shù),如果沒有搜到,基本可以確定這個游戲是基于cocos2d-x引擎且使用C++編寫的游戲。
2、C++基礎(chǔ)
C++語言以及C++程序的逆向分析是很大的話題,這里僅簡單提一下,如果讀者很欠缺C++相關(guān)的知識,應(yīng)該先找相關(guān)書籍學(xué)習(xí),不可急于求成。
2.1 類指針
C++語言是兼容C語言的偏底層語言,因此在介紹C++的面向?qū)ο蟮母拍钪笆紫刃枰私庖幌轮羔槨?/p>
通常語境下,我們說“指針”其實全稱是“指針變量”,也就是說它其實是一個變量,“指針”其實就是“內(nèi)存地址”的意思,所以“指針變量”就可以理解為“內(nèi)存地址變量”,就是一個保存內(nèi)存地址的變量。對應(yīng)的,不同類型的指針,說的就是那個內(nèi)存地址保存的變量的類型,比如“函數(shù)指針”,我們就可以理解為,這是一個變量,這個變量保存的是一個地址,這個地址指向的位置是一個函數(shù)。
“類指針”就是一種指針變量,這個指針的類型不是C++的基本類型,而是我們自定義的“類”。類指針通常用來作為基址,索引類的成員變量,或者虛函數(shù)。所謂“基址”,跟匯編中說的基址是一個意思。
2.2 虛表
如果一個類有虛函數(shù),那么它的內(nèi)存結(jié)構(gòu)中,頭部就首先會有4個字節(jié)用來存儲一個指針變量。這個指針變量就叫“虛表指針”,它指向的位置是一個函數(shù)指針數(shù)組,這個數(shù)組就叫“虛表”,也就是一連串的函數(shù)地址。這個數(shù)組里的每一個元素,都是這個類的虛函數(shù)的地址。同一個類的所有對象共享一個虛表。如果兩個類的虛函數(shù)不同,那么就會有不同的虛表。
虛表稍微了解即可,它的存在主要是為了實現(xiàn)多態(tài)。這里介紹是方便大家了解類的內(nèi)存結(jié)構(gòu),如果一個類有虛函數(shù),則它實例的頭部4個字節(jié)留給虛表指針,其余位置放置成員變量;如果沒有虛函數(shù),則內(nèi)存全放置成員變量。
2.3 類的成員函數(shù)
類的成員函數(shù)與一般的全局函數(shù)或者靜態(tài)函數(shù)唯一的區(qū)別在于,它的第一個參數(shù)是一個“隱式”的參數(shù),這個參數(shù)就是它所屬的對象的this指針?!半[式”說的其實是在語言層面看不見,但是在匯編代碼中可以看到。
所以在分析的時候如果看到函數(shù)的第一個參數(shù)是一個指針,那它可能就是一個對象的指針,而這個函數(shù)就有可能是個成員函數(shù)。
3、C++游戲分析方法
C++編寫的游戲分析起來會相對要難,但具體修改起來就會相對簡單,因此破解的重點還是在如何找到關(guān)鍵的函數(shù),或者關(guān)鍵的數(shù)據(jù)。這是一個逆向發(fā)散的過程,因此有許多方法都可以嘗試。
這里僅討論無符號或者僅有少數(shù)與游戲邏輯無關(guān)的符號下的游戲邏輯模塊的分析。區(qū)分一個游戲邏輯模塊有無符號,可以簡單地通過在IDA的函數(shù)列表中搜索關(guān)鍵字符串看結(jié)束,比如“HP”、“Boss”、“Player”等。
有符號的情況相對就會簡單很多,因此如有可能,最好拿到有符號的樣本進(jìn)行分析。有符號的模塊樣本通常會出現(xiàn)在游戲早期版本,或者某個特定的版本由于開發(fā)人員的疏忽而遺漏出來。盡管版本會不一致,但還是有很多可以借鑒的地方。
常規(guī)的C++程序逆向分析就是通過看匯編代碼,從而理解函數(shù)的功能。也可以通過函數(shù)的參數(shù)以及返回值去猜測函數(shù)功能,最后通過理解一個個函數(shù)功能而把整個程序的流程厘清,再找到關(guān)鍵點。這是一個費時費力的過程,因此一般僅用在關(guān)鍵函數(shù)分析處。整個分析過程還是有許多其他的技巧和方法可以提高效率,下面就介紹幾個常用的方法。
3.1 借助字符串信息
由于游戲開發(fā)過程中免不了要打印Log用于調(diào)試,或者由于別的原因在程序中保留了敏感字符串信息。因此直接在IDA中按快捷鍵“Shift+F12”列出所有字符串就可以獲取到相當(dāng)多的信息。如圖:
根據(jù)字符串信息,可以索引到相關(guān)函數(shù),方便對函數(shù)的功能進(jìn)行分析。
3.2 send函數(shù)回溯
游戲總會進(jìn)行網(wǎng)絡(luò)通信,而Android系統(tǒng)底層處理網(wǎng)絡(luò)通信的函數(shù)就是send函數(shù)。動態(tài)調(diào)試的時候可以在send函數(shù)處下斷,就可以斷到游戲與服務(wù)器的交互數(shù)據(jù)。但send函數(shù)過于底層,一般游戲都會有加密,這里斷到的數(shù)據(jù)通常都是加密后的數(shù)據(jù),因此需要向上回溯。
在向上回溯的過程中同時注意分析各層函數(shù)的作用,有些只是send函數(shù)的封裝,有些就可能會涉及到加密,或者組包。我們的目的是找到組包函數(shù)和它的上層。在組包函數(shù)處修改,就可以影響游戲與服務(wù)器的底層通信數(shù)據(jù);組包函數(shù)的上層一般就是功能函數(shù),直接修改功能函數(shù)就可以影響游戲邏輯,最終可以更“自然”地影響到游戲的封包。
這個過程中可以借助IDA腳本,過濾一些頻繁調(diào)用的函數(shù),比如心跳函數(shù);也可以打印log,分析調(diào)用來源和它們的調(diào)用頻率。
3.3 輸出log
在一些頻繁被調(diào)用的函數(shù),或者是有明文信息的函數(shù)處,如果有必要,也可以采用IDA腳本編程的方式打印log進(jìn)行分析。如果調(diào)用過于頻繁,腳本的速度跟不上,也可以采用注入進(jìn)程并下Hook的方式打印log,速度就會快很多。具體的注入方法詳見其他篇,這里不多說。
4、破解
C++游戲的破解相對比較簡單,通常都是注入游戲進(jìn)程,然后干涉游戲邏輯,具體來說可以用以下幾種方法:
1、Hook關(guān)鍵函數(shù),修改傳入?yún)?shù)。比如存在一個set_MaxHP函數(shù),可以修改傳入的參數(shù),修改怪物或者玩家的血量。2、Hook關(guān)鍵函數(shù),修改返回值。比如存在一個computeDamge函數(shù),可以修改函數(shù)的返回值,實現(xiàn)秒怪或者無敵的功能。3、Hook關(guān)鍵函數(shù),多次調(diào)用。比如存在一個hit函數(shù),可以多次調(diào)用該函數(shù)實現(xiàn)多次打擊。4、Hook關(guān)鍵函數(shù),直接返回。比如存在一個dead函數(shù),直接跳過執(zhí)行,可以實現(xiàn)不死效果。5、直接修改判斷邏輯。注入到進(jìn)程,或者遠(yuǎn)程ptrace后直接在二進(jìn)制層面直接修改匯編指令。比如存在一個判斷,殺怪?jǐn)?shù)大于10則通關(guān),可以修改為殺怪?jǐn)?shù)小于10則通關(guān)。