Friday, 20 September 2013

Xposed使用说明

Xposed原理简介

Xposed基于两个部分,底层是替换/system/bin/app_process,增加Hook替换函数的接口,主体框架为XposedBridge,由de.robv.android.xposed.XposedBridgemain方法入口。

开发一个基于Xposed的插件

这里以一个动态监测sendTextMessage的Demo为例介绍如何基于Xposed框架实现一个插件。

  1. AndroidManifest.xml

    Xposed会读取Application下的相关meta-data,例如这里:

     <meta-data android:value="true" android:name="xposedmodule"/>
     <meta-data android:value="2.1*" android:name="xposedminversion"/>
     <meta-data android:value="Test for Xposed." android:name="xposeddescription"/>
    
  2. IXposedHookLoadPackage IXposedHookLoadPackage接口的handleLoadPackage方法在Package Load前调用。

     public class Main implements IXposedHookLoadPackage {
         public void handleLoadPackage(final LoadPackageParam pkg) throws Throwable {
             XposedBridge.log("Loaded app: " + pkg.packageName);
    

    在测试程序运行后输出日志如下:

     09-17 17:25:11.319: I/Xposed(13475): Loaded app: com.example.smshook
    
  3. findAndHookMethod

    实现对指定类的指定方法进行Hook,并且通过override beforeHookedMethodafterHookedMethod来记录和改变原始行为。

         findAndHookMethod("android.telephony.SmsManager", pkg.classLoader, "sendTextMessage",
                 String.class,
                 String.class,
                 String.class,
                 PendingIntent.class,
                 PendingIntent.class,
         new XC_MethodHook() {
         protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
             XposedBridge.log("before send");
             Object[] args = param.args;
             XposedBridge.log(args[0] + ": " + args[2]);
         }
    
         protected void afterHookedMethod(MethodHookParam param) throws Throwable {
             XposedBridge.log("after send");
         }
     });
    

    在测试程序点击发送短信后输出日志如下:

     09-17 17:25:12.150: I/Xposed(13475): before send
     09-17 17:25:12.150: I/Xposed(13475): 10086: test hello world.
     09-17 17:25:12.160: I/Xposed(13475): after send
    

参考

Cydia Substrate使用说明

Cydia Substrate是一个基于Hook的代码修改框架,其可以在Android、iOS平台使用,并实现修改系统默认代码。这里关注的是其在Android下的使用方式和基本原理。

使用说明

Substrate SDK实现了对Native API和Java API的Hook技术。

使用条件:

  1. 手机需要提权
  2. 需要安装Substrate
  3. 开发环境需要下载SDK

Java API Hook实例

  1. 修改AndroidManifest.xml

    • 添加权限

        <uses-permission android:name="cydia.permission.SUBSTRATE"/>
      
    • 在Application中需要添加meta-data,这里value可以替换成自己的实现类

        <meta-data android:name="com.saurik.substrate.main"
        android:value=".Main"/>
      
  2. 实现类必须有一个静态的 initialize方法,没有参数,返回为空

  3. 编译时需要将substrate-api.jar放入project/libs

相关源码:

MS.hookClassLoad("android.telephony.SmsManager",
    new MS.ClassLoadHook() {
       public void classLoaded(Class<?> arg0) {

          Method sendTextMessage;
          try {
             sendTextMessage = arg0.getMethod("sendTextMessage",
                new Class[] {
                 String.class,
                 String.class,
                 String.class,
                 PendingIntent.class,
                 PendingIntent.class
             });
          } catch (NoSuchMethodException e) {
              sendTextMessage = null;
          }

          if (sendTextMessage != null) {
             final MS.MethodPointer old = new MS.MethodPointer();
             MS.hookMethod(arg0, sendTextMessage,
                   new MS.MethodHook() {
                      public Object invoked(Object arg0,
                        Object... args)
                        throws Throwable {
                          Log.d("SMSHOOK", "pid = " + android.os.Process.myPid() + 
                                  "uid = " + android.os.Process.myUid());
                          Log.d("SMSHOOK", args[0] + ":" + args[2]);
                          return old.invoke(arg0, args);

                            }                   
                   }, old);
          }
       }
    });

运行结果:

09-20 10:28:12.121: D/SMSHOOK(2095): before send.
09-20 10:28:12.141: D/SMSHOOK(2095): pid = 2095uid = 10000
09-20 10:28:12.141: D/SMSHOOK(2095): 10086:test hello world.

Native Hook 实例

  1. 相关Android.mk

     LOCAL_MODULE    := smshook.cy                                                      
     LOCAL_SRC_FILES := main.cpp                                                        
    
     LOCAL_LDLIBS := -L$(LOCAL_PATH)/../lib -lsubstrate-dvm  
    
    • lib后缀为.cy.so
    • 需要以CPP方式编译
    • 需要链接libsubstrate-dvm.so
  2. 相关AndroidManifest.xml

    • 添加权限

        <uses-permission android:name="cydia.permission.SUBSTRATE"/>
      
    • installLocation设置

        android:installLocation="internalOnly"
      
    • Application相关设置

        Application的android:hasCode="false"
      

相关源码:

MSConfig(MSFilterExecutable, "/system/bin/app_process")                         

static jint (*_Resources$getColor)(JNIEnv *jni, jobject _this, ...);            

static jint $Resources$getColor(JNIEnv *jni, jobject _this, jint rid) {         
        jint color = _Resources$getColor(jni, _this, rid);                      
            return color & ~0x0000ff00 | 0x00ff0000;                            
}                                                                               

static void OnResources(JNIEnv *jni, jclass resources, void *data) {            
    // ... code to modify the class when loaded                                 
    jmethodID method = jni->GetMethodID(resources, "getColor", "(I)I");         
    if (method != NULL)                                                         
        MSJavaHookMethod(jni, resources, method,                                
            &$Resources$getColor, &_Resources$getColor);                        
}                                                                               

// this is a macro that uses __attribute__((__constructor__))                   
MSInitialize {                                                                  
    // ... code to run when extension is loaded                                 
    MSJavaHookClassLoad(NULL, "android/content/res/Resources", &OnResources);   
}