1. 程式人生 > >android黑科技系列——微信定位聊天記錄中照片的位置信息插件開發詳解

android黑科技系列——微信定位聊天記錄中照片的位置信息插件開發詳解

poi 圖片查看 遍歷 什麽 term 反射 還需要 資料 避免

一、前言

最近關於微信中,朋友之間發送原圖就可能暴露你的位置信息,其實這個問題不在於微信,微信是為了更好的體驗效果,才有發送原圖功能,而對於拍照,發送普通圖片微信後臺都會過濾圖片的exif信息,這樣就不會攜帶位置信息了。我們本身用手機自帶的相機拍攝照片默認都是會在圖片中添加位置信息的。當然我們也可以手動的關閉這個功能。這一點個人覺得不能怪微信。因為更好的逆向學習,和用戶體驗,本文將開發一套更加好用的插件,就是選擇圖片直接利用微信自帶的地圖功能,定位圖片位置。這個過程會很麻煩。但是本文會逐一詳細介紹的。在介紹這個插件之前,必須了解我之前介紹的一款插件功能:如何轉發小視頻到朋友圈插件,本文的插件是基於這個插件的基礎之上操作的。所以必須看懂這個插件原理才能繼續閱讀本文。

二、添加入口菜單

下面來開始操作了,首先不多說了,先給大家看看插件的效果,這樣會有一個感官認識:

技術分享

我們在聊天中,點擊一張圖片,然後會彈出一個菜單,我們需要在這個菜單中添加一項就是定位入口,那麽這裏的第一個突破口,就是如何找到添加這個入口呢?這個簡單。我們可以通過默認的菜單文案找到關鍵代碼,這裏通過反編譯微信之後,查看他的字符串信息:

技術分享

然後在用Jadx打開微信全局搜索即可:

技術分享

這裏有多個,但是為什麽選擇第二個呢?因為我們點進去會發現正是我們想要的菜單,這裏搜索結果不算多,可以一個個嘗試查看:

技術分享

這裏正好對應上了,那個彈出菜單的三個選項。所以入口就在這裏了,下面看看他是如何添加菜單的:

技術分享

這裏定義了一個內部類,然後遍歷列表開始構造菜單信息,點進去方法看看如何構造:

技術分享

看到了MenuItem類就可以完全確定了,這裏是構造菜單了,看到這裏傳入的兩個參數一個是菜單索引值,一個是菜單名稱,構造完之後在存入到全局變量列表ktX中,後面我們需要直接操作這個ktX列表數據:

技術分享

既然找到了這裏添加菜單的位置,下面我們就開始利用Xposed進行hook,添加我們自定義的菜單了,但是在操作之前,我們需要解決兩個問題:

第一個問題:看到上面我們需要hook的類ImageGalleryUI的內部類,這個需要我們去反編譯之後的smali文件夾中找到這個內部類名稱。

第二個問題:是hook的那個b方法參數是對象類型,這裏需要先加載這個類類型才能進行hook操作

我們去反編譯之後的smali文件夾看看這個內部類叫啥:

技術分享

這裏看到有十幾個內部類,這裏我們需要通過上面的那個內部類的方法簽名判斷,所以依次打開每個內部類文件進行確認,最終確認到了是ImageGalleryUI$12.smali這個類:

技術分享

找到這個內部類之後,下面就是正常的hook代碼了:

技術分享

不過,這裏需要註意,我們需要把菜單添加到最末尾,所以還需要拿到已經添加的菜單個數,也就是上面提到的那個全局菜單列表,這裏用反射獲取即可。而且需要保存這個列表大小信息,後面再處理菜單點擊事件還要用到。

操作完成之後,我們就開始安裝這個Xposed模塊,重啟生效,看看是否添加成功了:

技術分享

看到這裏是添加成功了,所以這一步就完成了,下面開始攔截這個菜單的點擊事件了。繼續看代碼:

技術分享

看到這裏有很多賦值的地方,可以猜想eCN是管理菜單的核心類,點進去查看:

技術分享

這裏可以確定了,就是這個類管理菜單的功能,他還實現了菜單的點擊實現接口,找點擊菜單的回調方法:

技術分享

這裏看到會通過heu中的菜單列表,找到MenuItem菜單對象,然後調用het的d方法處理菜單點擊事件,看看het在哪裏賦值的:

技術分享

看看變量kVb的定義:

技術分享

果然沒錯,這個又是一個內部類,回調d方法,獲取菜單對象和菜單索引值,然後處理菜單的點擊事件。那麽這裏我們依然需要找到這個內部類,然後hook即可。去smali文件夾依次通過方法的簽名信息找到對應的內部類文件:

技術分享

這裏hook就簡單了:

技術分享

安裝這個模塊,重啟生效,看看點擊之後的日誌信息:

技術分享

