Supervisor fabiosun Posted June 14, 2021 Supervisor Share Posted June 14, 2021 Waiting for the managers of the patches for owners of AMD CPUs to decide to release the new ones for everyone Below is a simple method to start understanding how you can move to study on your own Several years ago Pikeralpha gave directions if you want below you can try it too https://github.com/Piker-Alpha/ssdtPRGen.sh/issues/261#issuecomment-246691848 then analyse Patches name you need to find ie : i386_switch_lbrs and search with an editor you prefer: Spoiler i386_switch_lbrs: ffffff80003b2f50 pushq %rbp ffffff80003b2f51 movq %rsp, %rbp ffffff80003b2f54 pushq %r15 ffffff80003b2f56 pushq %r14 ffffff80003b2f58 pushq %r12 ffffff80003b2f5a pushq %rbx ffffff80003b2f5b movq %rsi, %r12 ffffff80003b2f5e testq %rdi, %rdi ffffff80003b2f61 je 0xffffff80003b2f77 ffffff80003b2f63 movq _kernel_task(%rip), %r14 ffffff80003b2f6a cmpq %r14, 0x6a8(%rdi) ffffff80003b2f71 setne %sil ffffff80003b2f75 jmp 0xffffff80003b2f80 ffffff80003b2f77 movq _kernel_task(%rip), %r14 ffffff80003b2f7e xorl %esi, %esi ffffff80003b2f80 movq 0x6a8(%r12), %r15 ffffff80003b2f88 testb %sil, %sil ffffff80003b2f8b jne 0xffffff80003b2f96 ffffff80003b2f8d cmpq %r14, %r15 ffffff80003b2f90 je 0xffffff80003b3165 ffffff80003b2f96 movl $0x1d9, %ecx ## imm = 0x1D9 ffffff80003b2f9b rdmsr ffffff80003b2f9d andl $-0x2, %eax ffffff80003b2fa0 movl $0x1d9, %ecx Above spoiler is the patch location in 11.4 kernel obviously is not so simple to solve in many cases.. but I think it is a good start if you want understand for your own to transform kernel in a txt files you can use this command: otool -tV /S*/L*/Kernels/kernel > ~/Documents/kernel.txt I would like to advice to start with previous kernel (with yet discovered kernel patches I mean) 🙂 2 1 Link to comment Share on other sites More sharing options...
Supervisor fabiosun Posted June 14, 2021 Author Supervisor Share Posted June 14, 2021 1 Link to comment Share on other sites More sharing options...
Moderators tomnic Posted June 22, 2021 Moderators Share Posted June 22, 2021 http://translate.google.com/translate?js=n&prev=_t&hl=en&ie=UTF-8&layout=2&eotf=1&sl=ru&tl=en&u=http%3A%2F%2Fwww.vmgu.ru%2Farticles%2Fred-pill-virtualization-security If only we could adapt this program as an EFI module to be loaded by OpenCore... 1 Link to comment Share on other sites More sharing options...
Moderators tomnic Posted June 23, 2021 Moderators Share Posted June 23, 2021 (edited) https://github.com/mhaeuser/AmdXnuSupportPkg This is the most promising project to correctly emulate a real Intel CPU, without the hassle to patch the xnu kernel at every release... unfortunately we lost the contribute of the original developer because he retired, probably because of the bad behaviour of the AMD "community", so trying to make it work will be a big trouble... Edited June 23, 2021 by tomnic 1 1 Link to comment Share on other sites More sharing options...
Moderators tomnic Posted June 29, 2021 Moderators Share Posted June 29, 2021 This is what I've understood starting from the debug log of clover, I think it is similar with OC. For example, let's pick the patch algrey - cpuid_set_info - jmp to calculations and set cpuid_cores_per_package - 10.15/10.16 it is complete because we have a hex find, a mask find, a hex replace and a mask replace. It says: Find: 7571E800000000488B050000000048890500000000 Mask: FFFFFF00000000FFFFFF00000000FFFFFF00000000 Replace: 744E000000000090890D00000000E97E0000006690 Replace Mask: FFFF0000000000FFFFFF00000000FFFFFFFFFFFFFF How does the patch engine work? We are searching a hex pattern, the "find" one, but we're using a byte mask: this changes a bit our search criteria: 7571E8 00000000 488B05 00000000 488905 00000000 (find) FFFFFF 00000000 FFFFFF 00000000 FFFFFF 00000000 (mask find) ----------------------------------------------- 7571E8 xxxxxxxx 488B05 xxxxxxxx 488905 xxxxxxxx So we're effectively searching 7571E8 xxxxxxxx 488B05 xxxxxxxx 488905 xxxxxxxx ... where xxxxxxxx is a wildcard! Every hex combination found in place of xxxxxxxx of its exact bytes lenght is good. Looking in the clover debug log we can find some precious info about the patches: 55:733 0:010 OC: Kernel patch [9] algrey - cpuid_set_info - jmp to calculations and set cpuid_cores_per_package - 10.15/10.16 55:749 0:015 Replace 7571E800000000488B050000000048890500000000/FFFFFF00000000FFFFFF00000000FFFFFF00000000(7571E8B6090000488B0577EAED0048890538EBED00) by 744E000000000090890D00000000E97E0000006690/FFFF0000000000FFFFFF00000000FFFFFFFFFFFFFF(744EE8B609000090890D77EAED00E97E0000006690) at ofs:1273 The effective code found in the kernel is: 7571E8B6090000488B0577EAED0048890538EBED00 7571E8 B6090000 488B05 77EAED00 488905 38EBED00 7571E8 xxxxxxxx 488B05 xxxxxxxx 488905 xxxxxxxx ...a nice match with our find mask!!! So now in the replace side we do the same calculations: 744E000000000090890D00000000E97E0000006690 FFFF0000000000FFFFFF00000000FFFFFFFFFFFFFF 744E 0000000000 90890D 00000000 E97E0000006690 FFFF 0000000000 FFFFFF 00000000 FFFFFFFFFFFFFF ---------------------------------------------- 744E xxxxxxxxxx 90890D xxxxxxxx E97E0000006690 We must replace in the actual found hex bytes "string" found with the previous calculations, 7571E8B6090000488B0577EAED0048890538EBED00: 7571E8B6090000488B0577EAED0048890538EBED00 (actual found code) 744E000000000090890D00000000E97E0000006690 (replace data) FFFF0000000000FFFFFF00000000FFFFFFFFFFFFFF (replace mask) 744E 0000000000 90890D 00000000 E97E0000006690 (replace data) FFFF 0000000000 FFFFFF 00000000 FFFFFFFFFFFFFF (replace mask) 7571 E8B6090000 488B05 77EAED00 48890538EBED00 744E xxxxxxxxxx 90890D xxxxxxxx E97E0000006690 ---------------------------------------------- 744E E8B6090000 90890D 77EAED00 E97E0000006690 The xxxxxxxx hex "string" must be left exactly as it has been found, the other bytes must be replaced... so the final actual replace is 744EE8B609000090890D77EAED00E97E0000006690. Offsets are calculated and applied automatically by OC / Clover kernel patch engine. Link to comment Share on other sites More sharing options...
Moderators iGPU Posted June 29, 2021 Moderators Share Posted June 29, 2021 7 hours ago, tomnic said: This is what I've understood starting from the debug log of clover, I think it is similar with OC. For example, let's pick the patch algrey - cpuid_set_info - jmp to calculations and set cpuid_cores_per_package - 10.15/10.16 it is complete because we have a hex find, a mask find, a hex replace and a mask replace. It says: Find: 7571E800000000488B050000000048890500000000 Mask: FFFFFF00000000FFFFFF00000000FFFFFF00000000 Replace: 744E000000000090890D00000000E97E0000006690 Replace Mask: FFFF0000000000FFFFFF00000000FFFFFFFFFFFFFF How does the patch engine work? We are searching a hex pattern, the "find" one, but we're using a byte mask: this changes a bit our search criteria: 7571E8 00000000 488B05 00000000 488905 00000000 (find) FFFFFF 00000000 FFFFFF 00000000 FFFFFF 00000000 (mask find) ----------------------------------------------- 7571E8 xxxxxxxx 488B05 xxxxxxxx 488905 xxxxxxxx So we're effectively searching 7571E8 xxxxxxxx 488B05 xxxxxxxx 488905 xxxxxxxx ... where xxxxxxxx is a wildcard! Every hex combination found in place of xxxxxxxx of its exact bytes lenght is good. Looking in the clover debug log we can find some precious info about the patches: 55:733 0:010 OC: Kernel patch [9] algrey - cpuid_set_info - jmp to calculations and set cpuid_cores_per_package - 10.15/10.16 55:749 0:015 Replace 7571E800000000488B050000000048890500000000/FFFFFF00000000FFFFFF00000000FFFFFF00000000(7571E8B6090000488B0577EAED0048890538EBED00) by 744E000000000090890D00000000E97E0000006690/FFFF0000000000FFFFFF00000000FFFFFFFFFFFFFF(744EE8B609000090890D77EAED00E97E0000006690) at ofs:1273 The effective code found in the kernel is: 7571E8B6090000488B0577EAED0048890538EBED00 7571E8 B6090000 488B05 77EAED00 488905 38EBED00 7571E8 xxxxxxxx 488B05 xxxxxxxx 488905 xxxxxxxx ...a nice match with our find mask!!! So now in the replace side we do the same calculations: 744E000000000090890D00000000E97E0000006690 FFFF0000000000FFFFFF00000000FFFFFFFFFFFFFF 744E 0000000000 90890D 00000000 E97E0000006690 FFFF 0000000000 FFFFFF 00000000 FFFFFFFFFFFFFF ---------------------------------------------- 744E xxxxxxxxxx 90890D xxxxxxxx E97E0000006690 We must replace in the actual found hex bytes "string" found with the previous calculations, 7571E8B6090000488B0577EAED0048890538EBED00: 7571E8B6090000488B0577EAED0048890538EBED00 (actual found code) 744E000000000090890D00000000E97E0000006690 (replace data) FFFF0000000000FFFFFF00000000FFFFFFFFFFFFFF (replace mask) 744E 0000000000 90890D 00000000 E97E0000006690 (replace data) FFFF 0000000000 FFFFFF 00000000 FFFFFFFFFFFFFF (replace mask) 7571 E8B6090000 488B05 77EAED00 48890538EBED00 744E xxxxxxxxxx 90890D xxxxxxxx E97E0000006690 ---------------------------------------------- 744E E8B6090000 90890D 77EAED00 E97E0000006690 The xxxxxxxx hex "string" must be left exactly as it has been found, the other bytes must be replaced... so the final actual replace is 744EE8B609000090890D77EAED00E97E0000006690. Offsets are calculated and applied automatically by OC / Clover kernel patch engine. tomnic , Thanks, the is a very clear explanation of the mask function. *** Now, leading from this is the 'what'? That is, what exactly are we replacing? Does the substituted data make this section inoperable, avoiding the panic and boot failure? The other questions, stemming from the initial link by fabiosun, that is still unclear to me is: how is this location even chosen? Is it found by looking at the error log during a failed boot? In the link fabiosun provided there is a discussion about XCPM and locating ”_xcpm_init:". (I don't what to talk about XCPM in detail but use this as a model of how we're to approach the topic of patch creation.) What wasn't clear in that link was what lead to looking at ”_xcpm_init:" in particular? Again, was there an error code from a log that pointed out this particular section as causing the panic? Next, there is an extraction from the kernel: "xxd -s 0x2283c0 -l 28 -psu /S*/L*/Kernels/kernel”. I'm assuming that without a drive reference, this is doing an extraction of the boot kernel. However, during patch creation, by definition, we are not working on a boot kernel since it won't boot. So we need to reference a drive with the problematic macOS already installed, or can this be extracted from the macOS Installer app? The other confusing issue was the chosen offset of 0x20000. Why this value? (Maybe Piker discussed it elsewhere and it was common knowledge at the time, but I don't understand why this value was chosen.) To summarize: how are the patch locations located, via error logs? how is the value to be substituted determined (the replacement value)? which file is examined for this section, an already installed drive with the new macOS, or the installation app for this new macOS? *** One target for how this is worked out may be the new code needed for Big Sur 11.4.0. There was a change in the "DhinakG - cpuid_set_cpufamily - force CPUFAMILY_INTEL_PENRYN - 11.3b1" after 11.3.0 Maybe this is a good place to start to see how this all is done? (And it seems that Monterey 12.0 broke this and needs a different, but similar value to 11.4.) Link to comment Share on other sites More sharing options...
Supervisor fabiosun Posted June 30, 2021 Author Supervisor Share Posted June 30, 2021 11 hours ago, iGPU said: The other questions, stemming from the initial link by fabiosun, that is still unclear to me is: how is this location even chosen? Is it found by looking at the error log during a failed boot? For that particular example pikeralpha showed the way to find location and what to find inside (callq tab and relative value) 11 hours ago, iGPU said: In the link fabiosun provided there is a discussion about XCPM and locating ”_xcpm_init:". (I don't what to talk about XCPM in detail but use this as a model of how we're to approach the topic of patch creation.) What wasn't clear in that link was what lead to looking at ”_xcpm_init:" in particular? Again, was there an error code from a log that pointed out this particular section as causing the panic? this was related to an instant reboot after ++++++ stage (in that time Clover was the main bootloader) Pikeralpha showed "how to" then clover devs integrated this patch in an automatic way..and many users (me too) asked to have a flag because it caused some problem in their application way _xcpm init is the first search to do in that case in disassembled kernel Obscure for me was why to change value in C3 and the offset value to subtract from many OS Offset was the same to substract...but unkown how to find new one if it happens OT (a GoldFish64 patch for Monterey b1 has only a replace with C3 value) 11 hours ago, iGPU said: Next, there is an extraction from the kernel: "xxd -s 0x2283c0 -l 28 -psu /S*/L*/Kernels/kernel”. I'm assuming that without a drive reference, this is doing an extraction of the boot kernel. However, during patch creation, by definition, we are not working on a boot kernel since it won't boot. So we need to reference a drive with the problematic macOS already installed, or can this be extracted from the macOS Installer app? you must have (if systems does not start) a copy of the kernel you have to disassemble with Otool command Link to comment Share on other sites More sharing options...
Moderators tomnic Posted June 30, 2021 Moderators Share Posted June 30, 2021 12 hours ago, iGPU said: To summarize: how are the patch locations located, via error logs? how is the value to be substituted determined (the replacement value)? which file is examined for this section, an already installed drive with the new macOS, or the installation app for this new macOS? *** One target for how this is worked out may be the new code needed for Big Sur 11.4.0. There was a change in the "DhinakG - cpuid_set_cpufamily - force CPUFAMILY_INTEL_PENRYN - 11.3b1" after 11.3.0 Maybe this is a good place to start to see how this all is done? (And it seems that Monterey 12.0 broke this and needs a different, but similar value to 11.4.) How are the patch location located, via error logs? I think that this is fully automated by the patch engine of the chosen bootloader, the found offset is shown in the debug log. If you use a hex editor and go to that offset you'll find exactly the found pattern. Replaced values are only loaded in memory not actually written to the kernel. P.s.: IMHO the offset piker uses, 0x200000, is related to its specific xcpm patch. Every patch has a different one, as you can see analyzing any debug log in the patch applying section. How is the value to be substituted determined (the replacement value)? This involves both assembly and xnu knowledge: the pattern we choose to replace some code is actually machine language code created by anybody who deeply knows xnu... the goal is to bypass or modify specific functions not suitable for AMD cpus. If you physically apply the patch and disassemble the kernel you'll get perfectly working assembly code, different from the source, but "perfect" to be directly run by AMD cpus. P.s.: IMHO the right procedure would be: analyze the full source xnu kernel once published by Apple here https://opensource.apple.com/source/xnu/, change the functions / values not suitable for AMD cpus in c++ language, compile them and create a find / replace with masks to maintain durability and portability of the binary patches to obtain the same modded code without replacing the actual kernel. Which file is examined for this section, an already installed drive with the new macOS, or the installation app for this new macOS? You can take the kernel from the installation app or an official apple update package, or even from a real booted mac or intel hackintosh, installation kernel and booted kernel usually are the same version. Link to comment Share on other sites More sharing options...
Supervisor fabiosun Posted July 9, 2021 Author Supervisor Share Posted July 9, 2021 (edited) [For Hackers] An utility to search a masked string Maybe an useful utility made by @slice Edited July 9, 2021 by fabiosun Link to comment Share on other sites More sharing options...
Moderators iGPU Posted July 19, 2021 Moderators Share Posted July 19, 2021 (edited) A Reverse-Reverse-Engineering Patch Tutorial For those who already know what I'm posting here and consider this simplistic: sorry. I'm presenting this information for those, who like myself, may be unaware of how patches are created. Virtually every time I've read about a new patch, the patch is presented only by itself or only with the smallest of hints as to how it was created. Recently, I've spent hours trying to get the SmallTree I211 kext to work under Monterey. I've not yet succeeded, but the attempt led me to think a patch might be necessary. SInce I didn't know how to make a patch, I thought a good way to learn might be to "reverse engineer" an existing patch. That thought led me to study patches for the Aquantia ethernet port. There is a long thread over at InsanelyMac (here) where Aquantia patches are discussed for various macOS releases. These patches seemed to have become necessary with the release of Catalina and Big Sur (Mieze and Shikumo seem to have done most of the work). Recently, a new patch for Aquantia was found to be necessary for Monterey; it was discussed in this post by Mieze (from whom I've gleaned the most about kext patches). This means there are several examples to test-out the reverse engineering process. (BTW, what's described below was also tried out on the Big Sur Aquantia patch and this process works with that patch too.) 1. Initial Attempt - OTOOL/HEX FIEND My first attempts to reverse engineer the Aquantia patch began by using the tools discussed in the first post on this thread (from Piker Alpha, using otool (part of macOS): extracting the contents of the Aquantia kext file into a text file), along with using Hex Fiend (a download). The Aquantia kext file is located inside the IONetworkingFamily kext as a plugin (you have to dig a bit to find it!): IONetworkingFamily/Contents/Plugins/AppleEthernetAquantiaAqtion/Contents/MacOS/AppleEthernetAquantiaAqtion. [Note that all editing and work below was carried out on a copy of the kext file that was transferred from "S/L/E/IONetworkingFamily" to the desktop, so nothing destructive was done to the original file.] The text file can be created with otool with the following command (drag and drop your file location in place of the "/~/~/" section): otool -tV /~/~/AppleEthernetAquantiaAqtion > ~/Documents/Aquantia.txt And this same AppleEthernetAquantiaAqtion file can be examined with Hex Fiend. The combination of otool's resulting text file (upper left) and Hex Fiend (upper right) are shown below, where they're also compared with the link from Mieze (bottom left): Unfortunately, I couldn't figure out how to derive the patch from this data. 2. Successful Attempt - IDA64 It wasn't until I did some searching and came across a tool from the Belgium company, Hex-Rays. They offer a free download (here) of the IDA64 macOS app to try out and that is what I'll present next. The idea behind using this app is to de-compile the kext file. But what I'm actually trying to do is "reverse engineer" Mieze's "reverse engineering" of the de-compiled kext file. If successful, then we can learn how to better make patches. We can start this process from some knowledge shared on that thread: we know the area in the kext to examine ("checkConfigSupport", shown in above image) and the given Find string ("41 C7 45 00 00 00 00 00 E9"). Between these two items, we can zero-in on the area that needs to be patched. The first step is in opening the file (again, the nested AppleEthernetAquantiaAqtion file contained within IONetworkingFamily from the latest Monterey ß3) with the IDA64 app. When opening, the default settings in IDA64 are best (shown in Spoiler below). Spoiler Once opened, the initial screen can have the windows rearranged (initial view shown in Spoiler below). Spoiler I prefer the Function View be expanded on the left as shown below (also shown is the search window which is accessed from the menu bar). This particular search item was chosen based on discussions in the InsanelyMac thread, where Mieze describes (in Spoiler): Spoiler "In earlier versions the driver already checked certain hash values in order to identify Apple devices but with 10.13.4 they added a new function called checkConfigSupport() where they perform these checks and they have added more hash values to check helping to distinguish original Apple NICs from flashed 3rd party device and in case checkConfigSupport() returns 0, the driver will refuse the device. I haven't found the time to reverse engineer checkConfigSupport() in detail [ed. Mieze later did this in thread,] but I patched the "je" instruction which causes the driver to fail in case of the return value 0. Now it works." At the end of this post, Mieze also adds: "In order to enable the driver's debug output, you might want to add "apple-axge-debug=0xff" to your kernel flags." When this search is completed, and the Function View item on the left double-clicked, the following can be seen in the right pane. But the result is not obvious as the presentation is a bit complicated: the right pane must be scrolled (shown as separate images in the Spoiler below). Spoiler initial view: scroll down and see this: scroll down some more: and then final view we need to study: After scrolling the right pane, we can begin the process. On the left pane, note that the Aquantia item is "107" which references the AQC107 port name. Next, even after scrolling, there are many windows in the right hand pane. Since we're reverse engineering, we already know that we're looking for something that should say "__ZN30AppleEthernetAquantiaAqtion10718checkConfigSupportERiS0". This is highlighted below on the right. As pointed out in the InsanelyMac thread, we need to change the value of "0" to "1", but first we need to find the corresponding hex code. We do this by clicking on the "mov" command (highlighted below right). Once the "mov" command is selected, the corresponding hex code will also be selected for us, but to see this, we need to change views. To see the hex code, change views by clicking on Hex View near to the top of the window. The new view switches the right pane from the IDA View above to the Hew View below. Again, since we clicked on the "mov" command in the above step, the correct hex code for this command is already highlighed in dark green. We then look for the Find string which is "41 C7 45 00 00 00 00 00 E9", but notice that the "mov" command did not contain the "E9". The next byte seems to be chosen when patching to help ensure only one site is patched. The replacement will simply over write this byte with the same value. But to change the "0" to "1", we need know which byte to change. This can easily be tested in real time by editing the hex code as shown below: right-click on the byte to change. The cursor will be in the middle of the byte to change the right least significant value as shown next. To make this change 'stick', we need to apply it. This is done by again right-clicking. This change can be verified by switching from the Hex View to the IDA View. If incorrect, switch back to the Hex View, re-edit as needed and re-apply and return to the IDA View once more to verify if now correct. If the correct byte was changed, you'll see the following: At this point, we can see that the Find value of "41 C7 45 00 00 00 00 00 E9" and the replacement value of "41 C7 45 00 01 00 00 00 E9" now all make sense and this seems to be how this patch was derived. If anyone has any comments or corrections to the above let me know and I'll edit this post. [BTW, I compared the Monterey ß3 Aquantia file to that of Monterey ß1, using Hex Fiend: there is no difference. However, this is quite a difference in this same file between Monterey and the latest release of Big Sur.] ADDENDUM - Future Approaches Spoiler Much of Mieze's work seems to be from studying Linux Aquantia driver's source code, so this is another avenue for us to study too (as of this writing, I have not). Mieze also suggests another patch approach in this post: "checkConfigSupport().... tries to retrieve the NIC's "built-in" property from IORegistry. "...If the "built-in" property isn't found, the check of the global chip identification register is skipped and the NIC will be accepted without further tests. This opens up a new opportunity for a patch which may even survive driver updates. Replacing the string "built-in" with something else by a Clover patch also causes the driver to accept the chip and even the error message disappears (I can confirm that this works!)." This "built-in" approach is very interesting. I saw this entry during the writing of this post and intend to revisit it in a few days. Edited July 20, 2021 by iGPU 1 1 Link to comment Share on other sites More sharing options...
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now