While modifying the behavior of high-level runtimes such as Java or Objective-C can often be something that can be done using supported features (such as custom class loaders or runtime APIs), native code can make the challenge of code instrumentation daunting.

In some limited circumstances (when one is dealing with public exported symbols being linked between dynamic libraries) it might be possible to use features of the dynamic loader (such as "interpose" or "preload") to swap out entire symbols, we do not always have things that simple.

If you instead need to be able to modify the behavior of a private symbol, or even often a public one that is being called from the same library or translation unit (and thereby does not get linked at runtime), you need more powerful primitives; this is certainly the case if you need to change code inside of a function.

For this purpose, Substrate provides an API that allows developers to not only replace most any point in native code with their own behavior, but also be able to call through to the original code (which can require complex disassembly and re-assembly of "program counter" or "instruction pointer" relative logic.

void MSHookFunction(void *symbol, void *hook, void **old);
Parameter Description
symbol The address of code to instrument with replacement code. This is normally, but need not be, a function.
hook The address of an ABI-compatible replacement for the code at the address referenced by symbol.
old A pointer to a function pointer that will be filled in with a stub which may be used to call the original implementation. This can be NULL if you do not proceed to the original.
void *(*oldConnect)(int, const sockaddr *, socklen_t);

void *newConnect(
    int socket, const sockaddr *address, socklen_t length
) {
    if (address->sa_family == AF_INET) {
        sockaddr_in *address_in = address;
        if (address_in->sin_port == htons(6667)) {
            sockaddr_in copy = *address_in;
            address_in->sin_port = htons(7001);
            return oldConnect(socket, &copy, length);
        }
    }

    return oldConnect(socket, address, length);
}

MSHookFunction(&connect, &newConnect, &oldConnect);