PS3 PS1 libcrypt support on PS3 official emus - research thread

Here are the fixed patches for Spyro 3 and Sydney 2000 UK. I kinda stole the trick from @krHACKen to use the labels in the ELF file to inject own code. Codes are adapted from the Babydock original patches from 2000, I hope he doesn't mind. All patches were tested only in the no$psx for the code validation. So any further testing is welcomed.

Spyro 3 was hard to find unreferenced and consecutive labels for the code injection. I had to jump between two places in the executable file anyway. To check if the Libcrypt is passed, you need to go to the Sheila level. To trigger the crack protection, according to the various sources, 500 gems need to be collected and (or?) skateboard challenge passed. As long as the Zoe does not notice you about a hacked copy, then the patch is working correctly. Data are patched after the first decryption and the original values are restored after the encryption. The place where the jump is made does not seem to be checked by the game until the own code is executed.

Sydney 2000 does use a few code overlays. The memory does change after the booting of game, during the loading of menus, events, gyms, etc. The check is performed before the first loading screen, and the BPC register is cleared. It does look suspicious to me, but I haven't encountered any other checks in game (or maybe I haven't played enough, I suspect one minute is not enough probably). There is a different MW routine in the memory when the menu is loaded, but it does not seem to be executed and is replaced with the different code during the loading of event. That is why the original PDX patch is not working correctly, because it does patch that offset after a new code overlay is loaded, glitching the graphics completely. It would be good to test this game extensively too, but I bet nobody would be willing to destroy his gamepad because of all that stupid button mashing.

After all, the Sydney 2000 does look like a LC2 routine to me, not LC3 one.
 

Attachments

Here are the fixed patches for Spyro 3 and Sydney 2000 UK. I kinda stole the trick from @krHACKen to use the labels in the ELF file to inject own code. Codes are adapted from the Babydock original patches from 2000, I hope he doesn't mind. All patches were tested only in the no$psx for the code validation. So any further testing is welcomed.

Spyro 3 was hard to find unreferenced and consecutive labels for the code injection. I had to jump between two places in the executable file anyway. To check if the Libcrypt is passed, you need to go to the Sheila level. To trigger the crack protection, according to the various sources, 500 gems need to be collected and (or?) skateboard challenge passed. As long as the Zoe does not notice you about a hacked copy, then the patch is working correctly. Data are patched after the first decryption and the original values are restored after the encryption. The place where the jump is made does not seem to be checked by the game until the own code is executed.

Sydney 2000 does use a few code overlays. The memory does change after the booting of game, during the loading of menus, events, gyms, etc. The check is performed before the first loading screen, and the BPC register is cleared. It does look suspicious to me, but I haven't encountered any other checks in game (or maybe I haven't played enough, I suspect one minute is not enough probably). There is a different MW routine in the memory when the menu is loaded, but it does not seem to be executed and is replaced with the different code during the loading of event. That is why the original PDX patch is not working correctly, because it does patch that offset after a new code overlay is loaded, glitching the graphics completely. It would be good to test this game extensively too, but I bet nobody would be willing to destroy his gamepad because of all that stupid button mashing.

After all, the Sydney 2000 does look like a LC2 routine to me, not LC3 one.

Nice. Can I host these PPF files as part of my pop-fe repository? I already host krHACKens files.
And if so, do you have a credits line you want me to use?

This is the credits line for krHACKens ppf I host:

'SCES01444': { 'credit': 'Libcrypt patch contributed by krHACKen',
'magic_word': 48452,
'ppf': 'libcrypt/Jackie Chan Stuntmaster (Europe).ppf',
'url': 'http://redump.org/disc/3985/'},

The credits line is printed to the screen everytime pop-fe detects this disk and applies the patch.
 
A little bit of credit would be fine to get the potential negative feedback about the patches.

Anyway, the Spyro 3 1.0 and Sydney 2000 UK patches will be replaced soon with the "perfect" versions. These updated patches will be meant to apply to the existing PARADOX patches available. I have fixed a lot of things not working correctly and I am going to test them now. As they are using the memory resident code, it gives a lot more control of the game itself.

I am interested in disabling the Spyro's memory scanning completely too, but I do not have a time to test it properly. The memory checks may be embedded in the different code overlays loaded throughout the game. It is 22 years late to spend too much time on that game.
 
I've made some progress in understanding the subchannel files in the EBOOT's. I couldn't understand why the last sector was missing a CRC value, turns out I was looking at the file wrong...once I understood the correct format of the file I found out that I wasn't looking at CRC values but at sector offsets.

View attachment 35673

So if we take the first sector value of the file which is AF000000 and convert it to Little Endian we get 000000AF. If we convert that to decimals we get 175 which means this is sector 175.
The next entry is 560C0000, again we take the steps described above and end up with a decimal value of 3158. To verify if the sector entry is correct we can calculate the difference in MSF values between the two entries by converting them to frames and calculate the difference between the two values:

(conversion to frames done here, set the frame rate to 75)
first entry: 00:04:24 to frames -> 324 frames
second entry: 00:44:07 to frames -> 3307 frames

3307 - 324 = 2983 frames

Then we calculate the difference between the two entries in hex:

first entry: 000000AF
second entry: 00000C56

00000C56 - 000000AF = BA7 which converted to decimal is 2983.

value of first sector entry (175) + difference between the two entries (2983) = value of second sector entry (3158).

What if we look at a sector with Libcrypt protection? If we take a look here we see that the first entry is sector 14579 with M:S:F value 03:14:29. Taking a look at the subchannel file in the EBOOT we can't find that M:S:F value, but we do find one on row 8 that is close to it (03:14:28 in the absolute columns). If we convert the sector value of that row (385D) to decimal we get 14429. The start sector of the data on a PS1 disc is 150, so if we add that to the converted sector value we get 14579 which does match the Libcrypt sector!

