Cydiasubstrate对于果粉来说一点也不陌生,越狱必备也提供了很多modules供用户个性化使用。当然Cydiasubstrate也推出了Android版。当然Xposed也能实现了对应的功能,但两者实现的技术手段有些不一样,由于Xposed开源,也有不少相关文章分析了实现方式,其主要原理是替换了/system/bin/app_process这个程序,在机子启动时加载自身的XposedBridge.jar完成对虚拟机的劫持。而Cydiasubstratet并不开源但根据比对两者"installer",我猜测Cydiasubstrate应该是采用注入的方式完成hook的:
[img]http://dl2.iteye.com/upload/attachment/0104/5544/63548529-c88c-3a24-abe2-e6766cc5ace3.jpg[/img]
总的来说,要学习还是建议Xposed毕竟是开源,要快速部署我还是比较推荐Cydiasubstrate,毕竟开发简洁,也支持Native。这一篇文章主要介绍Cydiasubstrate modules 的java开发。官方网站 [url]http://www.cydiasubstrate.com/[/url] 文档简单明了,也提供了下载地址,也有saurik 就Xposed区别的声明[url]http://www.cydiasubstrate.com/id/34058d37-3198-414f-a696-73e97e0a80db/[/url]
编写模块之前我们需要一些部署工作:

[b]1.root手机[/b]
由于不舍得拿自己的机子开刀,索性在模拟器上进行了部署我们需要下载一些必备的工具su busybox mkfs.yaffs2.arm下载好了上面必备的工具,我们就开始root 吧

adb shell  
#mount -o remount,rw /dev/block/mtdblock0 /system  
adb push su /system/bin/  
#chmod 4755 /system/bin/su  
#exit  
adb install super.apk  
adb install busybox.apk


各种安装好后,在adb shell中执行 su grep等扩展命令成功后,证明我们完成了相应的工作,但这时候别急,如果关掉模拟器的话,是不会写到对应system.img里的,当我们下次重新启动模拟器的时候,一切又回到的原点,所以我们还需要如下操作:


adb shell  
#mkdir /filesname  
#exit  
adb push mkfs.yaffs2.arm /filesname  
adb shell  
#cd /filesname  
#./mkfs.yaffs2.arm /system /filesname/my_system.img  
#exit  
adb pull /filesname/my_system.img


接着将该my_system.img替换 $ANDROID_SDK/sdk/system-images/android-xx 下的system.img即可



[b]2.应用设置[/b]


安装好com.saurik.substrate.apk之后


[img]http://dl2.iteye.com/upload/attachment/0104/5546/d53c2d72-c2b7-31bf-80c8-de8fe64d838f.jpg[/img]


[b]3.模块开发[/b]


首先得先下载Cydiasubstrate SDK,打开AndroidSDK Manager -> tools -> add on site


[img]http://dl2.iteye.com/upload/attachment/0104/5552/60482501-9f87-3a70-a541-8de4b56e64fe.jpg[/img]


不一会就下好了,之后可以开始进行开发,创建一个新工程吧,完成的功能是对系统发送的短信进行监听,首先将如下关键字加入到AndroidManifestxml中:


<meta-data android:name="com.saurik.substrate.main" android:value=".Main"/>  
<uses-permission android:name="cydia.permission.SUBSTRATE"/>


AndroidManifestxml如下:


<?xml version="1.0" encoding="utf-8"?>  
<manifest xmlns:android="http://schemas.android.com/apk/res/android"  
    package="com.rois.hookdroid"  
    android:versionCode="1"  
    android:versionName="1.0" >  

    <uses-sdk  
        android:minSdkVersion="8"  
        android:targetSdkVersion="15" />  

    <application  
        android:allowBackup="true"  
        android:icon="@drawable/ic_launcher"  
        android:label="@string/app_name"  
        android:theme="@style/AppTheme" >  

        <meta-data android:name="com.saurik.substrate.main" android:value=".Main"/>  

        <activity  
            android:name="com.rois.hookdroid.CydiaTest"  
            android:label="@string/app_name" >  
            <intent-filter>  
                <action android:name="android.intent.action.MAIN" />  

                <category android:name="android.intent.category.LAUNCHER" />  
            </intent-filter>  
        </activity>  
    </application>  

    <uses-permission android:name="cydia.permission.SUBSTRATE"/>  

