利用 HTTP Request 工具就可以模擬 Ingress App 發送 HTTP Request
但由於 Ingress 的 HTTP Request 經 SSL / TLS 進行加密,應如何解密 ?
在說明方法前,在下必須澄清,雖然本文提及 SSL / TLS 解密,但並非 SSL / TLS 指出已經不安全
而是在下利用 中間人攻擊 來側聽 在下與伺服器的資訊
關於 SSL / TLS 可以到 SSL / TLS @ Wiki 查閱
基於 Ingress 的 HTTP Request 經 SSL / TLS 的加密
使用 Wireshark 等 Packet Capture Tools 雖然能側聽到資訊,但由於資訊被加密,因此不能閱讀
若需要使用 Wireshark 將資訊解密,必須加入伺服器的 私鑰 (private key) ,但閣下不可能擁有伺服器的私鑰
因此要借用 代理伺服器 (Proxy Server) 進行 對稱私鑰加密
以在下使用 Linux Mint 為例
安裝 mitmproxy (mitm 就是 man in the middle 中間人 的縮寫)
在 Terminal 輸入
sudo apt-get install mitmproxy或按此安裝
安裝後輸入
mitmproxy -p 8888-p 8888 是指定 mitmproxy 使用 8888 port ,若不指定則是 8080 ,指定與否並不重要
mitmproxy 起動後, mitmproxy 會不斷監察通過 代理伺服器 時的資訊
先進行測試
開啟瀏覽器如 Firefox 到「偏好設定」
按「進階」>「網絡」>「設定」
選取「手動設定 Proxy」
在「HTTP Proxy」輸入 127.0.0.1 ,Port 為 8888 (與 mitmproxy 的 port 相同)
點選「所有通訊協定都使用此 Proxy 代理伺服器」
將「直接連線」清空
設定完成按「確定」
瀏覽具 HTTPS 的網頁進行測試如 https://www.google.com.hk/
由於經由 mitmproxy 連線至目標網頁,而且代理伺服器並未驗證,會出現「這個連線未受信任」導致不能瀏覽
到「偏好設定」
按「進階」>「憑證」>「檢視憑證清單」
到「憑證機構」分頁
按「匯入」
選取由 mitmproxy 產生的憑證 (.cer 格式),檔案位於 ~/.mitmproxy/mitmproxy-ca-cert.cer
選取後將點選
「信任此憑證機構以識別網站」
「信任此憑證機構以識別郵件用戶」
「信任此憑證機構以識別軟體製造商」
後按「確定」
匯入後會發現經由 mitmproxy 簽署的憑證
重新整理 HTTPS 網頁能瀏覽,並發現經 mitmproxy 驗證
回到 mitmproxy 介面會發現資訊已經被側聽
在 Terminal 輸入
ifconfig尋找 代理伺服器 的 IP
使用 Android 裝置,前往「設定」>「Wi-Fi」
在已連線的 Wi-Fi 通訊,長按後,按「修改網絡」
按「進階選項」後
在「Proxy」選擇「手動」
並在「Proxy 主機名稱」輸入 代理伺服器的 IP (或 主機名稱)
及在「Proxy 通訊埠」輸入 代理伺服器 所使用的 port
其餘保留原設定
設定後按「儲存」
瀏覽具 HTTPS 的網頁進行測試時
會發生與剛才相同的情況而不能瀏覽網頁
前往「設定」>「安全性」
按「從儲存裝置安裝」
安裝由 mitmproxy 產生的憑證 (.cer 格式)
(可以借用 E-Mail 將由 mitmproxy 產生的憑證儲存至 Tablet 裝置,有更好的方法由閣下自行處理)
將憑證命名為「mitmproxy」後按「確定」
到「信任的憑證」
在「使用者」分頁中可查證 mitmproxy 的憑證已經安裝
點選憑證可以查看資訊
重新整理 HTTPS 網頁便可瀏覽
使用 iOS 裝置,前往「設定」>「Wi-Fi」
在已連線的 Wi-Fi 通訊,按「更多資訊」
將「HTTP 代理伺服器」選取為「手動」
並在「伺服器」輸入 代理伺服器的 IP (或 主機名稱)
及在「傳輸埠」輸入 代理伺服器 所使用的 port
其餘保留原設定
設定後按「儲存」
以 Safari 瀏覽使用 HTTPS 的網頁同樣不能瀏覽
取得 mitmproxy 的 .cer 憑證
按「安裝」
輸入解鎖密碼
按「安裝」
按「安裝」確認安裝
完成安裝 mitmproxy 憑證
可以檢視 mitmproxy 的憑證資訊
更多 mitmproxy 的憑證資訊
重新整理 HTTPS 網頁便可瀏覽
開啟 Ingress
mitmproxy 側聽到資訊
以 https://m-dot-betaspike.appspot.com/rpc/gameplay/getPaginatedPlexts 為例
選取後按 ENTER 可以查看資訊
其中
HTTP Request header 的 Cookie, Content-Type, X-XsrfToken
及 HTTP Request body 的 JSON 中的 clientBlob
為關鍵資訊
Cookie 中有一個稱為 SACSID 的資料,並以 ~AJKiYc 為開頭的長字串 (1.92.1 之前為 AJKiYc ,沒有「蛇線」)
Content-Type 必定為 application/json; charset=UTF-8
X-XsrfToken 為一個 41長度的字串,分開2部分
第一部分為 27長度的字串,第二部分為13長度的 Unix Timestamp MS 字串,兩部分中間有一個「:」分隔
Request header 及 JSON 的資料是區分大小寫
按 TAB 可以切換 Request 及 Response
Response 都是 JSON
複製剛才的 HTTP Request header 及 HTTP Request body 的關鍵資訊
再使用如 CURL 的 HTTP Request Tools 發送 HTTP Request
便可以不經 Ingress App 向 Ingress 的伺服器發送 HTTP Request
經過資料搜集後檢查到 Ingress 的 HTTP Request URL
Host 暫時必定是 m-dot-betaspike.appspot.com 並以 HTTPS 為通訊協定
- very-long-string 是故名思義就是一組非常長的字串,是由 Ingress 產生,但暫時未知產生方法
因此 clientBlob 的資料仍然需要由 Ingress App 協助 - 在 Ingress 中,任何物件都有稱為 guid 的特殊編號,包括 Agent, Portal, Link, Field 都有
guid 的格式為「^[0-9a-z]{32}\.[0-9a-z]{2}$」
執行對應操作涉及 Ingress 的物件都要遞交 guid - location 或 playerLocation 需要提供 Agent 身處的經度及緯度
經度及緯度格式均為 「^[0-9a-f]{8}$」即 8位的16進制數值,不足8位,必須補 0
經度及緯度之間有「,」分隔而不存在空格
location 或 playerLocation 必須定屬性名稱不能互換
估計是已經發佈後,再修改需要花時間進行重構,所以沒有統一名稱
/rpc/gameplay/addMod 安裝 Mod JSON 範例 { "params": { "clientBasket": { "clientBlob": "very-long-string" }, "modableGuid": "portal-guid", "modResourceGuid": "mod-guid", "playerLocation": "00000000,00000000", "index": 0 } }index 為 portal 可安裝 Mod 的位置,為 0 至 3 |
/rpc/gameplay/collectItemsFromPortalWithGlyphResponse Glyph Hack JSON 範例 { "params": { "clientBasket": { "clientBlob": "very-long-string" }, "portalGuid": "portal-guid", "location": "00000000,00000000", "glyphGameRequested": false, "userInputGlyphSequence": { "bypassed": false, "glyphSequence": [ { "glyphOrder": "order-0" }, { "glyphOrder": "order-1" }, { "glyphOrder": "order-2" } ], "inputTimeMs": 0 } } }bypassed 為 false 表示不略過 Glyph Hack glyphOrder 為進行 Glyph 時的畫圖次序的字串 |
/rpc/gameplay/collectItemsOrGlyphsFromPortal Hack JSON 範例 { "params": { "clientBasket": { "clientBlob": "very-long-string" }, "portalGuid": "portal-guid", "location": "00000000,00000000", "glyphGameRequested": false } }glyphGameRequested 為 false 表示不使用 Glyph Hack ,但 Glyph Hack 本身亦有另一種 HTTP Request |
/rpc/gameplay/collectItemsOrGlyphsFromPortal Hack No Key JSON 範例 { "params": { "clientBasket": { "clientBlob": "very-long-string" }, "portalGuid": "portal-guid", "location": "00000000,00000000", "glyphGameRequested": false, "spewInfluenceGlyphSequence": { "bypassed": false, "glyphSequence": [ { "glyphOrder": "NOKEY" } ], "inputTimeMs": 0 } } }與 Glyph Hack 的 JSON 相似 分別是 userInputGlyphSequence 改成 spewInfluenceGlyphSequence 而 glyphOrder 指定為 NOKEY |
/rpc/gameplay/collectItemsFromPortalWithGlyphResponse Request Glyph JSON 範例 { "params": { "clientBasket": { "clientBlob": "very-long-string" }, "portalGuid": "portal-guid", "location": "00000000,00000000", "glyphGameRequested": true } } |
/rpc/gameplay/completePassphraseObjective 進行任務時,進行輸入 Passphrase 操作 JSON 範例 { "params": { "clientBasket": { "clientBlob": "very-long-string" }, "missionGuid": "portal-guid", "location": "00000000,00000000", "waypointIndex": 0, "passphraseAnswer": "passphrase" } }passphraseAnswer 為填寫問題的答案字串 |
/rpc/gameplay/createLink 建立 Link JSON 範例 { "params": { "clientBasket": { "clientBlob": "very-long-string" }, "originPortalGuid": "from-portal-guid", "destinationPortalGuid": "to-portal-guid", "linkKeyGuid": "portal-key-guid", "playerLocation": "00000000,00000000" } } |
/rpc/gameplay/deployResonatorV2 部署 Resonator JSON 範例 { "params": { "clientBasket": { "clientBlob": "very-long-string" }, "itemGuids": [ "resonator-guid" ], "portalGuid": "from-portal-guid", "location": "00000000,00000000", "preferredSlot": 0 } }preferredSlot 為 -1 或 0 至 7 當設定為 -1 時,Resonator 會部署在與 Agent 對應的方向 當設定 0 至 7 時,為指定方向
|
/rpc/gameplay/dischargePowerCube 使用 PowerCube JSON 範例 { "params": { "clientBasket": { "clientBlob": "very-long-string" }, "itemGuid": "power-cube-guid", "playerLocation": "00000000,00000000" } } |
/rpc/gameplay/dropItem 掉下物品 JSON 範例 { "params": { "clientBasket": { "clientBlob": "very-long-string" }, "itemGuid": "inventory-guid", "playerLocation": "00000000,00000000" } } |
/rpc/gameplay/fieldTripCardViewed 進行任務時,進行觀看 Portal 操作 JSON 範例 { "params": { "clientBasket": { "clientBlob": "very-long-string" }, "missionGuid": "mission-guid", "location": "00000000,00000000", "fieldTripCardGuid": "trip-guid" } } |
/rpc/gameplay/fireUntargetedRadialWeaponV2 使用 XMP Burster 或 Ultra Striker 攻擊 JSON 範例 { "params": { "clientBasket": { "clientBlob": "very-long-string" }, "encodedBoost": "unknown-encoded-hex-value", "itemGuid": "weapon-guid", "playerLocation": "00000000,00000000" } }encodedBoost 只在使使用 XMP Burster 或 Ultra Striker 攻擊時產生 暫時未知如何計算產生需要依靠 Ingress App |
/rpc/gameplay/flipPortal 使用 Ada Refactor 或 JARVIS Virus JSON 範例 { "params": { "clientBasket": { "clientBlob": "very-long-string" }, "portalGuid": "owned-portal-guid", "resourceGuid": "flip-card-guid", "location": "00000000,00000000" } } |
/rpc/gameplay/getMissionDetails 檢視任務資訊 JSON 範例 { "params": { "clientBasket": { "clientBlob": "very-long-string" }, "value": "mission-guid", "playerLocation": "00000000,00000000" } } |
/rpc/gameplay/getModifiedEntitiesByGuid 檢視 Portal 資訊 JSON 範例 { "params": { "clientBasket": { "clientBlob": "very-long-string" }, "guids": [ "portal-guid" ], "location": "00000000,00000000", "timestampsMs": [ 0 ] } } |
/rpc/gameplay/getNearbyMissions 列出附近任務 JSON 範例 { "params": { "clientBasket": { "clientBlob": "very-long-string" }, "location": "00000000,00000000" } } |
/rpc/gameplay/getTopMissionsForPortal 列出 Portal 的任務 JSON 範例 { "params": { "clientBasket": { "clientBlob": "very-long-string" }, "value": "portal-guid", "playerLocation": "00000000,00000000" } } |
/rpc/gameplay/pickUp 拾取物品 JSON 範例 { "params": { "clientBasket": { "clientBlob": "very-long-string" }, "itemGuid": "inventory-guid", "playerLocation": "00000000,00000000" } } |
/rpc/gameplay/rateMission 評價任務 JSON 範例 { "params": { "clientBasket": { "clientBlob": "very-long-string" }, "missionGuid": "mission-guid", "location": "00000000,00000000", "rating": 1000000 } }rating 為 1000000 表示「是」,為 0 表示「否」 |
/rpc/gameplay/rechargeResonatorsV2 補充 Resonator 能量 JSON 範例 { "params": { "clientBasket": { "clientBlob": "very-long-string" }, "isBoostRecharge": false, "location": "00000000,00000000", "portalGuid": "mission-guid", "resonatorSlots": [ 0, 1, 2, 3, 4, 5, 6, 7 ] } }resonatorSlots 指定對應方向,可不全選全部 Resonator |
/rpc/gameplay/recycleItemsBulk 回收物品 JSON 範例 { "params": { "clientBasket": { "clientBlob": "very-long-string" }, "itemGuids": [ "inventory-0-guid", "inventory-1-guid", "inventory-2-guid" ], "playerLocation": "00000000,00000000" } } |
/rpc/gameplay/remoteRechargeResonatorsV2 遙距補充 Resonator 能量 JSON 範例 { "params": { "clientBasket": { "clientBlob": "very-long-string" }, "isBoostRecharge": false, "location": "00000000,00000000", "portalKeyGuid": "portal-guid", "resonatorSlots": [ 0, 1, 2, 3, 4, 5, 6, 7 ] } } |
/rpc/gameplay/startMission 開始任務 JSON 範例 { "params": { "clientBasket": { "clientBlob": "very-long-string" }, "value": "mission-guid", "playerLocation": "00000000,00000000" } } |
/rpc/gameplay/updateContainer 載入 或 卸載 物品 JSON 範例 { "params": { "clientBasket": { "clientBlob": "very-long-string" }, "containerGuid": "capsule-guid", "inventoryGuidsToLoad": [ "inventory-0-guid", "inventory-1-guid", "inventory-2-guid" ], "containerGuidsToUnload": [ "inventory-0-guid-in-specific-capsule", "inventory-1-guid-in-specific-capsule", "inventory-2-guid-in-specific-capsule" ], "playerLocation": "00000000,00000000" } } |
/rpc/gameplay/upgradeResonatorV2 升級 Resonator JSON 範例 { "params": { "clientBasket": { "clientBlob": "very-long-string" }, "emitterGuid": "resonator-guid", "portalGuid": "portal-guid", "location": "00000000,00000000", "resonatorSlotToUpgrade": 0 } }resonatorSlotToUpgrade 與 resonatorSlots 對應的位置數值相同 |
/rpc/geoInfo/getPortalImages 列出 Portal 的圖片 JSON 範例 { "params": { "portalGuid": "portal-guid", "maxItemsPerPage": 10 } }maxItemsPerPage 最大數值為 10 |
/rpc/player/say 發送 Comm 訊息 JSON 範例 { "params": { "factionOnly": true, "message": "message" } }factionOnly 為 true 表示只有與自己相同陣形的 Agent 才能查看,false 表示不同陣形的 Agent 亦可查看 message 為傳送的訊息 |
/rpc/playerUndecorated/getGameScore 顯示全球分數 JSON 範例 { "params": [ ] } |
/rpc/playerUndecorated/getInventory 列出物品 JSON 範例 { "params": { "lastQueryTimestamp": 0 } }lastQueryTimestamp 為 unix timestamp 準確至毫秒,該時間後所獲得的物品,當為 0 時表示全部物品 |
/rpc/playerUndecorated/getInviteInfo 列出邀請資訊 JSON 範例 { "params": [ ] } |
/rpc/playerUndecorated/getNickNamesFromPlayerIds 以 GUID 取回 Agent 代號 JSON 範例 { "params": [ [ "agent-guid" ] ] } |
/rpc/playerUndecorated/getPaginatedMissionBadges 載入更多任務徽章 JSON 範例 { "params": [ { "continuationToken": "continuation-token" } ] }首個 continuationToken 需於 /rpc/playerUndecorated/getAgentProfile 創建,列出往後最多 10個 任務徽章 之後的 continuationToken 便能透過自身創建 |
/rpc/playerUndecorated/getPlayerProfile 顯示 Agent 資訊 JSON 範例 { "params": [ "agent-code" ] }agent-code 為 Agent 代號,例如在下的 HKGoldenMrA |
/rpc/playerUndecorated/getRegionScoreByLocation 顯示地區分數 JSON 範例 { "params": { "location": "00000000,00000000" } } |
/rpc/playerUndecorated/inviteViaEmail 發送邀請 E-Mail JSON 範例 { "params": { "inviteeEmailAddress": "email", "customMessage": "message" } }inviteeEmailAddress 為收件者的 E-Mail ,必須透過邀請 E-Mail 進行安裝 Ingress App 的新玩家才計算 Recruiter 成就 |
/rpc/playerUndecorated/redeemReward 兌換獎勵 JSON 範例 { "params": [ "passcode" ] }passcode 為兌換獎勵的兌換碼 |
/rpc/playerUndecorated/setNotificationSettings 設定語言、是否顯示通知、促銷、其他 Agent 通訊、Portal 被攻擊、邀請、最新消息資訊 JSON 範例 { "params": [ { "clientBasket": { }, "notificationSettings": { "locale": "en_US", "shouldSendEmail": true, "maySendPromoEmail": true, "shouldPushNotifyForAtPlayer": true, "shouldPushNotifyForPortalAttacks": true, "shouldPushNotifyForInvitesAndFactionInfo": true, "shouldPushNotifyForNewsOfTheDay": true } } ] }locale 為設定語言 shouldSendEmail 為設定是否顯示通知資訊 maySendPromoEmail 為設定是否顯示促銷資訊 shouldPushNotifyForAtPlayer 為設定是否顯示其他 Agent 通訊資訊 shouldPushNotifyForPortalAttacks 為設定是否顯示Portal 被攻擊資訊 shouldPushNotifyForInvitesAndFactionInfo 為設定是否顯示邀請資訊 shouldPushNotifyForNewsOfTheDay 為設定是否顯示最新消息資訊 |
/rpc/playerUndecorated/setPortalDetailsForCuration 更新 Portal 資訊 JSON 範例 { "params": [ { "curationType": "PLAYER_EDIT", "portalGuid": "portal-guid", "title": "title", "description": "description" } ] }curationType 暫時必須為 PLAYER_EDIT title 為 Portal 的顯示名稱 description 為 Portal 的顯示描述資料 title 及 description 不能為空字串,最少必須使用其中一種屬性,不使用的屬性為保持原來資料 |
/rpc/playerUndecorated/setProfileSettings 設定是否顯示詳細 Agent 的資訊 JSON 範例 { "params": [ { "areMetricsPublic": true } ] }areMetricsPublic 為設定能否讓其他 Agent 查看數據 true 為可以查看,false 為不能 |
不同的錯誤代號及對應的錯誤訊息
錯誤代號 | 錯誤訊息 |
---|---|
CONTAINED_WITHIN_CAPTURED_REGION | Portal is within existing field |
CROSSES_EXISTING_LINK | Link crosses an existing link |
DESTINATION_MUST_BE_FULL | Portal missing Resonators |
DESTINATION_UNOWNED | Neutral destination Portal |
DESTINATION_WRONG_TEAM | Enemy Portal |
EDGE_ALREADY_EXISTS | Link already exists |
INDEX_OUT_OF_BOUNDS | INDEX_OUT_OF_BOUNDS |
INVENTORY_FULL | Too many items in Inventory. Your Inventory can have no more than 2000 items |
ITEM_DOES_NOT_EXIST | Item does not exist |
MISSION_DOES_NOT_EXIST | MISSION_DOES_NOT_EXIST |
NEED_MORE_ENERGY | You don't have enough XM |
NO_MISSION_ACTIVE | NO_MISSION_ACTIVE |
ORIGIN_LINK_CAPACITY_REACHED | Portal can't support more Links |
OUT_OF_RANGE | Portal is out of range |
PLAYER_LIMIT_REACHED | PLAYER_LIMIT_REACHED |
PORTAL_AT_MAX_RESONATORS | Portal has all resonators |
PORTAL_BELONGS_TO_ENEMY | Enemy Portal |
PORTAL_OUT_OF_RANGE | Portal out of range |
SERVER_ERROR | Server error |
RESONATORS_FULLY_CHARGED | Fully charged |
TOO_MANY_RESONATORS_FOR_LEVEL_BY_USER | Too many resonators with same level by you |
TOO_OFTEN | Portal burned out! It may take significant time for the Portal to reset |
TOO_SOON_5_SECS | Portal running hot! Unsafe to acquire items. Estimated time to cooldown: 5 seconds |
TOO_SOON_10_SECS | Portal running hot! Unsafe to acquire items. Estimated time to cooldown: 10 seconds |
TOO_SOON_20_SECS | Portal running hot! Unsafe to acquire items. Estimated time to cooldown: 20 seconds |
TOO_SOON_30_SECS | Portal running hot! Unsafe to acquire items. Estimated time to cooldown: 30 seconds |
TOO_SOON_60_SECS | Portal running hot! Unsafe to acquire items. Estimated time to cooldown: 60 seconds |
TOO_SOON_120_SECS | Portal running hot! Unsafe to acquire items. Estimated time to cooldown: 120 seconds |
TOO_SOON_180_SECS | Portal running hot! Unsafe to acquire items. Estimated time to cooldown: 180 seconds |
TOO_SOON_240_SECS | Portal running hot! Unsafe to acquire items. Estimated time to cooldown: 240 seconds |
TOO_SOON_BIG | Portal running hot! Unsafe to acquire items. Estimated time to cooldown: 300 seconds |
在下以 Java 編寫了一個仍未算完全的工具,有興趣可以參與及改進
https://bitbucket.org/hkgoldenmra/google-api-for-java
可以使用 git 下載
git clone https://bitbucket.org/hkgoldenmra/google-api-for-java.git
雖然這種遊戲方法相信不是 Ingress 期望玩家的遊玩方法,但這種技術令在下學習更多知識
本文章得到 朝陽科技大學資訊管理系碩士論文:手機應用程式隱私窺探報告 參考
拜讀!
回覆刪除