Sunday, 25 September 2016

Lapic Kernel Patcher

Lapic Kernel Patcher


A couple months ago I created a program that can patch Macs kernels to prevent the lapic kernel panic from occuring on hackintoshs. Heres the story of how I developed this patch.
 Local APIC Error, ESR: 64 " @/source/xnu/xnu_1504.15.2/osfmk/1386/lapic.c:704 
This is caused by HPs APIC table not being initialize the same way that occurs in Macs. A temporary solution to this is to boot with the cpus = 1 kernel flag. This limits your processor to only using part of its full potential though. A better way of fixing this issue, discovered by yehla2amer in 2010, was to recompile Apples kernel after adding this lapic write command to the part where the kernel initializes it:
 /* NMI: ummasked, off course */ 
LAPIC_WRITE(LVT_LINT1, LAPIC_LVT_DM_NMI);
However, this fix is only possible after Apple release the source code to its kernels. Which usually takes 2 - 3 months after the update is available. If your curious, Apple releases its kernels source code here. In addition, kernels that are recompile lose the capabilities to sign in to FaceTime, iCloud, and other Apple software. Back in March, when Apples 10.8.3 update was released, I attempted to find a better solution that could be applied without this delay and that wouldnt have any negative side affects.

I started off by updating my hackintosh to 10.8.3. I noticed the immediate kernel panic the occurred was similar to the ones in all previous kernels. As a side note, my laptop also has Windows 8 installed with latest MacDrive software. MacDrive allows you to read/write to HFS/HFS+ partitions uses Windows native file explorer. So I booted up my computer into Windows and opened 10.8.3s kernel with IDA Pro. The disassembler will automatically recognize that this file is in a Mach-O format, so youll be asked which architecture of the kernel to disassemble. Since Apple dropped 32bit support in Mountain Lion, my only option is the 64bit part.


I searched through the strings until I found the one relating to the kernel panic. It ended up being at offset 0xFFFFFF0006A556A.

 
So I checked were it was being referenced from. It was only used in one place, which was the _lapic_interrupt subroutine. As you can see, it calls the kernel panic after loading the strings address into rdi. This CPU register is almost always used as the destination in stream operations.


 In order to prevent this kernel panic from happening, there are a few different things we can do. We can alter all the conditional jumps that lead to 0xFFFFFF800020BD814 so that they never jump there, or we can prevent the subroutine from calling the kernel panic by removing the call. I choose to the second option. So lets look at the hex view of this function to see what well actually be changing. The call to the kernel panic is done with this byte sequence E8 3C FD F5 FF, so lets replace all the bytes with the hex value for no operation, 90. The resulting process looks like this:


So now 0xFFFFFF800020BD814 looks like this:


After appling these changes with a hex editor to 10.8.3s mach_kernel file, I was now able to boot into Mountain Lion without any kernel panics. Since this modified the original kernel, I could still use FaceTime and iCloud without any problems. After posting my modified kernel online, a osx86.net user named sherlocks contacted me about applying this patch to the 10.7.5 kernel. This same fix, applied to both the 32bit and 64bit part of that kernel, resulted in the same success.

After that, we both decided to start working on a user-friendly way so that anyone could easily apply this patch. We also wanted it to be able to patch all previous and future kernels released by Apple. To accomplish this, I examined how the 10.8.3, 10.7.5, and a few other kernels called the lapic kernel panic in order to find a similarity between them. The byte pattern I found for the 64bit part was this. All numbers are hex values:
 If offset i: 65 8B 04 25 14 00 00 00 
And if offset i + 23: 65 8B 04 25 14 00 00 00
Then offset i + 1E: Call to kernel panic (5 bytes)
And the byte pattern for the 32bit part was:
 If offset i: 65 A1 0C 00 00 00 
And if offset i + 1E: 65 A1 0C 00 00 00
Then offset i + 19: Call to kernel panic (5 bytes)
So all we have to do is replace the 5 bytes at offset i + 1E for 64bit and i + 19 for 32bit with nops. This same pattern exists in all kernels released since at least 10.6.0. Ive never looked at any earlier than that. We assume it will stay the same for all future kernels. So we created a simple command line argument program that could apply this patch, but sherlocks recommended that we add a GUI to it. About a week later we released version 0.4 to the public. We named our program Lapic Kernel Patcher, and its available to download here.

?
About two weeks ago, another osx86.net user named gsly contacted me about adding my patch to Clovers kernel patcher feature. I thought that was a great idea, so I sent him what I had discovered. He was done a few days later, and revision 1731 of Clover has implemented his addition. Clover keeps their latest releases hosted here. To use it, simply add these lines to your config.plist:
 <key>KernelAndKextPatches</key> 
<dict>
<key>KernelLapic</key>
<true/>
...
</dict>
Im currently using Chameleon as my bootloader, so I havent been able to test it. Unfortunately Chameleon doesnt have as simple of a kernel patcher feature like Clover, so it would be difficult to implement it there.

Yesterday I was searching online to see if someone has tested my patches on Apples newest 10.8.4 kernel. I ran across an article on Yuan Lukitos blog where he has confirmed that my program successfully patches that kernel.

Wow, that was a long blog post. Hope you enjoyed it and learned something in the process.

Available link for download