📄 segacrpt.c
字号:
/******************************************************************************
Sega encryption emulation by Nicola Salmoria
Several Sega Z80 games have program ROMs encrypted using a common algorithm
(but with a different key).
The hardware used to implement this encryption is either a custom CPU, or an
epoxy block which probably contains a standard Z80 + PALs.
You can think of the decryption algorithm as a black box which takes as
input D3, D5, D7, M1, A0, A4, A8 and A12, and returns the decrypted D3, D5
and D7. [Dn are the data lines, An the address lines, M1 is the Z80 pin which
tells whether the CPU is accessing data or opcodes]. D0, D1, D3, D4 and D6
are always unaffected.
We can summarize that using a XOR mask laid out like this:
0 1 2 3 4 5 6 7 8 9 a b c d e f
0 A A A A A A A A B B B B B B B B
1 A A A A A A A A B B B B B B B B
2 C C C C C C C C D D D D D D D D
3 C C C C C C C C D D D D D D D D
4 A A A A A A A A B B B B B B B B
5 A A A A A A A A B B B B B B B B
6 C C C C C C C C D D D D D D D D
7 C C C C C C C C D D D D D D D D
8 D D D D D D D D C C C C C C C C
9 D D D D D D D D C C C C C C C C
a B B B B B B B B A A A A A A A A
b B B B B B B B B A A A A A A A A
c D D D D D D D D C C C C C C C C
d D D D D D D D D C C C C C C C C
e B B B B B B B B A A A A A A A A
f B B B B B B B B A A A A A A A A
on the left edge you have the most significant nibble of the data, on the top
edge the least significant nibble. For example, if the input data is 0xc0, it
will be XORed with D. As you can see, the table is symmetrical, so the 8
possible combinations of D3, D5 and D7 only require 4 different XOR values.
Since only D3, D5 and D7 are affected, A, B, C and D can have only these
values: 0x00, 0x08, 0x20, 0x28, 0x80, 0x88, 0xa0, 0xa8.
Another important thing to note is that A XOR B XOR C XOR D must always be 0;
that is, it must cause a permutation. If that weren't the case, there would
be values impossible to obtain.
We need 32 of these tables, one for every possible combination of M1, A0, A4,
A8 and A12. However, all the games currently known are full of repetitions
and only use 6 different tables, the only exception being Pengo which has 7
(but one of them is { 0x00, 0x00, 0x00, 0x00 } ). This is most likely a
limitation of the hardware.
In all games currently known, only bytes in the memory range 0x0000-0x7fff
(A15 = 0) are encrypted. My guess is that this was done to allow games to
copy code to RAM (in the memory range 0x8000-0xffff) and execute it from
there without the CPU trying to decrypt it and messing everything up.
However Zaxxon has RAM at 0x6000, and the CPU doesn't seem to interfere with
it; but it doesn't execute code from there, so it's possible that the CPU is
encrypting the data while writing it and decrypting it while reading (that
would seem kind of strange though). Video and sprite RAM and memory mapped
ports are all placed above 0x8000.
Given its strict limitations, this encryption is reasonably easy to break,
and very vulnerable to known plaintext attacks.
Ninja Princess:
there is a (bootleg?) board which has a standard Z80 + 2 bipolar PROMs
instead of the custom CPU. The encryption table is different from the
original Ninja Princess; it is actually the same as Flicky.
The first PROM is 32x8 (?) and contains the number (0..5) of the table to
use depending on M1, A0, A4, A8, A12:
00: 11 00 33 22 00 44 44 00 11 33 33 22 44 44 44 22
10: 11 55 55 33 44 22 55 22 11 33 55 33 44 44 11 22
The second PROM is 256x4 and contains the 6 different XOR tables:
A D B C C B D A
00: 09 09 0A 0A 0A 0A 09 09
08: 0E 08 0B 0D 0D 0B 08 0E
10: 0A 0C 0A 0C 0C 0A 0C 0A
18: 0B 0E 0E 0B 0B 0E 0E 0B
20: 0C 0C 0F 0F 0F 0F 0C 0C
28: 08 0D 0B 0E 0E 0B 0D 08
[the remaining bytes are all 0F]
bit 3 is not used.
bits 0-2 is the XOR code inverted (0 = 0xa8, 1 = 0xa0 ... 6 = 0x08 7 = 0x00)
Here is a diagram showing how it works:
data to XOR
decode value
A ---
D7 --------------- 0| |
D3 --------------- 1| |
D5 --------------- 2| P |D
A --- D | R |0 ---|>--- D3
M1 --- 0| P |0 --- 3| O |1 ---|>--- D5
A0 --- 1| R |1 --- 4| M |2 ---|>--- D7
A4 --- 2| O |2 --- 5| 2 |3
A8 --- 3| M |3 --- 6| |
A12 --- 4| 1 |4 --- 7| |
--- ---
List of encrypted games currently known:
CPU Part # Game Comments
315-5010 Pengo unencrypted version available
315-5013 Super Zaxxon used Zaxxon for known plaintext attack
315-5018 Yamato not decoded yet
315-5028 Sinbad Mystery not decoded yet
315-5033 Regulus
???-???? Mister Viking
315-5048 SWAT used Bull Fight for k.p.a.
315-5051 Flicky &
Ninja Princess (bootleg)
???-???? Water Match not available yet
315-5061 Future Spy
315-5065 Bull Fight
315-5093 Pitfall II
315-5098 Ninja Princess used Sega Ninja for k.p.a.
315-5102 Sega Ninja unencrypted version available
315-5110 I'm Sorry used My Hero for k.p.a.
315-5115 TeddyBoy Blues
315-5135 Heavy Metal &
Wonder Boy (set 1 & 2; bootlegs?)
???-???? My Hero bits 0 and 1 in all ROMs swapped as well
The following games use a different encryption algorithm:
315-5162 4D Warriors used I'm Sorry for k.p.a.
315-5177 Wonder Boy (set 3) not decoded yet
315-5178 Wonder Boy (set 4) used Wonder Boy Deluxe for k.p.a.
???-???? Gardia not decoded yet
The following games use another different encryption algorithms, much more
secure than the previous two, which has not been broken yet. It might be
similar to the one used in System 16 games.
317-5014?DakkoChan Jansoh
317-0029 Block Gal NEC MC8123B 651 packaged like System16's 68000
317-0030 Perfect Billiards
317-0064 Ufo Senshi Yohko Chan
The following are System 16 games, the CPU is a custom 68000 built by
Hitachi (FD1089 or FD1094).
314-0033? ??????
317-0080 Passing Shot
317-0092 Tetris (16A)
317-0093 Cotton
317-0110 Golden Axe
317-0116 Bay Route
317-0139 Bloxeed
317-0168 Aurail
317-0179ATetris (16B)
317-0181ACotton
317-???? Line of Fire
Some text found in the ROMs:
Yamato SECULITY BY M,MIZUNAGA
Regulus SECULITY BY SYUICHI,KATAGI
Regulus CAN YOU COPY ?CAN YOU COPY ?CAN YOU [Yes I can, thank you ;-)]
Mister Viking SECURITY BY S.KATAGI CONTROL CHIP M140
SWAT SECURITY BY S.KATAGI
Flicky SECURITY BY S.KATAGI
******************************************************************************/
#include "driver.h"
static void sega_decode(const unsigned char xortable[32][4])
{
int A;
unsigned char *RAM = Machine->memory_region[Machine->drv->cpu[0].memory_region];
for (A = 0x0000;A < 0x8000;A++)
{
int row,col;
unsigned char src;
src = RAM[A];
/* pick the translation table from bits 0, 4, 8 and 12 of the address */
row = (A & 1) + (((A >> 4) & 1) << 1) + (((A >> 8) & 1) << 2) + (((A >> 12) & 1) << 3);
/* pick the offset in the table from bits 3 and 5 of the source data */
col = ((src >> 3) & 1) + (((src >> 5) & 1) << 1);
/* the bottom half of the translation table is the mirror image of the top */
if (src & 0x80) col = 3 - col;
/* decode the opcodes */
ROM[A] = src ^ xortable[2*row][col];
/* decode the data */
RAM[A] = src ^ xortable[2*row+1][col];
if (xortable[2*row][col] == 0xff) /* table incomplete! (for development) */
ROM[A] = 0x00;
if (xortable[2*row+1][col] == 0xff) /* table incomplete! (for development) */
RAM[A] = 0xee;
}
/* copy the opcodes from the not encrypted part of the ROMs */
for (A = 0x8000;A < 0x10000;A++)
ROM[A] = RAM[A];
}
void myheroj_unmangle(void)
{
int A;
unsigned char *RAM;
/* additionally to the usual protection, all the program ROMs have data lines */
/* D0 and D1 swapped. */
RAM = Machine->memory_region[Machine->drv->cpu[0].memory_region];
for (A = 0;A < 0xc000;A++)
RAM[A] = (RAM[A] & 0xfc) | ((RAM[A] & 1) << 1) | ((RAM[A] & 2) >> 1);
/* the tile gfx ROMs are mangled as well: */
RAM = Machine->memory_region[1];
/* the first ROM has data lines D0 and D6 swapped. */
for (A = 0x0000;A < 0x4000;A++)
RAM[A] = (RAM[A] & 0xbe) | ((RAM[A] & 0x01) << 6) | ((RAM[A] & 0x40) >> 6);
/* the second ROM has data lines D1 and D5 swapped. */
for (A = 0x4000;A < 0x8000;A++)
RAM[A] = (RAM[A] & 0xdd) | ((RAM[A] & 0x02) << 4) | ((RAM[A] & 0x20) >> 4);
/* the third ROM has data lines D0 and D6 swapped. */
for (A = 0x8000;A < 0xc000;A++)
RAM[A] = (RAM[A] & 0xbe) | ((RAM[A] & 0x01) << 6) | ((RAM[A] & 0x40) >> 6);
/* also, all three ROMs have address lines A4 and A5 swapped. */
for (A = 0;A < 0xc000;A++)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -