1. 程式人生 > >Android逆向分析之Xposed的hook技術

Android逆向分析之Xposed的hook技術

轉載自:http://blog.csdn.net/qq_18870023/article/details/51753587

Android逆向工程裡常用到的工具除了的dex2jar,jd-gui,  Apktool之外還有一個Xposed。

這個工具是一個在不修改APK的情況下,影響其執行過程的服務框架。可以根據自己的需求編寫模組,讓模組控制目標應用的執行。

因為本人也是新手,對於Xposed用法還有很多的不熟悉,所以只對其hook技術進行簡單的介紹,並讓hook技術應用到以後的逆向分析工程中。

至於什麼是hook,不瞭解的話就先去百度一下,這裡基於菜鳥有限的經驗,我只能說是一種函式攔截技術~

首先,下載Xposed框架,我這裡就不提供下載了,然後手機必須得先root,不然是無法安裝Xposed框架的,畢竟hook技術已經是個系統級的過程,所以你懂的~


這只是一個框架而已,並沒有什麼功能,為了實現個人需求,我們還需要自己編寫模組,讓這個框架去載入你的模組。

舉個栗子,你要去知道手機某個應用包中的某個類中的某個方法中的某個引數,那麼你的模組就要指明那個包,哪個類,哪個方法,當系統重啟時載入目標應用包時,載入了你的模組的Xposed框架會識別到,接下來,如果你指明的應用中的某一方法被系統執行了,那麼Xposed也會識別到,然後讓你的模組去Hook(顧名思義,就是就是鉤子,陷阱的意思;也可以說是攔截)這個方法,並可以利用模組的介面讓方法的引數和返回結果暴露出來。

在本次的部落格中,只是結合例子簡單的介紹Xposed的hook,實際上Xposed的功能貌似不止於此~

框架弄好了,接下來就可以根據需求編寫模組了,不過,再此之前先明確一下需求,我們可以用一個簡單的登入系統APP進行測試。

先貼個簡單的程式碼出來先:

  1. publicclass LoginActivity extends Activity {  
  2.     privatefinal String ACCOUNT="samuel";  
  3.     privatefinal String PASSWORD="123456";  
  4.     private EditText etAccount, etPassword;  
  5.     private Button btnLogin;  
  6.     @Override
  7.     protectedvoid onCreate(Bundle savedInstanceState) {  
  8.         super.onCreate(savedInstanceState);  
  9.         setContentView(R.layout.activity_login);  
  10.         etAccount=(EditText)findViewById(R.id.et_account);  
  11.         etPassword=(EditText)findViewById(R.id.et_password);  
  12.         btnLogin=(Button)findViewById(R.id.btn_login);  
  13.         btnLogin.setOnClickListener(new View.OnClickListener() {  
  14.             @Override
  15.             publicvoid onClick(View v) {  
  16.                 if (isOK(etAccount.getText().toString(), etPassword.getText().toString())) {  
  17.                     Toast.makeText(LoginActivity.this"登入成功", Toast.LENGTH_SHORT).show();  
  18.                 } else {  
  19.                     Toast.makeText(LoginActivity.this"登入失敗", Toast.LENGTH_SHORT).show();  
  20.                 }  
  21.             }  
  22.         });  
  23.     }  
  24.     privateboolean isOK(String account, String password){  
  25.         return account.equals(ACCOUNT) && password.equals(PASSWORD);  
  26.     }  

很簡單的一個登入頁面,其中的關鍵函式isOk(String, String)是用來驗證賬號密碼是否正確的,其中我已定死為賬號:samuel,密碼:123456,也就是說我必須輸入以上兩個字串,才能完成驗證。

那麼,重點就來了,我們就可以利用Xposed的模組hook到isOK(String, String)這個函式,並攔截到賬號和密碼,甚至可以修改賬號和密碼!!!

So,需求明確了,那麼我們就可以針對性編寫模組了。

編寫模組步驟:

1、先新建一個Android Project,這個工程不需要介面,所以在工程建立導向時不需要新增MainActivity和layout_main.xml,就一個Empty工程即可;

2、在空工程的java資料夾中新建一個類,該類就是一個模組類,這裡命名為“Module”,接下來就要配置一下AndaroidManfest.xml和新增xposed_init檔案,如下圖;


3、配置AndroidManifest.xml,其中的meta-data內容要照搬,反正我之前沒照搬說明上的demo,結果出錯了,所以那三個meta-data最好是照著寫。

  1. <manifestxmlns:android="http://schemas.android.com/apk/res/android"
  2.     package="com.samuelzhan.xposehook">
  3.     <applicationandroid:allowBackup="true"android:label="@string/app_name"
  4.         android:icon="@mipmap/ic_launcher"android:theme="@style/AppTheme">
  5.         <meta-data
  6.             android:name="xposedmodule"
  7.             android:value="true"/>
  8.         <meta-data
  9.             android:name="xposeddescription"
  10.             android:value="Hook Test!"/>
  11.         <meta-data
  12.             android:name="xposedminversion"
  13.             android:value="54"/>
  14.     </application>
  15. </manifest>

4、在main資料夾下建立一個assets資料夾,並在裡面建立一個普通的檔案,命名為“xposed_init”,然後開啟檔案,在裡面新增一句字串,即   包名+模組類名。


5、新建一個資料夾,命名為“lib”或者“jar”,然後放進一個XposedBridgeApi.jar包,如上圖,並在該jar包上右鍵Add as Library。這裡必須注意兩點細節,一是,放jar包的資料夾名字一定是“lib”或“jar”,親測放到“libs”裡沒用;二是,需要在build.gradle裡的dependencies將compile改為provided,不然會報錯。聽說是系統裡已有該jar包內容,再次打包進去會衝突,所以改為provided,不要管那條紅色波浪線,無礙~


6、編寫模組類Module:

  1. publicclass Module implements IXposedHookLoadPackage {  
  2.     @Override
  3.     publicvoid handleLoadPackage(XC_LoadPackage.LoadPackageParam loadPackageParam) throws Throwable {  
  4.         if (loadPackageParam.packageName.equals("com.samuelzhan.logintest")) {  
  5.             XposedHelpers.findAndHookMethod("com.samuelzhan.logintest.LoginActivity",  
  6.                     loadPackageParam.classLoader,  
  7.                     "isOK",  
  8.                     String.class,  
  9.                     String.class,  
  10.                     new XC_MethodHook() {  
  11.                         @Override
  12.                         protectedvoid beforeHookedMethod(MethodHookParam param) throws Throwable {  
  13.                         }  
  14.                         @Override
  15.                         protectedvoid afterHookedMethod(MethodHookParam param) throws Throwable {  
  16.                         }  
  17.                     });  
  18.         }  
  19.     }  
  20. }  
說明:

Module繼承了IXposedHookLoadPackage介面,當系統載入應用包的時候回回調 handleLoadPackage;

XposedHelpers的靜態方法 findAndHookMethod就是hook函式的的方法,其引數對應為   類名+loadPackageParam.classLoader(照寫)+方法名+引數型別(根據所hook方法的引數的型別,即有多少個寫多少個,加上.class)+XC_MethodHook回撥介面;

這裡的第一個引數類名必須要有包名字首,即“packageName+className”,還有一點,如果程式碼被混淆過,即使你明知道程式碼中要hook的類名和方法名,但都不一定能用,必須以smali中的名字為準,比如:isOk()混淆之後在smali中的函式名為a,那麼hook的時候就必須寫a,而不是isOK,第一個引數類名同理!

引數裡有一個監聽類XC_MethodHook,該類在hook前後回撥,通過回撥方法的MethodHookParam可以攔截到函式引數。

Xposed除了hook目標應用的函式之外,還可以hook某些類的構造方法,對應的方法為XposedHelpers.findAndHookConstructor()。

至此,一個模組基本已完成,接下來將其打包 Build->Generate Signed APK...生成一個APK,並安裝在手機上。因為沒有MainActivity,所以安裝後不會彈出任何介面,但若果此時手機已安裝了Xposed,那麼Xposed會在訊息欄彈一個訊息,通知你“模組已更新”,此時可以選擇Xposed選單中的 “框架”->"軟重啟",重啟手機(軟重啟不會斷電,相當於電腦的重啟,比硬重啟要快)。


到這裡,已經可以hook函數了。

現在,試著去攔截isOK(String, String)函式中的賬號密碼,先在回撥函式中新增日記列印程式碼將其賬號密碼引數暴露出來,順便把返回結果也顯示一下:

  1. new XC_MethodHook() {  
  2.     @Override
  3.     protectedvoid beforeHookedMethod(MethodHookParam param) throws Throwable {  
  4.         XposedBridge.log("賬號:"+(String)param.args[0]+"   密碼:"+(String)param.args[1]);  
  5.         Log.d("zz","賬號:"+(String)param.args[0]+"   密碼:"+(String)param.args[1]);  
  6.     }  
  7.     @Override
  8.     protectedvoid afterHookedMethod(MethodHookParam param) throws Throwable {  
  9.         Log.d("zz", param.getResult().toString());  
  10.     }  
  11. });  
