PS3 PS1 libcrypt support on PS3 official emus - research thread

Ronnie can you check this ?, there is a disalignment in the ISO.BIN.EDAT "section" table in wiki introduced since this edit
https://www.psdevwiki.com/ps3/index.php?title=ISO.BIN.EDAT&diff=44695&oldid=41851

The previous versions of the table was considering all the areas are aligned to 0x400 (the size of a block), the area that was named "tracks table" in that edit (and "Audio tracks table" in the actual version) was given a size of 0x620 (exceeds one block), you have been working with audio tracks latelly, what do you think about this ?
If the audio tracks table is really bigger than one block we should represent it as a contiguous area of two blocks (0x800)
In ther words, it would include the area we are naming in the actual version as "Game Params Table"... so it would be needed to change the names to give them a common name and represent it as a single entity

The real annoyance about this detail is the area that comes next "Game Params Table" in the actual version of the table is not starting at an offset aligned to 0x400, is hard to know where it starts because a lot of the values are unused/filled by zeroes but i would say it "should" start at 0x1400 (following the offsets of the table in wiki that represents the first disc of a multidisc game)

The relative offset of the "magic word" discussed in the latest posts here depends of where we consider it starts the "Game Params Table"
 
Last edited:
I was roaming inside ps1netemu and I noticied the titleID of bird of steel (ps3), any idea why it's in there ?
sry, about the offtopic
 
3. I do not really know. More info needs to be gathered by inspecting the Classics. But what is more important to me, we will not go further until somebody starts debugging the emulator itself. In my opinion, the best way to sort it out is to add a subchannel support into the Cobra core. It would work with the ps1_emu, but may not work with the ps1_netemu. After all, I am not a programmer, so I do not know how complicated is to do that.
I have already looked at the Cobra code, it's subchannel Q ready & all the OS SCSI support stuff is subchannel ready too.
Cobra already fills up subchannel Q when the appropriate READ_CD scsi command options are passed to it.
So my first impressions lead me to believe that adding sbi support in Cobra should be quite straightforward, adding the sbi support C files to the Cobra project & a few lines of code in storage_ext.c should do the trick in theory.
 
Last edited:
well the Magic word method seems to work so far on CTR and FF8, i just tried it on Disc1 of FF8 and it seems to be working fine, for magic words add them at
0x12B0 for single disc or 0x16B0 for Multidisc
I kinda expected it not to work so well but it seems to play fine (only played the opening but everything seems to be working)
So that could be 1 method for PS3 PS1Classics (not sure if it works with all games but it works with those 2)
And yeah i am interested in how the PSP runs, from what i remember it has its own launcher inside the eboot.psp called DATA.PSP (or eboot.bin depending on the program used to extract) so it would be interesting to see if this could be made possible for psp owners, if not then the PPF method is probably best like you said, there are so few libcrypt games anyway

Can you try out the magic-word branch of pop-fe ?
The patch is only in the magic-word branch for now.

It attempts to detect if the disk is libcrypt enabled by checking the game-id to a new dict gamedb/libcrypt that I built from the webpage but I must have missed about ~10 disks or so since it does not contain all 229 disks.
Then if it is recognized as libcrypt, it fetches the data from redump.org and generates the magic word
and finally injects it at 0x12b0 in psisoimg0000.
Can you test it, if it works for your disks and the generated ISO.BIN.DAT looks good ?

If it works, it should make it easier to test since you dont have to manually go and hexedit the ISO.BIN.DAT and stuff

EDIT: for multi-disc games it is probably only going to work for the first disk, since that is the only disk I use when checking the game-id. I will have to change this to check the game id and generate a magic word for each disk in the set before it will likely work. But lets at least test disc1 and a bunch of single disc games. If this works well we might have mostly solved the issue of creating EBOOT.PBP packages for PS3.

EDIT2: I have fixed pop-fe now so that it checks the game-id for each disk and generates a unique MagicWord for each disc in multi-disc games, instead of just checking the first disk and then using the same magic-word on every disk in the series.
That is updated in the magic-word branch.
Then I looked at redump for FF8 UK and it looks like that all 4 disks have the same magic-word anyway, so I guess Jokes on me ?
 
Last edited:
Ronnie can you check this ?, there is a disalignment in the ISO.BIN.EDAT "section" table in wiki introduced since this edit
https://www.psdevwiki.com/ps3/index.php?title=ISO.BIN.EDAT&diff=44695&oldid=41851

