The most important task a developer of Substrate extensions performs is to modify the operation of existing code. To do this implies being able to both replace any method as well as be able to call through to the original implementation.

This API allows the developer to provide a callback to be executed in place of the original method. This callback is an object that implements an interface MS.MethodHook, which has a single method named "invoked". This will typically be an anonymous inner class.

In order to call through to the original implmentation (such as if the modification is simply to alter the arguments being passed) an instance of MS.MethodPointer is passed and filled in during the hook; this object has a method called "invoke" that canbe used to call the original code.

The developer can choose to pass a single argument of type MS.MethodAlteration. This class implements MS.MethodHook and extends MS.MethodPointer, allowing the developer to avoid having to declare these separately. It is expected most users will use this version of the API.

If multiple developers attempt to hook the same API, the calls will stack: the last hook of the function will have an "original implementation" that calls through to the previous hook, which in turn will call through to whatever hook came before it, until eventually you find the original.

The type signature of the various functions are fully general, in that they take and returns "boxed" arguments in an array: each primitive typed argument will be represented as an Object. For convenience, developers can call invoke using variadic arguments.

Note: For Objective-C developers used to MSHookMessageEx, it should be noted at this API currently does not allow for hooking "below" a method at a different point in the inheritance hierarchy. It is intended that this will be fixed in a future release of Substrate.

void hookMethod(Class _class, Member member, MS.MethodHook hook, MS.MethodPointer old);
void hookMethod(Class _class, Member member, MS.MethodAlteration alteration);
Parameter Description
_class Java Class for which member will be instrumented.
member Reflected Method (or Constructor) to instrument. Note: you cannot hook a Field (this is checked while compiling).
hook An instance of MS.MethodHook whose boxed invoked method will be called instead of the code of member.
old An instance of MS.MethodPointer that will be filled in using information from the original implementation of member. You will be able to call invoke on this object using boxed arguments to call that original method implementation.

This type signature is slightly more flexible and is very similar to other APIs provided by Substrate, such as MSHookFunction and MSHookMessageEx. However, developers are encouraged to use the version below, as it is both simpler and less error-prone by not requiring a separate MS.MethodPointer.

Class _class = Class.forName("java.net.InetSocketAddress");

Constructor method = _class.getConstructor(
    String.class, Integer.TYPE);

final MS.MethodPointer old = new MS.MethodPointer();

MS.hookMethod(_class, method, new MS.MethodHook() {
    public Object invoked(Object _this, Object... args)
        throws Throwable
    {
        String host = (String) args[0];
        int port = (Integer) args[1];

        if (port == 6667)
            port = 7001;

        return old.invoke(_this, host, port);
    }
}, old);
Parameter Description
_class Java Class for which member will be instrumented.
member Reflected Method (or Constructor) to instrument. Note: you cannot hook a Field (this is checked while compiling).
alteration An instance of MS.MethodAlteration whose boxed invoked 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.
Class _class = Class.forName("java.net.InetSocketAddress");

Constructor method = _class.getConstructor(
    String.class, Integer.TYPE);

MS.hookMethod(_class, method, new MS.MethodAlteration() {
    public Object invoked(Object _this, Object... args)
        throws Throwable
    {
        String host = (String) args[0];
        int port = (Integer) args[1];

        if (port == 6667)
            port = 7001;

        return invoke(_this, host, port);
    }
});