decryption support for gjspace and more comments (nw)

This commit is contained in:
andreasnaive 2015-08-20 00:26:08 +02:00
parent 70ce9a1742
commit 8f47435daa
3 changed files with 97 additions and 43 deletions

View File

@ -462,7 +462,7 @@ READ16_MEMBER( namcos10_state::nand_data_r )
UINT16 data = nand_read2( nand_address * 2 ); UINT16 data = nand_read2( nand_address * 2 );
// logerror("read %08x = %04x\n", nand_address*2, data); // logerror("read %08x = %04x\n", nand_address*2, data);
//printf("read %08x = %04x\n", nand_address*2, data); // printf("read %08x = %04x\n", nand_address*2, data);
/* printf( "data<-%08x (%08x)\n", data, nand_address ); */ /* printf( "data<-%08x (%08x)\n", data, nand_address ); */
@ -544,7 +544,9 @@ DRIVER_INIT_MEMBER(namcos10_state,mrdrilr2)
DRIVER_INIT_MEMBER(namcos10_state,gjspace) DRIVER_INIT_MEMBER(namcos10_state,gjspace)
{ {
int regSize = machine().root_device().memregion("user2")->bytes(); int regSize = machine().root_device().memregion("user2")->bytes();
decrypt_bios(machine(), "user2", 0x8400, regSize, 0x0, 0x2, 0xe, 0xd, 0xf, 0x6, 0xc, 0x7, 0x5, 0x1, 0x9, 0x8, 0xa, 0x3, 0x4, 0xb); decrypt_bios(machine(), "user2", 0x0008400, 0x0029400, 0x0, 0x2, 0xe, 0xd, 0xf, 0x6, 0xc, 0x7, 0x5, 0x1, 0x9, 0x8, 0xa, 0x3, 0x4, 0xb);
decrypt_bios(machine(), "user2", 0x0210000, 0x104e800, 0x0, 0x2, 0xe, 0xd, 0xf, 0x6, 0xc, 0x7, 0x5, 0x1, 0x9, 0x8, 0xa, 0x3, 0x4, 0xb);
decrypt_bios(machine(), "user2", 0x1077c00, regSize, 0x0, 0x2, 0xe, 0xd, 0xf, 0x6, 0xc, 0x7, 0x5, 0x1, 0x9, 0x8, 0xa, 0x3, 0x4, 0xb);
memn_driver_init(); memn_driver_init();
} }
@ -672,6 +674,11 @@ static MACHINE_CONFIG_DERIVED(ns10_gamshara, namcos10_memn)
MCFG_DEVICE_ADD("decrypter", GAMSHARA_DECRYPTER, 0) MCFG_DEVICE_ADD("decrypter", GAMSHARA_DECRYPTER, 0)
MACHINE_CONFIG_END MACHINE_CONFIG_END
static MACHINE_CONFIG_DERIVED(ns10_gjspace, namcos10_memn)
/* decrypter device (CPLD in hardware?) */
MCFG_DEVICE_ADD("decrypter", GJSPACE_DECRYPTER, 0)
MACHINE_CONFIG_END
static MACHINE_CONFIG_DERIVED(ns10_knpuzzle, namcos10_memn) static MACHINE_CONFIG_DERIVED(ns10_knpuzzle, namcos10_memn)
/* decrypter device (CPLD in hardware?) */ /* decrypter device (CPLD in hardware?) */
MCFG_DEVICE_ADD("decrypter", KNPUZZLE_DECRYPTER, 0) MCFG_DEVICE_ADD("decrypter", KNPUZZLE_DECRYPTER, 0)
@ -889,7 +896,7 @@ GAME( 2000, mrdrilr2, 0, namcos10_memm, namcos10, namcos10_state, mrdril
GAME( 2000, mrdrlr2a, mrdrilr2, namcos10_memm, namcos10, namcos10_state, mrdrilr2, ROT0, "Namco", "Mr. Driller 2 (Asia, DR22 Ver.A)", MACHINE_NOT_WORKING | MACHINE_NO_SOUND ) // PORT_4WAY joysticks GAME( 2000, mrdrlr2a, mrdrilr2, namcos10_memm, namcos10, namcos10_state, mrdrilr2, ROT0, "Namco", "Mr. Driller 2 (Asia, DR22 Ver.A)", MACHINE_NOT_WORKING | MACHINE_NO_SOUND ) // PORT_4WAY joysticks
GAME( 2000, ptblank3, 0, namcos10_memn, namcos10, namcos10_state, gunbalna, ROT0, "Namco", "Point Blank 3 (Asia, GNN2 Ver.A)", MACHINE_NOT_WORKING | MACHINE_NO_SOUND ) GAME( 2000, ptblank3, 0, namcos10_memn, namcos10, namcos10_state, gunbalna, ROT0, "Namco", "Point Blank 3 (Asia, GNN2 Ver.A)", MACHINE_NOT_WORKING | MACHINE_NO_SOUND )
GAME( 2000, gunbalina, ptblank3, namcos10_memn, namcos10, namcos10_state, gunbalna, ROT0, "Namco", "Gunbalina (Japan, GNN1 Ver.A)", MACHINE_NOT_WORKING | MACHINE_NO_SOUND ) GAME( 2000, gunbalina, ptblank3, namcos10_memn, namcos10, namcos10_state, gunbalna, ROT0, "Namco", "Gunbalina (Japan, GNN1 Ver.A)", MACHINE_NOT_WORKING | MACHINE_NO_SOUND )
GAME( 2001, gjspace, 0, namcos10_memn, namcos10, namcos10_state, gjspace, ROT0, "Namco / Metro", "Gekitoride-Jong Space (10011 Ver.A)", MACHINE_NOT_WORKING | MACHINE_NO_SOUND ) GAME( 2001, gjspace, 0, ns10_gjspace , namcos10, namcos10_state, gjspace, ROT0, "Namco / Metro", "Gekitoride-Jong Space (10011 Ver.A)", MACHINE_NOT_WORKING | MACHINE_NO_SOUND )
GAME( 2001, mrdrilrg, 0, namcos10_memn, namcos10, namcos10_state, mrdrilrg, ROT0, "Namco", "Mr. Driller G (Japan, DRG1 Ver.A)", MACHINE_NOT_WORKING | MACHINE_NO_SOUND ) // PORT_4WAY joysticks GAME( 2001, mrdrilrg, 0, namcos10_memn, namcos10, namcos10_state, mrdrilrg, ROT0, "Namco", "Mr. Driller G (Japan, DRG1 Ver.A)", MACHINE_NOT_WORKING | MACHINE_NO_SOUND ) // PORT_4WAY joysticks
GAME( 2001, mrdrilrga, mrdrilrg, namcos10_memn, namcos10, namcos10_state, mrdrilrg, ROT0, "Namco", "Mr. Driller G ALT (Japan, DRG1 Ver.A)", MACHINE_NOT_WORKING | MACHINE_NO_SOUND ) // PORT_4WAY joysticks GAME( 2001, mrdrilrga, mrdrilrg, namcos10_memn, namcos10, namcos10_state, mrdrilrg, ROT0, "Namco", "Mr. Driller G ALT (Japan, DRG1 Ver.A)", MACHINE_NOT_WORKING | MACHINE_NO_SOUND ) // PORT_4WAY joysticks
GAME( 2001, knpuzzle, 0, ns10_knpuzzle, namcos10, namcos10_state, knpuzzle, ROT0, "Namco", "Kotoba no Puzzle Mojipittan (Japan, KPM1 Ver.A)", MACHINE_NOT_WORKING | MACHINE_NO_SOUND ) GAME( 2001, knpuzzle, 0, ns10_knpuzzle, namcos10, namcos10_state, knpuzzle, ROT0, "Namco", "Kotoba no Puzzle Mojipittan (Japan, KPM1 Ver.A)", MACHINE_NOT_WORKING | MACHINE_NO_SOUND )

View File

@ -16,57 +16,65 @@ to what is described here needs further investigation.
In type-2 PCBs, the encrypted data is always contained in the first ROM of the In type-2 PCBs, the encrypted data is always contained in the first ROM of the
game (8E), and it's always stored spanning an integer number of NAND blocks game (8E), and it's always stored spanning an integer number of NAND blocks
(the K9F2808U0B is organized in blocks of 16 KiB, each containing 32 pages of (the K9F2808U0B is organized in blocks of 16 KiB, each containing 32 pages of
0x200 bytes). The first part of the encrypted data is stored at about the end 0x200 bytes). Usually the first part of the encrypted data is stored at about the end
of the ROM, and apparently all the blocks in that area are processed in of the ROM, with all the blocks in that area processed in reverse order (first the
reverse order (first the one nearest the end, then the second nearest, etc); one nearest the end, then the second nearest, etc); the second part goes immediately
the second part goes immediately after it from a logic perspective, but it's after it from a logic perspective, but it's, usually, physically located at the area
physically located at the area starting at 0x28000 in the ROM. Games, after starting at 0x28000 in the ROM. However, in at least a couple of games, there are
out-of-order blocks (details below). Games, after
some bootup code has been executed, will copy the encrypted content from some bootup code has been executed, will copy the encrypted content from
the NANDs to RAM, moment at which the decryption is triggered. Physical locations the NANDs to RAM, moment at which the decryption is triggered. Physical locations
of the encrypted programs in the first NAND, together with the RAM region where of the encrypted programs in the first NAND, together with the RAM region where
they are loaded, are summarized in the following table: they are loaded, are summarized in the following table ( ' indicating processing
in reverse order of the constituting blocks) :
game head region tail region RAM address game data regions RAM address
-------- ---------------- -------------- ----------- -------- ---------------------------------- -----------
chocovdr [fdc000,1000000) [28000,1dc000) 80010000 chocovdr [fdc000,1000000)' + [28000,1dc000) 80010000
gamshara [fdc000,1000000) [28000,144000) 80010000 gamshara [fdc000,1000000)' + [28000,144000) 80010000
knpuzzle [fc8000,fcc000) [28000,40c000) 80030000 gjspace [fd4000,ff8000)' + [28000,80000) 80010000
konotako [fdc000,1000000) [28000,b4000) 80010000 + [fd0000,fd4000) + [80000,200000)
mrdrilrg [fd4000,fd8000) [28000,3dc000) 80030000 knpuzzle [fc8000,fcc000)' + [28000,40c000) 80030000
nflclsfb [fdc000,1000000) [28000,204000) 80010000 + [fc4000,fc8000) + [40c000,458000)
startrgn [fdc000,1000000) [28000,b4000) 80010000 konotako [fdc000,1000000)' + [28000,b4000) 80010000
mrdrilrg [fd4000,fd8000)' + [28000,3dc000) 80030000
nflclsfb [fdc000,1000000)' + [28000,204000) 80010000
panikuru [fdc000,fe0000)' + [28000,ac000) 80030000
startrgn [fdc000,1000000)' + [28000,b4000) 80010000
knpuzzle constitutes an interesting case, as it seem to be playing some tricks Both knpuzzle & gjspace present a NAND block which is out of order with respect
in order to obfuscate the location of the main program; first, both regions to the normal layout; besides, that block is physically located immediately before
are padded by encrypted blank regions (at [fc4000,fc8000) & [40c000,458000)), the end-of-ROM region, in what maybe is an attempt to hinder the
maybe in an attempt to hinder the recognition of the extremes of the recognition/reconstruction of the encrypted data.
encrypted data; second, some kind of protection trap seem to simulate a loading
of the encrypted region as if it were using the same head region and RAM address
than most sets ([fdc000,1000000) & 80010000), while those aren't the correct
values for it.
Most games do a single decryption run, so the process is only initialized once; Most games do a single decryption run, so the process is only initialized once;
however, at least one game (gamshara) does write to the triggering register however, at least three of them (gamshara, mrdrilrg & panikuru) do reinitialize the
more than once, effectively resetting the internal state of the decrypter internal state of the decrypted several times. As of 2015-08-19, only gamshara shows signs
several times. (gamshara do it every 5 NAND blocks; the lowest nibble written to of doing it by writing to the triggering register; how the others two are triggering the
the register seem to control the initial value of the state; see details in the reinitializations is still unclear. gamshara does a reinitialization every 5 NAND blocks
implementation). (16 times in total); mrdrilrg does the second one after 0x38000 bytes and then subsequent
ones every 32 blocks (8 times in total); panikuru does one every 2 blocks up to a total
of 16 times.
The calculation of the XOR masks seem to operate this way: most bits are The calculation of the XOR masks seem to operate this way: most bits are
calculated by using linear equations over GF(2) taking as input data the bits from calculated by using linear equations over GF(2) taking as input data the bits from
previously processed words; however, one nonlinear calculation is performed previously processed words; however, one nonlinear calculation is performed
per word processed, and that calculation can affect several bits from the per word processed, and that calculation typically affect just one bit (the only
mask (but, apparently, the same nonlinear terms affect all of them), known exception is mrdrilrg, where the same nonlinear terms are
though in most cases only one bit is involved. Till now, most of the linear affecting two of them). Till now, all the formulae seem to depend only on the
relations seem to depend only on the previous 3 words, but there are some previous 3 words, and the first mask after a (re-)initialization is always zero, so
bits from those showing nonlinear behaviour which seem to use farther words; chances are the mask bits are calculated one word in advance, having access to the
this is still being investigated, and the implementation is probable to current encrypted and decrypted words plus two further words in each sequence, maybe stored
change to reflect new findings. in 32 bits registers. All the nonlinear terms reverse-engineered till now are of the form
A x B, where A and B are linear formulae; thus, as everything else in the schema involves
only linear relations, those nonlinear terms are probably caused by an Y-combinator taking
the resuls of two such linear relations as input, and deciding between both branches based
on another linear formula.
The bits affected by the nonlinear calculations are given below: The bits affected by the nonlinear calculations are given below:
chocovdr -> #10 chocovdr -> #10
gamshara -> #2 gamshara -> #2
gjspace -> a subset of {#3, #4, #5, #10, #11}, maybe all of them gjspace -> none
gunbalina -> #11 gunbalina -> #11
knpuzzle -> #1 knpuzzle -> #1
konotako -> #15 konotako -> #15
@ -85,9 +93,9 @@ equivalent datasets, nothing else.
TO-DO: TO-DO:
* Research the nonlinear calculations in most of the games. * If further dumps support the theory of the calculations just depending on 3 previous words,
* Determine how many previous words the hardware is really using, and change change the implementation accordingly to reflect that.
the implementation accordingly. * Research how type-1 encryption is related to this.
Observing the linear equations, there is a keen difference between bits using Observing the linear equations, there is a keen difference between bits using
just a bunch of previous bits, and others using much more bits from more words; just a bunch of previous bits, and others using much more bits from more words;
@ -107,6 +115,7 @@ really exist.
const device_type CHOCOVDR_DECRYPTER = &device_creator<chocovdr_decrypter_device>; const device_type CHOCOVDR_DECRYPTER = &device_creator<chocovdr_decrypter_device>;
const device_type GAMSHARA_DECRYPTER = &device_creator<gamshara_decrypter_device>; const device_type GAMSHARA_DECRYPTER = &device_creator<gamshara_decrypter_device>;
const device_type GJSPACE_DECRYPTER = &device_creator<gjspace_decrypter_device>;
const device_type KNPUZZLE_DECRYPTER = &device_creator<knpuzzle_decrypter_device>; const device_type KNPUZZLE_DECRYPTER = &device_creator<knpuzzle_decrypter_device>;
const device_type KONOTAKO_DECRYPTER = &device_creator<konotako_decrypter_device>; const device_type KONOTAKO_DECRYPTER = &device_creator<konotako_decrypter_device>;
const device_type NFLCLSFB_DECRYPTER = &device_creator<nflclsfb_decrypter_device>; const device_type NFLCLSFB_DECRYPTER = &device_creator<nflclsfb_decrypter_device>;
@ -205,9 +214,14 @@ int gf2_reducer::gf2_reduce(UINT64 num)const
// static UINT16 mrdrilrg_nonlinear_calc(UINT64 previous_cipherwords, UINT64 previous_plainwords, const gf2_reducer& reducer) // static UINT16 mrdrilrg_nonlinear_calc(UINT64 previous_cipherwords, UINT64 previous_plainwords, const gf2_reducer& reducer)
// { // {
// UINT64 previous_masks = previous_cipherwords ^ previous_plainwords; // UINT64 previous_masks = previous_cipherwords ^ previous_plainwords;
// return (reducer.gf2_reduce(0x00000a00a305c826ull & previousMasks) & reducer.gf2_reduce(0x0000011800020000ull & previousMasks)) * 0x0011; // return (reducer.gf2_reduce(0x00000a00a305c826ull & previous_masks) & reducer.gf2_reduce(0x0000011800020000ull & previous_masks)) * 0x0011;
// } // }
// static UINT16 panikuru_nonlinear_calc(UINT64 previous_cipherwords, UINT64 previous_plainwords, const gf2_reducer& reducer)
// {
// return ((reducer.gf2_reduce(0x0000000088300281ull & previous_cipherwords) ^ reducer.gf2_reduce(0x0000000004600281ull & previous_plainwords))
// & (reducer.gf2_reduce(0x0000a13140090000ull & previous_cipherwords) ^ reducer.gf2_reduce(0x0000806240090000ull & previous_plainwords))) << 2;
// }
static UINT16 chocovdr_nonlinear_calc(UINT64 previous_cipherwords, UINT64 previous_plainwords, const gf2_reducer& reducer) static UINT16 chocovdr_nonlinear_calc(UINT64 previous_cipherwords, UINT64 previous_plainwords, const gf2_reducer& reducer)
{ {
@ -253,6 +267,27 @@ static const ns10_decrypter_device::ns10_crypto_logic gamshara_crypto_logic = {
gamshara_nonlinear_calc gamshara_nonlinear_calc
}; };
static UINT16 gjspace_nonlinear_calc(UINT64 previous_cipherwords, UINT64 previous_plainwords, const gf2_reducer&)
{
return 0;
}
static const ns10_decrypter_device::ns10_crypto_logic gjspace_crypto_logic = {
{
0x0000000000000240ull, 0x0000d617eb0f1ab1ull, 0x00000000451111c0ull, 0x00000000013b1f44ull,
0x0000aab0b356abceull, 0x00007ca76b89602aull, 0x0000000000001800ull, 0x00000000031d1303ull,
0x0000000000000801ull, 0x0000000030111160ull, 0x0000000001ab3978ull, 0x00000000c131b160ull,
0x0000000000001110ull, 0x0000000000008002ull, 0x00000000e1113540ull, 0x0000d617fdce8bfcull,
}, {
0x0000000000008240ull, 0x000000002f301ab1ull, 0x00000000050011c0ull, 0x00000000412817c4ull,
0x00000004c338abc6ull, 0x000000046108602aull, 0x0000000000005800ull, 0x00000000c3081347ull,
0x0000000000000801ull, 0x0000000061001160ull, 0x0000000061183978ull, 0x00000000e520b142ull,
0x0000000000001101ull, 0x000000000000a002ull, 0x0000000029001740ull, 0x00000000a4309bfcull,
},
0x2e7f,
gjspace_nonlinear_calc
};
static UINT16 knpuzzle_nonlinear_calc(UINT64 previous_cipherwords, UINT64 previous_plainwords, const gf2_reducer& reducer) static UINT16 knpuzzle_nonlinear_calc(UINT64 previous_cipherwords, UINT64 previous_plainwords, const gf2_reducer& reducer)
{ {
UINT64 previous_masks = previous_cipherwords ^ previous_plainwords; UINT64 previous_masks = previous_cipherwords ^ previous_plainwords;
@ -354,6 +389,11 @@ gamshara_decrypter_device::gamshara_decrypter_device(const machine_config &mconf
{ {
} }
gjspace_decrypter_device::gjspace_decrypter_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
: ns10_decrypter_device(GJSPACE_DECRYPTER, gjspace_crypto_logic, mconfig, tag, owner, clock)
{
}
knpuzzle_decrypter_device::knpuzzle_decrypter_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) knpuzzle_decrypter_device::knpuzzle_decrypter_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
: ns10_decrypter_device(KNPUZZLE_DECRYPTER, knpuzzle_crypto_logic, mconfig, tag, owner, clock) : ns10_decrypter_device(KNPUZZLE_DECRYPTER, knpuzzle_crypto_logic, mconfig, tag, owner, clock)
{ {

View File

@ -66,6 +66,12 @@ public:
gamshara_decrypter_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); gamshara_decrypter_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
}; };
class gjspace_decrypter_device : public ns10_decrypter_device
{
public:
gjspace_decrypter_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
};
class knpuzzle_decrypter_device : public ns10_decrypter_device class knpuzzle_decrypter_device : public ns10_decrypter_device
{ {
public: public:
@ -93,6 +99,7 @@ public:
extern const device_type CHOCOVDR_DECRYPTER; extern const device_type CHOCOVDR_DECRYPTER;
extern const device_type GAMSHARA_DECRYPTER; extern const device_type GAMSHARA_DECRYPTER;
extern const device_type GJSPACE_DECRYPTER;
extern const device_type KNPUZZLE_DECRYPTER; extern const device_type KNPUZZLE_DECRYPTER;
extern const device_type KONOTAKO_DECRYPTER; extern const device_type KONOTAKO_DECRYPTER;
extern const device_type NFLCLSFB_DECRYPTER; extern const device_type NFLCLSFB_DECRYPTER;