The previous versions of the table was considering all the areas are aligned to 0x400 (the size of a block), the area that was named "tracks table" in that edit (and "Audio tracks table" in the actual version) was given a size of 0x620 (exceeds one block), you have been working with audio tracks latelly, what do you think about this ?
If the audio tracks table is really bigger than one block we should represent it as a contiguous area of two blocks (0x800)
In ther words, it would include the area we are naming in the actual version as "Game Params Table"... so it would be needed to change the names to give them a common name and represent it as a single entity

The real annoyance about this detail is the area that comes next "Game Params Table" in the actual version of the table is not starting at an offset aligned to 0x400, is hard to know where it starts because a lot of the values are unused/filled by zeroes but i would say it "should" start at 0x1400 (following the offsets of the table in wiki that represents the first disc of a multidisc game)

The relative offset of the "magic word" discussed in the latest posts here depends of where we consider it starts the "Game Params Table"

Blocks 4 and 5 are a little messy because the audio track table can be, and for some games are, larger than 0x400.
It doesn't bother me that much other than it makes it a bit more difficult to translate between offset of a field inside block 5 versus offset of that same field relative to the start of psisoimg0000
Maybe combining blocks 4 and 5 into a single 0x800 byte large block?

EDIT: I split the audio track table into two so now the boundary between blocks 4 and 5 are at 0x1400 and both blocks are 0x400 in size. What do you think?
 
Last edited:
I have already looked at the Cobra code, it's subchannel Q ready & all the OS SCSI support stuff is subchannel ready too.
Cobra already fills up subchannel Q when the appropriate READ_CD scsi command options are passed to it.
So my first impressions lead me to believe that adding sbi support in Cobra should be quite straightforward, adding the sbi support C files to the Cobra project & a few lines of code in storage_ext.c should do the trick in theory.


Are you saying that cobra already automatically generates correct subchannel data on the fly for read_cd command?

If so, maybe you don't even need the sbi files at all. I suspect that libcrypt actually does not check the actual content of the subchannel, but only whether it is valid or corrupted.
If that is the case you would only need the magic-word and not the entire sbi file.
The code would then basically just be to add an extra conditional of the form:
check the sector number against the magic-word.
If the corresponding bit in the magic-word is 1 for this sector, then just randomly corrupt the data before returning it to the application.

It is worth testing.
 
Are you saying that cobra already automatically generates correct subchannel data on the fly for read_cd command?

If so, maybe you don't even need the sbi files at all. I suspect that libcrypt actually does not check the actual content of the subchannel, but only whether it is valid or corrupted.
If that is the case you would only need the magic-word and not the entire sbi file.
The code would then basically just be to add an extra conditional of the form:
check the sector number against the magic-word.
If the corresponding bit in the magic-word is 1 for this sector, then just randomly corrupt the data before returning it to the application.

