Xposed框架
Xposed框架通過修改Android系統的源碼,並替換Android的主程序Zygote(Init 是所有Linux程序的起點,而Zygote於Android,正如它的英文意思,是所有java程序的’孵化池’),從而能夠控制Android進程的執行流程,hook java層的API。xposed的具體解析可以參考深入理解Android(三):Xposed詳解
首先在app_main.cpp中,對appRuntime.cpp進行了修改,其中onVmCreated(JNIEnv* env)修改如下:
在onVmCreate中,它將調用libxposed_dalvik.so中的xposedInitLib函數,然後再調用so中設置的onVmCreated函數。這個onVmCreated函數由xposedInitLib設置。
在app_main.cpp的main方法中,進行了對xposed的環境初始化:
最後,如果xposed框架啓用成功,那麼zygote的入口類將由以前的com.android.internal.os.ZygoteInit變成de.robv.android.xposed.XposedBridge。
下面我們按照執行流程,把相關函數分析一遍:
AppRuntime的onVmCreated,它最終會導致libxposed_dalvik.so中的onVmCreated被調用。我們直接分析最後這個onVmCreated。
然後AppRuntime裏會調用de.robv.android.xposed.XposedBridge.main函數。
所以通過調用XposedBridge.main函數,可以給APK進程的一些特定函數掛上鉤子,從而能夠監聽該函數,進而通過beforeHookedMethod和afterHookedMethod方法可以分別實現調用函數前的操作和調用函數後的操作。
Hook用到的具體函數
下面給出我在做Android惡意程序分析時需要hook的函數的一些操作,該程序參考了halfkiss的框架。
- 用到的Xposed的函數: 首先定義一個抽象類MethodHookCallBack繼承自Xposed的XC_MethodHook類,該類有兩個方法:beforeHookedMethod(MethodHookParam param)和AfterHookedMethod(MethodHookParam param)方法,這兩個方法分別對應於要hook的函數調用之前所要執行的動作與該函數調用之後所要執行的動作。比如:
public void beforeHookedMethod(MethodHookParam param)
{
Log.i("Before hook");
}
上面的例子說明在調用要hook的函數之前打印一段log爲Before hook。
Xposed的hook的主函數hookMethod(Member hookMethod, XC_MethodHook callback),其中參數hookMethod表示要hook的函數,該函數可以通過java的反射機制獲得,具體怎麼獲得在下面會講到,參數callback就是前面講到的Xposed函數的XC_MethodHook類,該類主要是表示該對要hook的函數做怎樣的處理。具體的hookMethod方法如下圖所示:
由hookMethod可知,一個目標函數可以掛多個鉤子,這些鉤子由一個集合來存儲。然後我們將轉到JNI層去看看hookMethodNative幹了什麼事情。這纔是hook的核心。分析如下圖所示:
所以當apk執行被hook的函數時,實際執行的是hookMethodCallBack函數,該函數就是鉤子函數,我們來看看hookmethodCallBack函數具體是怎麼執行的,該函數在libXposed_dalvik.cpp中。
在xposedHandleHookedMethod函數中會以此執行鉤子函數,即在前面介紹的XC_MethodHook函數,然後再會執行程序的原函數。
在此,Hook需要用到的基本函數已經介紹完畢。接下來會介紹如何利用Xposed來實現hook敏感函數的操作。
hook敏感函數
- 首先定義MethodHookCallBack類繼承自XC_MethodHook,該函數實現了beforeHookedMethod和afterHookedMethod函數,主要是獲得HookParam類,該類主要是存儲了一些MethodHookParam的一些參數。然後調用該類中beforeHookedMethod(HookParam param)或者afterHookedMethod(HookParam param)。
public abstract class MethodHookCallBack extends XC_MethodHook {
@Override
protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
// TODO Auto-generated method stub
super.beforeHookedMethod(param);
HookParam hookParam = HookParam.fromXposed(param);
this.beforeHookedMethod(hookParam);
if(hookParam.hasResult())
param.setResult(hookParam.getResult());
}
@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
// TODO Auto-generated method stub
super.afterHookedMethod(param);
HookParam hookParam = HookParam.fromXposed(param);
this.afterHookedMethod(hookParam);
if(hookParam.hasResult())
param.setResult(hookParam.getResult());
}
public abstract void beforeHookedMethod(HookParam param);
public abstract void afterHookedMethod(HookParam param);
}
- 根據字符串找到要hook的函數,主要是利用java的反射函數,如果有興趣的可以去查閱一下java的反射機制,主要是通過字符串來得到相應的類,函數或變量等,具體代碼如下:
public static Method findMethod(String className, ClassLoader classLoader, String methodName,
Class<?>... parameterTypes)
{
try {
Class clazz = classLoader.loadClass(className);
Method method = clazz.getDeclaredMethod(methodName, parameterTypes);
method.setAccessible(true);
return method;
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
我們通過該方法可以獲得要hook的具體method。
- 定義抽象類AbstractBahaviorHookCallBack繼承自前面講到的MethodHookCallBack類,該類具體實現當調用要hook的函數時,就打印該函數。具體實現如下:
public abstract class AbstractBahaviorHookCallBack extends MethodHookCallBack {
@Override
public void beforeHookedMethod(HookParam param) {
// TODO Auto-generated method stub
/*int length = param.args.length;
Object[] m = param.args;
String args = "/";
for(int i = 0; i < length;i++)
{
args+=(String)m[i]+"/";
}*/
Logger.logD("Invoke "+ param.method.getDeclaringClass().getName()+"->"+param.method.getName());
this.descParam(param);
//this.printStackInfo();
}
@Override
public void afterHookedMethod(HookParam param) {
// TODO Auto-generated method stub
//Logger.log_behavior("End Invoke "+ param.method.toString());
}
private void printStackInfo(){
Throwable ex = new Throwable();
StackTraceElement[] stackElements = ex.getStackTrace();
if(stackElements != null){
StackTraceElement st;
for(int i=0; i<stackElements.length; i++){
st = stackElements[i];
if(st.getClassName().startsWith("com.android.binpang")||st.getClassName().startsWith("de.robv.android.xposed.XposedBridge"))
continue;
Logger.logD(st.getClassName()+":"+st.getMethodName()+":"+st.getFileName()+":"+st.getLineNumber());
}
}
}
public abstract void descParam(HookParam param);
}
- 具體要實現的hook函數
Method sendTextMessagemethod = FindMethod.findMethod(
"android.telephony.SmsManager", ClassLoader.getSystemClassLoader(),
"sendTextMessage", String.class,String.class,String.class,PendingIntent.class,PendingIntent.class);
hookhelper.hookMethod(sendTextMessagemethod, new AbstractBahaviorHookCallBack() {
@Override
public void descParam(HookParam param) {
// TODO Auto-generated method stub
Logger.logI("Send SMS ->");
String dstNumber = (String)param.args[0];
String content = (String)param.args[2];
Logger.logI("SMS DestNumber:"+dstNumber);
Logger.logI("SMS Content:"+content);
}
});
該示例函數是hook了android.telephony.SmeManager/sendTextMessage函數,當調用該函數的時候,會打印出來要發送的目標號碼,及發送的message的內容。
- 監聽的敏感函數列表
SmsManager
- android.telephony.SmsManager/sendTextMessage
- android.telephony.SmsManager/getAllMessagesFromIcc
- android.telephony.SmsManager/sendDataMessage
- android.telephony.SmsManager/sendMultipartTextMessage
TelephonyManager
- android.telephony.TelephonyManager/getLine1Number
- android.telephony.TelephonyManager/listen
AccountManager
- android.accounts.AccountManager/getAccounts
- android.accounts.AccountManager/getAccountsByType
ActivityManager
- android.app.ActivityManager/killBackgroundProcesses
- android.app.ActivityManager/forceStopPackage
AlarmManager
- android.app.AlarmManager/setImpl
AudioRecord
- android.media.AudioRecord
Camera
- android.hardware.Camera/takepicture
- android.hardware.Camera/setPreviewCallback
- android.hardware.Camera/setPreviewCallbackWithBuffer
- android.hardware.Camera/setOneShotPreviewCallback
ConnectivityManager
- android.net.ConnectivityManager/setMobileDataEnabled
ContentResolver
- android.content.ContentResolver/qurey
- android.content.ContentResolver/registerContentObserver
- android.content.ContentResolver/insert
- android.content.ContentResolver/bulkInsert
- android.content.ContentResolver/delete
- android.content.ContentResolver/update
- android.content.ContentResolver/applyBatch
ContextImpl
- android.app.ContextImpl/registerReceiver
MediaRecorder
- android.media.MediaRecorder/start
- android.media.MediaRecorder/stop
Internet
- java.net.URL/openConnection
- org.apache.http.impl.client.AbstractHttpClient/execute
NotificationManager
- android.app.NotificationManager/notify
ApplicationPackageManager
- android.app.ApplicationPackageManager/installPackage
- android.app.ApplicationPackageManager/deletePackage
- android.app.ApplicationPackageManager/getInstalledPackages
Xposed編程步驟
- 首先在xposedbridgeapi.jar包導入到項目中,這裏採用了XposedBridgeApi-54.jar包
- 再項目的assets文件夾中新建一個xposed_init文件(沒有後綴),該文件表示該xposed模板的主函數類的具體路徑,比如該項目爲
- 在AndroidManifest.xml文件的標籤下添加xposed的一些信息,以便Xposed能夠識別該模板。
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.methodhook"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="18"
android:targetSdkVersion="21" />
<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<activity
android:name="com.binpang.methodhook.MainActivity"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<meta-data
android:name="xposedmodule"
android:value="true" />
<meta-data
android:name="xposedminversion"
android:value="40" />
<meta-data
android:name="xposeddescription"
android:value="Monitor the System's apis" />
</application>
</manifest>
- 在Android手機(或模擬器,建議使用模擬器,一般的模擬器都已經root過了)中安裝XposedInstaller(需要root權限), 由於Xposed替換了Android的一些程序,所以需要重啓才能生效。
- 然後啓動該模板程序,使其安裝到Android手機中,然後再Xposed的模板中找到它,並打鉤,如圖所示:
演示hook結果
通過短信軟件向5554號碼發送”hello,world”內容,如圖所示:
結果查找logcat如圖所示:
具體可以參考我的github