前幾天受高人指點意外發(fā)現(xiàn)了開啟Android世界的新大陸邓嘹,就是這個叫Hook(''鉤子'')的東西。聽起來很神奇惰说,周末抽時間研究了一番,發(fā)現(xiàn)確實是一個值得去研究的技術缘回。
什么是 Hook助被?
江湖上稱它為“鉤子”,它能夠在事件傳送到終點前截獲并監(jiān)控事件的傳輸切诀。它能夠將自己的代碼“融入”被鉤住的進程中揩环,成為目標進程的一部分。這么說來幅虑,它可以Hook住系統(tǒng)的API丰滑,然后通過注入自己代碼的方式去改變系統(tǒng)方法的行為、以及對系統(tǒng)方法的監(jiān)聽倒庵;除此以外褒墨,它還能通過實現(xiàn)一個程序,去篡改其他應用程序的行為擎宝。
原理:Hook技術本質是函數(shù)調用郁妈,由于處于Linux用戶狀態(tài),每個進程有自己獨立的進程控件绍申,所以必須先注入所要Hook的進程空間噩咪,修改其內(nèi)存中進程代碼,替換過程表的符號地址极阅,通過ptrace函數(shù)附加進程胃碾,向遠程進程注入so庫,從而達到監(jiān)控以及遠程進程關鍵函數(shù)掛鉤
Xposed框架
要是說起這個框架筋搏,那可就真的牛逼了仆百。什么微信自動搶紅包、微信步數(shù)作弊......這些騷操作都是這個框架干出來的奔脐。
在Android系統(tǒng)中俄周,應用程序進程以及系統(tǒng)服務進程都是由Zygote 進程 fork 出來的。Xposed框架深入到Android核心機制中髓迎,正式通過改造Zygote 進程來實現(xiàn)一系列的操作峦朗。
其使用方法我這里不做過多的說明,百度就能有一大堆的使用教程竖般。
關于Xposed框架的具體實現(xiàn)原理甚垦,我建議可以參考Dalvik虛擬機原理及Xposed hook原理這篇文章。
劫持登錄Demo
又是這個栗子...不過不要緊,我們最重要的是學習原理和用法艰亮,一通百通闭翩。
btnHook.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
String userName = etUserame.getText().toString();
String userPassword = etPassword.getText().toString();
if (checkInfo(userName, userPassword)) {
Toast.makeText(getApplicationContext(), "登錄成功", Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(getApplicationContext(), "登錄失敗", Toast.LENGTH_SHORT).show();
}
}
});
private boolean checkInfo(String userName, String userPassword) {
return userName.equals("jy") && userPassword.equals("123");
}
我模擬了一個登錄的情景,并規(guī)定只有輸入用戶名和密碼分別是jy和123的條件下才能正常登錄迄埃。
為了實現(xiàn)劫持登錄的效果疗韵,這里新建一個類去實現(xiàn) IXposedHookLoadPackage
,然后重寫 handleLoadPackage
方法侄非。
/**
* 包加載時候的回調
*/
@Override
public void handleLoadPackage(XC_LoadPackage.LoadPackageParam lpparam) throws Throwable {
XposedBridge.log("Loaded app : " + lpparam.packageName);
XposedHelpers.findAndHookMethod("cn.edu.hrbeu.jy.hooktest.MainActivity", lpparam.classLoader, "checkInfo",
String.class, String.class, new XC_MethodHook() {
@Override
protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
XposedBridge.log("hook start");
XposedBridge.log("參數(shù)1: " + param.args[0]);
XposedBridge.log("參數(shù)2: " + param.args[1]);
}
@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
XposedBridge.log("劫持前返回的result: " + param.getResult());
param.setResult(true);
XposedBridge.log("劫持后返回的result: " + param.getResult());
XposedBridge.log("hook finish");
}
});
}
在啟動了任意應用程序之后蕉汪,都會執(zhí)行一次這個方法,然后根據(jù) packageName
來找到你需要去Hook的某個app的某個方法逞怨。這里者疤,我找到了我的 MainActivity
以及驗證登錄信息的 checkInfo()
方法。
在 findAndHookMethod()
中有兩個回調方法叠赦,根據(jù)名字可以看出一個是方法執(zhí)行前的回調驹马,另一個是方法執(zhí)行之后的回調。
先來看看程序界面和運行結果:
可以看到的是除秀,我輸入的內(nèi)容與我之前設定的賬號密碼并不同糯累,但還是顯示了登錄成功。來簡單分析一下:
首先册踩,我輸入了錯誤的賬號密碼泳姐,所以正常情況我的checkInfo()
方法會返回 false 。所以劫持前的result 會返回 false,就像Log日志里面的一樣。然后我將 param.setResult(true);
將返回的結果設置成了 true...再作為最終的結果返回诚镰,所以說無論我輸入什么都會顯示登錄成功...
分析
雖然我做的只是最簡單的修改了自己實現(xiàn)的方法,但是其實無論是系統(tǒng)API 還是說別的app里面的方法扒怖,只要知道方法名和參數(shù)類型较锡,理論上我們都可以去Hook住它們业稼,并且可以監(jiān)聽或者修改這些方法的一些行為。