編輯:關於Android編程
Android逆向工程裡常用到的工具除了的dex2jar,jd-gui, Apktool之外還有一個Xposed。
這個工具是一個在不修改APK的情況下,影響其運行過程的服務框架。可以根據自己的需求編寫模塊,讓模塊控制目標應用的運行。
因為本人也是新手,對於Xposed用法還有很多的不熟悉,所以只對其hook技術進行簡單的介紹,並讓hook技術應用到以後的逆向分析工程中。
至於什麼是hook,不了解的話就先去百度一下,這裡基於菜鳥有限的經驗,我只能說是一種函數攔截技術~
首先,下載Xposed框架,我這裡就不提供下載了,然後手機必須得先root,不然是無法安裝Xposed框架的,畢竟hook技術已經是個系統級的過程,所以你懂的~
這只是一個框架而已,並沒有什麼功能,為了實現個人需求,我們還需要自己編寫模塊,讓這個框架去加載你的模塊。
舉個栗子,你要去知道手機某個應用包中的某個類中的某個方法中的某個參數,那麼你的模塊就要指明那個包,哪個類,哪個方法,當系統重啟時加載目標應用包時,加載了你的模塊的Xposed框架會識別到,接下來,如果你指明的應用中的某一方法被系統執行了,那麼Xposed也會識別到,然後讓你的模塊去Hook(顧名思義,就是就是鉤子,陷阱的意思;也可以說是攔截)這個方法,並可以利用模塊的接口讓方法的參數和返回結果暴露出來。
在本次的博客中,只是結合例子簡單的介紹Xposed的hook,實際上Xposed的功能貌似不止於此~
框架弄好了,接下來就可以根據需求編寫模塊了,不過,再此之前先明確一下需求,我們可以用一個簡單的登錄系統APP進行測試。
先貼個簡單的代碼出來先:
public class LoginActivity extends Activity { private final String ACCOUNT="samuel"; private final String PASSWORD="123456"; private EditText etAccount, etPassword; private Button btnLogin; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_login); etAccount=(EditText)findViewById(R.id.et_account); etPassword=(EditText)findViewById(R.id.et_password); btnLogin=(Button)findViewById(R.id.btn_login); btnLogin.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { if (isOK(etAccount.getText().toString(), etPassword.getText().toString())) { Toast.makeText(LoginActivity.this, "登錄成功", Toast.LENGTH_SHORT).show(); } else { Toast.makeText(LoginActivity.this, "登錄失敗", Toast.LENGTH_SHORT).show(); } } }); } private boolean isOK(String account, String password){ return account.equals(ACCOUNT) && password.equals(PASSWORD); }
那麼,重點就來了,我們就可以利用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最好是照著寫。
4、導入一個XposedBridgeApi.jar包,如上圖,並Add AS Library。這裡注意,需要在build.gradle裡的dependencies將compile改為provided,不然會報錯。聽說是系統裡已有該jar包內容,再次打包進去會沖突,所以改為provided,不要管那條紅色波浪線,無礙~
5、編寫模塊類Module:
public class Module implements IXposedHookLoadPackage { @Override public void handleLoadPackage(XC_LoadPackage.LoadPackageParam loadPackageParam) throws Throwable { if (loadPackageParam.packageName.equals("com.samuelzhan.logintest")) { XposedHelpers.findAndHookMethod("com.samuelzhan.logintest.LoginActivity", loadPackageParam.classLoader, "isOK", String.class, String.class, new XC_MethodHook() { @Override protected void beforeHookedMethod(MethodHookParam param) throws Throwable { } @Override protected void afterHookedMethod(MethodHookParam param) throws Throwable { } }); } } }說明:
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)函數中的賬號密碼,先在回調函數中添加日記打印代碼將其賬號密碼參數暴露出來,順便把返回結果也顯示一下:
new XC_MethodHook() { @Override protected void beforeHookedMethod(MethodHookParam param) throws Throwable { XposedBridge.log("賬號:"+(String)param.args[0]+" 密碼:"+(String)param.args[1]); Log.d("zz","賬號:"+(String)param.args[0]+" 密碼:"+(String)param.args[1]); } @Override protected void afterHookedMethod(MethodHookParam param) throws Throwable { Log.d("zz", param.getResult().toString()); } });我在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技術,我怎樣輸入都能成功登陸。
new XC_MethodHook() { @Override protected void beforeHookedMethod(MethodHookParam param) throws Throwable { //修改參數 param.args[0]="samuel"; param.args[1]="123456"; } @Override protected void afterHookedMethod(MethodHookParam param) throws Throwable { Log.d("zz", param.getResult().toString()); } });
不錯,顯示登陸成功,說明修改參數成功。
其實Xposed貌似還有其他更強大的功能,這裡只用了冰山一角進行逆向分析而已~
在最近的兩篇Qt on Android中學習了怎麼使用基礎的JNI以及如何使用外部IDE來管理Qt應用的Java部分。這章呢,我們繼續前進,關注如何擴展我們的
一 概述我們用ItemDecoration為RecyclerView打造了帶懸停頭部的分組列表。其實Android版微信的通訊錄界面,它的分組title也不是懸停的,我們
Activity是Android系統的4個應用程序組件之一。通過傳統方法顯示的Activity都是充滿整個屏幕,也就是全屏的Activity。事實上,Activity不僅
RxAndroid是RxJava的擴展, 可以優雅地處理異步請求. 以前的文章講述過一些, 這次再補充些內容, 熟悉RxAndroid的使用方法.本文源碼的GitHub下