Cycript

1 min read Original article ↗

Example

Say we have a program that opens /etc/passwd to check our password. We would prefer that it uses /var/passwd-fake. First, we need the address of fopen.

cy# fopen = dlsym(RTLD_DEFAULT, "fopen")
(typedef void*)(0x7fff900c34ec)

We can't work with this function without a type signature, though, so let's cast it to a Functor. With Cycript we can use high-level C typedef syntax.

cy# fopen = (typedef void *(char *, char *))(fopen)
(extern "C" void *fopen(char *, char *))

Next, let's @import Substrate, so we can use MS.hookFunction to modify fopen: we will swap in our fake passwd file, as well as log all the arguments.

cy# @import com.saurik.substrate.MS
cy# var oldf = {}
cy# var log = []
cy# MS.hookFunction(fopen, function(path, mode) {
        if (path == "/etc/passwd")
            path = "/var/passwd-fake";
        var file = (*oldf)(path, mode);
        log.push([path.toString(), mode.toString(), file]);
        return file;
    }, oldf)

In addition to our nefarious modification, this let's us see all of the calls to fopen, as well as track what the returned FILE * values were. Let's try it out.

cy# fopen("/etc/passwd", "r");
(typedef void*)(0x7fff72c14280)
cy# log
[["/var/passwd-fake","r",(typedef void*)(0x7fff72c14280)]]