First 8 Libcrypt sectors comparison:
View attachment 35675

However, here we see something odd: The sector values match, but the MSF values dont. The difference is 1 frame. Also there is no mention of CRC values or Magic Word in these files.

I've added the extracted EBOOT subchannel data in an excel file, maybe you guys can find more.
Your research has been documented in wiki and a new version of the psxtract tool able to extract the subchannel data from the "PSOne classics" has been released by @kozarovv
https://www.psdevwiki.com/ps3/ISO.BIN.EDAT#Subchannel_data

Good work :encouragement:
 
I've made some progress in understanding the subchannel files in the EBOOT's. I couldn't understand why the last sector was missing a CRC value, turns out I was looking at the file wrong...once I understood the correct format of the file I found out that I wasn't looking at CRC values but at sector offsets.

View attachment 35673

So if we take the first sector value of the file which is AF000000 and convert it to Little Endian we get 000000AF. If we convert that to decimals we get 175 which means this is sector 175.
The next entry is 560C0000, again we take the steps described above and end up with a decimal value of 3158. To verify if the sector entry is correct we can calculate the difference in MSF values between the two entries by converting them to frames and calculate the difference between the two values:

(conversion to frames done here, set the frame rate to 75)
first entry: 00:04:24 to frames -> 324 frames
second entry: 00:44:07 to frames -> 3307 frames

3307 - 324 = 2983 frames

Then we calculate the difference between the two entries in hex:

first entry: 000000AF
second entry: 00000C56

00000C56 - 000000AF = BA7 which converted to decimal is 2983.

value of first sector entry (175) + difference between the two entries (2983) = value of second sector entry (3158).

What if we look at a sector with Libcrypt protection? If we take a look here we see that the first entry is sector 14579 with M:S:F value 03:14:29. Taking a look at the subchannel file in the EBOOT we can't find that M:S:F value, but we do find one on row 8 that is close to it (03:14:28 in the absolute columns). If we convert the sector value of that row (385D) to decimal we get 14429. The start sector of the data on a PS1 disc is 150, so if we add that to the converted sector value we get 14579 which does match the Libcrypt sector!

First 8 Libcrypt sectors comparison:
View attachment 35675

However, here we see something odd: The sector values match, but the MSF values dont. The difference is 1 frame. Also there is no mention of CRC values or Magic Word in these files.

I've added the extracted EBOOT subchannel data in an excel file, maybe you guys can find more.

Appologies for the thread-necro. (I forgot about this)
First of all, Great discovery and analysis.

I have implemented this and tested it on pop-fe and it seems to work on all the games I have tested with. I guess this will work on 100% of all libcrypt protected games while just using the magic-word might work on almost but not quite all games.

For anyone interested, a simple python function that takes a magic-word and generates the corresponding subchannel blob to inject into the ISO.BIN.DAT for the emulator to use can be found here https://github.com/sahlberg/pop-fe/blob/ad47d12a8cb9d55588faf676ac8a7ab90301227b/pop-fe.py#L1545


Interesting why the subchannel blob from official PSN games contain so many seemingly other random sectors than just the 16 pairs that are actually used by libcrypt. Maybe this was just done to try to obfuscate what was going on and how/what libcrypt does ? I only create blobs that contain the 32 sectors for libcrypt and none of these additional random sectors and the blobs I create seem to work just fine.

EDIT to add: This also works for EBOOTs created for PSP. The main difference is that on PS3 ISO.BIN.DAT the offset is the physical file offset while on PSP the offset is relative to the start of the PSISOIMG section.
 
Last edited:
However, here we see something odd: The sector values match, but the MSF values dont. The difference is 1 frame. Also there is no mention of CRC values or Magic Word in these files.

Belated but better late than never. The 1 frame difference is AFAIK that when you read the subchannel for sectors, if the subchannel crc is corrupted what you get from the CDROM is actually the subchannel for THE PREVIOUS SECTOR instead. Hence the -1 frame.
Hence the sectors that has a MSF that is -1 from what is expected are those sectors where libcrypt expects the subchannel to be corrupted.
 
Last edited:
After some testing and verifying using duckstation it turns out that it does not matter WHAT the corruption is just that the sector is corrupted.
Thus I now create working SBI files straight from the magic-word.
I use the magic word to figure out which sectors should be corrupted and thus listed in the SBI file and I just write all 0xff for all the 10 bytes of QSUB data. And it works because libcrypt apparently only checks if the sector is good or bad and does not check what it actually contains.

This means that in order to defeat libcrypt you don't need any SBI files from redump. You just need the magic word and then it is trivial to create a new SBI file that will work for the emulator.
Here is code I use to automatically create an SBI file: https://github.com/sahlberg/pop-fe/blob/1de5fb7bb05b62ac08b842a612b8570645e1f4b9/pop-fe.py#L1605

This means an emulator does not need to include the "official" SBI files (which some might not want to do). It just needs to contain the list of disc-ids and the magic-word and can then automatically create an SBI file. Making it a lot more user friendly than having to ask the user to download the sbi files from the internet. (Or instead of even generating the sbi file, an emulator can just use the magic word directly and decide "should I garbage up the QSUB for this sector by just filling it with 0xff or should I use the correct data? in the SCSI READ_CD emulatio?")
 
Last edited:
Well, it is not a breakthrough discovery. Sony did use it for few games inside the ps1_netemu embedded patches. I think @sandungas did figure it out in this thread. They embedded just a sector list, including the Libcrypt ones. I have successfully replaced them with Sydney 2000 sectors, passing all the checks.
 

Similar threads

Back
Top