[程式] 從原始碼了解 Pokémon Go /譯:簡志偉
從原始碼了解 Pokémon Go INSIDE
http://www.inside.com.tw/2016/08/24/source-code-of-pokemon-go
原文為 《Unbundling Pokémon Go》
https://applidium.com/en/news/unbundling_pokemon_go/
譯者簡志偉,為軟體開發者,譯文刊載於 Medium http://goo.gl/PqFI9
INSIDE 獲授權轉載。
----------
最近 Pokémon Go 實在太紅了,加上自己是技術控,看到這篇文 ”Unbundling Poké
mon Go”:在講如何用逆向工程得到 App 的原始碼,並分析其運作機制,在此翻譯分享
給大家。
本翻譯文已取得 Adrien Couque 的同意,全文如下:
最近不知從哪兒冒出來,Pokémon Go 在一個禮拜內席捲了全世界,我們從裡面發現一些
有趣的東西。
雖然,這個 App 目前只在三個國家公開下載 (美國、澳洲和紐西蘭),但它仍然讓
Twitter 和 Facebook 相形失色。它打敗了 Candy Crush 成為美國最成功的手機遊戲,
不僅證明了對開發者帶來收益,在地商家也注意 Pokémon Go 會為他們帶來客源,任天
堂公司的市值因而增加 90%。
這個遊戲在這麼短的時間就成為家喻戶曉的話題,激勵著我們想去看看它內部的構造。這
篇文以 Pokémon Go App 為例子,說明如何透過逆向工程取得 Android App 的程式碼,
同時分析其網路連線請求來得知更多的資訊。
準備 APK
要做逆向工程之前你必須先有 APK 檔案,而取得 Pokémon Go 的 APK 檔案並不困難,
這裡就不詳述。請注意安裝來源不明的 APK 會有很大的安全風險,但其實 Google Play
會對 App 做一些分析以降低風險,因此一般人最好還是透過 Google Play 下載安裝 App
。但對於逆向工程來說,最喜歡這些惡意的 APK,因為很有趣。在這裡,我們是針對
7/7 釋出的 Pokémon Go 0.29.0 版本進行分析。
先講一下,做了逆向工程後,我們仍然會看不到一些東西:
任何跟 build code 有關的東西。
任何跟測試和持續整合 (continuous integration) 的東西。
其他特殊版本 (例如 debug 版本):在開發當中,你可能會有某些特殊的功能但不會放在
最終的產品裡,因為我們是要分析 Pokémon Go 正式釋出的版本,所以特殊功能應該不
會被放在這裡面。
後端服務的程式碼。很多人可能想知道演算法是如何決定神奇寶貝出現的地點。但這個演
算法是放在後端,我們只能知道如何跟後端傳送資料,無法知道內部演算法的邏輯。
APK 的內容
我們來看一下 APK 的內部構造。事實上,APK 只是一個 zip 壓縮擋,其包含:
http://inside.com.tw/wp-content/uploads/-000//1/1*-x5yUG5lS3zMadIbzErXHQ.png