我在beforeHookedMethod中寫了兩種方法日誌,第一個是XposedBridge的靜態log,這個日誌會顯示在Xposed的日誌選項裡,個人不喜歡這種方法,因為每次執行你要hook的程式,又必須切換頁面到Xposed檢視日誌,太麻煩了,但它有個優點,相比Android中的Log.d(),它能顯示丟擲的異常,而Android Log不可以。第二個Android Log就不用說了,這裡我兩種都用了。

編寫完後,我們重新打包這個模組,並安裝到手機上,然後讓手機軟重啟,每次更新安裝模組都必須得重啟才生效。

好,重啟後,我們執行一下目標應用,輸入賬號密碼~


然後看看Android Studio中的Logcat和 Xposed中的日誌選項:



可以看到,兩者都可以看到攔截到的密碼賬號。因為正確的賬號密碼為samuel  123456,這裡只是隨便輸入zzz   aaa,所以返回的結果是false,當然也在回撥函式afterHookedMethod中可以捕獲得到,這裡顯示false,說明登陸驗證失敗。

除了能讀取引數之外,hook技術還可以修改函式引數。

比如,接下來我修改模組,讓其無論輸入什麼,我都實現登陸,那我先在hook中把賬號密碼修改成samuel  123456,也就是說,通過hook技術,我怎樣輸入都能成功登陸。

  1. new XC_MethodHook() {  
  2.     @Override
  3.     protectedvoid beforeHookedMethod(MethodHookParam param) throws Throwable {  
  4.         //修改引數
  5.         param.args[0]="samuel";  
  6.         param.args[1]="123456";  
  7.     }  
  8.     @Override
  9.     protectedvoid afterHookedMethod(MethodHookParam param) throws Throwable {  
  10.         Log.d("zz", param.getResult().toString());  
  11.     }  
  12. });  

然後重新打包,安裝,重啟手機,再次執行登陸頁面的程式,再次輸入zzz   aaa看看:



不錯,顯示登陸成功,說明修改引數成功。

其實Xposed貌似還有其他更強大的功能,這裡只用了冰山一角進行逆向分析而已~