It is worth testing.
Here is the SCSI_CMD_READ_CD command code, the subchannel stuff is explicit enough:
Code:
case SCSI_CMD_READ_CD:

		{

			ScsiCmdReadCd *cmd = (ScsiCmdReadCd *)indata;

			ReadCdIso2352Cmd read_cmd;

			event_t event;

			uint64_t outsize;

			uint8_t *buf;

			int ret;

			int user_data = 1;

 

			if (cmd->misc == 0)			

				user_data = 0;			

 

			else if (cmd->misc != 0xF8 && cmd->misc != 0x10)

			{

				#ifdef DEBUG

					DPRINTF("Unexpected value for misc: %02X\n", cmd->misc);

				#endif

				return -1;

			}

 

			if (cmd->rv_scsb != 0 && cmd->rv_scsb != 2)

			{

				#ifdef DEBUG

					DPRINTF("Unexpected value for subchannel: %02X\n", cmd->rv_scsb);

				#endif

				return -1;

			}

 

			if (GET_EXPECTED_SECTOR_TYPE(cmd) != 0)

			{

				#ifdef DEBUG

					DPRINTF("Unexpected value for expected sector type: %d\n", GET_EXPECTED_SECTOR_TYPE(cmd));

				#endif

				return -1;

			}

 

			uint32_t length = GET_READ_SIZE(cmd);

			uint32_t lba = cmd->lba;

			process_t process = get_current_process_critical();

 

			if (is2048)

			{

				#ifdef DEBUG

					DPRINTF("Read CD on 2048 iso (lba=0x%x, length=0x%x)!!! Not implemented.\n", lba, length);

				#endif

				return 0; // Fallback to real disc, let's see what happens :)

			}

 

			if (user_data)			

				outsize = length * cd_sector_size;			

			else			

				outsize = 0;			

 

			if (cmd->rv_scsb == 2)			

				outsize += (length*sizeof(SubChannelQ));			

 

			#ifdef DEBUG

				if (outsize == 0)			

					DPRINTF("Warning: outsize is zero\n");			

			#endif

 

			if (outsize > outlen)

			{

				ret = page_allocate_auto(process, outsize, 0x2F, (void **)&buf);

				if (ret != 0)

					return -1;

			}

			else			

				buf = outdata;			

 

			if (cmd->rv_scsb == 0)

			{

				read_cmd.start_sector = lba;

				read_cmd.sector_count = length;

				read_cmd.buf = buf;

				read_cmd.process = process;

 

				event_port_send(command_port, CMD_READ_CD_ISO_2352, (uint64_t)&read_cmd, 0);

				ret = event_queue_receive(result_queue, &event, 0);

				if (ret == 0)

					ret = (int)(int64_t)event.data1;

 

				if (ret != 0)

					return -1;

			}

			else

			{

				uint8_t *p = buf;

 

				for (int i = 0; i < length; i++)

				{

					if (user_data)

					{

						read_cmd.start_sector = lba;

						read_cmd.sector_count = 1;

						read_cmd.buf = p;

						read_cmd.process = process;

 

						event_port_send(command_port, CMD_READ_CD_ISO_2352, (uint64_t)&read_cmd, 0);

						ret = event_queue_receive(result_queue, &event, 0);

						if (ret == 0)

							ret = (int)(int64_t)event.data1;

 

						if (ret != 0)

							return -1;

 

						p += cd_sector_size;

					}

 

					SubChannelQ *subq = (SubChannelQ *)p;

					memset(subq, 0, sizeof(SubChannelQ));

 

					ScsiTrackDescriptor *track = find_track_by_lba(lba);

					subq->control_adr = ((track->adr_control << 4)&0xF0) | (track->adr_control >> 4);

					subq->track_number = track->track_number;

					subq->index_number = 1;

 

					if (user_data)

						lba_to_msf_bcd(lba, &subq->min, &subq->sec, &subq->frame);

 

					lba_to_msf_bcd(lba+150, &subq->amin, &subq->asec, &subq->aframe);

					subq->crc = calculate_subq_crc((uint8_t *)subq);

 

					p += sizeof(SubChannelQ);

					lba++;

				}

			}

 

			if (outsize > outlen)

			{

				memcpy(outdata, buf, outlen);

				page_free(process, buf, 0x2F);

			}

 

			return 1;

 

			//#ifdef DEBUG

				//DPRINTF("READ CD, sector %x size %x, expected sector type: %d\n", cmd->lba, s, GET_EXPECTED_SECTOR_TYPE(cmd));

				//DPRINTF("Misc: %02X, rv_scsb: %02X, outlen = %lu\n", cmd->misc, cmd->rv_scsb, outlen);

			//#endif

 

		}

		break;


And here are the scsi structures in play.
Code:
typedef struct _ScsiCmdReadCd

{

	uint8_t opcode;

	uint8_t rv_est_raddr;

	uint32_t lba;

	uint8_t length[3];

	uint8_t misc;

	uint8_t rv_scsb;

	uint8_t control;

} __attribute__((packed)) ScsiCmdReadCd;

 

typedef struct _SubChannelQ

{

	uint8_t control_adr;

	uint8_t track_number;

	uint8_t index_number;

	uint8_t min;

	uint8_t sec;

	uint8_t frame;

	uint8_t zero;

	uint8_t amin;

	uint8_t asec;

	uint8_t aframe;

	uint16_t crc;

	uint8_t pad[3];

	uint8_t p;

} __attribute__((packed)) SubChannelQ;

As you can notice in the code, there are statements to debug data, some DEBUG code is commented but could be uncommented (it would leak the scsi command rv_scsb prop which value is used to decide whether to process subchannel) & the debug Cobra version rebuilt. Or more debug statements can be added to leak the entire subchannel data..

Debug output (DPRINTF statements) is broadcasted to socat udp port 18194.
 