</manifest>


我新建的项目src目录如下:


[img]http://dl2.iteye.com/upload/attachment/0104/5556/593ed8e2-3fac-3216-9c66-37d39e23442d.jpg[/img]


Main是必须包含的,完成一些必要的初始化工作,有initialize函数负责,MS.hookClassLoad的功能在于:当xxxx类要被加载的时候,使用我们自己构造的ClassLoader,我这里是要hook android.telephony.SmsManager类实现对对短信的监听,Main如下:


package com.rois.hookdroid;  

import com.rois.core.SmsHookClassLoader;  
import com.saurik.substrate.MS;  



public class Main {  
    static void initialize(){  
        MS.hookClassLoad("android.telephony.SmsManager", SmsHookClassLoader.getInstance());  
    }  
}


当然这里我把对应的ClassLoader继续了一次封装,因为要是对多个类进行hook,代码也实现在同一个文件我会有强迫症,看官网的教程更加简洁,SmsHookClassLoader如


下:


package com.rois.core;  

import java.lang.reflect.Method;  
import android.app.PendingIntent;  
import android.util.Log;  
import com.rois.utils.Config;  
import com.saurik.substrate.MS;  

public class SmsHookClassLoader implements MS.ClassLoadHook{  

    private static SmsHookClassLoader smsHookClassLoader;  

    public SmsHookClassLoader() {  
        super();  
    }  

    public static SmsHookClassLoader getInstance(){  
        if (smsHookClassLoader == null) {  
            smsHookClassLoader = new SmsHookClassLoader();  
        }  
        return smsHookClassLoader;  
    }  

    @SuppressWarnings({ "unchecked", "rawtypes" })  
    public void classLoaded(Class<?> SmsManager) {  
        //code to modify the class when loaded  
        Method sendTextMessage;  
        try {  
            sendTextMessage = SmsManager.getMethod("sendTextMessage",   
                    new Class[]{String.class,String.class,String.class,PendingIntent.class,PendingIntent.class});  

        } catch (NoSuchMethodException e) {  
            sendTextMessage = null;  
        }  
        MS.hookMethod(SmsManager, sendTextMessage, new MS.MethodAlteration() {  
            public Object invoked(Object _this,Object... _args) throws Throwable{  
                Log.i(Config.TAG,"SEND_SMS");  
                Log.i(Config.TAG,"destination:"+_args[0]);  
                Log.i(Config.TAG,"source:"+_args[1]);  
                Log.i(Config.TAG,"text:"+_args[2]);  
                return invoke(_this, _args);  
            }  
        });  

    }  

}


主要是我们需要实现:


1.MS.ClassLoadHook中的classLoaded(Class<?> xxxx)函数,其表示在android.telephony.SmsManager第一次被加载的时候,我们要执行的classLoaded的功能,这里我通过反射找到sendTextMessage函数。


2.利用void hookMethod(Class _class, Member member, MS.MethodAlteration alteration);对方法进行hook,第一个参数为classLoaded传下来的类参数,第二个参数为之前反射得到需要hook的方法,第三个参数为MS.MethodAlteration它完成了最后跳转的封装。


3.我们需要实现MS.MethodAlteration.invoked(Object _this, Object... args),在这个方法中完成我们的自定义功能,this表示类,args为该函数的参数,由于我们是监听短信发送,所以,仅仅打印log……


[img]http://dl2.iteye.com/upload/attachment/0104/5558/7537965e-ce20-3de4-883d-108dd5a2f664.jpg[/img]


通过这个Application标签,我们知道这段代码被加载在了com.android.mms 我们的短信进程中进行


Cydiasubstrate很简洁,这样下来在hook几个方法动态分析的demo就搞定了,当然官网说支持native,我看了下demo感觉只是说可以通过native实现功能,好像不能hook native函数,也希望了解的人给我一个答案。折腾了一天,虽然实现了功能,没有学到任何东西,除非分析它的工作原理,那么还是洗洗睡吧