Onyx the Black Cat v0.4 for Snow Leopard

I had this one working for a long time but I hadn’t released it because I was trying to hijack fork and vfork calls. My objective was to introduce an int3 so I could attach the debugger to a selected process. At that time I suspected that VLOK was forking and I couldn’t debug the new process since follow on fork gdb function isn’t implemented in OS X (so this looks like a good idea for a protection ;-) ). My idea was to inject an int3 or pause the new process so I could attach another gdb to it. Those attempts failed and one of these days I need to get back to the problem and think better about it (if you have a solution for how to do it in the kernel module feel free to contribute!!!).

The method to grab sysent address changed again in Snow Leopard and for now there is an hardcoded address. The method is to find nsysent address (nm /mach_kernel | grep nsysent) and then subtract 0×2850 from it. Matthie Suiche described a method in the paper ADVANCED MAC OS X PHYSICAL MEMORY ANALYSIS.
“Under Mac OS X Snow Leopard (10.6), we have to proceed with a different methodology. First, we have to retrieve the value of nsysent variable, then we multiply its value with the size of sysent structure, and then we subtract this value to nsysent offset to obtain the offset of sysent table.”

I would prefer a more elegant solution to this :-)

The structures had to change and more stuff had to be ripped off from xnu kernel headers. They are still incomplete but what is there is enough for current purposes.

Here it is:
onyx-the-black-cat-v0.4.tgz
(SHA1(onyx-the-black-cat-v0.4.tgz)= 5dff3c4a9246f2886b470aa0ab60b5e237ca3659)