Last edited:
According to the netemu hardcoded table, available on the wiki, flag in the parenthesis, bold value is the Magic Word):
1. LC games with a forced Magic Word:
- Disney's Mulan (00000015000089ea),
- V-Rally 2 (000000150000c0ee),
- Soul Reaver UK (000000150000b722).
2. LC games with a some kind of patch, I do not know what is it for:
- Crash Team Racing (000000020017d3d4),
- MediEvil (000000020017d57c),
- Vagrant Story (000000020017d67c).

I confirm the CTR is working without patches on the ps1_netemu. So the MediEvil should work too, but I am not gonna test it, because the crash does happen after some playtime.

I have already looked at the Cobra code, it's subchannel Q ready & all the OS SCSI support stuff is subchannel ready too.
Cobra already fills up subchannel Q when the appropriate READ_CD scsi command options are passed to it.
So my first impressions lead me to believe that adding sbi support in Cobra should be quite straightforward, adding the sbi support C files to the Cobra project & a few lines of code in storage_ext.c should do the trick in theory.

What about other subchannels? They are not needed, but I think the priority would be to support the whole .SUB files from the proper 1:1 dumps for the sake of completeness. The point is to correctly parse only the Q subchannel as it is the most important of course (sorry for ignorance, I do not know how does it work on a software level). If you take a closer look on the .sbi files you will notice the format is broken by design - it does lack the CRC checksum of the Q subchannel. I am not really sure how it is working correctly on the emulators.

Then I looked at redump for FF8 UK and it looks like that all 4 disks have the same magic-word anyway, so I guess Jokes on me ?

Yeah, it seems the FF8 UK has got the same MW for all discs.

If so, maybe you don't even need the sbi files at all. I suspect that libcrypt actually does not check the actual content of the subchannel, but only whether it is valid or corrupted.
If that is the case you would only need the magic-word and not the entire sbi file.
The code would then basically just be to add an extra conditional of the form:
check the sector number against the magic-word.
If the corresponding bit in the magic-word is 1 for this sector, then just randomly corrupt the data before returning it to the application.

Your approach is kinda flawed, because it is more complicated than just a plain support of the original subchannel data.
 
Last edited:
Your approach is kinda flawed, because it is more complicated than just a plain support of the original subchannel data.

Very likely and I think you are right. I only am interested in EBOOT, so only PS3 PKG and PSP EBOOTs but not really much in other emulators.
All this 'insert magic-word into ISO.BIN.DAT' or 'SBI files' will, I think, never work for PSP EBOOTs anyway so I am switching back to looking at an approach to 'if libcrypt disk, download PPF and apply it'. That will work both for raw EBOOT in PSP and also as embedded EBOOT in PS3 PKG.


For emulators where you have sourcecode and can emulate the cdrom drive, i.e.cobra, I still think that something that uses SBI files and teached cobra to return whatever libcrypt expects is the superior solution.
 
edit : fixed another error from libcrypt magic word finder for formula one 99 the correct value is 9D 0D.

the error comes from fact the first four bytes are null an not counted on the script of the program.
Excel 1 - coder 0 :D
In case you need more magic words to compare with, for possible error checking, I've extracted all the magic words that were in my Action Replay codelist, sorted like in the wiki.
It's missing Spyros, a bunch of nordic localizations of some Disney games, a French football game and basically anything that was Redump'ed after I stopped maintaining POPStarter.
File attached.

@krHACKen , your list of professionally made PPF files for that decently large chunk of games,
would you be ok with me adding your PPFs to pop-fe once I get time to seriously work on it again in january?
Sure.
 

Attachments

I confirm the CTR is working without patches on the ps1_netemu. So the MediEvil should work too, but I am not gonna test it, because the crash does happen after some playtime.



What about other subchannels? They are not needed, but I think the priority would be to support the whole .SUB files from the proper 1:1 dumps for the sake of completeness. The point is to correctly parse only the Q subchannel as it is the most important of course (sorry for ignorance, I do not know how does it work on a software level). If you take a closer look on the .sbi files you will notice the format is broken by design - it does lack the CRC checksum of the Q subchannel. I am not really sure how it is working correctly on the emulators.
Cobra calculates the CRC of the subcQ data on the fly as it processes each lba, that CRC is included in the lbas subcQ data of the Cobra scsi output.
We should be able to do the same with the sbi data, shouldn't we?
Code:
.... 
subq->crc = calculate_subq_crc((uint8_t *)subq);
...
Afaik support is provided for subc Q only.

