A small improvement to OS X “rootkitery”: bruteforcing sysent discovery, fast & easy!

I love to read about the Human brain and yesterday I was feeling weird about this thing. As far as I know, everyone (publicly) was trying to search sysent in one way or another after Apple removed the sysent symbols but not bruteforcing it. It seems no one bothered to question the original method (Landon Fuller?) and just kept using it. Are there any historical reasons for this? I can’t remember any. Sometimes, we are just blind to the simple things and solutions and don’t question them. It’s very probable that someone already posed the same question about the known methods (this is not cold fusion :P). Let’s continue…

This is a simple method to bruteforce 32 and 64bits kernels (tested with Snow Leopard and Lion) and retrieve sysent address. The __DATA segment where the sysent symbol is located is around 250kbytes in size, which is pretty a small space to search. My first method required the kernel base address to be configured, which isn’t a great issue – historically, it is quite stable. Computers exist to automate tasks and @snare “complained” about hardcoding that address. I was trying to fix checkidt to 64bits and the solution to overcome the hardcoded address just came to mind. The IDT can be used for this! Just retrieve the IDT address, then the address of interrupt 80 (or some other implemented interrupt handler) and you know where the kernel is loaded. Now it is just a matter of finding the start of the kernel mach-o address, reading the __DATA segment to know its address and size, and then bruteforce search sysent array.
This can be even easier if we just bruteforce beyond and before the int 80 handler – not a sexy approach, we want elegant bruteforcing ;-).

The PoC code is for an userland util that retrieves the information through /dev/kmem. I did a kernel port, which works without any problems (it’s even easier to implement). On my Mac it takes 0m0.035s to find sysent (0m0.012s on a 64bits Mac Mini server – thanks to Saure for all tests). That is very good for what should be a future-proof method to retrieve sysent. Unfortunately, hijacking sysent isn’t sexy anymore!

In other news, Snare finally created his own blog, available at http://ho.ax. He started with a nice article about kernel debugging in VMWare, updating my old one. Good work!
Of course this is competition so he should expect a very evil EFI rootkit one of these days with total destruction of his computer ;-). Give it a look while it lasts!

Well, time to move forward to the next project. Ideas continue to abound…

If you like to read and are looking for great books, I highly recommend “Thinking, Fast and Slow” by Daniel Kahneman, Dan Ariely’s two books, and “Being Wrong: Adventures in the Margin of Error” by Kathryn Schulz. The world would probably be a better place if everyone knew their potential “shortcomings”. There’s more behind the scenes in our brains that we consciously know and like to admit.


SHA256(bruteforcesysent.zip)= 14a7b55368ad9ec91d639c3b6f5a61319c8b5ece61d6eb1ae4dd98182abcc33d

P.S.: If you are a github fan, I have been uploading stuff there.
P.S.2: Don’t forget the IRC channel, more active lately, irc.freenode.net, #osxre !

13 thoughts on “A small improvement to OS X “rootkitery”: bruteforcing sysent discovery, fast & easy!

  1. Thank you for the method!
    Could you tell me, how to look sysent table to know, what number has each function?
    In your program it was hardcoded

      1. It is clear,that Int80 is the interrupt used for syscalls. But your program doesn’t find sysent address in assemble code of int80 hadler, therefore why you choose it? Maybe, it’s closer to kernel loading address? Thanks

        1. Ah!
          That’s because you get a valid kernel address from the IDT table and that’s the place where you start searching for the mach-o header.
          Then you retrieve information for the __DATA segment and search there the sysent table.

  2. Thanks,but it isn’t what I mean. Could you tell me, how to read/write into files from IOKit driver?I read that it is impossible, but it doesn’t sound as true:)
    And one more, I tried to transform your bruteforce code to IOKit driver. It is compile, but didn’t load because of i/o functions: driver couldn’t resolve it. Maybe I should use static link? (I coded on C/C++ and don’t know is something like this in OS X)

    1. Now you are getting me confuse. The int80 handler is a good way to find a valid kernel address where you can start searching from. It’s a good way because you can find it in the IDT table, which is pretty easy to do and reliable.
      I never tried it as a IOKit driver but only as a normal kernel module. The method works, you need to do some adaptations to the userland code, nothing very complicated.

  3. Hello, fG!
    Could you explain me some moment. There are system calls, which described in man. For example, take syscall getdirentriesattr. It has 8 args, as it wrote in man and sysent[222].sys_narg=8 too.
    But really, this syscall (kernel version?) takes 3 args, as it wrote in Dino Dai Zovi book.
    First question: 1) how it might be
    2) how can I know a real count and types of other syscalls (in kernel)
    Thanx,waiting for answer

  4. I have found args for each syscall function in sysproto.h just now. Sorry for worry. But I still don’t understand, why there are two versions of prototype for each syscall. If it’s kernel and user lands version, then how it works.

    1. The number of arguments is from the userland implementation that you can obtain from sysproto.h, as you have discovered. Its implementation is a bit weird due to endianness, but you just need to count the nr of parameters without the l and r.
      The kernel implementation of the syscalls is different. They receive a proc_t structure, the arguments encapsulated in a struct (usually uap) and a pointer to the return value.

      You can study the interrupt 80 handler (or the syscall/sysenter) handler to understand the mechanism of using syscalls.


Leave a Reply

Your email address will not be published. Required fields are marked *