XposedHook:hook敏感函数

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
2
3
4
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)。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
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的反射机制,主要是通过字符串来得到相应的类,函数或变量等,具体代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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的函数时,就打印该函数。具体实现如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
    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函数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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

  1. android.telephony.SmsManager/sendTextMessage
  2. android.telephony.SmsManager/getAllMessagesFromIcc
  3. android.telephony.SmsManager/sendDataMessage
  4. android.telephony.SmsManager/sendMultipartTextMessage

TelephonyManager

  1. android.telephony.TelephonyManager/getLine1Number
  2. android.telephony.TelephonyManager/listen

AccountManager

  1. android.accounts.AccountManager/getAccounts
  2. android.accounts.AccountManager/getAccountsByType

ActivityManager

  1. android.app.ActivityManager/killBackgroundProcesses
  2. android.app.ActivityManager/forceStopPackage

AlarmManager

  1. android.app.AlarmManager/setImpl

AudioRecord

  1. android.media.AudioRecord

Camera

  1. android.hardware.Camera/takepicture
  2. android.hardware.Camera/setPreviewCallback
  3. android.hardware.Camera/setPreviewCallbackWithBuffer
  4. android.hardware.Camera/setOneShotPreviewCallback

ConnectivityManager

  1. android.net.ConnectivityManager/setMobileDataEnabled

ContentResolver

  1. android.content.ContentResolver/qurey
  2. android.content.ContentResolver/registerContentObserver
  3. android.content.ContentResolver/insert
  4. android.content.ContentResolver/bulkInsert
  5. android.content.ContentResolver/delete
  6. android.content.ContentResolver/update
  7. android.content.ContentResolver/applyBatch

ContextImpl

  1. android.app.ContextImpl/registerReceiver

MediaRecorder

  1. android.media.MediaRecorder/start
  2. android.media.MediaRecorder/stop

Internet

  1. java.net.URL/openConnection
  2. org.apache.http.impl.client.AbstractHttpClient/execute

NotificationManager

  1. android.app.NotificationManager/notify

ApplicationPackageManager

  1. android.app.ApplicationPackageManager/installPackage
  2. android.app.ApplicationPackageManager/deletePackage
  3. android.app.ApplicationPackageManager/getInstalledPackages

Xposed编程步骤

  • 首先在xposedbridgeapi.jar包导入到项目中,这里采用了XposedBridgeApi-54.jar包
  • 再项目的assets文件夹中新建一个xposed_init文件(没有后缀),该文件表示该xposed模板的主函数类的具体路径,比如该项目为

  • 在AndroidManifest.xml文件的标签下添加xposed的一些信息,以便Xposed能够识别该模板。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
<?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