And here are the msf/lba Cobra conversion functions used, in the snippet I posted, to fill the subcQ data included in the scsi output:
Code:
static INLINE void lba_to_msf(uint64_t lba, uint8_t *m, uint8_t *s, uint8_t *f)

{

	*m = lba/(75*60);

	*s = (lba /75) % 60;

	*f = lba % 75;

}

 

static INLINE void lba_to_msf_bcd(uint64_t lba, uint8_t *m, uint8_t *s, uint8_t *f)

{

	lba_to_msf(lba, m, s, f);

	*m = itob(*m); //itob converts integer value to string? 

	*s = itob(*s);

	*f = itob(*f);

}

 

static inline uint64_t msf_to_lba(uint8_t m, uint8_t s, uint8_t f)

{

	uint64_t lba = m;		

	lba = (lba*60)+s;

	lba = (lba*75)+f;

	return lba;

}

To simplify, let's say that for each lba processed in a loop by the scsi read cd command when subc usage is specified, Cobra fills subcQ & adds crc like this:

Code:
... 
lba_to_msf_bcd(lba, &subq->min, &subq->sec, &subq->frame);

lba_to_msf_bcd(lba+150, &subq->amin, &subq->asec, &subq->aframe);

subq->crc = calculate_subq_crc((uint8_t *)subq);
...
 
Last edited:
Can you try out the magic-word branch of pop-fe ?
The patch is only in the magic-word branch for now.

It attempts to detect if the disk is libcrypt enabled by checking the game-id to a new dict gamedb/libcrypt that I built from the webpage but I must have missed about ~10 disks or so since it does not contain all 229 disks.
Then if it is recognized as libcrypt, it fetches the data from redump.org and generates the magic word
and finally injects it at 0x12b0 in psisoimg0000.
Can you test it, if it works for your disks and the generated ISO.BIN.DAT looks good ?

If it works, it should make it easier to test since you dont have to manually go and hexedit the ISO.BIN.DAT and stuff

EDIT: for multi-disc games it is probably only going to work for the first disk, since that is the only disk I use when checking the game-id. I will have to change this to check the game id and generate a magic word for each disk in the set before it will likely work. But lets at least test disc1 and a bunch of single disc games. If this works well we might have mostly solved the issue of creating EBOOT.PBP packages for PS3.

EDIT2: I have fixed pop-fe now so that it checks the game-id for each disk and generates a unique MagicWord for each disc in multi-disc games, instead of just checking the first disk and then using the same magic-word on every disk in the series.
That is updated in the magic-word branch.
Then I looked at redump for FF8 UK and it looks like that all 4 disks have the same magic-word anyway, so I guess Jokes on me ?
OK just tested the magic Branch and its working great with FF8, it found the magic word, only problem i had was the PKG was non-existant still (same thing happened before), so i made the PKG myself but other then that its working great on my PS3 (it spends AGES making the PKG then it cleans up and im left with nothing so im not sure if its deleting the PKG or it just never gets made properly), i checked all 4 discs (using reset and change disc) and all 4 load fine to the main menu and i played the opening scene and upto the first battle on CD1 and its all working great, this is really nice work
EDIT:- i also tested this method on my Vita's PSP emulator and it didn't work so im guessing the PSP handles it differently.
 
Blocks 4 and 5 are a little messy because the audio track table can be, and for some games are, larger than 0x400.
It doesn't bother me that much other than it makes it a bit more difficult to translate between offset of a field inside block 5 versus offset of that same field relative to the start of psisoimg0000
Maybe combining blocks 4 and 5 into a single 0x800 byte large block?

EDIT: I split the audio track table into two so now the boundary between blocks 4 and 5 are at 0x1400 and both blocks are 0x400 in size. What do you think?
Good, im still wondering where exactly starts the area we are naming "game params table", let me explain it using this screenshot made by devildwarf (official file at left, custom at right)
differences-jpg.35456

The second highlighted area (starting with 0xD3) is located at absolute offset 0x1220 (or at 0x1620 for the first disc of a multidisc game, like in the way is shown in wiki). And the magic word at left (starting with byte 0x71) is at absolute offset 0x12B0 (or at 0x16B0 for the first disc of a multidisc game, like in the way is shown in wiki)
In other words, we could say that the magic word is located at offset 0x90 relative to the start offset of the "game params table" area
But... if we consider the "game params table" starts at 0x1200 (0x1600 for first disc of multidisd) then is relative offset 0xB0
If i had to bet i would say it starts at 0x1200/1600 (at the half of a block)... lets say... sony is dividing a block (0x400) in half (0x200), the audio table takes 1 block and a half, and the game params area starts in the next half block

