1. 程式人生 > >XPosed外掛自動生成支付寶收款二維碼

XPosed外掛自動生成支付寶收款二維碼

一、前言 前一段時間才偶然看到這個論壇,並且看了一篇@jiangwei212 大神的《》,這才知道XPosed和VirtualXPosed的存在,覺得這個框架神器非常的有意思,所以繼續學習了框架原理和使用方法,我發現有一些做支付寶微信自動收款提醒的網站,有生成二維碼的功能,但是我沒有找到相關開源的外掛,所以就拿支付寶二維碼這個功能先練練手,這個外掛用來實現自定義備註內容和支付金額,自動生成付款二維碼。下面就是我hook支付寶,反編譯程式碼找到關鍵點的一些思路。二、尋找突破口 首先需要找到入手點,生成二維碼的頁面在支付寶首頁中的【收款】選項裡,點選進入後是一個可以設定金額備註生成二維碼的頁面,這個頁面可以用adb shell dumpsys activity top命令檢視到頂層Activity是哪一個,或者更簡單一點,在logcat中,搜尋ActivityManager,看看對應啟動的activity是哪一個,會發現是PayeeQRActivity:
 

接下來,就需要反編譯支付寶的apk,然後看一下這個類的實現,這裡會有兩個問題:

1. 我們都知道二維碼是把一些資訊寫入二維碼圖片中,那麼支付二維碼都需要寫入哪些資訊呢?

2. 知道了寫入資訊,那接下來便是如何生成一個二維碼了。

關於第一個問題,很容易想到,我們要能夠設定備註和金額,所以這兩個資訊也是必須的,其它還需要哪些資訊呢?需要我們看一下具體程式碼,首先就是onCreate方法:

  剛一進入onCreate,我們就能看到請求了一個UserInfo型別的資料,根據名稱應該知道和使用者資訊相關,再看下面的this.c

,就知道是用來標識使用者的唯一ID,還有使用者的暱稱和頭像,應該是用來在頁面做顯示。繼續分析流程:

程式碼塊(1)中看到從preference中讀取了一些字串型別的變數,從key的名稱看應該是和生成二維碼地址有關的資訊,但是前兩個變數的預設值是空,也就是你第一次進入這個頁面的時候,應該讀取出來是空值,之後某些地方會對他們進行賦值。

程式碼塊(2)是建立了一些服務介面類,從名稱看第一個最符合生成二維碼相關的資訊,如果檢視這個介面CollectMoneyRpc的宣告,會發現猜測是正確的,其中的一些方法就是設定金額,備註等資訊。

這些是設定金額和備註相關的Rpc服務介面,之後的程式碼會用到這些介面方法去設定金額和備註並返回資訊。

繼續下面的分析,之後onCreate程式碼就是獲取UI元件相關變數,設定點選監聽等等,比較重要的肯定是設定金額的按鈕:

其中設定金額的點選監聽事件是內部類bi,整個onCreate還有一個b()方法比較可疑,如果檢視該方法的話,會發現是在主執行緒中最終呼叫了一個a(boolean z, ImageView imageView)的方法,該方法可以明顯看出是用來真正生成二維碼並顯示在ImageView上:

至此,onCreate的流程分析完畢,收穫不小,幾乎所有相關的初始化工作都是在這裡進行了,總結一下看到的程式碼流程:

1. 獲取使用者id,有可能會根據id來設定二維碼中的資訊?

2. 獲取RPC遠端呼叫服務介面。

3. 設定和金額相關的按鈕點選監聽。

4. 呼叫生成二維碼方法生成二維碼,這裡就是你第一次進入該頁面而沒有設定任何金額和備註資訊是現實的預設支付二維碼。

 

那接下來,我們首先看一下設定金額和備註按鈕點選時,會發生什麼,方法就是上面提到的內部類bi:

直接看onClick方法,有兩個分支,如果PayeeQRActivity.this.j是空值,會啟動PayeeQRSetMoneyActivity,這個Activity肯定是設定金額和備註的activity了,至於this.j是什麼?先讓我們去看一下新的PayeeQRSetMoneyActivity,這個activity啟動的方式是startActivityForResult,那麼當該activity finish的時候,會回撥到PayeeQRActivity的onActivityResult,讓我們來看一下這幾個流程,先來看一下PayeeQRSetMoneyActivity:

