Skip to content

Latest commit

 

History

History
141 lines (129 loc) · 11.5 KB

blog.md

File metadata and controls

141 lines (129 loc) · 11.5 KB

Recently I had far too much time on my hands and a Kext binary which seemed to peak my interest. After spending a bit of time analyzing the binary in IDA Pro I wanted to prove out some theories I had by debugging it. A while back I had set up MacOS to be running as a QEMU/KVM machine - though I no longer had access to the hardware that I set this up on. The purpose of the previous usecase was to have lots of instances up (fuzzing) opposed to indepth debugging and I had never actually wondered about debugging the kernel. Anywho - I decided to relook into setting up a virtualized instance of MacOS and decided to go the VMWare Fusion route. I had a license on the computer I had in front of me, wanted to continually do snap shops, and just assumed it would be easy to get working locally. Well, I was sort of right?

The bulk of the VMWare fusion part was just following the knowledgebase article from VMWare - there really isn't any magic to do there.

After getting the VM built and set up - all the sources I found online seem to point out you will need to disable SIP and get your host environment set up. Patrick Wardle (documented this process)[https://objective-see.com/blog.html#blogEntry9] quiet well over on his blog, though it didn't "just work" for me - though I kept being stumped as to why. Honestly, I still have no idea what the issue was, though I've be able to impliment a work around for the time being. To summerize the steps from Patrick's page we need to do the following;

  • Disable SIP on the vm Boot into Recovery Mode, open a terminal and type csrutil disable. Reboot the VM
  • Enable Debugging in the Guest environment After the VM reboots, open a terminal and change the boot-args by doing the following; sudo nvram boot-args="debug=0x141 pmuflags=1 -v Reboot the VM

This is the first step that didn't work out quiet the way I had hoped. According to most sources online, setting debug=0x141 should cause the system to prompt you with a Waiting for remote debugger connection. while booting up. However, this never occured for me. After Googling more and more, I couldn't really find anyone who had mentioned this issue (thus the main motivation for writing this) - so I pushed on until I found a better explanation of the boot args. According to the Apple Developer Documentation page by setting 0x141 - these are the correct flags for us to set. Since 0x141 = (DB_HALT | DB_ARP | DB_LOG_PI_SCREEN), however it would appear thr DB_HALT option is non-functional at this point in time. If anyone knows the reasoning behind the, or if this is just a weird blunder on my part, feel free to comment here or shoot me a message. I canot seem to find any real reasoning behind this no longer working.

The work around for this, which I assume everyone doing kernel debugging is using at this point, is to use the DB_NMI flag, so the command we run to properly set up the boot-args will be; sudo nvram boot-args="debug=0x144 pmuflags=1 -v" Then rebooting the machine. This allows us to have the debugger listen for Non-Masking Iterrupts, which we can cause at any time. These can be create by pressing Esc + Control + Option + Command at the same time - if on a laptop where you have turned on the "Use function keys as function keys" option, you'll need to hold the fn key as well. This will overlay text on the top left of your screen indicating the IP address to connect too.

  • On host, download and install Apple's "Kernel Debug Kit" which is specific to the kernel of the guest environment you want to debug.
  • Start lldb on the host machine and point it at the kernel you just downloaded
    $ lldb
    (lldb) target create /Library/Developer/KDKs/KDK_10.11.5_15F34.kdk/System/Library/Kernels/kernel.development
    (lldb) command script import "/Library/Developer/KDKs/KDK_10.11.5_15F34.kdk/System/Library/Kernels/kernel.dSYM/Contents/Resources/DWARF/../Python/kernel.py
    

At this point if you have your guest properly set up and waiting for the debugger, you could now attach lldb directly to the ip address (lldb) kdp-remote 172.16.210.142

Viola! Well, sort of? It did work for a short time, approximately ~60 seconds or so. The debugger appears to attach fine, break points would be set and hit. Though after the first minute or so, it would seem the the remote connect somehow would continuously drop. Niether lldb or the guest environment would notice this or complain - just every command would seemingly either silently fail or error out for unknown Python reasons.

At this point I was getting a bit frustrated, I had to have done something wrong? The entire set up got trashed and I started again, checking every step to ensure I was doing it correctly. Though the resulting set up seemed to always have the same outcome - 60 or so seconds of debug time and then a reboot would be required to connect again. This clearly wasn't a workable option. Being hopped up on pain killers due to a motorcycle accident, I blindly started tweeting some rage about how silly debugging kernel code on MacOS seemed to be, no documentation I could find correctly explained getting it working and seemingly no one had ever run into this problem. Magically, complaining on twitter did something and a friend I met at Hoodsec mentioned something along the lines of "lldb kdb over udp is often laggy and not stable, use gdb". Without attempting to start an emacs vs vim style fight, I immediately loved the idea since I prefer gdb over lldb anyway - it just seems to be a comfort zone for me. Of to Google more about using gdb to debug kexts I come across Snare's post on the matter.

Not only is this post simple to understand, it is essentially the exact setup I was using. Turns out that VMWare made it pretty easy for us, since they have a debugStub which can be enable on any VM. Opening up the VM config file, for me it was in ~/VMs/OSX10_11_5.vmwarevm/OSX10_11_5.vmx and adding the following lines at the bottom (while VM is not running).

debugStub.listen.guest32 = "TRUE"
debugStub.listen.guest64 = "TRUE"

This seems like it will work out great, except Apple no longer ships gdb nor does it ship any macros to assist debugging for gdb anymore. Luckily someone has done all the work for us, thanks OSXreverser! Pedro wrote a great article a few years back about compiling gdb which can be found on his blog. After that, go snag the repo (gdbinit/kgmacros)[https://github.com/gdbinit/kgmacros] which contains the older macros which /mostly/ work for newer kernels. If you didn't already have the .gdbinit script from Pedro, you should also get and install that. After getting all this preparation work done, fire the VM back up and prepare gdb before connection. Target the kernel the guest machine is using, add the symbols for it and then load the helper macros and connect to the guess.

diff@rocksteady:[~/kext_work/] $ gdb /Library/Developer/KDKs/KDK_10.11.5_15F34.kdk/System/Library/Kernels/kernel
GNU gdb 6.3.50-20050815 (Apple version gdb-1824 + reverse.put.as patches v0.4) (Sat Jan  4 20:24:02 UTC 2014)
Copyright 2004 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB.  Type "show warranty" for details.
This GDB was configured as "x86_64-apple-darwin"...
gdb$
gdb$
gdb$ add-symbol-file /Library/Developer/KDKs/KDK_10.11.5_15F34.kdk/System/Library/Kernels/kernel.dSYM/
Added dsym "/Library/Developer/KDKs/KDK_10.11.5_15F34.kdk/System/Library/Kernels/kernel.dSYM/" to "/Library/Developer/KDKs/KDK_10.11.5_15F34.kdk/System/Library/Kernels/kernel.dSYM/Contents/Resources/DWARF/kernel".
gdb$
gdb$ source  ~/repo/kgmacros/kgmacros_mavericks
Loading Kernel GDB Macros package.  Type "help kgm" for more info.
/Users/diff/repo/kgmacros/kgmacros_mavericks:6745: Error in sourced command file:
No symbol "ctrace_stack_size" in current context.
gdb$ target remote localhost:8864
[New thread 1]
warning: Error 268435459 getting port names from mach_port_names
[Switching to process 1 thread 0x0]
0xffffff801f7a25b8 in ?? ()
-----------------------------------------------------------------------------------------------------------------------[regs]
  RAX: 0x0000000000000000  RBX: 0x000000000000FFFF  RBP: 0xFFFFFF8059AB3E10  RSP: 0xFFFFFF8059AB3DF0  o d i t s z a P c
  RDI: 0xFFFFFF801FE2D120  RSI: 0x0000000000000002  RDX: 0x00000000000000BC  RCX: 0x000000000000FFFF  RIP: 0xFFFFFF801F7A25B8
  R8 : 0x0000000000000001  R9 : 0xFFFFFF8021D4A5D0  R10: 0xFFFFFF8059B05000  R11: 0xFFFFFF8059B15000  R12: 0xFFFFFF801FE2D150
  R13: 0x000000000000000A  R14: 0x0000000000000001  R15: 0x0000000000000000
  CS: 0008  DS: 0000  ES: 0000  FS: 0000  GS: 0000  SS: 0010
  -----------------------------------------------------------------------------------------------------------------------[code]
  0xffffff801f7a25b8:  83 3d d9 d2 75 00 00          cmp    DWORD PTR [rip+0x75d2d9],0x0        # 0xffffff801feff898
  0xffffff801f7a25bf:  0f 85 7b ff ff ff             jne    0xffffff801f7a2540
  0xffffff801f7a25c5:  b8 01 00 00 00                mov    eax,0x1
  0xffffff801f7a25ca:  f0 48 29 05 ce d2 75 00       lock sub QWORD PTR [rip+0x75d2ce],rax        # 0xffffff801feff8a0
  0xffffff801f7a25d2:  48 83 c4 08                   add    rsp,0x8
  0xffffff801f7a25d6:  5b                            pop    rbx
  0xffffff801f7a25d7:  41 5e                         pop    r14
  0xffffff801f7a25d9:  41 5f                         pop    r15
  -----------------------------------------------------------------------------------------------------------------------------
  Kernel is located in memory at 0xffffff801f600000 with uuid of 749F71AC-4136-320E-8416-570E59A180B4
  Kernel slid 0x1f400000 in memory.
  Current language:  auto; currently minimal
gdb$ 

Awesome! Now we have a fully functional MacOS guest and a host connected with a debugger. Haven't had any issues with disconnects yet while using gdb. It also might be worth noting that many people have said you can also connect lldb to this debugStub using it's gdb-remote command using the command (lldb) gdb-remote localhost:8864.

After thoughts - something very wrong might be lurking in my set up and may have been causing the udp issues with the kernel debugger, especially since I can't really find anyone else discussing this problem. I was also loaded on pain medication due to motorcycle accident, so it is extremely likely that I misread something or came up with my solutions in backwards ways. Regardless, this seems to have worked. Discussing this on twitter and slack with a few people, it seems like many others rely on the VMWare debugStub - though (@i0n1c)[https://twitter.com/i0n1c] disagrees with me and said there must be something wrong with my set up, he is probably correct. If I end up solving the underlying issue, I will post here with the solution. This blog was primarily just to serve as a culmination of all the random things I ended up trying to get this to work so I don't have to go through the pain again. Hopefully someone else finds this useful.