While brainstorming about this i thought that maybe the audio tracks could indicate where it ends or could result in some rounded nmbers, dunno, but doesnt matters much now, is just a detail for wikifying purposes, the offsets in wiki are absolute but it would be better to change them to relative

Edit:
I just changed the offsets in the ISO.BIN.EDAT wiki page to relative anyway
 
Last edited:
OK just tested the magic Branch and its working great with FF8, it found the magic word, only problem i had was the PKG was non-existant still (same thing happened before), so i made the PKG myself but other then that its working great on my PS3 (it spends AGES making the PKG then it cleans up and im left with nothing so im not sure if its deleting the PKG or it just never gets made properly), i checked all 4 discs (using reset and change disc) and all 4 load fine to the main menu and i played the opening scene and upto the first battle on CD1 and its all working great, this is really nice work
EDIT:- i also tested this method on my Vita's PSP emulator and it didn't work so im guessing the PSP handles it differently.

That is really odd. It creates the PKG just fine here.
--ps3-pkg=ff8.pkg
Add -v for more verbose output. Maybe it is creating the pkg in a different directory?

EDIT: For PSP/VITA there is no ISO.BIN.DAT. I tried inserting the magic word in the corresponding place in the EBOOT.PBP but it did not work.
For PSP/VITA I think I will have to download and apply PPF patches.
 
That is really odd. It creates the PKG just fine here.
--ps3-pkg=ff8.pkg
Add -v for more verbose output. Maybe it is creating the pkg in a different directory?

EDIT: For PSP/VITA there is no ISO.BIN.DAT. I tried inserting the magic word in the corresponding place in the EBOOT.PBP but it did not work.
For PSP/VITA I think I will have to download and apply PPF patches.
still no PKG (checked the sub folders too and TMP and a few other locations) so not sure what is happening (testing on VM with Ubuntu 21.10)
posting a screenshot with the -v command
EDIT:-
full command im using is now
./pop-fe.py -v --ps3-pkg=FF8.pkg FF8CD1.img FF8CD2.img FF8CD3.img FF8CD4.img

Yeah i tried that too with the Vita's PSP emulator with no luck, its possibly in the DATA.PSP(or sometimes named eboot.bin) on PSP ? i have no way to decode that file so i cant say for sure
 

Attachments

  • pkg.jpg
    pkg.jpg
    326.6 KB · Views: 49
According to the netemu hardcoded table, available on the wiki, flag in the parenthesis, bold value is the Magic Word):
1. LC games with a forced Magic Word:
- Disney's Mulan (00000015000089ea),
- V-Rally 2 (000000150000c0ee),
- Soul Reaver UK (000000150000b722).
2. LC games with a some kind of patch, I do not know what is it for:
- Crash Team Racing (000000020017d3d4),
- MediEvil (000000020017d57c),
- Vagrant Story (000000020017d67c).

I confirm the CTR is working without patches on the ps1_netemu. So the MediEvil should work too, but I am not gonna test it, because the crash does happen after some playtime.
Btw, about that flags... the first group sems to be composed by 2 values
1) 0x15 (unknown, but probably indicates something related with libcrypt)
2) The magic word

And the second group:
1) 0x20 (unknown, but probably indicates something related with a different libcrypt mode)
2) An offset

If the second value of the second group is an offset it means is loading data from another area of the emulator .elf
If we think in them as 3 consecutive areas ordered from lower offset to higher offset (in the same way you listed them) we have:
0x17d3d4
0x17d57c
0x17d67c

And it would mean that every area have this size:
first (crash team racing) = 0x17d57c - 0x17d3d4 = 0x1A8
second (medievil) = 17d67c - 17d57c = 0x100
third (vagrant story) = unknown