首先依舊會請求一個CollectMoneyRpc服務介面,看來是要在這裡實際設定金額,然後會有個一sessionId,這個sessionId具體是什麼值我沒有找到,但是不影響繼續分析,然後根據支付寶設定金額頁面UI來看,最終會點選【確認】按鈕完成設定,也就是圖中的this.e和監聽回撥ct,ct最終的處理方法是該類的a方法:

一個真正使用rpc介面進行非同步呼叫的函式,RpcRunner的兩個引數第一個是非同步呼叫介面,第二個是處理返回結果,都非常簡單,下面那個帶引數的a方法,就是回撥結果呼叫的處理方法,他把處理post到主執行緒,執行cv方法,cv方法很重要,因為他是真正呼叫成功後返回結果的地方:

已經可以看到,結果中包含這些項:codeId,qr_money,beiZhu,qrCodeUrl,qrCodeUrlOffline,從名稱就都可以知道是什麼作用,然後通過呼叫setResult和finish把結果返回給PayeeQRActivity,而在PayeeQRActivity中的onActivityResult,無非就是去讀取這些結果然後生成二維碼,還記得生成二維碼的方法嗎?就是那個b()函式(最終呼叫的是a(boolean z, ImageView imageView)這個方法)。所以最好再來看一下生成二維碼的方法,需要用到什麼東西:

方法邏輯很清晰,用到哪些類,傳入哪些引數,都很清楚了,最後使用ZXingHelper的genCodeImageView方法生成二維碼並更新到ImageView上顯示,具體邏輯就不貼圖展示和分析了,以上就是程式碼層面上的分析,那麼做一下總結:

1. 關於之前說的第一個問題,生成二維碼用到哪些資訊並且怎樣生成,現在很清楚的知道,至少需要金額和備註,然後使用的是Rpc服務介面CollectMoneyRpc去生成二維碼資訊。

2. 關於之前的第二個問題,怎樣生成二維碼影象,這個也很清晰了,就是使用上面的a(boolean z, ImageView imageView)這個方法了。

那麼接下來就是根據這些分析結果來構造hook的條件了

 

一、先來看如何構造1提到的條件:

我們從前面分析的程式碼知道需要一個CollectMoneyRpc介面,他是通過下面的呼叫來生成的:

關鍵點是這個mMicroApplicationContext是怎麼來的,這個需要追溯到基類BaseActivity中,有個ActivityHelper輔助類,其中又再次使用LauncherApplicationAgent來獲取這個值,這個值是在LauncherApplicaitonAgent建構函式中來構造的,LauncherApplicationAgent又是一個單例類,他有個init方法,一看就是用來做初始化的,我們去hook這個init方法,然後反射拿到成員變數mMicroApplicationContext,直接給出程式碼:

 

拿到這個CollectMoneyRpc後,我們就可以根據設定金額以及備註引數進行呼叫了,反射從呼叫結果中拿到上面分析的哪些codeId,url,等等:

 

二、最後構造之前的2提到的條件:

已經說過真正生成二維碼是在哪個a(boolean, ImageView)方法中進行的,只要去按照這個方法中的引數構造,然後在反射使用ZXingHelper這個輔助類去寫二維碼圖片就可以實現了,直接給出程式碼:

 

三、總結

使用XPosed開發外掛還是新手,需要學習的東西還有很多,這次分析支付寶程式碼,使用的是舊版本的支付寶,最新版支付寶,jadx即使分包載入,我的電腦還是會卡死。。。支付寶程式碼反編譯後,還是很清晰的,混淆的不是很嚴重,但是從中也能看到支付寶的複雜性以及架構上的合理性,研究他的程式碼也能學到很多的東西,估計這個工作我還會持續進行。已經把整個工程上傳到github,文末是地址,如果這個東西不小心觸犯了誰的利益或者影響了軟體安全,可以聯絡我刪除,再次宣告,僅僅是個人學習目的使用,請勿他用,謝謝!!

 

AlipayQRHook開源地址:https://github.com/wayu002/AlipayQRHook