Android實現(xiàn)微信朋友圈發(fā)本地視頻功能
一、前言
前一篇文章已經詳細介紹了如何使用Xposed框架編寫第一個微信插件:搖骰子和猜拳作弊器 本文繼續(xù)來介紹如何使用Xposed框架編寫第二個微信插件,可以將本地小視頻發(fā)布到朋友圈的功能。在這之前我們還是要有老套路,準備工作要做好,這里還是使用微信6.3.9版本進行操作,準備工作:
1、使用apktool工具進行反編譯,微信沒有做加固防護,所以這個版本的微信包反編譯是沒有任何問題的。
2、借助于可視化反編譯工具Jadx打開微信包,后續(xù)幾乎重要分析都是借助這個工具來操作的。
二、猜想與假設
做好上面這兩步之后,加上我們在之前的那個編寫插件的基礎之上,我們本次操作就應該非常簡單了,還記得之前的插件的突破口是啥嗎?看過文章的同學應該了解通過分析界面的控件來獲取到id值,然后全局搜索得到的突破口,那么本文其實可能不需要這個方式了,而是另外一種方式,下面來詳細介紹一下。在這之前我們先來看看微信正常的發(fā)布小視頻到朋友圈的方式,會跳轉到這個發(fā)布頁面:
那么我們又要開始大膽的猜想了:
首先這個頁面有的元素:標題,小視頻,地理位置等信息,而這些信息應該會在請求發(fā)布的時候攜帶到服務器上。這個有點類似于小文件的上傳功能。所以這個視頻的文件是如何得到的。那么可以得到的假設:這個頁面是一個Activity頁面,可能從其他頁面跳轉過來的,同時會把這些元素信息通過intent攜帶過來,而小視頻是個文件,所以應該會攜帶文件的名稱。
三、逆向分析
有了這猜想之后,咋們就可以開始操作了,首先得到這個頁面的activity名稱,這個比較簡單了,直接使用一個命令即可:adb shell dumpsys activity top
看到這個頁面的名稱是SightUploadUI,我們借助Jadx反編譯微信之后,找到這個類:
我們直接看onCreate方法中有沒有對intent參數(shù)解析操作,或者我們可以在這個類中全局搜一下getIntent字段,也可以快速得到解析的地方:
看到第一個字段Kdescription,從字段的名稱來看應該是描述信息,而從下面的代碼setText調用更可以確認了這個就是標題信息。我們繼續(xù)查找:
又發(fā)現(xiàn)了一個字段KSightDraftEntrance,這塊代碼就有點多了,他是一個boolean類型,所以先不管了,因為后面即使是嘗試的話也就兩次操作,一次false一次true。不礙事的!可是到這里我們在也搜不到其他字段了,但是這個就和我們的預期不一樣了,還差幾個元素信息呢?最重要的視頻文件路徑沒有,所以這個就要想起在onCreate方法中有一個ae類初始化的時候把當前activity傳遞進去了,那么可能他內部繼續(xù)進行了參數(shù)解析,我們可以進去查看一下:
果然在他內部還有三個字段解析,分別是:KSightThumbPath,KSightPath,sight_md5;而從字段命名上來看猜想這個應該就是和視頻信息相關的字段了。這里只要有Android開發(fā)經驗的同學應該可以猜想:KSightPath字段是短視頻路徑,KSightThumbPath是短視頻的默認封面圖,sight_md5是短視頻的校驗值。到這里其實我們已經感覺快成功了,得到了這五個參數(shù),那么我們可以直接嘗試了操作了:
在本地存放一個短視頻,封面圖片,然后計算短視頻的md5碼,最后通過intent來啟動這個頁面即可。先不管后面的上傳過程了,咋們可以先試驗能成功跳轉到這個頁面展示本地小視頻功能。
可惜到這里我們有一個問題,就是怎么獲取這個啟動頁面的activity呢?也就是用哪個activity來啟動他呢?有的同學可能這么干?直接簡單明了的編寫一個小程序,然后用小程序的activity啟動這個頁面。這個猜想是可以的,不過我沒嘗試,因為我想微信做了activity啟動安全防護的,不可能在其他應用中可以啟動微信中的任意一個頁面。所以這里我就沒費那勁了。而是想到用微信自己的頁面來啟動他,那么如何獲取到微信的一個其他頁面呢?這個也簡單。咋們可以打開一個聊天頁面,繼續(xù)使用adb shell dumpsys activity top 命令查看頁面:
好了,就是這個LauncherUI頁面了,那么知道這個頁面下面怎么獲取這個對象呢?這時候就需要借助Xposed框架進行Hook了,代碼如下:
看到了吧,代碼很簡單的,我們hook頁面的onResume方法,因為這時候頁面已經初始化完成了是整個Activity生命周期中的比較晚的一個方法了,所以攔截他就可以了。然后在攔截回調用使用MethodHookParam的thisObject屬性就可以得到這個方法所屬的對象了,也就是LauncherUI類型了。
好了既然現(xiàn)在微信啟動頁面也有了,下面就簡單了,直接構造上面的五個參數(shù)得到intent直接啟動:
代碼很簡單,咋們直接運行模塊,然后重啟設備生效,然后打開微信界面瞬間看到效果了:
果然跳轉到這個頁面了,也就是說我們的猜想對了,下面我們點擊發(fā)送,會發(fā)現(xiàn)發(fā)送失敗了:
原因可能有兩個:
1、沒有弄對視頻文件的MD5碼
2、視頻格式不符合服務器接受的要求:視頻的長度和視頻的大小
關于第二個原因,其實網上有答案,就是微信這個發(fā)布的小視頻長度不能超過15s,大小不能超過1M。所以這里我就把本地視頻做成了符合這兩個標準的,再次操作依然是這樣的失敗效果。那么就有可能猜想是視頻的MD5碼校驗出問題了,上面看到代碼中我傳入的MD5碼是aaa,我是為了方便沒去弄。但是這里就必須寫了。獲取文件的MD5碼這里就不多解釋了,不過可惜的是,MD5弄成文件的還是失敗。那么這時候就猜想他或許不是真正意義上的MD5值了,可能加上了他自己的一個算法了。所以又來了一個問題,如何得到這個算法呢?
這時候就需要跟蹤代碼看看其他頁面跳轉到這個頁面攜帶過來的MD5碼是什么呢?我們可以這么干就是全局搜索那五個字段中的任意一個即可,這里在Jadx中全局搜索:sight_md5
我們點擊進入查看方法:
繼續(xù)查找這個方法在哪被調用了:
咋們繼續(xù)點擊進入查看:
這里看到了倒數(shù)第二個參數(shù)就是那個MD5碼值,我們在全局搜一下這個變量在哪里被使用到了:
看到這里有賦值的地方,點擊進入查看:
然后查看這個kbVar變量,在上面的代碼中:
這里我們可以先看看這個kb類的定義:
這里的aFL就是那個MD5碼值了,我們繼續(xù)上面的那個a方法查看哪些地方調用了,不過查找是沒有效果的,因為這個方法可能是抽象的,所以咋們得找到他抽象定義的地方,在上面就是一個抽象類c:
然后進入c類查看抽象方法a:
然后查找a方法調用的地方:
繼續(xù)查看這個方法的調用地方:
這時候我們多看一下,這個方法所屬的類是個單例:
那么繼續(xù)查看這個g方法被調用的地方,或者全局搜一下jJA這個變量的使用也可以的:
又回到了剛剛的那個MainSightContainerView類了,這里看到了賦值的地方了,而且是給aFL字段賦值的,這個就是上面看到kb類中的字段值,這里依然調用了一個方法計算MD5碼值,而且傳入的參數(shù)是視頻路徑:
這里首先判斷當前視頻文件是否存在,然后在進行文件操作:
真正加密算法是在a方法中,這里也可以看到因為計算文件的MD5碼是耗時的,所以這里做了一個優(yōu)化,只會計算文件的前100KB數(shù)據:
哎,到這里終于真相大白了,看到他的確是用了MD5算法,只是在后面自己又高了一個簡單的算法。所以這里我們?yōu)榱撕唵?,可以直接把這三個方法拷貝到我們的Xposed模塊代碼中:
然后在把之前的intent中的sight_md5字段值替換一下:
這時候咋們在之前的攔截的onResume方法中再次調用,然后重啟設備生效,點擊發(fā)送:
哈哈,到這里可以看到,發(fā)送成功啦啦,好興奮呀。終于實現(xiàn)了這個功能。以后可以盡情的裝逼了。
注意:在上面我們定位一個方法在哪些地方被調用,有時候可能找不到,但是不代表這個方法真的沒有被調用,而是因為這個方法是抽象的,直接跟蹤可能沒有效果,這時候就需要去抽象方法的定義地方去全局搜索就可以了。
四、添加發(fā)布事件
但是到這里我們是否就結束了本次操作了,其實并沒有,因為有的同學在上面的實踐中會發(fā)現(xiàn),有時候微信會打不開,一打開就閃退,其實這個原因是我們雖然攔截了LauncherUI頁面的onResume方法,但是這個頁面比較獨特的是微信中的首頁也是他,所以這就有可能出現(xiàn)你剛剛要打開微信頁面,有些初始化操作沒做完,而這時候你就立馬跳轉到SightUploadUI頁面去發(fā)布視頻會出現(xiàn)問題。所以這里就存在一個發(fā)布視頻的觸發(fā)時機,為了更好的體驗效果,我們決定做到更人性化,就是添加一個菜單可以點擊的時候再去觸發(fā)發(fā)布視頻邏輯。那么又來了一個問題就是如何在微信中添加一個我們自己想要的菜單?這個我覺得比上面那個還簡單點,我們準備在聊天界面中選中一條消息之后彈出的菜單中加一項子菜單:
就是在這里,我們加一項,有的同學覺得這個可能會比較麻煩,其實很簡單,我們只要找到這個菜單定義的地方即可。直接看看步驟:想得到這個菜單定義地方很簡單,咋們先去反編譯之后的values/strings.xml文件中找到這個字符串的定義:
得到他的id值是ne,然后在Jadx中全局搜索:R.string.ne
注意:這里可能有的同學會好奇,在之前一篇文章中不是得去public.xml中找到ne對應的id整型值,然后全局搜索嗎?這里可能和微信做了資源混淆工作有關,開始的時候通過整型值死活沒找到,最后無意間用了這種方式找到了。所以以后我們可以先用標準方案去public.xml中找到id對應的整型值,如果沒找到,在使用這種方式進行查找即可。
上面找到這個字符串定義的地方,直接點擊進入即可:
這里可以看到了,使用了系統(tǒng)提供的ContextMenu類進行菜單定義的,這里就需要你對這個類了解了。后面添加菜單就必須用add方法來進行添加了,不過這個方法還是比較簡單的,參數(shù)都比較好理解主要是菜單組的id值,菜單自身的id值,菜單名稱,然后在設置點擊事件即可。下面我們繼續(xù)看這個方法在哪里被調用了:
不過這個方法跟蹤沒有結果,猜想他可能是一個抽象方法,所以就去他定義的地方進行查看y類:
果然是一個抽象方法,這里在跟蹤就可以了:
點擊查找結果:
繼續(xù)看這段代碼之前的方法和類定義:
這里有一個變量fHr,也就是菜單創(chuàng)建的回調接口,在往上面查看:
到這里就看明白了,在ChattingUI有一個內部靜態(tài)類a,在這個類內部開始創(chuàng)建菜單,然后定義一個fHr變量代表菜單創(chuàng)建的回調接口類型,然后在onCreateContextMenu回調方法中進行子菜單添加工作。
好了上面就分析了菜單的創(chuàng)建代碼,下面咋們就開始操練了,還是得借助Xposed進行攔截了,這次攔截哪個呢?咋們可以攔截ChattingUI這個類的靜態(tài)內部類a,然后我們自己在定義一個創(chuàng)建菜單的接口,去替換fHr變量的值,最后我們只要在我們的回調接口中操作即可:
這里攔截代碼也是比較簡單的,主要是定義我們自己的回調接口,然后在替換fHr值即可,再來看看接口定義:
這里才是最關鍵的代碼了,在onCreateContextMenu回調方法中創(chuàng)建一個菜單,但是這里有一個問題就是怎么獲取到菜單組的id值,這個我們還得回到開始的那個添加菜單代碼:
看到,這里他是先通過view的tag得到dd對象,然后在調用position屬性即可,那么我們操作也就簡單了,繼續(xù)使用反射機制就可以得到這個值了。代碼如上。
代碼編寫完之后再次運行之后,重啟設備生效,打開一個聊天室然后選中一條消息:
哈哈看到這個菜單選項了,咋們點擊之后就可以跳轉到發(fā)布頁面了:
五、知識概要與技巧總結
好了到這里我們就完成了本文提到的如何將本地小視頻發(fā)布到朋友圈功能實現(xiàn),下面來總結一下本文的實現(xiàn)步驟以及能夠學習到的逆向技巧:
1、首先猜想微信發(fā)布視頻的頁面中的幾個重要元素信息:標題,視頻信息,地理位置等,然后這些信息可能在其他頁面通過intent傳遞過來的,那么應該不可能傳遞整個視頻數(shù)據,而是視頻路徑。
2、帶著猜想就去實踐,使用命令找到發(fā)布視頻的頁面activity名稱,然后去jadx中找到這個類分析intent中的字段,果然能夠得到五個重要的參數(shù)信息:Kdescription,KSightDraftEntrance,KSightThumbPath,KSightPath,sight_md5。
3、然后有了這五個字段再次猜想每個字段的含義,然后就直接做了一個簡單的實驗,在本地存放視頻和封面圖,然后在代碼中構造一個intent,啟動即可。
4、但是在啟動頁面的時候發(fā)現(xiàn)有一個問題就是微信應該做了頁面啟動的安全檢查,有些頁面只能在應用中其他頁面啟動,所以這里還需要得到微信中的一個頁面。這里就用了聊天界面,依然使用adb命令獲取聊天頁面類名稱,然后借助Xposed進行這個頁面的onResume方法攔截,然后在攔截之后啟動發(fā)布視頻頁面。
5、實驗之后發(fā)現(xiàn)既然可以直接調用起來,說明上面的第一步猜想對了,那幾個字段我們也猜對了,但是這時候發(fā)現(xiàn)點擊發(fā)送的時候出現(xiàn)了失敗現(xiàn)象。然后分析失敗的原因有兩個:一個是微信服務器對發(fā)布的視頻做了時長和大小限制,還有一個原因是視頻的MD5碼計算錯了。我們通過修改本地視頻的大小和時長之后再次實驗發(fā)現(xiàn)還是失敗,所以可以猜想應該是視頻的MD5碼計算錯誤了,微信自己有一個算法,所以得找到這個算法邏輯。
6、下面就是常規(guī)路線借助Jadx的查找方法調用功能進行跟蹤,在這個過程中學到一個技巧就是如果發(fā)現(xiàn)一個方法沒有被調用有可能是因為這個方法是抽象的,具體得去抽象類中定義的地方繼續(xù)跟蹤才有結果。
7、最終跟蹤到了MD5碼的算法,我們?yōu)榱撕唵?,直接把那幾個方法拷貝出來改一下直接使用,計算視頻的MD5碼,再次實驗之后發(fā)現(xiàn)發(fā)送成功了。
8、在最后發(fā)現(xiàn)一個問題,就是微信的很多頁面都叫做LauncherUI,所以如果攔截這個方法的onResume方法然后就發(fā)送視頻的話會出現(xiàn)問題,導致微信啟動失敗。所以這里就想弄一個事件來控制發(fā)送操作。
9、在聊天頁面中選中一條消息之后可以彈出一個菜單選項,決定在這里添加一項來觸發(fā)發(fā)送操作,這里定位到菜單的創(chuàng)建過程中,用到了前一篇文章中提到的查找資源id方法,但是這里需要注意的是可能微信自己做了資源混淆策略導致這個方法查找id值是失敗的,最后直接使用R.string.xxx這種方式找到了。
學習到的技巧:
1、新的逆向突破口,快速定位頁面,使用adb shell dumpsys activity top命令即可。
2、使用Jadx進行方法跟蹤時候如果發(fā)現(xiàn)沒有結果,可能這個方法是抽象的,需要找到這個抽象方法最原始的定義的地方繼續(xù)跟蹤即可。
3、微信可能做了資源混淆(或者以后遇到做了資源混淆的apk)的時候,如果發(fā)現(xiàn)通過public.xml中的id值查找不到結果,可以直接使用R.xxx.xxx進行查找id值。
六、說明
1、其實本文還可以做一個效果,就是上面在看到聊天界面選中一個消息的時候彈出一個我們自己定義的菜單,可以獲取到這個消息的類型(視頻,文字,圖片,表情等),以及具體信息,直接發(fā)送分享。而這個就需要解析選中之后的消息內容了,當然這個是在本文的項目代碼中已經做了。這里我就不做分析了。
2、因為本文使用了微信6.3.9版本,所以這里進行攔截的方法有:
com.tencent.mm.ui.LauncherUI的onResume方法。
com.tencent.mm.ui.chatting.ChattingUI.a的構造方法,替換fHr變量值。
對于每一個版本混淆之后的類名會發(fā)生變化,所以不要一味的用本文提到的代碼去實踐,要先看懂所有的逆向流程,具體版本具體分析才是王道。
嚴重聲明
本文的目的只有一個,分享更多逆向知識以及逆向技巧,沒有任何商業(yè)目的操作,如果有人利用本文知識實現(xiàn)任何商業(yè)目的帶來的一切法律責任將由操作者本身負責。與本文和作者沒有任何關系。也由衷的希望每位讀者能夠秉著技術學習的態(tài)度閱讀。
七、總結
本文就詳細介紹完了利用Xposed框架實現(xiàn)微信發(fā)送本地小視頻的功能,對于這個功能個人認為還是有用的,但是對于有些人可能并沒有那么用,因為現(xiàn)在在朋友圈中發(fā)布視頻的人會很少,因為即使發(fā)布了由于流量的限制不會有什么效果的。然后就是其實微信對于小視頻做了還是有很多限制的,而這些限制都是在服務端進行的,比如視頻的校驗,時長,大小等。這也就粉碎了小編想發(fā)布一個幾G的電影到朋友圈的夢想。最后當然還是希望每位讀者能夠從本文學習到更多的逆向技巧,小編沒寫這樣逆向文章就會很累,感覺自己被掏空了一樣,所以大家看完一定要記得多多點贊啦,如果有打賞就更好了!
相關文章
Material Design系列之自定義Behavior支持所有View
這篇文章主要為大家詳細介紹了Material Design系列之自定義Behavior支持所有View,具有一定的參考價值,感興趣的小伙伴們可以參考一下2016-09-09Android基于ibeacon實現(xiàn)藍牙考勤功能
這篇文章主要為大家詳細介紹了Android基于ibeacon實現(xiàn)藍牙考勤功能,具有一定的參考價值,感興趣的小伙伴們可以參考一下2018-10-10Android popupWindow彈出窗體實現(xiàn)方法分析
這篇文章主要介紹了Android popupWindow彈出窗體實現(xiàn)方法,結合具體實例形式分析了Android彈出窗體的布局及popupwindow屬性設置、事件監(jiān)聽相關操作技巧,需要的朋友可以參考下2017-07-07Android 中 viewpager 滑動指示器的實例代碼
本文通過實例代碼給大家介紹了android 中 viewpager 滑動指示器,代碼簡單易懂,非常不錯,具有參考借鑒價值,需要的朋友可以參考下2017-12-12Android ViewPager實現(xiàn)智能無限循環(huán)滾動回繞效果
這篇文章主要為大家詳細介紹了Android ViewPager實現(xiàn)智能無限循環(huán)滾動回繞效果,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下2017-07-07