That sizes makes sense if we keep in mind that medievil was the first game where libcrypt was implemented, is LC v1 (well redump lists it as LC2, and "Gekido: Urban Fightersw" as the only LC1
Anyway, medievil libcrypt was known for being a weak protection (easy to defeat) and the amount of data involved was smaller than any other libcrypt protected game
This is also why the medievil SBI file is way smaller than the SBI files of any other libcrypt protected game
There are only 6 SBI files with 228 bytes (16 libcrypt protected sectors), 1 for gekido and 5 for medieveil discs, while the SBI file for all other games are 452 bytes (32 libcrypt protected sectors). Note the amount of libcrypt protected sectors is exactly the double (while the file size is not the double)
We can download the whole redump collection of SBI files from this link btw http://redump.org/sbi/psx/ (only 6 files with size 228)

Also the size 0x1A8 for crash team racing is not so big anyway, if we compare it with the size of his SBI file in redump.org (0x1C4), this small difference of sizes could be because the SBI format is not exactly the same than the official

Long story short, it looks like is loading the subchannel data for that 3 games hardcoded inside the emu
I was roaming inside ps1netemu and I noticied the titleID of bird of steel (ps3), any idea why it's in there ?
sry, about the offtopic
The game name as a text or as an ID like BLUS12345 ?
 
Last edited:
2 id used in the same function : BLUS30831, NPUB30885
Weird, first idea that came to mind is that it could be something related with crosscompatibility in between the 2 consoles PS1<--->PS3
But usually that kind of features happens in the opposite way, i mean you run some PS3 content and it checks some PS1 content to "unlock" surprises in the PS3 game

But this seems to work in the opposite way, i mean... if the ID's of the PS3 games are inside the PS1 emu it means are readed when you are inside the PS1 emu so i cant imagine how it could check any kind of content from other PS3 game... maybe is the presence of the PS3 gamedata/save ?
Anyway, this would only make sense if the game company that released bird of steel on PS3 published other games for PS1 is the past, dunno, there is some "birds of steel" for PS1 ?

Edit:
Nah, the game company doesnt seems to be so old to publish games for PS1 https://en.wikipedia.org/wiki/Gaijin_Entertainment
 
Last edited:
Weird, first idea that came to mind is that it could be something related with crosscompatibility in between the 2 consoles PS1<--->PS3
But usually that kind of features happens in the opposite way, i mean you run some PS3 content and it checks some PS1 content to "unlock" surprises in the PS3 game

But this seems to work in the opposite way, i mean... if the ID's of the PS3 games are inside the PS1 emu it means are readed when you are inside the PS1 emu so i cant imagine how it could check any kind of content from other PS3 game... maybe is the presence of the PS3 gamedata/save ?
Anyway, this would only make sense if the game company that released bird of steel on PS3 published other games for PS1 is the past, dunno, there is some "birds of steel" for PS1 ?

Edit:
Nah, the game company doesnt seems to be so old to publish games for PS1 https://en.wikipedia.org/wiki/Gaijin_Entertainment

IIRC Konami did a trick like this before, in MGS4 during the Shadow Moses flashback. The game would switch to the PS1 emulator during this sequence and then switch back to PS3 mode once you'd finish that part of the game. Maybe this game has some old hidden Konami game built in...like for example Sky Jaguar (this is just a theory tho). They did release this on the PS1 under the name Konami Antiques MSX Collection Vol. 1 (and later on as a PSone Classics game for the PS3/PSP and Vita on PSN).

edit: I'm basing this Sky Jaguar theory on the fact that one of the gamefiles mentions Sky Aces as you can see in the attachment. That was the only Konami game I could find that has something to do with airplanes and contains the word sky lol.
 

Attachments

  • HxD_0aD1KWZEka.png
    HxD_0aD1KWZEka.png
    159.2 KB · Views: 47
Last edited:
Cobra calculates the CRC of the subcQ data on the fly as it processes each lba, that CRC is included in the lbas subcQ data of the Cobra scsi output.
We should be able to do the same with the sbi data, shouldn't we?
Code:
....
subq->crc = calculate_subq_crc((uint8_t *)subq);
...
Afaik support is provided for subc Q only.

And here are the msf/lba Cobra conversion functions used, in the snippet I posted, to fill the subcQ data included in the scsi output:
Code:
static INLINE void lba_to_msf(uint64_t lba, uint8_t *m, uint8_t *s, uint8_t *f)

{

    *m = lba/(75*60);

    *s = (lba /75) % 60;

    *f = lba % 75;

}

 

static INLINE void lba_to_msf_bcd(uint64_t lba, uint8_t *m, uint8_t *s, uint8_t *f)

{

    lba_to_msf(lba, m, s, f);

    *m = itob(*m); //itob converts integer value to string?

    *s = itob(*s);

    *f = itob(*f);

}

 

static inline uint64_t msf_to_lba(uint8_t m, uint8_t s, uint8_t f)

{

    uint64_t lba = m;

    lba = (lba*60)+s;

    lba = (lba*75)+f;

    return lba;

}

To simplify, let's say that for each lba processed in a loop by the scsi read cd command when subc usage is specified, Cobra fills subcQ & adds crc like this:

Code:
...
lba_to_msf_bcd(lba, &subq->min, &subq->sec, &subq->frame);

lba_to_msf_bcd(lba+150, &subq->amin, &subq->asec, &subq->aframe);

subq->crc = calculate_subq_crc((uint8_t *)subq);
...

The point is the LibCrypt's SubQ CRC is modified using one of two formulas:
Nocash PSX Specifications (problemkaputt.de)

Sunshine's Homepage - Online CRC Calculator Javascript (sunshine2k.de)
Use the CRC-16 custom option - polynomial 0x1021, initial 0x0, final XOR 0xFFFF, both reflection marks unchecked:

Let's start with the MediEvil. Take the first data without the last two bytes (bold values are the modified ones):
41 01 01 07 06 05 00 23 08 05
Calculate the checksum of these bytes - 0xFF38. XOR with 0x0080 - 0xFFB8. It is the modified checksum value for that LC scheme.

Now let's take a look into the CTR:
41 01 01 07 06 05 00 23 08 05
It does use the second scheme - we need to fix the modified timing data first:
41 01 01 03 06 05 00 03 08 05
Calculate the checksum - 0xB838, XOR with 0x8001 - 0x3839. It is the modified checksum of the second scheme, as you can see in the dumped data.

The third scheme does differ from the first one that the timing data could be not altered at all - only the CRC could - Ape Escape ESP, sector 16167:
41 01 01 03 33 42 00 03 35 42
Calculate the checksum - 0xE9E3, XOR with 0x0080 - 0xE963. And voila, that is the LC checksum.

Btw, about that flags... the first group sems to be composed by 2 values
1) 0x15 (unknown, but probably indicates something related with libcrypt)
2) The magic word

