djhackersdev / bemanitools

Runs recent Konami arcade games and emulates various arcade hardware.
The Unlicense
79 stars 15 forks source link

DDR X srcid output is incorrect #98

Closed icex2 closed 1 year ago

icex2 commented 2 years ago

In GitLab by @Corin on Jul 21, 2022, 24:05

Summary

Network srcid doesn't match the specified pcbid

Expected behavior

The sent srcid should match the pcbid

Current behavior

example: pcbid 01B5B1B6EC3A72D418C9 eamid 0101020304050607086F

The output in srcid is 01400107060504030208

Now, changing this to: pcbid 01B5B1B6EC3A72D418C9 eamid 01B5B1B6EC3A72D418C9

We instead see 0140B5D4723AECB6B118

You can see the characters are still in there but it looks like it's getting mangled between the two of them.

Detailed Description

Implementing network for X currently and weirdly we're seeing strange results from the srcid output.

It doesn't seem to actually be following what's defined in ddrhook for pcbid.

Even weirder, the srcid seems to change when the eamid is changed too.

Steps to reproduce

Stock config outside of pcbid/eamid, sniff the network and you'll see the results of this

  1. Set pcbid to 01B5B1B6EC3A72D418C9
  2. Set eamid to 0101020304050607086F
  3. Get your jumbled mess that is 01400107060504030208

Context (Environment)

Bemanitools version(s) affected

Game(s) and version(s) affected

icex2 commented 2 years ago

In GitLab by @Corin on Jul 22, 2022, 14:37

So 2 things I've noticed with this.

1: (should've noticed earlier) it's just using the eamid for the pcbid, not the pcbid field.

2: this byte remapping is the exact same as the pcbid checksum order: 1, 7, 6, 5, 4, 3, 2

Perhaps something is getting mixed up along the way?

icex2 commented 2 years ago

In GitLab by @33c17f40 on Jul 22, 2022, 18:09

I mentioned it to Ice in a DM on Discord but I don't think this is a bug and you should debug the game's code to figure out how it's generating the srcid exactly. Speaking of some recent experience with some Python 1/2 stuff because that's fresh in my head: the Python 1/2 games would create the "display" format of the dongle by taking the middle 6 bytes of the ID (so, skipping the header 01 and the ending checksum byte), shuffling those around, and then putting "01 40" (hardcoded) at the beginning.

I haven't seen any code in btools that would make that format out of a pcbid/eamid. I feel pretty good saying that what you're seeing is probably just how the game generates the srcid from the dongle data.

icex2 commented 2 years ago

In GitLab by @33c17f40 on Jul 22, 2022, 21:56

I had some free time so I checked it out in Ghidra. For ddr_2009063000 the relevant func is at 0x50f480.

As I suspected, the game is generating the values based on the dongle payload.

Generating /env/profile/sysid ("eamid"):

        str_snprintf(local_30,0x20,"0140%02X%02X%02X%02X%02X%02X%02X%02X",*(undefined *)secplug_data
                     ,*(undefined1 *)((int)secplug_data + 6),*(undefined1 *)((int)secplug_data + 5),
                     *(undefined *)(secplug_data + 1),*(undefined1 *)((int)secplug_data + 3),
                     *(undefined1 *)((int)secplug_data + 2),*(undefined1 *)((int)secplug_data + 1),
                     *(undefined1 *)((int)secplug_data + 7));
        std_setenv("/env/profile/sysid",local_30);
        log_body_misc("device","  network :%s",local_30);

Generating /env/profile/softid ("pcbid") + /env/profile/mcode:

        str_snprintf(local_30,0x20,"0140%02X%02X%02X%02X%02X%02X%02X%02X",*(undefined *)secplug_data
                     ,*(undefined1 *)((int)secplug_data + 6),*(undefined1 *)((int)secplug_data + 5),
                     *(undefined *)(secplug_data + 1),*(undefined1 *)((int)secplug_data + 3),
                     *(undefined1 *)((int)secplug_data + 2),*(undefined1 *)((int)secplug_data + 1),
                     *(undefined1 *)((int)secplug_data + 7));
        std_setenv("/env/profile/mcode",local_64);
        std_setenv("/env/profile/softid",local_30);
        log_body_misc("device","  software:%s",local_30);

If the mcode inside the dongle is "@@@@@@@@" then it goes down the eamid/sysid path, otherwise it takes the mcode and generates the pcbid/softid from the dongle serial ID inside the dongle payload.

For reference, this is the code that generates the dongle payload: https://dev.s-ul.net/djhackers/bemanitools/-/blob/master/src/main/ddrhook-util/p3io.c#L122-L150

So everything is working as intended. pcbid and eamid are used to generate the dongle payloads in the tools but the game itself has its own way of interpreting the pcbid and eamid embedded in the dongle payloads.

The only way I can imagine you getting it to work the way you are expecting is to do something like hook std_setenv and change all references to softid and sysid to what you want but that's a hack and I wouldn't really recommend.

Edit: To be more explicit, any attempts to change the way this works in bt5 for use with networks will mean that you're breaking support with other tools (if that matters at all), and more importantly with real hardware. Unscramble the srcid (scramble order is 1 7 6 5 4 3 2 8), prepend the expected 0x01 (if you allow any other value besides 01 at the beginning of the PCBID then you'll have to bruteforce it) and then generate the CRC value for the last byte to convert the srcid back into the pcbid format you're used to working with.

icex2 commented 2 years ago

In GitLab by @Corin on Jul 22, 2022, 23:20

Yeah I'm not here to break support.

I didn't realise that older games behaved like this and you're right about breaking actual hardware, no point having it behave differently.

My "hack" was basically what you mention:

$pcbid_array =  str_split(Core::$pcb_id, 2);
$map = [2, 8, 7, 6, 5, 4, 3, 9];
$reconstructed_pcbid = "";
foreach ($map as $map_key) {
    $reconstructed_pcbid .= $pcbid_array[$map_key];
}

Core::$pcb_id = PcbId::generate($reconstructed_pcbid);

I guess it's not so much a hack but actually the proper way to do it then in that case.

In the case of this then I'll close this issue, thanks for clearing things up!