Monday 21 December 2015

Running DTruss on OS X El Capitan



Dtruss in OS X, much alike strace in Linux, is a very useful tool providing the capability to look at what a program is doing (more precisely, how it interacts with the operating and file system) without having to debug it on the source code level. In a recent system update called El Capitan, however, the tool stopped operating with default settings due to the newly implemented System Integrity Protection mechanism. Trying to run dtruss now results in an error:
$ dtruss ls
dtrace: failed to initialize dtrace: DTrace requires additional privileges
$ sudo dtruss ls
dtrace: failed to execute ls: dtrace cannot control executables signed with restricted entitlement

Some solutions on the Internet suggest to fully or partially disable System Integrity Protection to allow dtruss to do its bidding. However, such dire measures are not really necessary in most cases, since all that is really needed is to let it know that the program you're running is signed with no "restricted entitlement", i.e. which is to be trusted and allowed to be "spied" on.

This short step-by-step guide shows how to run dtruss without meddling with SIP (and, thus, potentially compromising the computer's security).
We assume that we want to run dtruss on the standard command line utility ls. To run dtruss on any other application, just replace the corresponding lines with the path to your application.

1) Create a copy of the standard sudo utility in a non-protected directory and re-sign it with an ad-hoc signature. This is needed so that we could run our application with standard user privileges (dtruss itself requires administrator privileges).
$ sudo mkdir -p /usr/local/bin # the directory may already exist on your system
$ sudo cp /usr/bin/sudo /usr/local/bin/sudo
$ sudo codesign -fs- /usr/local/bin/sudo

2) Now, re-sign the application you want to trace with an ad-hoc signature. Note: it will not work if the application is located in one of the standard binary directories which are protected (/System, /bin, /sbin, /usr/bin). In that case you need to copy the application somewhere else.

$ cp /bin/ls /usr/local/bin # this is obligatory only if the binary is located in a protected directory, or if you want to preserve the signature on its original copy
$ sudo codesign -fs- /usr/local/bin/ls

3) Finally, you're good to run struss!
$ sudo dtruss -f /usr/local/bin/sudo -u `whoami` /usr/local/bin/ls
...
43024/0x14e0f8:  fchdir(0x4, 0x7FE2DC002600, 0x1000)         = 0 0
43024/0x14e0f8:  close_nocancel(0x4)         = 0 0
43024/0x14e0f8:  fstat64(0x1, 0x7FFF5DB92D88, 0x1000)         = 0 0
43024/0x14e0f8:  ioctl(0x1, 0x4004667A, 0x7FFF5DB92DCC)         = 0 0
43024/0x14e0f8:  write_nocancel(0x1, "AUTHORS\t\tChangeLog-2014\tREADME-alpha\tbootstrap.conf\tdoc\t\tm4\t\tthanks-gen\n@\004\b\0", 0x48)         = 72 0
43024/0x14e0f8:  write_nocancel(0x1, "BUGS\t\tMakefile.am\tTHANKS.in\tbuild-aux\tgnulib\t\tpo\n\004\b\0", 0x31)         = 49 0
43024/0x14e0f8:  write_nocancel(0x1, "COPYING\t\tNEWS\t\tbasicdefs.h\tcfg.mk\t\tgnulib-tests\tsed\n@\004\b\0", 0x34)         = 52 0
43024/0x14e0f8:  write_nocancel(0x1, "COPYING.DOC\tREADME\t\tbootstrap\tconfigure.ac\tlib\t\ttestsuite\n\b\0", 0x3A)         = 58 0
...

Used sources:
http://stackoverflow.com/a/33776939/161934
https://sourceware.org/gdb/wiki/BuildingOnDarwin

P.S. With this approach the first few system calls will belong to sudo and not your app. Just skip them. Or try suspending the process at its start and attaching to it with dtruss (I'm still figuring out the best way to do that myself without meddling with the dynamic linker...).
P.P.S. As it may be seen, this post was written by someone not very familiar with OS X. I'll greatly appreciate any comments on potential mistakes and misconceptions encountered in it.
P.P.P.S In this article we signed the application with an ad-hoc signature. If you want to create your own signature and sign the application with it, do the following:
  • Run the Keychain Access application (⌘+Space => "Keychain Access" => Enter)
  • Pick "Keychain Access" => "Certificate assistance" => "Create a Certificate"
  • Set the type of the certificate to "Code" and give it an arbitrary name "your_certificate_name" which you will need to re-enter later. Your username should do.
  • Create the certificate. 
  • Then, re-run codesign as indicated above, replacing "-" with your own signature.