OK,到這裏,我們就處理了菜單的點擊事件了,同時把圖片獲取位置信息的入口操作弄完了,下面就要開始本文的重點了,如果獲取這張圖片位置信息了。

三、獲取圖片存儲地址

我們知道Android中的圖片會把經緯度信息保存在圖片的exif中,而讀取這個信息代碼非常簡單:

技術分享

這裏的重點是,如何獲取我們想要操作的圖片位置呢?這個就需要借助之前提到的那個轉發視頻插件知識了,不了解的同學一定要去查看。這裏不多解釋了,直接把那個插件安裝之後,通過日誌查看突破口,我們在聊天界面選中一張圖片,然後查看日誌信息:

技術分享

這是當初微信視頻轉發的菜單攔截功能代碼,這裏我們通過打印日誌查看,這一次我們選中圖片信息:

技術分享

這時候,查看日誌:

技術分享

看到,這裏的圖片地址,信息是一個特殊字符串開頭的,我們可以全局搜索這個開頭前綴信息:

技術分享

這裏看到有很多都是這個f類:

技術分享

這裏看到這個方法,我們不妨先來直接hook他,看看有麽有日誌打印信息,把最後參數和返回值都打印一下,這樣來確定這個方法是否是我們想要的。這裏有點靠著嘗試思維,因為本來逆向就是靠猜的,而且攔截這麽一個方法也不費事:

技術分享

運行模塊,重啟生效,看看日誌信息:技術分享

盡然猜對了,看到圖片地址了,返回地址就是我們想要的圖片地址。那麽這裏就簡單了,我們直接hook這個方法然後保存這個方法的返回值即可,我們也發現了,這個方法會執行多次,不多我們只要在最後一次正確的保存圖片地址後面處理即可。

四、獲取圖片的位置信息

到這裏,圖片地址也拿到了,那些面就簡單了,開始獲取經緯度信息吧,但是拿到經緯度信息之後,如何獲取具體位置信息呢?這裏有幾種方案:

第一種方案:借助高德或者百度地圖提供的SDK,可以輸入經緯度就能拿到位置信息了,而且可以利用地圖View進行展示,不過這種方案不可用,因為我們知道這種地圖SDK使用的話都需要在xml中配置key信息。我們現在是hook代碼,如果再去反編譯微信,添加key,然後在回編譯就太費勁了。沒這個必要了。

第二種方案:借助百度提供的網頁url獲取位置信息,這個是百度開發的一個url請求,只要根據經緯度信息,就能返回json或者xml格式的位置信息,然後我們在利用微信內部的地圖功能進行展示具體位置。

這裏第二種方案是最靠譜的,不過第二種方案需要做兩件事:

第一件:通過開發的url獲取位置信息

獲取位置信息地址:http://api.map.baidu.com/geocoder/v2/

參數location:經緯度信息,用逗號連接

參數output:返回的數據格式,可以是json,或者xml

參數pois:這個可以忽略,直接用1即可

參數ak:這個是請求位置信息需要的key值,這個需要去百度平臺申請。

技術分享

好了,我們直接利用圖片的經緯度信息去請求這個位置信息,返回json數據,我們解析出位置主要地址,和後面的輔助地址。然後調用微信內部地圖信息即可。


第二件:利用微信內部地圖功能進行展示位置

我們知道微信內部用的是自家的地圖功能,我們可以利用命令找到入口,首先打開內部一個地圖信息,這個可以在聊天記錄中發送位置信息,然後打開即可。這時候利用:adb shell dumpsys activity top 命令獲取地圖界面:

技術分享

然後用Jadx工具全局搜索這個類即可。不過可惜的是,這裏搜索沒結果的:

技術分享

這時候要想到了,微信是拆包了,有多個dex文件,而之前已經說過了,微信的第二個dex是打包成jar文件,放在assets目錄中的:

技術分享

解壓jar文件拿到classes.dex就是他的第二個dex文件,我們用Jadx打開這個dex即可:

技術分享

這就搜索到了,我們點進去查看即可:

技術分享

那麽這裏就好辦了,我們可以啟動這個activity,通過intent傳遞需要的參數信息。但是這裏有兩個問題需要解決:

第一個問題:啟動Activity需要微信中的一個activity實例,這個我們可以hook上面提到的ImageGalleryUI這個類,拿到對象實例即可。這個hook很簡單,直接hook他的onResume方法,然後獲取對象實例即可:

技術分享

第二個問題:如何獲取啟動地圖頁面的intent中的參數信息,這個可以通過代碼分析,但是這裏可能攜帶的參數信息很多,為了避免遺漏,我們用另外一種方法就是,hook這個地圖頁面啟動的onResume方法,拿到對象實例,然後通過getIntent方法獲取當前頁面的intent數據,在拿到對應的Bundle結果,可以遍歷他所有的參數key和值信息,我們hook之後,隨便打開微信內部一個地圖信息,看看hook的參數日誌都有哪些,這裏我打開的是聊天記錄中發送的位置信息:

技術分享

這裏需要註意,因為我們已經知道這個類是在第二個dex中,所以hook操作就需要拿到正確的類加載器才能加載這個類進行hook操作。而hook多dex的應用,之前已經說過了,需要先hook應用的Application的attach方法,然後拿到正確的ClassLoader,才能繼續下面的hook操作。這個方法一定要記住。非常關鍵。

然後安裝模塊,重啟生效,看日誌信息:

技術分享

這裏看到的確有很多信息,不過這裏分析之後,發現只有這五個參數信息是最關鍵的,其他參數我麽可以照著抄過來就好了,關鍵的五個參數信息是:

kwebmap_slat:經度

kwebmap_lng:緯度

kPoiName:地圖頁面中展示的主地址

Kwebmap_locaion:地圖頁面中展示的從地址

kwebmap_scale:地圖默認縮放的大小

有了這上面的信息,下面就來啟動頁面代碼吧:

技術分享

這裏需要註意,啟動的地圖頁面Activity的類變量,一定要用多dex的hook方法加載到,這個時機也要最早的。然後保存下面即可。技術分享

然後就用之前已經hook到的ImageGalleryUI這個activity實例啟動即可。

五、插件功能流程總結

到這裏我們已經完成了大部分的工作了,下面來整理整個hook流程吧:

第一步:通過聊天中查看圖片信息hook方法拿到圖片地址進行保存。

第二步:獲取圖片的exif信息,獲取經緯度信息。

第三步:借助百度開發api通過經緯度信息獲取具體位置信息。

第四步:有了經緯度和位置信息,啟動微信內部的地圖頁面進行展示。

而在這個過程之前,我們還需要添加一個入口,那就是在聊天記錄中點擊圖片查看,然後長按彈出菜單中加一個展示位置信息入口。

有了這些步驟,還不算完美,因為我們在第三步是需要請求百度開發api的,這個是一個等待過程,所以這個過程中,我們還需要加一個loading樣式,不然插件體驗很不好的。而我做事只求完美,不求到位。這裏的loading樣式怎麽辦呢?還是拿來主義。利用微信內部資源實現即可。這裏也是一個技巧了,看我怎麽操作的:

首先去微信反編譯之後的資源目錄下查看,找到一個合適的作為loading圖片資源,這裏我看到這個資源:

技術分享

這個資源好看,然後我們自定義一個旋轉動畫,就類似於loading效果了,關於旋轉動畫不多說了,網上一大堆資料:

技術分享

這裏讀取資源,可以直接用上面資源的id值即可,這個值可以通過values/public.xml中獲取:

技術分享

然後自定義這個loading視圖:

技術分享

最後在借助WindowManager來進行展示loading視圖,這裏可以直接代碼編寫布局即可:

技術分享

好了,下面來看一下展示效果:

技術分享

六、總結

好了,到這裏,我們就全部介紹完了,知識點的確很多,文章也很長。因為我們做的功能太多了。哈哈,下面來總結本次操作的技術知識點:

第一、在獲取hook點的時候,有時候利用Xposed進行hook嘗試也是一種方案,比如本文的獲取圖片地址,以及獲取地圖啟動的參數信息,都是很好的例子。不要一根筋完全去分析代碼實現。hook打印參數和返回值信息也是很好的選擇。

第二、多dex應用進行hook的時候,一定要記得先hook應用的Application類的attach方法,獲取到正確的類加載,在進行後續的hook操作。

第三、通過經緯度信息獲取具體位置信息,可以利用百度開發api獲取,這個記住,以後或許還有很多地方要用到。

第四、如果在hook中想添加UI的功能,可以利用現有應用內部資源,利用代碼編寫布局動畫即可。

好了到這裏,也介紹完了插件功能了。不過可惜的是,這個不是所有的圖片都能獲取到位置信息的,開始的時候也說了,微信有一個發送原圖功能,也就是只有原圖可以獲取到經緯度信息,而通過微信內部拍照,或者發送壓縮圖都會被微信服務器過濾exif信息。我們本地已經沒辦法獲取到了。那麽此插件就喪失了功能。最後再來看一下插件效果圖:

技術分享

註意:

本文用到的是微信6.3.9版本,最新版本可能有區別,不過逆向過程大同小異。有很多同學問了很多次Jadx打開微信會卡死怎麽辦?因為微信內部資源太多。所以直接打開apk會卡死的。主要是Jadx解析微信資源文件非常耗內存。所以可以解壓apk之後直接用Jadx打開多個dex即可。希望以後不要再問我了。

android黑科技系列——微信定位聊天記錄中照片的位置信息插件開發詳解