Xposed框架
Xposed框架通过修改Android系统的源码,并替换Android的主程序Zygote(Init 是所有Linux程序的起点,而Zygote于Android,正如它的英文意思,是所有java程序的’孵化池’),从而能够控制Android进程的执行流程,hook java层的API。
首先在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的函数调用之前所要执行的动作与该函数调用之后所要执行的动作。比如:
1 | public void beforeHookedMethod(MethodHookParam param) |
上面的例子说明在调用要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)。
1 | public abstract class MethodHookCallBack extends XC_MethodHook { |
- 根据字符串找到要hook的函数,主要是利用java的反射函数,如果有兴趣的可以去查阅一下java的反射机制,主要是通过字符串来得到相应的类,函数或变量等,具体代码如下:
1 | public static Method findMethod(String className, ClassLoader classLoader, String methodName, |
我们通过该方法可以获得要hook的具体method。
- 定义抽象类AbstractBahaviorHookCallBack继承自前面讲到的MethodHookCallBack类,该类具体实现当调用要hook的函数时,就打印该函数。具体实现如下:
1 | public abstract class AbstractBahaviorHookCallBack extends MethodHookCallBack { |
- 具体要实现的hook函数
1 | Method sendTextMessagemethod = FindMethod.findMethod( |
该示例函数是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能够识别该模板。
1 | <?xml version="1.0" encoding="utf-8"?> |
- 在Android手机(或模拟器,建议使用模拟器,一般的模拟器都已经root过了)中安装XposedInstaller(需要root权限), 由于Xposed替换了Android的一些程序,所以需要重启才能生效。
- 然后启动该模板程序,使其安装到Android手机中,然后再Xposed的模板中找到它,并打钩,如图所示:
演示hook结果
通过短信软件向5554号码发送”hello,world”内容,如图所示:
结果查找logcat如图所示:
具体可以参考我的github