這裏描述一下每個檔案 (綠色) 和檔案夾 (紅色) 的功用:
Manifest 就是 Android Manifest,它就像 App 的身分證,裡面提供名字、圖示、版本
、權限、硬體限制和其他元件等資訊。當系統在安裝或升級 App 時也會需要它。
程式被編譯後都放在 classes.dex,你可以有一個以上的 classes.dex。
lib 檔案夾裝著的是函式庫。
res 和 assets 檔案夾裝著的是靜態資源檔案。
resources.arsc 是 Android 的特殊檔案,由編譯 R.java 產生的,它是用來連結程式和
靜態資源。
META-INF 檔案夾裝著的是中介資料 (metadata), 但我們在這裡不需要。
以上就是當你解壓縮 APK 後會看到的東西。
我們開始來看第一個檔案:classes.dex。
反編譯程式碼
dex 是 Dalvik Executable 的縮寫 (Dalvik 是 Android 系統裡的舊版虛擬器,現在新
的叫 ART,全名是 Android Runtime,但檔案的副檔名仍用 dex)。這是 Android 系統專
用的檔案格式,而且不容易讀取其內容。有兩個方式可以做到:第一種使用 smali 反組
譯工具將 dex 檔案內容轉成可易於閱讀的 bytecode,第二種使用 dex2jar 將內容轉成
傳統的 Java 檔案。
我們打算使用第二種方法將 dex 轉成 jar 檔 (jar 是一種壓縮檔,其包含所有的
.class 檔案)。接下來我們需要反編譯工具再將 .class 檔案轉換成 Java 程式碼。有
很多現成的反編譯工具,有各自個優缺點,我們使用 Jadx,你可以使用你慣用的,甚至
可以找到線上版的反編譯器。
我們現在有的大部份易於閱讀的 Java 程式碼,受限於反編譯器的限制,仍然有一部分的
程式碼無法被看見。事實上,還有一個反編譯器 Procyon,可能可以有更好的輸出結果。
有一點很重要:我們得到的程式碼並不是當初開發者所寫的原始碼,就像使用 Google 翻
譯將英文翻成法文後,再翻回英文,你會得到另一串新的英文。原因是當要翻成法文時,
根據英文的內容會針對單字或片語決定最佳的對應詞或句,再次翻回英文時,根據法文的
內容會再做一次決定最佳的對應詞或句的運算,這來回的過程各自獨立,結果就會產生差
異。這和程式碼的逆向工程的結果很像:我們反編譯出來的程式碼,其運作的行為會跟原
始碼一樣,但程式碼內容不會完全跟原始碼一樣,差異可能有函數名稱、變數名稱和註解
。
幸運的是,我們可以清楚得知 app 裡所用到的函式庫:
Android support libraries : support-v4, appcompat and support-annotations
Various parts of the Play Services
Jackson (JSON parser) : core, annotations and databind
Gson (JSON parser)
Otto (event bus)
Dagger (dependency injection)
RxJava / RxAndroid (reactive programming)
Apache Commons IO (utilities for I/O)
AdMob, now declared as firebase-ads (ads, analytics)
Upsight (analytics)
Crittercism, now known as Apteligent (monitoring and crash reporting)
Unity classes.jar (interaction between the Android framework and Unity)
Lunar Mobile Console (Unity logger for Android)
Voxelbusters’s Cross Platform Native Plugins (mainly used for sharing from
Unity)
Google VR SDK
如果你是 Android 開發者的話,可能會覺得奇怪:為什麼有兩個 JSON parser?一個做
reactive programming(譯注:作者 Ray Shih 對 reactive programming 的見解),一
個做 event bus?這其實是 transitive dependencies:函式庫會有相依性才能運作,但
寫程式有時候只會呼叫到其中幾個函式庫,你可以到這裡了解我們如何分析 transitive
dependencies。
清理掉一些沒有呼叫的函式庫後,得到一份更簡潔的清單:
Gson
Crittercism
Upsight
Admob/firebase-ads
Google VR SDK, Unity and associated
另外有種相依性則是由外到內,一層層包裹起來,像是 Upsight 裡頭包了大量的函式庫
,列出清單和函式數目:RxAndroid (4k), Dagger (~200), Commons IO (1k), Jackson
(10k), Otto (~50), various Play Services (12k), 自己開發的函式 (3k)。
+--- com.upsight.android:all:4.1.3
| +--- io.reactivex:rxandroid:1.0.1
| | \--- io.reactivex:rxjava:1.0.13
| +--- com.upsight.android:analytics:4.1.3
| | +--- io.reactivex:rxandroid:1.0.1 (*)
| | +--- com.google.dagger:dagger:2.0.2
| | | \--- javax.inject:javax.inject:1
| | +--- com.upsight.android:core:4.1.3
| | | +--- io.reactivex:rxandroid:1.0.1 (*)
| | | +--- com.google.dagger:dagger:2.0.2 (*)
| | | +--- commons-io:commons-io:2.4
| | | +--- com.fasterxml.jackson.core:jackson-databind:2.6.3
| | | | +--- com.fasterxml.jackson.core:jackson-annotations:2.6.0
| | | | \--- com.fasterxml.jackson.core:jackson-core:2.6.3
| | | \--- com.squareup:otto:1.3.8
| | +--- commons-io:commons-io:2.4
| | +--- com.fasterxml.jackson.core:jackson-databind:2.6.3 (*)
| | \--- com.squareup:otto:1.3.8
| +--- com.google.dagger:dagger:2.0.2 (*)
| +--- com.upsight.android:google-advertising-id:4.1.3
| | +--- io.reactivex:rxandroid:1.0.1 (*)
| | +--- com.upsight.android:analytics:4.1.3 (*)
| | +--- com.google.dagger:dagger:2.0.2 (*)
| | +--- com.android.support:support-v4:23.2.1 (*)
| | +--- com.google.android.gms:play-services-ads:8.4.0 -> 9.2.0 (*)
| | +--- com.upsight.android:core:4.1.3 (*)
| | +--- com.upsight.android:marketing:4.1.3
| | | +--- io.reactivex:rxandroid:1.0.1 (*)
| | | +--- com.upsight.android:analytics:4.1.3 (*)
| | | +--- com.google.dagger:dagger:2.0.2 (*)
| | | +--- com.upsight.android:core:4.1.3 (*)
| | | +--- commons-io:commons-io:2.4
| | | +--- com.fasterxml.jackson.core:jackson-databind:2.6.3 (*)
| | | \--- com.squareup:otto:1.3.8
| | +--- commons-io:commons-io:2.4
| | +--- com.fasterxml.jackson.core:jackson-databind:2.6.3 (*)
| | \--- com.squareup:otto:1.3.8
| +--- com.upsight.android:google-push-services:4.1.3
| | +--- io.reactivex:rxandroid:1.0.1 (*)
| | +--- com.upsight.android:analytics:4.1.3 (*)
| | +--- com.google.dagger:dagger:2.0.2 (*)
| | +--- com.android.support:support-v4:23.2.1 (*)
| | +--- com.google.android.gms:play-services-gcm:8.4.0 -> 9.2.0 (*)
| | +--- com.upsight.android:core:4.1.3 (*)
| | +--- com.upsight.android:marketing:4.1.3 (*)
| | +--- commons-io:commons-io:2.4
| | +--- com.fasterxml.jackson.core:jackson-databind:2.6.3 (*)
| | \--- com.squareup:otto:1.3.8
| +--- com.upsight.android:managed-variables:4.1.3
| | +--- io.reactivex:rxandroid:1.0.1 (*)
| | +--- com.upsight.android:analytics:4.1.3 (*)
| | +--- com.google.dagger:dagger:2.0.2 (*)
| | +--- com.upsight.android:core:4.1.3 (*)
| | +--- commons-io:commons-io:2.4
| | +--- com.fasterxml.jackson.core:jackson-databind:2.6.3 (*)
| | \--- com.squareup:otto:1.3.8
| +--- com.upsight.android:marketing:4.1.3 (*)
| +--- com.upsight.android:core:4.1.3 (*)
| +--- commons-io:commons-io:2.4
| +--- com.fasterxml.jackson.core:jackson-databind:2.6.3 (*)
| \--- com.squareup:otto:1.3.8
這表示你有數以千計的函式要分析。
雖然函式庫很多,但去掉了分析用工具、監測工具、當機回報和廣告,最主要的剩下 Pok
émon Go 用的遊戲引擎 Unity。這就是為什麼你打開 app 會有一個 Niantic 的標誌,
為的是讓用戶稍待片刻讓 Unity 引擎啟動,然後再出現一個進度條,顯示引擎讀取靜態
檔的狀態。你所有的互動操作都是在 Unity 的執行環境裡,所以不會看到任何 Android
原生的介面。
另一個受到注意的是:VR SDK。在 Pokémon Go Beta 的階段,有人用跟我們一樣的方法
發現 Cardboard/VR 等字眼在程式碼裡,在正式版的 app 使用聲明裡也提到 Cardboard
。但從我的分析來看,未來並不會有 VR 或 Cardboard 的相應功能。從我們的專業來看
,VR SDK 這個函式庫只是用來串接 Android framework 和 Unity,但如果真的要和
Cardboard 整合,就必須讓 Android framework 和 Unity 可以交互溝通,因此必須引
用大量的開源程式才能做到。但我們從現在的程式碼中並沒有看到。
到這裡,我們花了很多時間在清理程式,但還沒有一個真正能執行專案,因為還需要
resources 和 assets,讓我們繼續往下看。
靜態資源檔
要得到 resources 和 assets 比原始碼還簡單。事實上,assets 會原封不動地被打包進
App,幾乎所有的 assets 都用在 Unity,所以我們暫且先不管它們。Resources 比較有
趣,它們包括了 icons、layouts 和 wording。Resources 的內容會在 build 後變得不
易於閱讀或編輯,例如 xml layouts 檔案會轉為二進位格式,9-patches 檔案則失去判
讀縮放的依據。
好消息是有個工具叫 apktool,它可以幫助我們將 Manifest 和 resources 檔案轉會成
易於閱讀的格式內容,並且產生一個可執行的 Android 專案。一開始我們沒有用是因為
apktool 會將 classes.dex 轉成 smali 檔案,而不是我們要的 Java 程式碼。
現在有了反編譯的 resources 和 Manifest,另外也有 assets,再加上早些將程式碼先
清理乾淨,我們可以開始建立和執行一個完整的 Android 專案了。
編譯和執行
為了產生 APK,我們要編譯的 Java 程式碼前,需要建立一個 Android 專案和 build 的
指令。如果你還記得的話,因為這些東西並不在 APK 裡,所以我們得自己來,靠的是:
Gradle。
其中有一件有趣的事情就是 「最低 Android 版本需求」。App 在 Google Play 上的最
低需求是 Android KitKat(Android 4.4, API level 19),但在函式庫的分析中,
Google VR SDK 最高需求也只有到 API level 16(JellyBeans, or Android 4.1),我們
不清楚為什麼在 Google Play 的聲明要高於實際 API 需求 3 個版本。這麼做一開始就
排除了 20% 的 Android 使用者 (根據 Google’s latest numbers ),也許是故意的,
也或許是失誤。
不過目前最重要的是,我們已經有一個可以執行在手機上的專案了。如果你想要安裝這個
逆向工程版的 App,建議在你的 build.gradle 和 Manifest components/permissions
裡面先改掉 application id,避免和官方版的發生衝突,以確保官方版隨時可以更新。
安裝成功後,你會發現你卡在登入畫面。第一個登入選項是用 Google Sign-In。但是當
你點擊它時,它會進行驗證 App 簽署的憑證,顯然的是我們並沒有憑證,所以跳出錯誤
訊息:
GoogleAuthException: INVALID_AUDIENCE
為了避開這個限制,我們得花很大的力氣才有辦法,所以最簡單的做法是直接到 Google
Developer Console 申請一個新的 App,這樣逆向工程版 App 就可以有自己的憑證了,
登入成功後取得 token,但還是不能跟後端做資料交換。
第二個登入選項是透過 Pokémon Trainer Club 申請帳號。但因為太多人申請,伺服器
似乎已經關閉,等它恢復後,我們會再試看看逆向工程版 App 是否可以登入。
分析程式碼
這裡開始我們會簡短看一下程式碼。雖說這篇文是在講述逆向工程的概論,但這部分我們
會著重在 Pokémon Go App,而且每支 App 的分析可能都不太一樣。
我們稍早看到大部份的程式碼都執行在 Unity 引擎中,因為 Unity 是跨平台的,所以這
些程式碼可以執行在 iOS 和 Android 上。但有些則是基於 Android 原生的功能,例如
:
Sign-in / Registration (inside the package com.nianticlabs.nia.account)
In-App purchases (inside com.nianticlabs.nia.iap)
Interaction with Location, Network and Sensors (inside
com.nianticlabs.nia.location/ network/sensors)
Communication via Bluetooth with the Pokémon Go Plus (inside
com.nianticproject.holoholo.sfida)
第一眼看到最有趣的是 location/network/sensors 程式碼 (如果你假造你的位置或速度
,第一時間知道出現的位置和種類,然後可以抓到更多神奇寶貝的話…)
跟 Pokémon Go Plus 溝通,應該就是當你的手機放在背包或口袋的時候,能通知你附近
出現神奇寶貝。這部分程式碼可以和網路請求的分析做結合,讓 App 只通知你所感興趣
的神奇寶貝,例如你還沒蒐集到的那隻。
稍微看一下與 Pokémon Go Plus 溝通的程式碼:
boolean notifyCancelDowser();
boolean notifyError();
boolean notifyFoundDowser();
boolean notifyNoPokeball();
boolean notifyPokeballShakeAndBroken(String str);
boolean notifyPokemonCaught();
boolean notifyProximityDowser(String str);
boolean notifyReachedPokestop(String str);
boolean notifyReadyForThrowPokeball(String str);
boolean notifyRewardItems(String str);
boolean notifySpawnedLegendaryPokemon(String str);
boolean notifySpawnedPokemon(String str);
boolean notifySpawnedUncaughtPokemon(String str);
boolean notifyStartDowser();
這是非常有價值的資料!你可以打造你自己的裝置:
http://inside.com.tw/wp-content/uploads/-000//1/0*dkO68AHbbFyrlUn5.
截取網路連線
做逆向工程不代表就要大費周章地去拆解程式碼,你可以從 App 如何和外界事物互動,
這個方法適用於任何軟體。
App 基本上都會與螢幕連動,來做顯示或觸控的互動,另外還有:檔案系統、感測器、網
路等。
這裏我們最感興趣的是網路請求。如我們稍早提到的,遊戲最重要的邏輯運算都在伺服器
上頭,App 需要與伺服器做資料交換才可以運作,如果能擷取這些傳輸的資料,我們也許
可以不用再透過 App 就可以和伺服器溝通。
實際上,Pokémon Go 在處理網路請求時,用了一個叫 Optimistic Models 的方法。
Optimistic Models 讓使用者在 app 上做一個動作後,不需要等待伺服器的回應,就直
接往下一動作繼續操作,讓使用者感覺很流暢。如果後來伺服器報錯,它才會跳出警示。
所以你可以看到當你在傳送神奇寶貝的時候,並沒有顯示任何等待提示。目前 App 在這
個機制上還沒有運作得很流暢,主要是因為伺服器滿載,相信接下來幾個禮拜會改善。
所以,我們如何擷取網路請求?最簡單的方式是在 App 和伺服器中間架一個 proxy。可
是如果資料被 HTTPS 加密,你只能看到無關緊要的 metadata。
有一種方式叫 Man-in-the-Middle 攻擊。這種方式是你用 proxy 來騙 App 你是 Server
,然後騙 Server 你是 App。當你收到 App 的請求,用你的 app-side key 先解密,再
用 server-side key 加密送到 Server 取得回應,再用 server-side key 解密,再用
app-side key 加密送回 App。這樣你就可以取得完整的資料,而且 App 和 Server 並
不會知道你的存在。
顯然,如果故事就這樣結束,那所有在網路上的資料都會被看光光。事實上,這些加解密
用的 key 是需要被第三方驗證過的,就是 Certificate Authorities。你的手機或瀏覽
器只會信任驗證過的 key,否則回跳出警告訊息。因為手機是我們自己的,我們可以把
key 先裝在手機上,來擷取資料。
有現成的工具可以幫我們完成 proxy 的設置,像 mitmproxy 和 Charles。Charles 要付
費,但有使用介面可以導引我們做設定。下圖是 App 啟動時所截取到的網路請求:
http://inside.com.tw/wp-content/uploads/-000//1/0*EMChuPcYEqdpYnjO.
從這裡面可以學到很多東西,來看看頭幾個請求:
https://android.clients.google.com/c2dm/register3 : 註冊 push notifications
https://stats.unity3d.com/HWStatsUpdate.cgi : 可能是一個跟 Unity 有關的分析事
件
https://bootstrap.upsight-api.com/config/v1/a9cc12f87adc420baf964f187672ecb4/
: Upsight 的第一個分析事件
https://appload.ingest.crittercism.com/v0/appload : Crittercism 的第一個分析事
件
https://pgorelease.nianticlabs.com/plfe/rpc : 底下會詳述這項
https://play.googleapis.com/log : 跟 Play Services 後端溝通
http://lh4.ggpht.com/LakctgAXpXwe-3PMCWws8rCoVn1_TmyfAiWjWXm6VtsRjRl5v53n1JrWBumWmldzsBFxIUdRLXgsMewLjuyN:
這是一個對 Picasa 的請求,就是 PokéStop 的圖片
https://e.crashlytics.com : 跟 Crashlytics 溝通,但看起來是失敗
https://www.google.com/loc/m/api : GPS 位置
我們可以看到 App 很頻繁地跟 https://pgorelease.nianticlabs.com/plfe/ 做溝通,
而且一個 226 的數字接在 URL 後面,我猜這是為了做 Load balancing:也就是第一個
請求會被指定到某台伺服器去,接下來在同個 session 的所有請求都會導向一樣的伺服
器。
最後,「rpc」這個接在 URL 最後的東西代表 App 是透過 Remote Procedure Call 跟
Server 做溝通,因此所有的請求才都發到同一個 URL,這跟用 REST 方式不一樣。
看看請求的內容,既不像 JSON,也不是 XML,而且也沒有壓縮或加密過:所以我們可以
清楚看到 UUIDs 和 “pm0015” 等字串,這可能是使用 protocol buffers (或是 flat
buffers) 做序列化後的格式。Charles 會幫忙整理乾淨,也可以使用 protocol
buffers 的 command line,所以從:
整理成:
1: 53
2: 6032429073588813826
3: "pgorelease.nianticlabs.com/plfe/226"
7 {
1: "nr\026\335Z\206\241\317\257\275\224\'\353X\326\320_}\220
\316~\227\361\3670\'@\205\315t\221\233-C\367\211\r<j8y\024
\224\312v\342\2269~\304\202/\036\247\276\361\266,\033s\027\006\f^"
2: 1468599616357
3: "$\002\304\337.\034\270\361\214D\251nz\273fM"
}
100 {
}
100 {
}
這是請求 pgorelease.nianticlabs.com/plfe/rpc 返回的內容,其中有一個新的請求端
點:pgorelease.nianticlabs.com/plfe/226,是給之後的所有請求使用。
還可以看到很多 “\xxx”,這是 「octal escaping」。使用解碼器,內容從:
nr\026\335Z\206\241\317\257\275\224\'\353X\326\320_}\220
\316~\227\361\3670\'@\205\315t\221\233-C\367\211\r<j8y\024
\224\312v\342\2269~\304\202/\036\247\276\361\266,\033s\027\006\f^
變成:
nr5Z617754\'3X60_}06~7170\'@55t13-C71\r<j8y42v269~42/7616,s\f^
從結果推測,這像是出現在附近的神奇寶貝的物件列表,每個物件有自己的 UUID 和屬性
(例如 pm0015 代表 pokémon 015 號: Beedrill),其他可能是座標、戰鬥力和統計數
據。我們可以從請求
https://storage.googleapis.com/cloud_assets_pgorelease/bundles/android/pm0126
來證明這個假設,因為這個請求可以得到 pm0126 相關的 assets。
繼續看其他的請求的返回內容。例如,底下這應該是玩家的相關資訊:
100 {
1: 1
2 {
1: 1467925951134
2: "REDACTED: player name"
7: "\000\001\003\004\a"
8 {
8: 1
}
9: 250
10: 350
11 {
}
12 {
}
13 {
}
14 {
1: "POKECOIN"
}
14 {
1: "STARDUST"
2: 500
}
}
}
數字 1467925951134 是 Unix timestamp,指的是 07/07/2016 21:12,這應該是玩家的
註冊時間。在請求和返回的內容中,到處都可以看到 timestamp,有的精確度到
millisecond,有的到 nanosecond。
再深入些,我們可以看到很多成對的數字,像:0x40486ddc40000000,
0x4002d99520000000。這應該是座標,但不是被編碼成十六進制,而是 IEEE 754
doubles。這對十六進制的值轉成數字是:
http://inside.com.tw/wp-content/uploads/-000//1/0*uGNGyda8yod38n9w.
是我們辦公室的座標!我們將可以拿到的所有座標,猜想它的意義,都標記在地圖上:
the position of the user (黃色), points of interests / PokéStops (紅色) and
possible spawn points (綠色)
到目前為止,我們會讀取網路交換的資料、序列化的格式,還會分辨一些 id、
timestamps 和 GPS 座標,其他的留給有興趣的人研究。
結論:如何避免被逆向工程
看到這裡,身為開發者也許會覺得沒辦法防止被別人做逆向工程分析,其實是有的。
模糊你的 Java 程式碼是第一步:使用 Proguard。它會把所有的 package、fields 和
methods 的名字以亂數取代,讓分析更困難。如果你想要對這種 App 做分析,從
framework classes 開始。Proguard 不只用在模糊程式碼,也可以移除沒用到的
resources 和 methods。Proguard 很好用,我想 Pokémon Go 未來應該會用。
還有一種方式是減少 Java 程式碼,將部分功能改寫成 native libraries,這會增加分
析的難度,但對開發很不方便,而且有太多的 Java 與 native 串接,會導致效能下降。
我們能截取網路請求是因為 App 沒有使用 Certificate pinning。使用 basic Android
classes 或 OkHttp 是很平常的,而且很容易。但就像模糊程式碼,它並不能抵擋偏激的
攻擊者 (因為憑證也可以被逆向工程),但可以拖延他們一些時間。
最後,本文是相當基本的分析,我們沒有揭露任何遊戲的秘密,公開作弊的方法讓遊戲產
生不公平。但對開發者來說,你必須謹慎防範專業級的駭客。
這裡條列一下我們的發現:
程式碼沒有模糊化,這會很容易進行逆向工程分析。
我們可以重建可執行的專案
庫的依賴管理可以更好
未來沒有 VR 或 Cardboard 版本的跡象
可能可以降低 Android 版本需求
我們可以讀取跟位置 / 網路 / 感測器和 Pokémon Go Plus 相關的程式碼
容易擷取網路請求,因為缺少 certificate pinning
網路請求是透過 protobuffers-RPC 完成
你可以找到我們的逆向工程版程式碼:Github
https://github.com/applidium/PokemonGo_Android_RE
與我們聯絡: Twitter https://twitter.com/applidium
--
※ 發信站: 批踢踢實業坊(ptt.cc), 來自: 123.192.242.163
※ 文章網址: https://www.ptt.cc/bbs/GameDesign/M.1472563165.A.B9D.html
推
08/30 22:10, , 1F
08/30 22:10, 1F
推
08/30 23:45, , 2F
08/30 23:45, 2F
→
08/30 23:46, , 3F
08/30 23:46, 3F
推
08/30 23:49, , 4F
08/30 23:49, 4F
推
09/02 08:23, , 5F
09/02 08:23, 5F
推
09/07 08:54, , 6F
09/07 08:54, 6F
→
09/07 19:16, , 7F
09/07 19:16, 7F
→
09/07 19:27, , 8F
09/07 19:27, 8F
推
09/15 17:42, , 9F
09/15 17:42, 9F
GameDesign 近期熱門文章
PTT遊戲區 即時熱門文章
21
41