And the second group:
1) 0x20 (unknown, but probably indicates something related with a different libcrypt mode)
2) An offset

If the second value of the second group is an offset it means is loading data from another area of the emulator .elf
If we think in them as 3 consecutive areas ordered from lower offset to higher offset (in the same way you listed them) we have:
0x17d3d4
0x17d57c
0x17d67c

And it would mean that every area have this size:
first (crash team racing) = 0x17d57c - 0x17d3d4 = 0x1A8
second (medievil) = 17d67c - 17d57c = 0x100
third (vagrant story) = unknown

That sizes makes sense if we keep in mind that medievil was the first game where libcrypt was implemented, is LC v1 (well redump lists it as LC2, and "Gekido: Urban Fightersw" as the only LC1
Anyway, medievil libcrypt was known for being a weak protection (easy to defeat) and the amount of data involved was smaller than any other libcrypt protected game
This is also why the medievil SBI file is way smaller than the SBI files of any other libcrypt protected game
There are only 6 SBI files with 228 bytes (16 libcrypt protected sectors), 1 for gekido and 5 for medieveil discs, while the SBI file for all other games are 452 bytes (32 libcrypt protected sectors). Note the amount of libcrypt protected sectors is exactly the double (while the file size is not the double)
We can download the whole redump collection of SBI files from this link btw http://redump.org/sbi/psx/ (only 6 files with size 228)

Also the size 0x1A8 for crash team racing is not so big anyway, if we compare it with the size of his SBI file in redump.org (0x1C4), this small difference of sizes could be because the SBI format is not exactly the same than the official

Long story short, it looks like is loading the subchannel data for that 3 games hardcoded inside the emu

To be honest I do not really know what the last three patches are precisely doing. I do not like the guessing games, so I think the reverse engineering the emulator is needed to understand it properly. Either way, the protection is not triggered at all it seems on these cases.

The first three games with Magic Words are present even in the old ps1_emu. Maybe some emulation issues interfered with the protection.

The MediEvil has got less sectors with the LC, because no paired sectors were used. Probably a second paired sector was added to avoid a tracking problems, as the seeking may not be accurate. In general LibCrypt works the same way like the old SecuROM (no surprise, as the same company was responsible for it).
 
Last edited:

Similar threads

Back
Top