VioletExample Android Java

To demonstrate how to use Substrate to build an extension, we will now walk through the implementation of a concrete example: an extension that modifies the color of numerous interface components to become shades of violet. This extension is useless, but has the advantage of being immediately noticeable.

Step 1: Manifest Configuration

For our code to be loaded, our package must have the cydia.permission.SUBSTRATE permission.

We also the name of a class to be loaded, which we will define in the next step.

See Also:

Code Deployment: Android Java

<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>

Step 2: Library Skeleton

Once loaded, the static "initialize" method is executed, allowing us to run code that uses the public API provided by Substrate's MS class.

See Also:

Code Deployment: Android Java

import com.saurik.substrate.MS;

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

Step 3: Wait for Class

In order to change the code for a class, we first need a reference to that class. Substrate allows us to provide a callback that will be executed when classes with specific descriptors are loaded.

See Also:

Java API: MS.hookClassLoad

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

Step 4: Modify Implementation

The implementation of the method is proxied through the provided MS.MethodHook instance: all types—both in and out—are "boxed" to Object.

To call the previous implementation, we also set up an instance of MS.MethodPointer, which can be invoked at any time to run the original code.

Here, we call through to the original and modify the result, removing all green from the color and jacking up the red (yielding shades of violet).

Please note that this example explicitly avoids simplifications such as MS.MethodAlteration and the usage of Java generics for overall code clarity.

See Also:

Java API: MS.hookMethod

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

Step 5: Consolidate Code

Using Java generics and MS.MethodAlteration allows you to simplify the implementation: the return and object types can be explicitly specified, and the MS.MethodPointer old is not required.

MS.hookMethod(resources, getColor, new MS.MethodAlteration<Resources, Integer>() {
    public Integer invoked(Resources resources, Object... args)
        throws Throwable
    {
        return invoke(resources, args) & ~0x0000ff00 | 0x00ff0000;
    }
});