Android HOOK工具Cydia Substrate使用詳解

swordsman發表於2014-10-10

Cydia Substrate是一個程式碼修改平臺。它可以修改任何主程式的程式碼,不管是用Java還是C/C++(native程式碼)編寫的。而Xposed只支援HOOK app_process中的java函式,因此Cydia Substrate是一款強大而實用的HOOK工具。

官網地址: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

函式原型:void hookClassLoad(String name, MS.ClassLoadHook hook);

該方法實現在指定的類被載入的時候發出通知。因為一個類可以在任何時候被載入,所以Substrate提供了一個方法用來檢測使用者感興趣的類何時被載入。

引數

描述

name

包名+類名,使用java的.符號

hook

MS.ClassLoadHook的一個例項,當這個類被載入的時候,它的 classLoaded 方法會被執行。

MS.hookMethod

該API允許開發者提供一個回撥函式替換原來的方法,這個回撥函式是一個實現了MS.MethodHook介面的物件,是一個典型的匿名內部類。它包含一個invoked函式。

函式原型:

void hookMethod(Class _class, Member member, MS.MethodHook hook, MS.MethodPointer old);
void hookMethod(Class _class, Member member, MS.MethodAlteration alteration);

引數描述

(一)

引數

描述

_class

載入的目標類,為classLoaded傳下來的類引數

member

通過反射得到的需要hook的方法(或建構函式). 注意:不能HOOK欄位 (在編譯的時候會進行檢測).

hook

MS.MethodHook的一個例項,其包含的invoked方法會被呼叫,用以代替member中的程式碼

(二)

引數

描述

_class

載入的目標類,為classLoaded傳下來的類引數

member

通過反射得到的需要hook的方法(或建構函式). 注意:不能HOOK欄位 (在編譯的時候會進行檢測).

alteration

An instance of MS.MethodAlteration whose boxedinvoked method will be called instead of member. This instance will also be filled in using information from   the original implementation, allowing you to use invoke to call the original method implementation.

建議開發者使用第二種方式,這種方式使用起來簡單並且很少出錯,不需要一個單獨的MS.MethodPointer類例項。

使用方法

下面以官網的一個例項來說明cydia substrate的使用方法。該例項是實現將多個介面元件顏色修改為紫羅蘭色。

需要安裝:http://www.cydiasubstrate.com/download/com.saurik.substrate.apk

步驟一:建立一個空的Android工程。由於建立的工程將以外掛的形式被載入,所以不需要activity。將SDK中的substrate-api.jar複製到project/libs資料夾中。

步驟二:配置Manifest檔案

(1)需要指定許可權:cydia.permission.SUBSTRATE

(2)新增meta標籤,name為cydia.permission.SUBSTRATE,value為下一步中建立的類名.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>

步驟二:建立一個類,類名為Main。類中包含一個static方法initialize,當外掛被載入的時候,該方法中的程式碼就會執行,完成一些必要的初始化工作。

import com.saurik.substrate.MS;

public class Main {
    static void initialize() { 
        // ... code to run when extension is loaded
    }
}

步驟三:為了實現HOOK,達到修改目標類中的程式碼的目的,我們需要得到目標類的一個例項,如示例中的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例項實現原始碼的修改。

為了呼叫原來程式碼中的方法,我們需要建立一個MS.MethodPointer類的例項,它可以在任何時候執行原來的程式碼。

在這裡我們通過對原始碼中resources物件原始程式碼的呼叫和修改,將所有綠色修改成了紫羅蘭色。

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);
    }
}

安裝執行,重啟系統後發現很多字型顏色都變了。如下圖所示:

示例中MS.hookMethod的程式碼可以改成:

1 MS.hookMethod(resources, getColor, new MS.MethodAlteration<Resources, Integer>() {
2          public Integer invoked(Resources resources, Object... args)
3                  throws Throwable
4          {
5                  int color = invoke(resources, args);
6                  return color & ~0x0000ff00 | 0x00ffee00;
7          }
8 });

簡訊監控例項

在下面的例子中我們實現了簡訊監聽功能,將簡訊傳送人、接收人以及簡訊內容列印出來:

 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 }

執行後的結果為:

相關文章