26 (edited by Edness 2023-09-23 21:39:54)

Unrelated, I know you've already confirmed the multi-partition UMD GAME+MOVIE discs are most likely correct size in your original post, but out of curiosity if you have any on hand, could you provide the PFI for one of those too?

----------

Anyway: sceUmdExecGetConfigurationCmd() - Sends the expected command 0x46
This function doesn't seem to exist in FW 6.60, at least not in umdman.prx, so this is just what FW 3.52 does.  (It's possible it maybe still lives on a different module, so it's worth trying regardless.)

Function that calls it creates a 0x36 byte buffer on the stack.  The first 0x20 are meant for a different function call I'm pretty sure, but just for the sake of authenticity, I'm writing exactly how the function sets it up before calling.

  • 0x00-0x10 - int32 x 4

  • 0x20-0x28 - unk8 x 8 (it calls memset() with a pointer to 0x20 and writes the value 0xFF eight times)

  • 0x30-0x32 - int16 x 1 (store 0x08)

  • 0x32-0x34 - int16 x 1

  • 0x34-0x36 - int8   x 2

(Visualized)

sceUmdExecGetConfigurationCmd() is called with 3 arguments:

  • $a0 - UMD drive returned by sceUmdManGetUmdDrive()

  • $a1 - Pointer to 0x30 of that buffer

  • $a2 - Pointer to 0x20 of that buffer

----------

Lastly: sceUmdExecReadDiscInfoCmd() - Sends the expected command 0x51
While this function does exist in FW 6.60's umdman.prx, there doesn't seem to be any function that calls it - so this is also just based off what FW 3.52 does and prepares before calling.

