Android HOOK工具Cydia Substrate使用詳解
Cydia Substrate是一個代碼修改平臺。它可以修改任何主進(jìn)程的代碼,不管是用Java還是C/C++(native代碼)編寫的。而Xposed只支持 HOOK app_process中的java函數(shù),因此Cydia Substrate是一款強(qiáng)大而實(shí)用的HOOK工具。
官網(wǎng)地址:http://www.cydiasubstrate.com/
Demo地址:https://github.com/zencodex/cydia-android-hook
官方教程:http://www.cydiasubstrate.com/id/20cf4700-6379-4a14-9bc2-853fde8cc9d1
SDK下載地址:http://asdk.cydiasubstrate.com/zips/cydia_substrate-r2.zip
Substrate幾個重要API介紹
MS.hookClassLoad
函數(shù)原型:void hookClassLoad(String name, MS.ClassLoadHook hook);
該方法實(shí)現(xiàn)在指定的類被加載的時候發(fā)出通知。因?yàn)橐粋€類可以在任何時候被加載,所以Substrate提供了一個方法用來檢測用戶感興趣的類何時被加載。
參數(shù) |
描述 |
name |
包名+類名,使用java的.符號 |
hook |
MS.ClassLoadHook的一個實(shí)例,當(dāng)這個類被加載的時候,它的 classLoaded 方法會被執(zhí)行。 |
MS.hookMethod
該API允許開發(fā)者提供一個回調(diào)函數(shù)替換原來的方法,這個回調(diào)函數(shù)是一個實(shí)現(xiàn)了MS.MethodHook接口的對象,是一個典型的匿名內(nèi)部類。它包含一個invoked函數(shù)。
函數(shù)原型:
void hookMethod(Class _class, Member member, MS.MethodHook hook, MS.MethodPointer old); void hookMethod(Class _class, Member member, MS.MethodAlteration alteration);
參數(shù)描述
(一)
參數(shù) |
描述 |
|
加載的目標(biāo)類,為classLoaded傳下來的類參數(shù) |
|
通過反射得到的需要hook的方法(或構(gòu)造函數(shù)). 注意:不能HOOK字段 (在編譯的時候會進(jìn)行檢測). |
|
|
(二)
參數(shù) |
描述 |
|
加載的目標(biāo)類,為classLoaded傳下來的類參數(shù) |
|
通過反射得到的需要hook的方法(或構(gòu)造函數(shù)). 注意:不能HOOK字段 (在編譯的時候會進(jìn)行檢測). |
|
An instance of |
建議開發(fā)者使用第二種方式,這種方式使用起來簡單并且很少出錯,不需要一個單獨(dú)的MS.MethodPointer類實(shí)例。
使用方法
下面以官網(wǎng)的一個實(shí)例來說明cydia substrate的使用方法。該實(shí)例是實(shí)現(xiàn)將多個接口組件顏色修改為紫羅蘭色。
需要安裝:http://www.cydiasubstrate.com/download/com.saurik.substrate.apk
步驟一:創(chuàng)建一個空的Android工程。由于創(chuàng)建的工程將以插件的形式被加載,所以不需要activity。將SDK中的substrate-api.jar復(fù)制到project/libs文件夾中。
步驟二:配置Manifest文件
(1)需要指定權(quán)限:cydia.permission.SUBSTRATE
(2)添加meta標(biāo)簽,name為cydia.permission.SUBSTRATE,value為下一步中創(chuàng)建的類名.Main
- <manifest xmlns:android="http://schemas.android.com/apk/res/android">
- <application>
- <meta-data android:name="com.saurik.substrate.main"
- android:value=".Main"/>
- </application>
- <uses-permission android:name="cydia.permission.SUBSTRATE"/>
- </manifest>
步驟二:創(chuàng)建一個類,類名為Main。類中包含一個static方法initialize,當(dāng)插件被加載的時候,該方法中的代碼就會運(yùn)行,完成一些必要的初始化工作。
- import com.saurik.substrate.MS;
- public class Main {
- static void initialize() {
- // ... code to run when extension is loaded
- }
- }
步驟三:為了實(shí)現(xiàn)HOOK,達(dá)到修改目標(biāo)類中的代碼的目的,我們需要得到目標(biāo)類的一個實(shí)例,如示例中的resources。
- public class Main {
- static void initialize() {
- MS.hookClassLoad("android.content.res.Resources", new MS.ClassLoadHook() {
- public void classLoaded(Class<?> resources) {
- // ... code to modify the class when loaded
- }
- });
- }
- }
步驟四:通過MS.MethodHook實(shí)例實(shí)現(xiàn)原代碼的修改。
為了調(diào)用原來代碼中的方法,我們需要創(chuàng)建一個MS.MethodPointer類的實(shí)例,它可以在任何時候運(yùn)行原來的代碼。
在這里我們通過對原代碼中resources對象原始代碼的調(diào)用和修改,將所有綠色修改成了紫羅蘭色。
- public void classLoaded(Class<?> resources) {
- Method getColor;
- try {
- getColor = resources.getMethod("getColor", Integer.TYPE);
- } catch (NoSuchMethodException e) {
- getColor = null;
- }
- if (getColor != null) {
- final MS.MethodPointer old = new MS.MethodPointer();
- MS.hookMethod(resources, getColor, new MS.MethodHook() {
- public Object invoked(Object resources, Object... args)
- throws Throwable
- {
- int color = (Integer) old.invoke(resources, args);
- return color & ~0x0000ff00 | 0x00ff0000;
- }
- }, old);
- }
- }
安裝運(yùn)行,重啟系統(tǒng)后發(fā)現(xiàn)很多字體顏色都變了。如下圖所示:
示例中MS.hookMethod的代碼可以改成:
- MS.hookMethod(resources, getColor, new MS.MethodAlteration<Resources, Integer>() {
- public Integer invoked(Resources resources, Object... args)
- throws Throwable
- {
- int color = invoke(resources, args);
- return color & ~0x0000ff00 | 0x00ffee00;
- }
- });
短信監(jiān)控實(shí)例
在下面的例子中我們實(shí)現(xiàn)了短信監(jiān)聽功能,將短信發(fā)送人、接收人以及短信內(nèi)容打印出來:
- 1 import java.lang.reflect.Method;
- 2 import android.app.PendingIntent;
- 3 import android.util.Log;
- 4 import com.saurik.substrate.MS;
- 5
- 6
- 7 public class Main {
- 8
- 9 static void initialize() {
- 10
- 11 MS.hookClassLoad("android.telephony.SmsManager", new MS.ClassLoadHook() {
- 12
- 13
- 14 @Override
- 15
- 16 public void classLoaded(Class<?> SmsManager) {
- 17
- 18 //code to modify the class when loaded
- 19
- 20 Method sendTextMessage;
- 21
- 22 try {
- 23
- 24 sendTextMessage = SmsManager.getMethod("sendTextMessage",
- 25
- 26 new Class[]{String.class,String.class,String.class,PendingIntent.class,PendingIntent.class});
- 27
- 28
- 29 } catch (NoSuchMethodException e) {
- 30
- 31 sendTextMessage = null;
- 32
- 33 }
- 34
- 35 MS.hookMethod(SmsManager, sendTextMessage, new MS.MethodAlteration() {
- 36
- 37 public Object invoked(Object _this,Object... _args) throws Throwable{
- 38
- 39 Log.i("SMSHOOK","SEND_SMS");
- 40
- 41 Log.i("SMSHOOK","destination:"+_args[0]);
- 42
- 43 Log.i("SMSHOOK","source:"+_args[1]);
- 44
- 45 Log.i("SMSHOOK","text:"+_args[2]);
- 46
- 47 return invoke(_this, _args);
- 48
- 49 }
- 50
- 51 });
- 52
- 53
- 54 }
- 55
- 56 });
- 57
- 58 }
- 59
- 60 }
運(yùn)行后的結(jié)果為: