Glad it worked!
nice! I just now are learning how the regular expressions works on C++ I used them on text editing but is no the same
Learning regex is always handy at the end of the day! Sys-patch doesn't use regex by the way. It starts by looking for a pattern (it can be a full set of bytes or a set of multiple bytes (for example 0x0945.6787 will look for places where 09456787 - a random byte following by 6787 is set). Once you have found the pattern (at this point it can be in different places) it gives you an offset where you have to go based on the place the pattern was found and you have to retrieve the next 4 bytes.
For example if you found the value 09 45 54 67 87 in address 0x0000 and what comes after that is 01 24 35 67 89 0A if the code tells you that for this pattern you then have to check the value at offset 6 you have to pick the number 24 35 67 89. After that it checks the value bit by bit with AND mask to only check the relevant bits (I'll go in detail exactly what it is below). When all checks out, there is another offset that gives you the position of where you have to modify your code relative to the number you checked. Then it checks if the old value to replace is the expected one and then replace it.
With MrDude pattern it only checks a known pattern.
I think it is interesting to know exactly the purpose of all this and what exactly the patch is doing. Since atmosphere is open source it is relatively easy to trace everything.
The goal
The end goal of all of this is to bypass the ACID signature check. The ACID signature is something in the NCA meta data (called NPDM) where it verifies if the NCA that you're about to load was signed by nintendo (to prevent from launching hombrew nsp forwarders for example).
These checks were not done in HOS versions prior to 10.0.0. If you look at the atmosphere code you'll see the function that checks the signature here:
You can see that it checks the version of the current hos and if it is above or equal to version 10.0.0 you proceed with the signature check. The goal of the whole patch is to pretend that the condition (hos::GetVersion() >= hos::Version_10_0_0) is false so we don't need to do the check.
In order to do that we have to disassemble the loader. We find that the code above is the following assembly code :
sub_710001A050 is the address of the function GetVersion(). Basically what this code does is you call the function sub_710001A050. the function updates the register w0 with the version of the hos, you load W1 with the value 0x9FFFFF you compare the result in the registers w0 and w1 and if the result is equal or lower than 0x9FFFFF you jump to the offset 0x5f04 (you skip the if). The version of the HOS is coded in hexa with the major version number on the MSB the minor one next to it and so on. For example 10.0.0 will be coded as 0x0A000000. so if you're version is 10.0.0 <=> 0x0A000000 > 0x9FFFFF and so you don't jump.
To bypass this check all you have to do is modify the register you compare to (W1) with W0. The register compares its value to itself and the result is always true.
The hexa value of the operation CMP W0, W1 is 0x6B01001F. In my example this code is in the offset 0x5FBC (in the hexa file the numbers are in little endian)
To change CMP W0, W1 to CMP W0, W0 all you have to do is change one byte 0x6B00001F which is in the offset 0x5FBE. This is exactly what the patch does.
So now we know exactly what we are looking for and we know what we need to change. We now have to be able to find the pattern.
The MrDude algorithm
MrDude algorithm is pretty simple. it looks for the two instructions (the mov one next to the cmp one). The MOV operation is 0x12BEC001 (so 01C0BE12 in the file). MrDude looks for the pattern 01C0BE1206B00001F. Since it is unlikely that this code will appear more than once (since we rarely compare the value 0x9FFFF other than here and that the signature check is one of the first step you do in the loader) this pattern works pretty well.
The Sys-patch algorithm
Sys-patch does it differently. What it initially does is that it looks for the pattern 0xFD7BC6A8C0035FD6 which is an instruction to basically come back to a function when you're done with the current one (basically it's a return). Apparently it was well know by sys-patch that a return function was exactly 16 bytes away from our cmp function.
Once you found this pattern you have to jump 16 bytes (offset 16) to get to our cmp function
(you can see that if you start from FD and you count to 16 you'll get to 1F00016B).
Note that in this example the value is FD7BC8A8 and not FD7BC6A8. This is because Im using the new compiled version of atmopshere. Before this version the value was FD7BC6A8. This was the reason why sys-patch didn't work.
You might think that we're done but sys-patch goes a little bit further than that.
This part is a little bit tech-heavy. If you just want a summary of this part is that it checks before applying the patch that the pattern 1F00016B is a cmp instruction.
If you check the ARM documentation
https://developer.arm.com/documentation/ddi0487/latest/ you can see exactly what is the cmp instruction:
In our case sf = 0 Rm is equal to Wm and Rn Wn.
Note that CMP is a special case of SUBS that's why subs is mentioned in the sys-patch code. Our instruction is 0x6B01001F. Our op code (which is the part where you know what type of instruction you have to check) is 01101011000 the Rn value is 00000 imm6 00000 Rm 00001 and the rest is full of ones. It bascally means that you compare Register W0 to W1 and you don't make any kind of shift before you compare the value.
What sys-patch does is that it makes a right bit shift so it only gives you the last 12 bits (from 31 to 21). you end up with a 16 bit value of 0000 0011 0101 1000=> 0x0358. Sys-patch checks each bits from the new number from the first bit to the 11th one (the remaining zeros were added because of the shift so it is not needed to check). We don't need to check the shift bits (the 2nd and 3rd bits in our new number) because it can change depending on what the compiler decides to do. what we really want to check is the instruction type. This leaves us with an AND mask of 0x7F9. If the instruction is a CMP one the result of the mask needs to be 0x358.
Note that if the value was for example 0000 0011 0101 1110 the result will stil be valid and will still be 0x358, as we said earlier we don't pay attention to the values of the 3rd and 2nd bits.
Sys-patch then checks the value of the register we are comparing from (w1) and verifies if it is indeed register number 1. To do this it makes a 16 bit right shift to the initial value so we can have the Rm bit in the lowest bits. In our example the new value will become 0000 1101 0110 000 0001. Since Rm takes 5 bits you need to make a AND mask of 0x1f to get the value. We end up with 1 which is exactly what we were looking.
There you have it you finally found that the instruction that you have is the correct one! Now you need to mention where to replace the old value with the new one.It is 2 bytes from our instruction (0x1F 00 01 6B (
remember in memory it is in little endian but the value that you read is indeed 6b01001f).
Now you can finally apply this goddamn patch. You first check if the value has been already modified, you apply the patch and then you do all the stuff mentioned above to check if the instruction is still a cmp but this time Rm is 0 and voila! you're done!