As with the function above, I'm pretty sure you can just create a 12 byte array, all memset()'d to 0xFF and use that alone, but for the sake of authenticity - it creates a 0x2C byte buffer on the stack:

  • 0x00-0x10 - int32 x 4

  • 0x10-0x12 - int16 x 1

  • 0x20-0x2C - unk8 x 12 (it calls memset() with a pointer to 0x20 and writes the value 0xFF 12 times

(Visualized)

sceUmdExecReadDiscInfoCmd() is called with 3 arguments:

  • $a0 - UMD drive returned by sceUmdManGetUmdDrive()

  • $a1 - Number 12 (Likely the size of the buffer in the next arg)

  • $a2 - Pointer to 0x20 of that buffer

----------

Random side note: The C library functions (at least the two that I've encountered - strncmp(), and memset()) seem to be unnamed in your asm dump.  Instead they're generic SysclibForKernel_NID() names, but luckily JPCSP has a more complete list of resolved NID hashes which was useful in cases like these.

Edness wrote:

I know you've already confirmed the multi-partition UMD GAME+MOVIE discs are most likely correct size in your original post, but out of curiosity if you have any on hand, could you provide the PFI for one of those too?

Stealth feat. WipEout Pure Stealth Edition http://redump.org/disc/57052/

 00 00 00 00 00 00 00 00 12 00 00 00 00 00 00 00
 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
 00 16 00 00 80 00 31 E0 00 03 00 00 00 FC D3 3F
 00 09 C0 BF 00 03

Edness wrote:

Anyway: sceUmdExecGetConfigurationCmd() - Sends the expected command 0x46

Edness wrote:

Lastly: sceUmdExecReadDiscInfoCmd() - Sends the expected command 0x51

Thanks research. I'll code and test in the near future.

Edness wrote:

Random side note:

Thanks to you I know SysclibForKernel_NID().

sceUmdExecGetConfigurationCmd()
I coded, but the fuction error occurred (0x8021100f).

    unsigned char bufConfig[0x36] = {};
    memset(&bufConfig[0x20], 0xff, 8);
    bufConfig[0x30] = 8;

    _sceUmdManWaitSema();
    res = _sceUmdExecGetConfigurationCmd(pUmdDrive, &bufConfig[0x30], &bufConfig[0x20]);
    _sceUmdManSignalSema();
    if (res < 0) {
        OutputPspError("_sceUmdExecGetConfigurationCmd", 0, res);
        sceKernelDelayThread(5 * 1000000);
    }
    else {
        uid = sceIoOpen("ms0:/_sceUmdExecGetConfigurationCmd.bin", PSP_O_CREAT | PSP_O_TRUNC | PSP_O_WRONLY, 0777);
        sceIoWrite(uid, bufConfig, sizeof(bufConfig));
        sceIoClose(uid);
    }

sceUmdExecReadDiscInfoCmd()
Also 0x8021100f error occurred.

    unsigned char bufDiscInfo[0x2c] = {};
    memset(&bufDiscInfo[0x20], 0xff, 12);

    _sceUmdManWaitSema();
    res = _sceUmdExecReadDiscInfoCmd(pUmdDrive, 12, &bufDiscInfo[0x20]);
    _sceUmdManSignalSema();
    if (res < 0) {
        OutputPspError("_sceUmdExecReadDiscInfoCmd", 0, res);
        sceKernelDelayThread(5 * 1000000);
    }
    else {
        uid = sceIoOpen("ms0:/_sceUmdExecReadDiscInfoCmd.bin", PSP_O_CREAT | PSP_O_TRUNC | PSP_O_WRONLY, 0777);
        sceIoWrite(uid, bufDiscInfo, sizeof(bufDiscInfo));
        sceIoClose(uid);
    }

29 (edited by Edness 2023-09-26 17:03:15)

Error code 0x8021100F seems to be returned in some places by ata.prx.  More specifically, it seems to occur if the value at the address 0xBD700007 isn't divisible by 2 (or at least if bit 0 is set) after calling sceAtaAccessDataPort()?  Not sure.
Looking at the PSP memory map, it does seem to be in the ATA/UMDMAN hardware register region, at least.


Edit 1: This seems to have more info about those hardware registers.


Edit 2: Looks like those functions might be meant for the DVD drive present on devkits?  ata.prx has two functions - sceAtaIsDvdDrive() and sceAtaIsUmdDrive() - both of which seem to read from the same location.  The functions just read from 0x00000000, but I assume the system redirects these accordingly upon loading.  (Or maybe it's intentionally disabled like this?)

IsDvdDrive returns whatever value is currently there, but IsUmdDrive returns 0 or 1 if the (unsigned) value there is less than 1 (in other words a bool on whether the value is 0 or not.)  And both functions that later call sceUmdExecGetConfigurationCmd() and  sceUmdExecReadDiscInfoCmd(), first also call sceAtaIsUmdDrive() and exit out of it, if it doesn't return 0.

Edness wrote:

Random side note: The C library functions (at least the two that I've encountered - strncmp(), and memset()) seem to be unnamed in your asm dump.  Instead they're generic SysclibForKernel_NID() names, but luckily JPCSP has a more complete list of resolved NID hashes which was useful in cases like these.

Added the fuction name in documents.
https://github.com/saramibreak/UmdImage … asm352.txt
https://github.com/saramibreak/UmdImage … m352_c.txt

Edness wrote:

Looks like those functions might be meant for the DVD drive present on devkits? ... IsUmdDrive returns 0 or 1 if the (unsigned) value there is less than 1 (in other words a bool on whether the value is 0 or not.)  And both functions that later call sceUmdExecGetConfigurationCmd() and  sceUmdExecReadDiscInfoCmd(), first also call sceAtaIsUmdDrive() and exit out of it, if it doesn't return 0.

As you say, if sceAtaIsUmdDrive returns 0, that is NOT UMD DRIVE, sceUmdExecReadDiscInfoCmd is called.

    0x0000C794: 0x0C003FA5 '.?..' - call func sceAtaIsUmdDrive(delay)
    0x0000C798: 0x00000000 '....' - nop        
    0x0000C79C: 0x1040000E '..@.' - if($v0 == 0) goto loc_0000C7D8 (delay)

loc_0000C7D8:        ; Refs: 0x0000C79C 
    0x0000C7D8: 0x3C060393 '...<' - $a2 = 0x393 << 16
    0x0000C7DC: 0x0C0029D6 '.)..' - call func sceUmdManSetAlarm(delay)
    0x0000C7E0: 0x34C48700 '...4' - $a0 = $a2 | 0x8700
 :
 :
    0x0000C824: 0x2405000C '...$' - $a1 = 12
    0x0000C828: 0x0C001368 'h...' - call func sceUmdExecReadDiscInfoCmd(delay)

Yeah, this would also probably explain why those two SCSI-like functions seem to either be removed or never referenced in newer PSP FW umdman.prx.

@Edness
Do you know what data is outputted by sceUmdExecMechaStatCmd? This func is called by umd9660.prx. https://github.com/saramibreak/UmdImage … asm352.txt

I think it's Mechanical Status of Mode Sense (5Ah) or Mechanism Status (BDh).

    unsigned char bufMecha[16] = {};

    res = _sceUmdExecMechaStatCmd(pUmdDrive, 16, bufMecha);
    if (res < 0) {
        OutputPspError("_sceUmdExecMechaStatCmd", 0, res);
        sceKernelDelayThread(5 * 1000000);
    }
    else {
        uid = sceIoOpen("ms0:/_sceUmdExecMechaStatCmd.bin", PSP_O_CREAT | PSP_O_TRUNC | PSP_O_WRONLY, 0777);
        sceIoWrite(uid, bufMecha, sizeof(bufMecha));
        sceIoClose(uid);
        pspPrintf("_sceUmdExecMechaStatCmd.bin is generated\n");
    }

LocoRoco http://redump.org/disc/33078/

 00 00 00 00 00 01 00 04 80 00 00 00 27 09 27 09

Jigen Kairou http://redump.org/disc/54489/
Changed the buf size to 30.

 00 00 00 00 00 01 00 04 80 00 00 00 37 02 37 02
 37 02 37 02 37 02 37 02 37 02 37 02 37 02

Dissidia 012: Duodecim Final Fantasy http://redump.org/disc/25036/
Changed the buf size to 106.

 00 00 0D 2C AF 01 00 04 80 00 00 00 22 D9 22 D9
 22 D9 22 D9 22 D9 22 D9 22 D9 22 D9 22 D9 22 D9
 22 D9 22 D9 22 D9 22 D9 22 D9 22 D9 22 D9 22 D9
 22 D9 22 D9 22 D9 22 D9 22 D9 22 D9 22 D9 22 D9
 22 D9 22 D9 22 D9 22 D9 22 D9 22 D9 22 D9 22 D9
 22 D9 22 D9 22 D9 22 D9 22 D9 22 D9 22 D9 22 D9
 22 D9 22 D9 22 D9 22 D9 22 D9

It seems the correct buf size is 14.

It sends the command 0xBD, so your 2nd assumption is correct.  umd9660.prx seems to set the 2nd argument to 16, but I agree with the visible padding data that it's likely meant to be 14.  They probably just set it bigger just to be safe from accidentally truncating data.

I noticed there's sceUmdExecReadUMDStructureCmd() here too, and here it actually does set the write size at 0x08 of the buffer to 0x800, which makes it kinda interesting that it crashed when you tried that size.  Although here it doesn't create the 2nd buffer on the stack, it seems to be likely pre-allocated in another function that would call this one with a pointer to it, but the preceding function doesn't exist anymore in FW 3.52.

Edness wrote:

It sends the command 0xBD, so your 2nd assumption is correct.  umd9660.prx seems to set the 2nd argument to 16, but I agree with the visible padding data that it's likely meant to be 14.  They probably just set it bigger just to be safe from accidentally truncating data.

Thank you.

Edness wrote:

I noticed there's sceUmdExecReadUMDStructureCmd() here too.

I changed the code and confirmed not to crash.

    unsigned char bufStruct[2064] = {};
    bufStruct[9] = 8;
    res = _sceUmdExecReadUMDStructureCmd(pUmdDrive, bufStruct, &bufStruct[16]);
    if (res < 0) {
        OutputPspError("_sceUmdExecReadUMDStructureCmd", 0, res);
        sceKernelDelayThread(5 * 1000000);
    }
    else {
        uid = sceIoOpen("ms0:/_sceUmdExecReadUMDStructureCmd.bin", PSP_O_CREAT | PSP_O_TRUNC | PSP_O_WRONLY, 0777);
        sceIoWrite(uid, bufStruct, sizeof(bufStruct));
        sceIoClose(uid);
        pspPrintf("_sceUmdExecReadUMDStructureCmd.bin is generated\n");
    }

Dissidia 012: Duodecim Final Fantasy

 00 00 00 00 00 00 00 00 FC 07 00 00 00 00 00 00
 08 00 00 00 80 00 31 E0 00 03 00 00 00 FC AB 2F
 00 09 C0 BF 00 01 00 00 00 00 00 00 00 00 00 00
 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
 :
 :
 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00

36 (edited by Edness 2023-10-02 12:01:58)

Nice.  Out of curiosity, is the PFI data dumping currently only limited to FW 3.52 (or rather any FW below 3.70 where NIDs weren't randomized?)  Because eventually I would like to dump that data from my UMDs too just for safekeeping.  (Although since the disc format info is now known, I could just fake generate it myself...)

If that's the case, is knowing the NID enough to make it possible on newer firmwares?  This did motivate me to look into a bit deeper in how PSP FW stuff works.  For example, in FW 6.60 and 6.61, sceUmdExecReadUMDStructureCmd() should use the NID 0x406E8F99 if my understanding is correct.

Otherwise, if it was possible to do on any FW regardless, or if it needs more than just the NID, then ignore the above, haha.

Edness wrote:

is the PFI data dumping currently only limited to FW 3.52 (or rather any FW below 3.70 where NIDs weren't randomized?)

Unfortunately yes.

Edness wrote:

in FW 6.60 and 6.61, sceUmdExecReadUMDStructureCmd() should use the NID 0x406E8F99 if my understanding is correct.

NID is correct but the correct function name is sceUmdExecReadUMDStructureCmd + 128 bits string.
https://uofw.github.io/upspd/docs/Silve … index.html

These new nids are not actually “random” but instead, they now append a new 128bit “randomising key” to the end of each string before the SHA1 hash is calculated. A 128bit value is almost impossible to bruteforce practically so these new nids cannot be cracked anymore.

For this reason, we cannot know the real function name. If quantum computers reach a practical level, they may solve the problem.

38 (edited by Edness 2023-10-05 13:17:58)

Yeah, I already read about the 128-bit addition for NID randomizing before, but in theory if just the NIDs were known across the 3.70+ FWs, would that also work for UmdImageCreator to dump the PFI?  Or do you specifically need the full name too?  Since the SCSI command is known to be 0xAD, it should be possible to search backwards.

I just wrote a proof of concept script that can do exactly that tongue

https://cdn.discordapp.com/attachments/340499300754915329/1158479114961952791/image.png

Edit 1: Just scanned and retrieved all ReadUMDStructure NIDs from firmwares 3.70-6.61 out of interest.  This likely can work for other SCSI-like functions here too.  But now the bigger question is - is it possible to easily get the current firmware number via software, or is that also behind a NID hashed function?  (If it is possible, what format does it normally return?  BCD?  String?)

Edit 2: Well, I generated something.  I can at least confirm the accuracy of my script for <3.70 and 6.60, so anything in-between is (probably) correct too.  sceUmdExecReqSenseCmd() and sceUmdExecInquiryCmd() seem to actually never change their NIDs on any firmware, and always remain as 0x2CBE959B and 0x1B19A313 respectively.  sceUmdManGetUmdDrive() also seems to always remain as 0x47E2B6D8.

If this is of any use to you - great!  If not - it was a fun experiment for me, at least.  Do note that not every function exists in every firmware revision, but I did confirm the asm portion of all these firmware revision groups are identical.  Seems like the NIDs only change if the asm is different - could be the random 128-bit addition is some form of a hash of the asm data.  (Unlikely)

    // the PRX modules store each FW digit as its own byte
    // e.g. FW 3.71 = 0x03070110 at 0x010F50 in umdman.prx
    // so here it's converted to a short BCD value, 0x371
    // fw >> 8 & 0xF | fw >> 12 & 0xF0 | fw >> 16 & 0xF00

    short firmware = 0x660;

    unsigned int sceUmdExecReqSenseCmd = 0x2CBE959B; // 0x03
    unsigned int sceUmdExecInquiryCmd  = 0x1B19A313; // 0x12
    unsigned int sceUmdExecStartStopUnitCmd     = 0; // 0x1B
    unsigned int sceUmdExecPreventAllowMediaCmd = 0; // 0x1E
    unsigned int sceUmdExecRead10Cmd            = 0; // 0x28
    unsigned int sceUmdExecSeekCmd              = 0; // 0x2B
    unsigned int sceUmdExecPrefetch10Cmd        = 0; // 0x34
    unsigned int sceUmdExecGetConfigurationCmd  = 0; // 0x46
    unsigned int sceUmdExecGetEventStatusCmd    = 0; // 0x4A
    unsigned int sceUmdExecReadDiscInfoCmd      = 0; // 0x51
    unsigned int sceUmdExecModSelectCmd         = 0; // 0x55
    unsigned int sceUmdExecModSenseCmd          = 0; // 0x5A
    unsigned int sceUmdExecReadUMDStructureCmd  = 0; // 0xAD
    unsigned int sceUmdExecMechaStatCmd         = 0; // 0xBD
    unsigned int sceUmdExecAllocateFromReadCmd  = 0; // 0xF0
    unsigned int sceUmdExecReadMKICmd           = 0; // 0xF1
    unsigned int sceUmdExecReportCacheCmd       = 0; // 0xF2
    unsigned int sceUmdExecClearCacheInfoCmd    = 0; // 0xF3
    unsigned int sceUmdExecGetMediaInfoCmd      = 0; // 0xF4
    unsigned int sceUmdExecSetAccessLimitCmd    = 0; // 0xF6
    unsigned int sceUmdExecSetLockLengthCmd     = 0; // 0xF7
    unsigned int sceUmdExecSetAreaLimitCmd      = 0; // 0xF8
    unsigned int sceUmdExecReadCapacityCmd      = 0; // Any?

    if (firmware < 0x370) {
        // FW 1.00 - 3.60
        sceUmdExecStartStopUnitCmd     = 0xE3F448E0; // 0x1B
        sceUmdExecPreventAllowMediaCmd = 0x2A08FE9A; // 0x1E
        sceUmdExecRead10Cmd            = 0x1B1BF9FD; // 0x28
        sceUmdExecSeekCmd              = 0x250E6975; // 0x2B
        sceUmdExecPrefetch10Cmd        = 0x18DE1880; // 0x34
        sceUmdExecGetConfigurationCmd  = 0xC25D7212; // 0x46
        sceUmdExecGetEventStatusCmd    = 0x65E1B97E; // 0x4A
        sceUmdExecReadDiscInfoCmd      = 0xD7A2F4A2; // 0x51
        sceUmdExecModSelectCmd         = 0xCEE55E3E; // 0x55
        sceUmdExecModSenseCmd          = 0x2A39569B; // 0x5A
        sceUmdExecReadUMDStructureCmd  = 0x3D44BABF; // 0xAD
        sceUmdExecMechaStatCmd         = 0xE5B7EDC5; // 0xBD
        sceUmdExecAllocateFromReadCmd  = 0x68577709; // 0xF0
        sceUmdExecReadMKICmd           = 0xF819E17C; // 0xF1
        sceUmdExecReportCacheCmd       = 0x98345381; // 0xF2
        sceUmdExecClearCacheInfoCmd    = 0x73E49F8F; // 0xF3
        sceUmdExecGetMediaInfoCmd      = 0x108B2322; // 0xF4
        sceUmdExecSetAccessLimitCmd    = 0x7094E3A7; // 0xF6
        sceUmdExecSetLockLengthCmd     = 0xD31DAD7E; // 0xF7
        sceUmdExecSetAreaLimitCmd      = 0x61C32A52; // 0xF8
        sceUmdExecReadCapacityCmd      = 0x5AA96415; // Any?
    }
    else if (firmware < 0x380) {
        // FW 3.70, 3.71, 3.72, 3.73
        sceUmdExecStartStopUnitCmd     = 0xD4132E08; // 0x1B
        sceUmdExecPreventAllowMediaCmd = 0xB629961F; // 0x1E
        sceUmdExecRead10Cmd            = 0x9E7564BC; // 0x28
        sceUmdExecSeekCmd              = 0xE8A768B5; // 0x2B
        sceUmdExecPrefetch10Cmd        = 0x9E722740; // 0x34
        sceUmdExecGetConfigurationCmd  = 0x607BF8CA; // 0x46
        sceUmdExecGetEventStatusCmd    = 0x84F3759A; // 0x4A
        sceUmdExecReadDiscInfoCmd      = 0x466839B7; // 0x51
        sceUmdExecModSelectCmd         = 0xDDB308E9; // 0x55
        sceUmdExecModSenseCmd          = 0x200810E8; // 0x5A
        sceUmdExecReadUMDStructureCmd  = 0x3D94D00C; // 0xAD
        sceUmdExecMechaStatCmd         = 0x6CEDA538; // 0xBD
        sceUmdExecAllocateFromReadCmd  = 0x9EE39B6A; // 0xF0
        sceUmdExecReadMKICmd           = 0xB157769B; // 0xF1
        sceUmdExecReportCacheCmd       = 0x9D9848F2; // 0xF2
        sceUmdExecClearCacheInfoCmd    = 0x0933B6FB; // 0xF3
        sceUmdExecGetMediaInfoCmd      = 0x92E6E273; // 0xF4
        sceUmdExecSetAccessLimitCmd    = 0xD5CC2085; // 0xF6
        sceUmdExecSetLockLengthCmd     = 0xB865CC4C; // 0xF7
        sceUmdExecSetAreaLimitCmd      = 0x928C1752; // 0xF8
        sceUmdExecReadCapacityCmd      = 0x5CD9ACF5; // Any?
    }
    else if (firmware < 0x395) {
        // FW 3.80, 3.90, 3.93
        sceUmdExecStartStopUnitCmd     = 0x62506AA0; // 0x1B
        sceUmdExecPreventAllowMediaCmd = 0x1B70C53F; // 0x1E
        sceUmdExecRead10Cmd            = 0x33072B62; // 0x28
        sceUmdExecSeekCmd              = 0x818506C1; // 0x2B
        sceUmdExecPrefetch10Cmd        = 0x8AF305CC; // 0x34
        sceUmdExecGetConfigurationCmd  = 0x3809B921; // 0x46
        sceUmdExecGetEventStatusCmd    = 0x5F37BD96; // 0x4A
        sceUmdExecReadDiscInfoCmd      = 0x3BF9BE3E; // 0x51
        sceUmdExecModSelectCmd         = 0xB6BCF945; // 0x55
        sceUmdExecModSenseCmd          = 0x05CF9760; // 0x5A
        sceUmdExecReadUMDStructureCmd  = 0x2A12BF44; // 0xAD
        sceUmdExecMechaStatCmd         = 0xD1FFD521; // 0xBD
        sceUmdExecAllocateFromReadCmd  = 0xCEBDE68B; // 0xF0
        sceUmdExecReadMKICmd           = 0x350EEA2B; // 0xF1
        sceUmdExecReportCacheCmd       = 0xE7D62A27; // 0xF2
        sceUmdExecClearCacheInfoCmd    = 0xECAF10D9; // 0xF3
        sceUmdExecGetMediaInfoCmd      = 0x81C55E67; // 0xF4
        sceUmdExecSetAccessLimitCmd    = 0x90746ECA; // 0xF6
        sceUmdExecSetLockLengthCmd     = 0xC945EE7E; // 0xF7
        sceUmdExecSetAreaLimitCmd      = 0xB9A0113D; // 0xF8
        sceUmdExecReadCapacityCmd      = 0x62473046; // Any?
    }
    else if (firmware < 0x420) {
        // FW 3.95, 3.96, 4.00, 4.01, 4.05
        sceUmdExecStartStopUnitCmd     = 0x57436030; // 0x1B
        sceUmdExecPreventAllowMediaCmd = 0x9DAD4CC0; // 0x1E
        sceUmdExecRead10Cmd            = 0x74F29ED7; // 0x28
        sceUmdExecSeekCmd              = 0x14EAAA28; // 0x2B
        sceUmdExecPrefetch10Cmd        = 0x9ABD6DE1; // 0x34
        sceUmdExecGetConfigurationCmd  = 0xFE0D2641; // 0x46
        sceUmdExecGetEventStatusCmd    = 0xF8912660; // 0x4A
        sceUmdExecReadDiscInfoCmd      = 0x67D4D414; // 0x51
        sceUmdExecModSelectCmd         = 0xE90AEA97; // 0x55
        sceUmdExecModSenseCmd          = 0xCA2EA0FF; // 0x5A
        sceUmdExecReadUMDStructureCmd  = 0x12BA4DDE; // 0xAD
        sceUmdExecMechaStatCmd         = 0x0925EE00; // 0xBD
        sceUmdExecAllocateFromReadCmd  = 0xD01B4969; // 0xF0
        sceUmdExecReadMKICmd           = 0x43FD7090; // 0xF1
        sceUmdExecReportCacheCmd       = 0x529635A7; // 0xF2
        sceUmdExecClearCacheInfoCmd    = 0x01B1AA7E; // 0xF3
        sceUmdExecGetMediaInfoCmd      = 0x4461C19E; // 0xF4
        sceUmdExecSetAccessLimitCmd    = 0x3E6B9E50; // 0xF6
        sceUmdExecSetLockLengthCmd     = 0xADA614C2; // 0xF7
        sceUmdExecSetAreaLimitCmd      = 0x376BFD4F; // 0xF8
        sceUmdExecReadCapacityCmd      = 0x965D8417; // Any?
    }
    else if (firmware < 0x500) {
        // FW 4.20, 4.21
        sceUmdExecStartStopUnitCmd     = 0x0EE48C15; // 0x1B
        sceUmdExecPreventAllowMediaCmd = 0xBDE7298B; // 0x1E
        sceUmdExecRead10Cmd            = 0xEC3FDCEF; // 0x28
        sceUmdExecSeekCmd              = 0x9E2FB7DF; // 0x2B
        sceUmdExecPrefetch10Cmd        = 0x4F2B52DC; // 0x34
        sceUmdExecGetConfigurationCmd  = 0x251AD684; // 0x46
        sceUmdExecGetEventStatusCmd    = 0xA17129C2; // 0x4A
        sceUmdExecReadDiscInfoCmd      = 0xB7CE4D74; // 0x51
        sceUmdExecModSelectCmd         = 0x2E730DEF; // 0x55
        sceUmdExecModSenseCmd          = 0x9430AFEF; // 0x5A
        sceUmdExecReadUMDStructureCmd  = 0xE006F0E9; // 0xAD
        sceUmdExecMechaStatCmd         = 0xBE559B33; // 0xBD
        sceUmdExecAllocateFromReadCmd  = 0x7A2B484B; // 0xF0
        sceUmdExecReadMKICmd           = 0xF9BBA21C; // 0xF1
        sceUmdExecReportCacheCmd       = 0x05FE3D00; // 0xF2
        sceUmdExecClearCacheInfoCmd    = 0xB88C1DF1; // 0xF3
        sceUmdExecGetMediaInfoCmd      = 0x361B88FE; // 0xF4
        sceUmdExecSetAccessLimitCmd    = 0xCDB02062; // 0xF6
        sceUmdExecSetLockLengthCmd     = 0x1BDFD70C; // 0xF7
        sceUmdExecSetAreaLimitCmd      = 0x531937DB; // 0xF8
        sceUmdExecReadCapacityCmd      = 0xB24480CB; // Any?
    }
    else if (firmware < 0x570) {
        // FW 5.00, 5.01, 5.02, 5.03, 5.05, 5.50, 5.51, 5.55
        sceUmdExecStartStopUnitCmd     = 0x1B2B8759; // 0x1B
        sceUmdExecPreventAllowMediaCmd = 0x66B4CC78; // 0x1E
        sceUmdExecRead10Cmd            = 0x98D75CC0; // 0x28
        sceUmdExecSeekCmd              = 0xAEC4DA2C; // 0x2B
        sceUmdExecPrefetch10Cmd        = 0x1BE0124C; // 0x34
        sceUmdExecGetConfigurationCmd  = 0x19BCD653; // 0x46
        sceUmdExecGetEventStatusCmd    = 0xF2B1A490; // 0x4A
        sceUmdExecReadDiscInfoCmd      = 0xBD102376; // 0x51
        sceUmdExecModSelectCmd         = 0x9FC2FD97; // 0x55
        sceUmdExecModSenseCmd          = 0x585F1728; // 0x5A
        sceUmdExecReadUMDStructureCmd  = 0xD4E51A75; // 0xAD
        sceUmdExecMechaStatCmd         = 0x8BDE7034; // 0xBD
        sceUmdExecAllocateFromReadCmd  = 0x32D89DA4; // 0xF0
        sceUmdExecReadMKICmd           = 0xF9C66D4A; // 0xF1
        sceUmdExecReportCacheCmd       = 0x7065FD6E; // 0xF2
        sceUmdExecClearCacheInfoCmd    = 0x1F0338FE; // 0xF3
        sceUmdExecGetMediaInfoCmd      = 0xBDF4842D; // 0xF4
        sceUmdExecSetAccessLimitCmd    = 0xFCA1A098; // 0xF6
        sceUmdExecSetLockLengthCmd     = 0xC7D14FBE; // 0xF7
        sceUmdExecSetAreaLimitCmd      = 0x16588BAA; // 0xF8
        sceUmdExecReadCapacityCmd      = 0xDD017FFE; // Any?
    }
    else if (firmware < 0x600) {
        // FW 5.70
        sceUmdExecStartStopUnitCmd     = 0x89AA72CD; // 0x1B
        sceUmdExecPreventAllowMediaCmd = 0xB6BE48A4; // 0x1E
        sceUmdExecRead10Cmd            = 0x6C0C6E60; // 0x28
        sceUmdExecSeekCmd              = 0x8AAE6940; // 0x2B
        sceUmdExecPrefetch10Cmd        = 0xB7089372; // 0x34
        sceUmdExecGetConfigurationCmd  = 0x62212597; // 0x46
        sceUmdExecGetEventStatusCmd    = 0x5361EBAF; // 0x4A
        sceUmdExecReadDiscInfoCmd      = 0xF4B80F3C; // 0x51
        sceUmdExecModSelectCmd         = 0xFA124BD3; // 0x55
        sceUmdExecModSenseCmd          = 0xA50AD929; // 0x5A
        sceUmdExecReadUMDStructureCmd  = 0x0D3372E8; // 0xAD
        sceUmdExecMechaStatCmd         = 0x8322DB90; // 0xBD
        sceUmdExecAllocateFromReadCmd  = 0xE2234907; // 0xF0
        sceUmdExecReadMKICmd           = 0x2DC746B5; // 0xF1
        sceUmdExecReportCacheCmd       = 0xE590AD02; // 0xF2
        sceUmdExecClearCacheInfoCmd    = 0x3C0ACB0D; // 0xF3
        sceUmdExecGetMediaInfoCmd      = 0x468AC548; // 0xF4
        sceUmdExecSetAccessLimitCmd    = 0xA78D71C3; // 0xF6
        sceUmdExecSetLockLengthCmd     = 0x6236483E; // 0xF7
        sceUmdExecSetAreaLimitCmd      = 0x57BD4866; // 0xF8
        sceUmdExecReadCapacityCmd      = 0xBBEA87FB; // Any?
    }
    else if (firmware < 0x630) {
        // FW 6.00, 6.10, 6.20
        sceUmdExecStartStopUnitCmd     = 0x5CF0DFAC; // 0x1B
        sceUmdExecPreventAllowMediaCmd = 0xCDA8E394; // 0x1E
        sceUmdExecRead10Cmd            = 0x319C9905; // 0x28
        sceUmdExecSeekCmd              = 0x849A4325; // 0x2B
        sceUmdExecPrefetch10Cmd        = 0x65FD0561; // 0x34
        sceUmdExecGetEventStatusCmd    = 0x48D85CEE; // 0x4A
        sceUmdExecReadDiscInfoCmd      = 0xB87FA807; // 0x51
        sceUmdExecModSelectCmd         = 0x6B92F9E8; // 0x55
        sceUmdExecModSenseCmd          = 0x57E17255; // 0x5A
        sceUmdExecReadUMDStructureCmd  = 0x806D66A7; // 0xAD
        sceUmdExecAllocateFromReadCmd  = 0xC54D7B8F; // 0xF0
        sceUmdExecReadMKICmd           = 0xD047DEBC; // 0xF1
        sceUmdExecClearCacheInfoCmd    = 0x04E5EFFA; // 0xF3
        sceUmdExecGetMediaInfoCmd      = 0xE2BAAD9C; // 0xF4
        sceUmdExecSetLockLengthCmd     = 0xBFDA8AC7; // 0xF7
        sceUmdExecReadCapacityCmd      = 0x2B79C006; // Any?
    }
    else if (firmware < 0x650) {
        // FW 6.30, 6.31, 6.35, 6.36, 6.37, 6.38, 6.39
        sceUmdExecStartStopUnitCmd     = 0x7B9C43C9; // 0x1B
        sceUmdExecPreventAllowMediaCmd = 0xC9509423; // 0x1E
        sceUmdExecRead10Cmd            = 0x5B0F6FC6; // 0x28
        sceUmdExecSeekCmd              = 0x64AEDFB3; // 0x2B
        sceUmdExecPrefetch10Cmd        = 0xAE3F99E2; // 0x34
        sceUmdExecGetEventStatusCmd    = 0x5D7C8F9E; // 0x4A
        sceUmdExecReadDiscInfoCmd      = 0x717EF202; // 0x51
        sceUmdExecModSelectCmd         = 0x047BCEA0; // 0x55
        sceUmdExecModSenseCmd          = 0x03DE43F5; // 0x5A
        sceUmdExecReadUMDStructureCmd  = 0x05C33243; // 0xAD
        sceUmdExecAllocateFromReadCmd  = 0xC447F257; // 0xF0
        sceUmdExecReadMKICmd           = 0x01EA806F; // 0xF1
        sceUmdExecClearCacheInfoCmd    = 0x87070DC7; // 0xF3
        sceUmdExecGetMediaInfoCmd      = 0x8F628DAF; // 0xF4
        sceUmdExecSetLockLengthCmd     = 0xFC40080F; // 0xF7
        sceUmdExecReadCapacityCmd      = 0x5802953B; // Any?
    }
    //else if (firmware < 0x660) {} // FW 6.50 (UNRELEASED)
    else {
        // FW 6.60, 6.61
        sceUmdExecStartStopUnitCmd     = 0x5219AF31; // 0x1B
        sceUmdExecPreventAllowMediaCmd = 0x5AC94A3C; // 0x1E
        sceUmdExecRead10Cmd            = 0xE3716915; // 0x28
        sceUmdExecSeekCmd              = 0xB01F65CE; // 0x2B
        sceUmdExecPrefetch10Cmd        = 0xC615D6C9; // 0x34
        sceUmdExecGetEventStatusCmd    = 0xBD974D70; // 0x4A
        sceUmdExecReadDiscInfoCmd      = 0xF861E69B; // 0x51
        sceUmdExecModSelectCmd         = 0x2C5F9A65; // 0x55
        sceUmdExecModSenseCmd          = 0xEB0841CE; // 0x5A
        sceUmdExecReadUMDStructureCmd  = 0x406E8F99; // 0xAD
        sceUmdExecAllocateFromReadCmd  = 0x8DA33BBD; // 0xF0
        sceUmdExecReadMKICmd           = 0x6D17FD57; // 0xF1
        sceUmdExecClearCacheInfoCmd    = 0x77E81350; // 0xF3
        sceUmdExecGetMediaInfoCmd      = 0x27C1869A; // 0xF4
        sceUmdExecSetLockLengthCmd     = 0xEEBF3121; // 0xF7
        sceUmdExecReadCapacityCmd      = 0xCC40BED8; // Any?
    }

Edness wrote:

but in theory if just the NIDs were known across the 3.70+ FWs, would that also work for UmdImageCreator to dump the PFI?  Or do you specifically need the full name too?

I assumed I needed a real function name, but it turned out that's not true. I confirmed that PFI can be dumped by 0x406E8F99.
Other functions have also already been analized by comparing the asm of 3.52 (Only 6.61).
https://github.com/saramibreak/UmdImage … alysis.txt

Edness wrote:

Edit 2

Thanks. Mostly as expected in relation to the opcode. I'm especially interested in sceUmdExecReadMKICmd. What is MKI? It's Media Key Identifier? Media Key Info???

40 (edited by Edness 2023-10-04 09:23:39)

The ReadMKI function itself seems pretty large, and the preceding functions that call it are a bit all over the place too.  It seems to take values from 2 functions above, the 1st of which calls the lower function that contains the ReadMKI call with (UMD drive, 0, 8, 0)

A 5 byte buffer is created on the stack, arg1 and arg2 being stored as int16s at 0x00 and 0x02, and arg3 as an int8 to 0x04.
If I am reading it correctly, you can just write 0x08 at buffer[0x2] and that's it.

sceUmdExecReadMKICmd() is called with 4 arguments:

  • $a0 - UMD drive (as always)

  • $a1 - Pointer to the buffer

  • $a2 - Number 8 (from buffer[0x2])

  • $a3 - Number 448 (0x1C0)

Overall, I would say this is it, if it weren't for some unusual calls between the buffer creation and the actual ReadMKI call.  It calls memset(0x1C0, 0x00, 0x8000) - I'm not sure if 0x1C0 a valid address.
And right after that, it calls sceKernelDcacheInvalidateRange(0x1C0, 0x4000), (the 2nd arg being 8 (from arg2) << 11 = 0x4000), implying the address 0x1C0 is somewhere in the CPU data cache region?  No idea.
Does that also mean it expects you to get the output back from d-cache too?

I tried it. _sceUmdExecReadMKICmd() succeeded but bufMKI is all zero bytes except bufMKI[2].

    unsigned char bufMKI[448] = {};
    bufMKI[2] = 8;
    
    char* p = (char*)(0x08800000);
    memset(p, 0x00, 0x8000);
    sceKernelDcacheInvalidateRange(p, 0x4000);
    
    res = _sceUmdExecReadMKICmd(pUmdDrive, bufMKI, 8, p);

42 (edited by Edness 2023-10-05 13:19:56)

I think the address has to be 0x1C0, it seems to be firmware hardcoded.  sceUmdExecReadMKICmd() (and also sceUmdExecRead10Cmd()) both call a subroutine which contains a function named sceUmdManSPKGetMKI() - this always returns 0x1C0.  And after that, it calls another d-cache function sceKernelDcacheWritebackInvalidateRange(0x1C0, 0x4000), arg0 coming from SPKGetMKI, and arg1 coming from 8 << 11, the 8 coming from ReadMKI's arg2.

Without a debugger to see what exactly it's doing, it's hard to know if those addresses are relocated by the system or not.  However, could you try calling sceUmdManSPKGetMKI() on its own and print out what address it returns?  Maybe this will give an answer whether you truly have to put 0x1C0 or not.  (And you could likely use the output of that to set up the ReadMKI call.)

----------

This is unrelated, but I did a bit more research about the SCSI commands that umdman.prx has functions for.  Some firmware revisions have functions that send the commands 0xA3 and 0xA4, but neither of them have any NIDs associated.  And today I noticed what looks to be an array of whitelisted commands it can send.  In addition to the FW NID map function I wrote a few replies back, it looks like it would allow commands 0x00, 0x23, 0x25, 0xA3, 0xA4, 0xB6, 0xBB, and vendor specific commands 0xF5, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD.  None of these also have a specific NID-hashed function.

However, sceUmdExecReadCapacityCmd() seems to be the only function that allows putting your own command as arg0, followed by the UMD drive as arg1 of course.  While I assume this is where you would normally put 0x23/0x25, I wonder if it would be possible to exploit and take advantage of this function to send other commands.  Though there is no function that calls it in any firmware it looks like (checked 1.50, 3.52, 6.60), so knowing that it wants for arg2 and arg3 will need guesswork.
I've edited the 3.70-6.60 NID map to also include this function commented with "Any?"

Edness wrote:

could you try calling sceUmdManSPKGetMKI() on its own and print out what address it returns?

    void* p = _sceUmdManSPKGetMKI();

p is 0x880f1240

Edness wrote:

sceUmdExecReadCapacityCmd() seems to be the only function that allows putting your own command as arg0, followed by the UMD drive as arg1 of course.

Yes. I've already comfirmed that this func can be called and succeeded.

    unsigned char bufCapa[8] = {};
    res = _sceUmdExecReadCapacityCmd(0x25, pUmdDrive, 8, bufCapa);

The result is here. (Dissidia 012: Duodecim Final Fantasy)

 00 0D 2C B0 00 00 08 00

1st 4 bytes show total sectors. It matches redump db. 2nd 4 bytes show the block size in bytes. It's always 0x800.

44 (edited by Edness 2023-10-05 15:54:20)

sarami wrote:
    void* p = _sceUmdManSPKGetMKI();

p is 0x880f1240

Looks like that is in kernel module address space 0x88000000-0x8837FFFF, per documentation.
This does make more sense than just plain 0x1C0, but now part of me wonders if this is a valid region of data that can be overwritten, or if this is just the offset of the module itself, indicating its base is at 0x880F1080.  I am probably overthinking it, but do try the ReadMKI function with the SPKGetMKI address (if it allows you to write to kernel memory like that).  At worst it'll just blank out assembly instructions of the module and crash tongue

Also, at first I couldn't find any mention of this MKI thing anywhere on the internet, but I just now stumbled upon an archived thread that mentions "UMD MKI" once.  Doesn't say what it stands for, but it's something.

Edness wrote:

I am probably overthinking it, but do try the ReadMKI function with the SPKGetMKI address (if it allows you to write to kernel memory like that).  At worst it'll just blank out assembly instructions of the module and crash

The result is no error and no crash but buffer is all zero bytes except buffer[2].

46 (edited by Edness 2023-10-05 17:36:24)

Hmm, can you memcpy the 0x4000 or 0x8000 bytes of data back from the SPKGetMKI address?  It likely wrote something there and left the buffer for the function arg alone.  Normally it's supposed to just be a separate 5 byte buffer that's passed to the ReadMKI function anyway, so I'm not expecting much to be written there.

For good measure maybe also copy the data from the MKI address before memset'ing it to 00, to see if there's already something there.

47 (edited by sarami 2023-10-06 14:13:11)

unsigned char bufSPK[0x4000] = {};
void* p1 = _sceUmdManSPKGetMKI();
memcpy(bufSPK, p1, 0x4000);

It crashed by memcpy.

Edness wrote:

Normally it's supposed to just be a separate 5 byte buffer that's passed to the ReadMKI function anyway, so I'm not expecting much to be written there.

5 bytes = 40 bits. DVD has 40 bits key of CSS, so I've expected that UMD also has some kind of 40 bits key (media key?).

SPK is SPecial Key? SPecific Key?

48 (edited by Edness 2023-10-07 13:52:05)

sarami wrote:

5 bytes = 40 bits. DVD has 40 bits key of CSS, so I've expected that UMD also has some kind of 40 bits key (media key?).

SPK is SPecial Key? SPecific Key?

Possible.

Another guess I have could be it's some form of Disc ID - Sony already has a unique ID for every disc on PS2 and PS3.  (If not from the MKI command, maybe from another one.)
On PS2 the (DNAS) Disc ID is also 5 bytes long.  And while currently on Redump only the first two bytes are removed due to being serialized/random, from my observations I'm pretty sure it's supposed to be the first three bytes (see [PS2] Burnout Revenge (Europe, Australia) (En,Fr,De) as an example) followed by the region on the 4th byte (0x20 = Asia, 0x30 = USA, 0x40 = Europe etc.), making it 16.7 million unique Disc IDs for each game on PS2.
Likewise, PS3's Disc ID being 16 bytes long, the last 4 bytes are also removed for each entry, also followed by the region on the 5th byte (0x01 = Asia, 0x03 = USA, 0x04 = Europe etc.), making it theoretically 4.2 billion unique IDs per game.

With this in mind, I wouldn't be surprised if Sony also had some form of unique Disc ID for PSP, too.  Although wouldn't the 0x08 written at buf[2] interfere with it?

Edness wrote:

On PS2 the (DNAS) Disc ID is also 5 bytes long. 

Edness wrote:

PS3's Disc ID being 16 bytes long

How do we get it?

I'm not sure, your guess is as good as mine.  It could be one of the 0xF0 commands, or it could be something completely different.

Another note, I noticed the SCSI command whitelist in older FW revisions normally has 3 x int32 values per element, the 3rd one always seemingly being null.  However FW 1.50 actually uses that 3rd value as a pointer to a string with the original command name.  (In newer FW like 6.60 the array is 2x int8.)  The command names for 0x00-0xC0 are pretty standard besides DVD->UMD replacements, but the 0xF0 command names without any associated function/NID could be useful too.

    {0x00, 0x01}, // TEST_UNIT_READY
    {0x03, 0x02}, // REQUEST_SENSE
    {0x12, 0x02}, // INQUIRY
    {0x1B, 0x01}, // START_STOP_UNIT
    {0x1E, 0x01}, // PREVENT_ALLOW_MEDIA
    {0x23, 0x02}, // READ_FORMAT_CAPACITIES
    {0x25, 0x02}, // READ_UMD_CAPACITY
    {0x28, 0x08}, // READ10
    {0x2B, 0x01}, // SEEK
    {0x34, 0x01}, // PREFETCH10
    {0x46, 0x02}, // GET_CONFIGURATION
    {0x4A, 0x02}, // GET_STAT_EVENT
    {0x55, 0x04}, // MODE_SELECT10
    {0x5A, 0x02}, // MODE_SENSE10
    {0xAD, 0x02}, // READ_UMD_STRUCTURE
    {0xB6, 0x04}, // SET_STREAMING
    {0xBB, 0x01}, // SET_SPEED
    {0xBD, 0x02}, // MECHANISM_STATUS

    {0xF0, 0x02}, // DETECT_UMD_PSP
    {0xF1, 0x08}, // READ_UMD_MKI
    {0xF2, 0x02}, // REPORT_CACHE
    {0xF3, 0x01}, // CLEAR_CACHE_INFO
    {0xF4, 0x02}, // GET_MEDIA_INFO
    {0xF5, 0x02}, // TEST
    {0xF6, 0x01}, // SET_ACCESS_LIMIT
    {0xF7, 0x01}, // SET_LOCK_LENGTH
    {0xF8, 0x01}, // SET_AREA_LIMIT
    {0xF9, 0x02}, // GET_ERROR_LOG
    {0xFA, 0x02}, // TEST_PI
    {0xFB, 0x04}, // TEST_PO
    {0xFC, 0x02}, // GET_ADJUST_DATA
    {0xFD, 0x04}, // SET_ADJUST_DATA