許多 apk 也都是用網路獲取服務以及下載資訊,不過都是 https 連線相當地安全。即使是用 tcpdump 等等工具,其實都只會看到加密過的資料在傳來傳去,不知道裡面參數到底是什麼。
那麼有沒有辦法知道這個 apk 是如何發起連線的呢?
是可以的,既然手機上有安裝 apk,資訊是都在裡面的,雖然大部分都沒有辦法反組譯回到原本的 java 程式,但是還是可以透過類似 asm 的 smali 語言看到在做些什麼事,
再透過 smalidea 的幫忙,更可以利用 Android-Studio 遠端連線到 Android-Emulator 上的這隻程式,看看目前正在執行那段程式,記憶體上是什麼樣的值。
首先得先裝到 apk,網路上現在有很多 apk 的收集網站,可以挑一個就可以把想到版本的 apk 給抓下來。
那麼反組譯 apk 是容易的,只要透過 apktool 就可以,如果是 Arch Linux 的話就 yay 安裝即可。
$ yay -S apktool
#open url to download apk
$ apktool d install/apks/com.she.eReader_2021-04-16.apk
$ ls com.she.eReader_2021-04-16/smali*
如此就可以看到這個 apk 的 code 都被反組譯在 smali 等等的資訊夾裡面了,大致上透過這些就可以推斷原本的 jave 是怎麼寫的,有那一些 classes 以及裡面有那些 methods。
雖然可以看到 apk 裡面的 smali 的 code 了,但要憑空猜測會有什麼結果其實是相當困難,尤其是遇到網路傳回來的資料,是要真的跑過連過才會知道的,所以如果真的可以在程式跑得時候能夠中斷暫停下來,好好地觀察上面各個變數以及暫存器上的值就再好也不過了。
而 Android-Studio 上面就有一個 plugin 可以方便顯示 smali 語言在執行時期的資訊,叫做 smalidea,可以在他們的官方網站下載並且手動安裝上。
不過官方 github 的說明以及網路上查到怎麼接上去的方法實在太眼花撩亂,底下就分享我最近自行試過可以成功接上遠端 Android Process 的步驟當作參考
如果能夠看到像這樣的話,應該可以正常選擇到 Process 遠端接上去了。
能夠用 debugger 接上去正在跑的 apk,查到網頁的說明是有幾種方法。而通常可以下載到的 apk,應該都不是 Debug mode,所以是接不上去的。
雖然嘗試過用 apktool 然後更改 AndroidManifest.xml 自行加上 debug mode 再包起來,其實也是無法安裝,畢竟沒有相同的簽章。而其他的方法可能都需要一隻 rooted 的手機更改才行。
所以最方便推薦地就還是用 Android-Emulator 來跑了,環境也相對乾淨。
而特別注意的是,看到 smalidea 的 issue/16 說到,要正確看到 register 的話,最好是 Android 11(R) 之後。
的確是如此,原本用的 emulator 是跑 api-28 的,雖然可以接上去設定中斷點看到 memory 放什麼,但 register 都選不到,必須要換成 api-30 的 emulator 才都可以。
那麼就已想要的部份設定中斷點觀察吧,一開始想做的就是看看怎麼樣下載資料的,所以稍微查找了一下把斷點停在要 connect() 之前。
如下圖一樣,而右下的部份就可以選擇 register 來觀察,以這邊為例其實就可以看到送出去的 https 的 url 是什麼,以及 requestHeaders 是帶出去些什麼選項。
雖然沒有那麼直接,但已經知道怎麼發 http request 了,就可以來自行寫個小程式連連看是不是也可以下載,
curl -v -L --http1.1 \
-H 'Os: Android' \
-H 'Accept: Application/json-v1' \
-H 'Ver: 5.83' \
-H 'App: HamiBook' \
-H 'Vendor: google' \
-H 'Model: sdk_gphone_x86_arm' \
-H 'OsVer: 11' \
-H 'Accept-Encoding: identity' \
-H 'User-Agent: Dalvik/2.1.0 (Linux; U; Android 11; sdk_gphone_x86_arm Build/RSR1.201013.001)' \
--output a.zip \
"https://bookfeed.kollect.com.tw/books/getBookByParms?sessionKey=guest&book_id=0100320028&format=5&resolution=432&device=gphone&isTrial=0&type=r&pkgid=PKG_10001"
執行下去是真的可以的,雖然抓回來的 a.zip 還不是真正的 zip 檔案,不過是的確有東西大量的存起來,接著就來看但原本 apk 下載完之後接下來都做些什麼處理,用相同的方式繼續即可。
為了這個又裝了很巨大的 Android-Studio,也必須要另外跑一個 Android-Emulator,不過如果能夠都知道如何處理這些網路服務的話,最終其實就是連 Android-Emulator 都不必跑的,也會更 reliable。感謝 apktool 以及 smalidea 提供了這麼有趣的東西。
def extract(book_id, data_dir):
m = hashlib.md5()
md5_input = ''.join([d for d in book_id if d not in ['3', book_id[-1]]])
m.update(md5_input.encode('ascii'))
zip_pswd = m.hexdigest()
print(md5_input)
print(zip_pswd)
zip_path = data_dir / f'{book_id}.zip'
with zipfile.ZipFile(zip_path) as z:
z.extract(
'content.pdf',
path=data_dir / f'{book_id}', pwd=m.hexdigest().encode())