D4DJ API 開發心得

在 2022/06/09 我終於完成了對於繁中伺服器的API開發

 

開發緣由

其實就只是興趣使然

繼去年的PJSK (初音未來聯名的音G), 我就沒有再多碰任何遊戲了

但PJSK的遊玩時間其實一直沒有很多, 因為實在沒有多餘心力去打歌 (畢竟下班回家就是osu常駐了)

今年偶然在LINE社群中看到 D4DJ 繁中服開跑了, 我二話不說就是載來研究 (對 我猜我還是沒啥時間玩)

 

研究過程

在一開始, 肯定會先查查Github上有沒有已經開源的代碼, 如果有就不用廢那麼大功夫

結果一查才發現原來這遊戲已經有兩年歷史了...

不過很神奇的, 經過了兩年 Github上居然都沒有任何開源的api

隨便查查都只有Assets的解密代碼而已...

 

關於資源(Assets)

現在的手遊基本上都會給資源包加密了, D4DJ也不例外

畢竟git上隨手一查就滿街都是, 這裡就是直接硬幹使用

KEY = base64.b64decode(網路上開源的那個Key)

cipher = AES.new(KEY, AES.MODE_CBC, data[:16])
d = cipher.decrypt(data[16:])
d = unpad(d, 16)

硬幹上Python大概長這樣, 就是普遍遊戲使用的CBC加密

iv = 資料的前16碼, D4DJ的開發者很乖, 因為我曾經遇過有用CBC加密, 但都不是前16碼iv的規則去走

解完密後還需要經過msgpack的解壓縮流程, 網上找找就好

 在這裡你可能會遇到的是ExtType

這是MsgPack的原生系統, 用來支持自定義的類型壓縮

D4DJ由C#去開發 (Unity3D), 故可想而知 它們肯定是使用 C#的MessagePack去做壓縮的

有這個想法後, 果斷去google就對了

一查就有, 思路正確就沒啥大礙了

在接回前面所講的ExtType, 你稍微讀它們的README就會發現它們有使用自定義的ExtType

並且剛好就是你解包時會遇到的Code 100

這裡可以慢慢去看, 是真的不難去理解

目前我只遇到 Code 98 99 和 100, 都是搭配 lz4 壓縮去使用

 

探討遊戲API

資源解完了, 就是時候抓包看他的API路徑了

抓包只要你有模擬器, 搭配Proxy就可以實現

 

D4DJ在啟動時會連接OneSignal取得Token

然後登入後去Call遊戲server進行登入

最後才是載資源

 

假如你已經嘗試拆包過了, 那麼你就會發現一件事

那就是它們的資源伺服器以及遊戲伺服器的Url都沒有硬編碼在Apk中 (反觀死亡愛麗絲..)

可是這中間的過程中也沒看到任何取得端點的請求

你甚至會發覺你連登入的請求也沒抓到, 僅抓到下載資源的請求而已

 

D4DJ使用的傳輸

拆包後, 可以看看他們引用了哪些庫, 藉此去推斷它們使用了何種傳輸 (既然不能Proxy抓包 那肯定是用到socket連線)

除了messagePack外 可以明顯看到Grpc的庫, 說到這你應該就有頭緒了

Grpc似乎有反代理的機制(idk 我也不熟), 因為就算是HTTP2, 應該也能抓包

上網查查只能靠Wireshark去解析了

打開Wireshark的確是能看到請求, 但這種封包其實難以理解

Grpc使用buf壓縮的傳輸技術, 你幾乎看不出明碼 (對 就像Thrift一樣)

在這裡我已經是半放棄狀態 (真的頭疼了好幾天)

4天過去了, 毫無進展 第1個活動也結束了...

 

MemoryDump

真的走投無路了

這是一個非常下下策的一條路 (上次這麼做是為了 SINoALICE的日服API)

使用gameguardian去dump內存

導入HxD去看, 在這裡 你只能用搜索的方式慢慢去篩

就算通訊是走SOCKET 你還是可以抓到一些path和請求標頭諸如此類的明碼資訊

這裡搭配遊戲拆包, 查了一些比較有可能的"靜態"值去搜索 (為啥要靜態? 阿代表他不會改變阿)

後來用了 base-bin 找到了一串資料, 這一查也順便得到了api的path!!

 

Base-Bin

base-bin是啥呢?

在這裡只有兩種可能

1是標頭 2是資料, 如果都不是 那就只是單純內存了

網路找找並沒啥資訊, 畢竟關鍵字還是太少, 但畢竟是用grpc去做傳輸, 所以我還是去看了grpc的文檔

還真的有...

總而言之可以先記下, base-bin是請求標頭, 並且使用base64去做加密 (不過內存附近是沒看到base64字串??)

知道是請求標頭後, 那麼內存附近看到的字串十之八九就是遊戲的api (很明顯因為是 /XXXService/XXXXX... )

至於網域.. 其實一樣關鍵字查內存下去就有, 成功的話你應該會得到兩組網域

對應path丟去chrome, 結果發現其中一個是可以被請求的!!! (另一個開F12看, 標頭會顯示 grpc-message, 更能確定整個服務都走grpc)

恭喜, 在這裡我終於拿到一個完整的URL, 即使還不知道標頭和請求資料, 但我還是燃起了些許鬥志繼續了探索...

 

 

在Python上實現Grpc

既然很清楚的知道D4DJ是走grpc, 並且我們也有了一組完整的URL

照著google的教學去寫, 在這裡你可能會遇到 Grpc Status: Unavailable

其實這個錯誤我也是看了有半天, 後來找了網路看了別人寫的範例才發覺這是跟ssl有關

簡單來說就是生成Channel的方式有兩種: 安全與不安全

D4DJ使用安全通道, 照著上圖寫法去改就可以正常連接囉!! 

順便附上參考代碼的來源

 

 

Grpc的請求資料

能夠正常連接伺服器端點了, 那這時你就會苦惱一件事:

proto

 

Grpc使用buf去進行資料傳輸, 也就是說它把原始的資料去進行了一次壓縮

而就像Thrift一樣, Grpc也要定義一種叫做proto的類型文件

第二個頭疼的點...

哀... 研究個api還要學那麼多, 真不知道是上輩子欠了多少債 QQ

 

我一樣先透過之前dump下來的內存去關鍵字, 奇怪的是, 內存中沒有它理應要有的.proto檔案

雖然我想應該不可能直接把proto檔案放進遊戲裡拉, 但還是抱著一絲希望去找 QQ

說到這, 沒錯 我又踏上了放棄的路上

 

 

 

文長, 打了快半小時, 好睏, 我看我分兩篇好了zZ

下篇應該很快會出來 ((希望