cbashmacossystem-callsdtrace

recording `open` syscalls on mac


I would like to know what calls are made to open(2) in a bash script.

I wrote the following program which intercepts syscalls:

#include <fcntl.h>
#define _GNU_SOURCE
#include <dlfcn.h>
#include <stdio.h>
#include <stdlib.h>

#define DYLD_INTERPOSE(_replacment,_replacee) \
__attribute__((used)) static struct{ const void* replacment; const void* replacee; } _interpose_##_replacee \
__attribute__ ((section ("__DATA,__interpose"))) = { (const void*)(unsigned long)&_replacment, (const void*)(unsigned long)&_replacee };

static
int
my_open(const char *filename, int oflag, mode_t mode)
{
    printf("$jason$ open: %s\n", filename);
    return open(filename, oflag, mode);
}
DYLD_INTERPOSE(my_open, open)

Which I then ran using:

clang -dynamiclib libfile.c -o libfile.dylib
export DYLD_INSERT_LIBRARIES=libfile.dylib
touch /tmp/testingtesting

It doesn't work.

I tried it with a program that I compiled and it works fine. I tried it with programs compiled by brew and it works fine. I read the source code for touch.c. It calls open(2).

I then disabled SIP and it worked fine. So, I concluded that it was SIP that was causing the problem. I don't want to disable SIP though.

What should I do? I was thinking about just allowing dtrace: csrutil enable --without dtrace. Because I think dtrace can track syscalls but I'm not sure if that is a safe option.


Solution

  • What you are doing is called library injection, and Apple works hard to remove this ability from their system.

    As a result of their efforts, with SIP enabled, you can do the DYLD_INSERT magic only to the apps that are not hardened (or hardened with several specific exceptions), which I suppose are the apps you built and brew ships. Apple binaries, one of which is touch, are usually hardened or protected in other ways.

    You don't have a big number of options here:

    1. Disable SIP and inject what you want
    2. Disable SIP partially and you may achieve some goals (dtrace may help)
    3. Write a kernel extension doing injection and somehow get the kext signature from the Apple - it could work with SIP enabled.

    All these options are for Intel-based macs, for m1 it could be even harder.

    Regarding the safety: cut the machine with SIP disabled from the external sources of data (Internet, USB-drives etc), do your research, then enable SIP back and connect mac again to the world.