2017-09-05 博客遷移 實(shí)習(xí)之競品分析
在實(shí)習(xí)的時(shí)候,項(xiàng)目里是要做一個(gè)類似競品的習(xí)題集需求,但是組里沒有習(xí)題資源,按照競品的題目一個(gè)個(gè)拼也不現(xiàn)實(shí),所以便有了扒取競品Apk數(shù)據(jù)的想法。
競品效果見下圖

逆向一開始還是老套路,ApkTool、JD-GUI走起,先大致瀏覽一遍逆出來的AndroidManifest,對(duì)Activity界面的名稱有個(gè)大致的了解。然后再用JD-GUI大致瀏覽一遍各個(gè)文件包名。
因?yàn)橐堑氖瞧灞P數(shù)據(jù),在確定數(shù)據(jù)是存在本地的情況下,本能的看看databases有啥,結(jié)果發(fā)現(xiàn)有個(gè)叫book.db的東西。

其中horse、kill、polgar、tactical是我們想要的習(xí)題集數(shù)據(jù)。
看看polgar存的數(shù)據(jù)好了,結(jié)果發(fā)現(xiàn)數(shù)據(jù)一堆亂碼

一開始以為是編碼問題,所以把book.db放到另外一個(gè)apk,試著用UTF-16,UTF-8, ASCII等各種編碼試了下,發(fā)現(xiàn)沒什么用,導(dǎo)出的依舊是亂碼,所以猜測(cè)數(shù)據(jù)里應(yīng)該是做了加密。
隨后開始看代碼,先通過JD-GUI找到對(duì)應(yīng)讀取DB的代碼地方,具體定位方法最快的方法是直接搜字符串“_fen”或“_pgn”。

以獲取fen為例,在拿到fen的BLOB數(shù)據(jù)后,傳到了localj對(duì)象的b方法,b方法最終會(huì)調(diào)用如下a方法,a方法會(huì)轉(zhuǎn)化成一個(gè)v對(duì)象。

代碼各種位運(yùn)算實(shí)在讓人頭疼,一開始是打算在smali代碼注入日志,然后重新打包,但是
1.這個(gè)v對(duì)象有很多參數(shù),到底哪個(gè)參數(shù)有用以及怎么用還不確定 ,雖然看代碼能看出個(gè)大概,但不好把握。
2.競品對(duì)重新打包做了處理,一直都打包失敗。
3.通過閱讀代碼可以看出棋盤界面是刷出來的時(shí)候才讀db對(duì)應(yīng)的數(shù)據(jù),1w多道題如果通過日志刷出的話,還要把每一頁都滑動(dòng)一下才能走到讀對(duì)應(yīng)db的邏輯,不太現(xiàn)實(shí)。
隨后想試試調(diào)試看看有沒有什么新發(fā)現(xiàn)。
關(guān)于調(diào)試,我用的是AndroidStudio調(diào)試smali代碼的方法。
具體環(huán)境搭建可參照Smalidea+IntelliJ IDEA/Android Studio動(dòng)態(tài)調(diào)試安卓app教程
手機(jī)打開到6個(gè)棋盤展示的界面,然后通過 adb shell dumpsys activity | grep "mFocusedActivity" 獲取當(dāng)前界面對(duì)應(yīng)的Activity名,然后找到對(duì)應(yīng)代碼,跟蹤相應(yīng)的邏輯(此處略)在棋盤初始化的時(shí)候加個(gè)斷點(diǎn),然后調(diào)試,意外的發(fā)現(xiàn)了一個(gè)fen字符串。

仿佛看到了曙光,對(duì)比了下,這個(gè)j就是對(duì)應(yīng)的之前說的v類的對(duì)象,打開j發(fā)現(xiàn)有個(gè)長度64的數(shù)組。

很容易想到棋盤就是64個(gè),很有可能跟這有關(guān)系,經(jīng)過逐一比對(duì),發(fā)現(xiàn)數(shù)據(jù)是以棋盤左下角為原點(diǎn)建立的數(shù)組,0代表無棋,1代表白王,2代表白后。。然后7代表黑王,8代表黑后,因?yàn)閲笠还簿?種棋型,所以這種就是x白、x+6黑的編碼方式,以此內(nèi)推可以推出馬、象、車、兵的id。
之后把BLOB數(shù)據(jù)轉(zhuǎn)換成16進(jìn)制排布,發(fā)現(xiàn)數(shù)據(jù)其實(shí)就是利用棋子id和奇偶對(duì)調(diào)的方式處理的,比如如果有數(shù)據(jù)0201,其實(shí)它的在棋盤的排布是2010,也就是第1個(gè)格子是白后,第3個(gè)格子是白王??紤]到版權(quán)問題,這部分細(xì)節(jié)就不公開了。
上述說的是獲取棋盤信息fen的過程,還有一個(gè)就是獲取答案pgn的過程。pgn在代碼里的使用是通過坐標(biāo)轉(zhuǎn)換的,BLOB的數(shù)據(jù)轉(zhuǎn)化規(guī)律定位到了如下函數(shù):

l的構(gòu)造函數(shù)有三個(gè)形參a,b,c(從左至右),分別代表原坐標(biāo)、目標(biāo)坐標(biāo)、兵升變參數(shù)。
整體逆向的感受還是挺麻煩的,這個(gè)過程會(huì)遇到很多坑,比如長期看混淆的代碼會(huì)被一些函數(shù)調(diào)用繞的暈頭轉(zhuǎn)向,不過之后也懂得放棄這種死磕代碼的做法,換一種角度看問題,嘗試調(diào)試看看能看出什么東西來,不然可能這個(gè)項(xiàng)目的習(xí)題獲取就一直做不成了。還有學(xué)過的東西肯定會(huì)有用的,雖然工作用的都是unity和c#,跟原生Android已經(jīng)相去甚遠(yuǎn),但學(xué)過的以后肯定會(huì)有用武之地,所以學(xué)東西不能一味的太功利化,提升自己能力才是關(guān)鍵。