XposedHook:hook敏感函数
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; iif(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
更多相关文章
- C语言函数的递归(上)
- Android多线程(三)HandlerThread源码原理解析
- Android单元测试之Robolectric
- Android(安卓)Studio真机测试时生成的程序出现闪退
- Android网络请求框架AsyncHttpClient (android-async-http)介绍
- # 读 Android(安卓)开发艺术探索 &8
- Android学习路线(二十七)键值对(SharedPreferences)存储
- Android系统的启动流程
- Android(安卓)资源加载与匹配