旅行青蛙分析(Android篇)


近期旅行青蛙這款游戲非常的火熱,周圍的朋友、家人都養了一只小青蛙。看到網上有人說這款游戲可以直接逆向編譯,沒有加密;所以在搜索相關資料后花了一些時間進行逆向分析與修改。這篇文章里,我將介紹如何獲取稀有明信片的方法以及如何逆向修改代碼后得到破解版本的“旅行青蛙”游戲的方法。

獲取稀有明信片

引入

我們在玩旅行青蛙的時候會發現,大部分小青蛙寄回來的明信片都很類似,即使有小伙伴(蝴蝶、青蛙、螃蟹、小老鼠),大家的動作都是很類似的。通過分析代碼可以知道,這些明信片是自動合成的。意思就是,會有幾個不同的背景模板、幾個動物的動作模板,排列組合進行合成,生成普通明信片。而所謂的稀有明信片,就是非排列組合合成的,而是單獨繪制的、精美的明信片。這里有稀有明信片的百度網盤下載地址 密碼:F338。

步驟

下面介紹如何獲取明信片,首先我們需要Android版旅行青蛙的安裝包apk文件,網上有很多下載地址,或者直接從官方下載到手機里並用adb導出到電腦里來即可。不管你用什么方式,安裝包獲取后,將后綴名更改為rar或者zip壓縮包的形式,再進行解壓(解壓后應該有assets、lib、res等等文件夾),這些解壓后的文件實際上都是旅行青蛙游戲的代碼構成部分。
然后我們需要用到Unity Studio,下載地址見這里,下載完成后直接在文件夾中運行Unity Studio.exe,左上角Load Folder,將../assets/bin/Data文件夾導入,會發現原來空的列表出現一大堆文件。按如圖所示切換到右邊的列表(Asset List):
40.png
接下來按照Size進行排序,基本上就是游戲的圖片構成以及模板:
41.png
經過長時間的搜尋會發現Size=525088就是我們要找的明信片形式:
42.png

43.png
由上述兩張圖可以看出,第一張為稀有明信片、第二張就為普通模板(加上前面的一些小動物可以構成普通明信片)。我們先將所有Size=525088的圖片全部導出:
44.png

36.png
經過一番本地的篩選,就可以獲得所有的稀有明信片了,這里放上3張:
tokusyu_09.png

tokusyu_15.png

tokusyu_13.png

逆向分析代碼

引入