Have fun,
fG!

  1. Fz’s avatar

    It seams that sctructures.h are redefining some structs. I’m getting lot of compiling errors like:

    In file included from /Users/…/Downloads/onyx-the-black-cat-snowleopard/onyx_the_black_cat.c:30:
    /Users/…/Downloads/onyx-the-black-cat-snowleopard/structures.h:439: error: redefinition of ‘struct _pcred’
    /Users/…/Downloads/onyx-the-black-cat-snowleopard/structures.h:449: error: redefinition of ‘struct _ucred’
    /Users/…/Downloads/onyx-the-black-cat-snowleopard/structures.h:457: error: redefinition of ‘struct extern_proc’
    /Users/…/Downloads/onyx-the-black-cat-snowleopard/structures.h:513: error: redefinition of ‘struct kinfo_proc’
    /Users/…/Downloads/onyx-the-black-cat-snowleopard/structures.h:515: error: redefinition of ‘struct eproc’

    Reply

  2. Fz’s avatar

    My fault.

    PROTip: Check that 10.6 is your active SDK :)

    Reply

    1. fG!’s avatar

      Yeah I was going to answer but you already found by yourself. Have to change project default to use 10.6 SDK.

      Thanks for the test :-)

      Reply

  3. Fz’s avatar

    Ok. The kext is working. Now PT_DENY_ATTACH/P_LNOATTACH is blocked. But for some reason functions/symbols are not loaded.

    I keep getting:

    Function “xxxxx” not defined.
    Make breakpoint pending on future shared library load? (y or [n])

    But those functions not only are present on the dump (class-dump) and showed by otx, also ARE called (checked sing dtrace)

    #!/usr/sbin/dtrace -qs

    pid$1::objc_msgSend:entry
    {
    self->isa = *(long *)copyin(arg0,4);
    printf(“-[%s %s]\n”,copyinstr(*(long *)copyin(self->isa + 8,
    4)),copyinstr(arg1));
    }

    Any idea why ?

    Reply

  4. Fz’s avatar

    Playing around with traced i just found one interesting object address. (Still I can’t read function names in gdb).

    gdb$ print (int)[0x42e150 licenseIsValid]
    $1 = 0×0

    How can I add a breakpoint into this function?

    gdb$ break licenseIsValid
    Function “licenseIsValid” not defined.

    Thank you!

    Reply

  5. navaja’s avatar

    Can’t get it to work. If I try to load it a second time my mac crashes and I have to reboot.

    navaja:~ navaja$ sudo kextload /System/Library/Extensions/onyx-the-black-cat.kext
    /System/Library/Extensions/onyx-the-black-cat.kext failed to load – (libkern/kext) kext (kmod) start/stop routine failed; check the system/kernel logs for errors or try kextutil(8).

    navaja:~ navaja$ sudo dmesg
    npvhash=4095
    PAE enabled
    64 bit mode enabled
    Darwin Kernel Version 10.3.0: Fri Feb 26 11:58:09 PST 2010; root:xnu-1504.3.12~1/RELEASE_I386

    [onyx-the-black-cat] Starting patching …
    [onyx-the-black-cat] Finding sysent table…
    [onyx-the-black-cat] Sanity check: verifying if number of syscalls arguments are the expected ones
    [onyx-the-black-cat] Sanity check: sanity check failed, could not find sysent table.
    [onyx-the-black-cat] Error: Cannot find sysent table
    Kext com.reverse.put.as.kext.onyx_the_black_cat start failed (result 0×5).
    Kext com.reverse.put.as.kext.onyx_the_black_cat failed to load (0xdc008017).
    Failed to load kext com.reverse.put.as.kext.onyx_the_black_cat (error 0xdc008017).

    Any suggestions?
    Perhaps it has something to do with the pt_deny_attach.kext I was using before?
    http://bit.ly/96OzCq

    Reply

    1. fG!’s avatar

      Most probably has to do with the fact that you are using a 64bit kernel!
      Issue this command “nm /mach_kernel | grep _nosys” and tell me what’s the output :-)

      Totally forgot about 64bit kernels!

      Reply

  6. navaja’s avatar

    The output is: ffffff800048996c T _nosys

    Does this mean that I should change this line in onyx_the_black_cat.c:
    table = (struct sysent *) ( 0×00831730 – 0×2710 );
    to this:
    table = (struct sysent *) ( 0x0048996c – 0×2710 );
    ?

    Reply

    1. fG!’s avatar

      The address should be 0xffffff800048996c. But the substract size must be different since we are talking about 64 bit addresses. Let me check and compute the right value and I will come back to you :-)

      Reply

  7. navaja’s avatar

    navaja:~ navaja$ nm -arch i386 /mach_kernel | grep _nosys
    004910f3 T _nosys

    navaja:~ navaja$ nm -arch x86_64 /mach_kernel | grep _nosys
    ffffff800048996c T _nosys

    Reply

  8. navaja’s avatar

    And here is the output for _nsysent for 32bit and 64bit arch:

    $ nm -arch i386 /mach_kernel | grep _nsysent
    00831730 D _nsysent
    0085df7c S _nsysent_size_check

    $ nm -arch x86_64 /mach_kernel | grep _nsysent
    ffffff800065ac90 D _nsysent
    ffffff8000695830 S _nsysent_size_check

    Reply

  9. fry’s avatar

    killer…. :D
    10x…

    cheers

    Reply

  10. Ans’s avatar

    Hello again fG!

    I just read that you was working on “Remote Buddy” too. Could you share your experience?. I’m a little bit lost on this one. I can’t get symbols correctly, and I’m running out of luck using just otx/hexeditor.

    I removed _ptraced calls and could locate CopyCore address but i don’t know if that helps. What are RBuddy encrypting on directories?.

    Thank you for all your work by the way.

    Reply

    1. fG!’s avatar

      I don’t remember much about Remote Buddy except that the author is very active in changing protections and he was a bit annoyed by my article. I would expect him to be improving the protection and making things harder. The nice trick he was using was the extended attributes to store information. That’s the reason that I coded that feature into onyx the black cat so I could easily monitor any attempts to it.

      Reply

  11. Reflejo’s avatar

    In 10.6.4, substracting 0×2850 will not work, It’s now located at -0x28b0 from the _nsysent symbol.

    table = (struct sysent *) ( 0x008317f0 – 0x28b0 );

    Reply

    1. negev’s avatar

      - table = (struct sysent *) ( 0×008317f0 – 0×28b0 );

      This causes my 10.6.4 mbp to panic, is this for 32bit? How does one find the 64bit values?

      Thanks!

      Reply

  12. provi’s avatar

    navaja you get it working on 64 bit kernel?? can you telll us which values you used in :

    table = (struct sysent *) ( 0x008317f0 – 0x28b0 );

    I used this ones:

    table = (struct sysent *) ( 0xffffff800065ad90 – 0x1D08D4 );

    it compiles but it throws two warnings:

    integer constant is too large for ‘long’ type
    cast to pointer from integer of different size

    how do I transform this on to 64bit??? any ideas??

    Reply

  13. xarg’s avatar

    10.6.4 64-bit:
    table = (struct sysent *) ( 0xFFFFFF80006569C0);

    Make sure to change to the 10.6 SDK and change the architectures from ppc and i386 to x86_64. A 64-bit address will not fit into a 32-bit pointer, so you will get a warning and loading the kext will crash your Mac.

    Reply

  14. gmcinnes’s avatar

    I don’t suppose anyone has figured out the magic numbers for 10.6.5 yet, have they?

    Here’s the output from above. I’m running an i386 kernel

    nm -arch i386 /mach_kernel | grep _nosys
    00495402 T _nosys

    nm -arch i386 /mach_kernel | grep _nsysent
    00831790 D _nsysent
    0085df9c S _nsysent_size_check

    I was trying to grok, from your comments, and from some of the linked articles, the algorithm for getting the offset, but I couldn’t. fG! if you post that, I can probably take it from there.

    Reply

    1. fG!’s avatar

      Hi,

      I don’t have really an algorithm and usually use an hex editor and the old offsets to land more or less in the range of the right address.
      The Mac Hackers Handbook book describes an algorithm to find it. I’ve been for quite some time to test it out. I really hate that stuff to be hardcoded. It’s not pretty ;-)
      Well I just upgraded to 10.6.5 so I will need to find it. Probably will do it tomorrow. I will post a comment here.

      fG!

      Reply

  15. gmcinnes’s avatar

    Thanks fG! I await eagerly :)

    Reply

    1. fG!’s avatar

      Hi again,

      The info you are looking is:
      table = (struct sysent *) ( 0×00831790 – 0x28b0 );

      You can use something like this to use between different versions:
      extern const char osrelease[];
      if (strcmp(osrelease,”10.0.0″) == 0)
      {
      table = (struct sysent *) ( 0×00831730 – 0×3710 );
      }
      else if (strcmp(osrelease,”10.1.0″) == 0) {
      table = (struct sysent *) ( 0×00831730 – 0×2710 );
      }
      else if (strcmp(osrelease,”10.2.0″) == 0) {
      table = (struct sysent *) ( 0×00831870 – 0×2850 );
      }
      //
      else if (strcmp(osrelease,”10.3.0″) == 0) {
      table = (struct sysent *) ( 0×00831730 – 0×2710 );
      }
      // OK
      else if (strcmp(osrelease,”10.4.0″) == 0) {
      table = (struct sysent *) ( 0x008317f0 – 0x28b0 );
      }
      else if (strcmp(osrelease,”10.5.0″) == 0) {
      table = (struct sysent *) ( 0×00831790 – 0x28b0 );
      }

      Have fun!

      Reply

  16. b0s’s avatar

    this only for 32 bit kernel
    how to do it in 64 bit kernel
    thx

    Reply

    1. fG!’s avatar

      Find the address of nosys and exit symbols, then search for them in mach_kernel (don’t forget Intel is little endian). The first match should be near the start of the sysent table (check Braeden Thomas that’s linked in a previous post). Then you can use old values to land near the range of the number of syscalls (download xnu kernel to verify the number for that version). If they don’t match, its’s a matter of searching near.

      Not the best method but it works :-)

      Reply

  17. 4n1’s avatar

    Hi,

    at first, great Site! I can’t get onyx to work on my snow leopard. When i try to load the kext, i get a validation error.

    kextutil:
    /System/Library/Extensions/onyx-the-black-cat.kext is invalid; can’t resolve dependencies.
    /System/Library/Extensions/onyx-the-black-cat.kext is invalid; can’t resolve dependencies.
    /System/Library/Extensions/onyx-the-black-cat.kext is invalid; can’t resolve dependencies.
    /System/Library/Extensions/onyx-the-black-cat.kext has problems:
    Validation Failures:
    Kext has a CFBundleExecutable property but the executable can’t be found:
    onyx-the-black-cat

    system.log:

    com.apple.kextd[17]: Can’t load /System/Library/Extensions/onyx-the-black-cat.kext – validation problems.

    com.apple.kextd[17]: Failed to load /System/Library/Extensions/onyx-the-black-cat.kext – (libkern/kext) validation failure (plist/executable).

    what i do wrong?

    btw.: table = (struct sysent *) ( 0×00831790 – 0x28b0 );

    works for me on SL

    thx

    Reply

    1. 4n1’s avatar

      sorry my fault. i think the kext is not compiled correctly.

      the tree structure contains only the Resources folder ..

      Reply

      1. fG!’s avatar

        Does it work now ?

        Reply