這里之所以選用Andriod的旅行青蛙進行逆向分析,一方面是因為旅行青蛙的Andriod比較好分析、是最簡單的情況,一般的Unity3D游戲都會用一些保護將dll腳本加密的,如果是這樣的話可能就需要調用hook函數來逐步分析、比較麻煩;另一方面是因為ios版本的旅行青蛙,會用到ll2cpp,不如Andriod好分析(利用dnSpy可以直接分析Andriod版本的C#腳本,代碼易懂好分析)

dnSpy分析C#腳本

在獲取明信片的步驟里,我們已經將旅行青蛙的安裝包apk文件進行了rar解壓,這里就不需要另外操作了。
然后我們需要用到dnSpy軟件進行反編譯,dnSpy下載地址在這里。點擊dnSpy.exe即可啟動,我們需要查看的是游戲的C#腳本,路徑為../assets/bin/Data/Managed/Assembly-CSharp.dll。反編譯后直接就能顯示代碼:

當然我們玩過游戲,應該認識游戲中的日文字,搜索讓我們輸入小青蛙姓名的句子(搜索的快捷鍵為Crtl+Shift+K),就可以在CallTutorial找到屏幕上顯示的句子和相應的代碼:
01.png

02.png

修改“青蛙命名”句子的例子

我們先以修改為小青蛙取名字的句子做一個例子:在日文句子處右擊選擇編輯IL指令,熟悉的匯編語言就出現了!!
我們可以看到位於164行處LDSTR(即Load String把字符串加壓入Evaluation Stack中)就是我們需要修改的日文句子,進行修改:
03.png
修改為:
04.png
點擊確定,回到C#腳本代碼界面就能看到原本的日文句子已經成功被修改成為自己修改的句子了,真機測試效果圖將放在結尾處。

修改三葉草數量

方法1:
05.png
分析代碼,圖中黃色圈出的部分是在購買時相關的。第一處為判斷,當Clover(中文就是三葉草)的存儲量比商品item的價格要大的時候就可以執行下面的操作;第二處是生成提示文本:"...是否要購買?",然后經過SetOnClick事件為True之后,就執行第三處的BuyItem()函數。所以我們可以輕易的判斷出,三葉草的數量的減少肯定和BuyItem()函數這個函數有關,跳轉到BuyItem()函數處:
06.png
圖中黃色圈住的部分調用了getCloverPoint(-itemDataFormat.price),之后的函數為GetItem(..,1),意思是商品item數加1,表示已購買;根據函數邏輯,黃色圈住的部分就是減少三葉草數量的函數,傳入的為-itemDataFormat.price,為一個負值;那么我們前往getCloverPoint()函數看看:
10.png
傳入的負值與原來的三葉草數量相加,相當於三葉草數量減少了商品價格的數,符合邏輯。我們若想修改腳本,自然就要打破這個邏輯,最容易想到的就是:既然買了商品會加上-itemDataFormat.price這個負值,若我們傳入的沒有這個負號不就可以了。所以右擊選擇編輯IL指令:
07.png
neg就是匯編指令中的負號的意思,將它nop掉就ok了:
08.png
點擊確定回到C#腳本看看效果:
09.png
可以看出負號已經沒有了!!所以購買物品時就不會減少三葉草的數量,反而是增加了。
方法二:
其實方法一已經足夠了,但是在閱讀源碼的時候,發現調用CloverPointStock()函數時,不管是購買還是收獲三葉草,都是會返回savaData里的數值(經過各種流程計算后的結果),return的結果是這樣子的形式的:
11.png
既然代碼是返回經過運算的一個值,呢不如直接返回一個特定的數,同樣進行修改:
12.png
修改為:(LDSFLD是 將靜態字段的值推送到計算堆棧上,后一級的LDFLD剛好構成級與級之間的調用關系,即savaData.CloverPoint)
13.png
返回的數值可以任選,比如我選的23333;確定后看效果:
14.png
修改成功。為了方便,我采用了第二種方法。

修改抽獎券

抽獎機制在旅行青蛙這款游戲中也是非常重要的,因為根據抽獎出來的珠子的顏色可以獲得小青蛙旅游時的加分,也決定了小青蛙前去的目的地。然而經常券不夠是個問題。所以搜索(Ctrl+Shift+K)“券”或“足”這個字,就可以定位到抽獎券代碼的位置:
15.png
黃色圈出的位置是說,如果獎券數量小於5,就提示券不足文本,如果獎券數量大於5就將獎券數量減5然后執行一次隨機抽球過程,這個隨機抽球后面會進行講解,這里先說怎么修改:我們可以將小於5更改為小於0,獎券數量始終減0,這樣子就實現了即使獎券數量為0仍然可以抽獎:
16.png
筆者在這里犯糊塗,將小於5更改為了大於0...在獎券為0的時候是可以抽獎的,但是一旦小青蛙帶回來新的券使券的數量大於0,就會出錯抽不起來了。。這是個顯而易見的錯誤,大家修改時注意一下就行了。

提高中獎概率

相信我們在抽獎的時候,大部分抽到的都是白玉,白玉是非常常見的,其他顏色的玉的顏色都很少見,筆者玩了2個月一個紅球或者黃球都沒有抽到,分析代碼后發現問題在這里:
17.png

18.png
抽中白玉的概率為60%,抽中藍玉的概率為27%,抽中綠玉的概率為9%,抽中紅玉的概率為3%,抽中黃玉的概率為1%。。。可想而知,抽中非白色玉的概率是多么的小。。。
下面我們再分析一下,是如何利用抽球概率抽球的呢?
19.png
首先用num存儲0到PrizeBallsRank.RankMax中的任何一個值,用num2存儲各種玉的PrizeBalls的值,當隨機選擇的num值比num2的值小的時候,就將result更新為這個num2的值,考慮到除了白玉之外的PrizeBalls的值都小的可怕,最高也才為27,所以非白色玉的可能性非常的小。
我們要做的當然就是將概率提升上去:
20.png
圖中0x3c、0x1B都是16進制表示的數,表示的數分別為60、27,所以我們可以對整體進行修改;值得一提的是,部分表示的數是在匯編指令中直接賦值的,比如ldc.i4.1,就是表示數1。按照16進制進行修改:
21.png
效果為:
22.png
由圖可見,概率大大的提升了!!

四葉草概率的提升

既然三葉草我們可以控制,呢么四葉草我們應該可以控制,找了很長時間的代碼,發現在CloverFarm文件中有關於三葉草、四葉草生成的方法:
23.png

24.png
代碼實際告訴我們,四葉草的生成與否是由bool型變量flag所決定的。如果flag為0的話,就生成三葉草,執行list.Add(this.NewCloverObject(j,this.cloverList[j],list))。如果flag為1的話,執行一次生成四葉草程序list.Add(this.NewCloverObject(j,this.cloverList[j],list,true)),然后flag再變為0;所以我們跳轉到生成四葉草程序去看看:
25.png
由圖中黃色圈出的部分可以看出,生成四葉草共有兩種判斷方式,首先是第一處的概率判斷,當Random.Range(0f,10000f)比fourLeaf_percent*100f的概率小的時候,就令cloverDataFormat.element=1,從而執行第三處的四葉草生成程序。好的,那么我們看看fourLeaf_percent的數值是多少呢?
26.png
由圖可見取值為1f,什么概念呢?就是變成四葉草的概率為1/100;第二種的判斷方式為fourLeafFlag是否為1,利用的就是flag,同樣flag變為1的過程也是概率極小的。所以我們可以手動更改概率,修改為:
27.png
這樣就將概率提升到80%了。
當然,我們也可以將fourLeafFlag這個第二處的判斷條件更改為

if(true)
   cloverDataFormat.element=1;

三葉草生成時間

網上之前提到了一個修改系統時間獲得三葉草的方法,確實可行的原因在這里,旅行青蛙用的是timespan進行生成三葉草的,即device time-last harvest time來判斷,旅行青蛙對於時間的檢測比較嚴格,因為在模擬旅行系統部分的代碼中,我們可以知道,小青蛙的旅游和回家和timespan是相關的,如果隨意修改系統時間影響的不僅僅是三葉草的生成速度,影響的還有小青蛙的模擬旅游系統。。。
而生成三葉草的確是和timespan相關:
29.png
這里調用了一個Clamp函數,我們跳轉過去看看:
28.png

30(准確時間為240min).png
我們知道Recyle就應該是三葉草的循環生成程序,而value如果小於cloverSpanMin就讓它等於cloverSpanMin;如果value大於cloverSpanMax,就讓它等於cloverSpanMax。而cloverSpanXXX的值為:
31.png
從函數中簡單理解就是,如果我們收割過三葉草后,相當於設置了一個計時器,我們的計時器默認開始為cloverSpanMin=300,即5min,直到cloverSpanMax=14400,即4個小時,所以長出一輪新的三葉草需要時間為4個小時。當我們遠超4個小時還沒有收三葉草的時候,由於value會大於cloverSpanMax,所以程序會始終讓value=14400,從而不會出現三葉草一直在增長的現象,修改最大時間的話就可以確保收獲的時間變短:
32.png
我修改為了360,即6min循環一次。

關於模擬旅行系統

為什么叫旅行青蛙,看了源碼后我想應該會有所了解,關於模擬旅行系統的代碼占據了所有代碼的一半之多。開發者真的在這個旅行系統上花費了很大的功夫!!導致這部分的代碼比較復雜,在這部分代碼中大量出現了生成日志log的函數,顯示小青蛙當前位置是在哪里、參與了什么活動、遇見了什么伙伴(這些在源碼中都是轉化為text寫到log里的),我估計是開發者們為了不混淆整個邏輯所做的一個措施吧。。。。
我簡要的分析一下,模擬旅行系統中最讓我吃驚的部分還是“圖論”部分,竟然涉及到了圖論,之前一直以為僅僅是根據時間判斷的而已,但是開發者卻真的是創建了結點與邊來表示旅行地點:
35.png
上圖利用到了路徑算法,代表真的是考慮到了旅行地點的變化。
此外,模擬旅行系統還涉及到了地形因素,如山、海、洞穴:
34.png
根據地形的不同,旅游時間會不同、是否能到達目的地也是不同的。我認為,模擬旅行系統其實就是借用圖論的架構進而表示旅行的時間,而所帶的物品、地形都會對旅行的時間有影響。而具體的模擬旅行系統所用的旅行時間也和在家休息時長、上一次旅行時間有關。而同時,旅行時間也決定了所能去的地點、下一次回來的時間、下一次出游的時間、能獲得的明信片:
33.png
從這里我們就知道明信片的生成其實也是和地點、時間有關的,圖片可以由地點的模板組合生成,也就是普通明信片的生成方法。
但是,模擬旅行系統可能還要復雜些。。。先附上一段代碼:
38.png
可以看出開發者考慮了是否到達、目的地、起始地、中途小青蛙是否會休息、會遇到誰、是要生成普通明信片還是稀有明信片....,開發者考慮了這些狀態,並用enum枚舉量進行了分析。
關於旅行系統,在寫博客的時候剛好看到一篇文章分析的非常非常全面,有興趣的可以借鑒閱讀一下。

反編譯生成Apk

當然不會是只將修改過的dll腳本文件替換就行了,這樣因為apk的簽名會不一致,所以不能正確安裝。這里我們需要對apk進行重新編譯,從而生成新的證書。
這里我使用的是ApkIDE,下載地址在這里
操作方法比較簡單,將原來的apk文件拖進窗口內,會自動進行解壓。將我們修改過的Assembly-CSharp.dll覆蓋原先的dll文件,然后編譯生成apk文件即可,生成步驟如下:
39.png

真機測試

測試結果如下:
IMG_9970.JPG

IMG_9972.JPG

IMG_9973.JPG

IMG_9974.JPG

IMG_9975.JPG

IMG_9979.JPG

教程寫的比較倉促,如果有什么錯誤,會在日后進行修改。轉載請申明出處,謝謝!!
----YunLambert


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM