Soon i will be releasing a set of roms to bypass a broken security daughter card on your Golden Axe 2.
As a proof of concept, i started to look into this a few days ago, and it turned out really easy.
Sega used a very lazy assembler, programmer, QA checker and what have you. Read below to find out how botched up the Golden Axe 2 release was..
I did this in October, around the 10th, and shared the info with a few people. On oct 21st, the info ended up on TCRF.net.
Maybe a coincidence. Whoever posted there please come forward where you found this. (Rabidrabid, who are you?)
Roms will be released around christmas, just like i did last year with the Espgaluda score save mod. Have patience
Preface
Let's explain a bit about GA2 and security the daughter card. It has a NEC V25 cpu on it, some ram, a rom (already dumped) and sits on the bus. It is designed to stop bootleggers. Sega had lots of games heavily bootlegged, and they lost revenue because of this. Previous platforms have battery backed 68K main cpu's with encryption tables that helped deter bootleggers for a looong time. Some of the System32 games have FD1149 solutions on them which today are still not fully understood. What went wrong with Golden Axe 2? It is a top-tier title with a strong IP that should be properly protected, right?
Bootup
The main cpu can 'talk' to the daughter card by shared ram. When the game boots, maincpu and secure v25 cpu start up. The game waits for some magic string to appear in RAM otherwise the main cpu code will stay in a loop. Other than that, there is also some sprite data reading from shared ram. If the daughter card dies, the game won't start. If you bypass the magic string check, the sprites will be looking like they are on LSD. Seems decent enough right?
Flaws
- Main cpu code not encrypted.
- Expected string can be seen in main cpu code roms. (oops.)
- Expected palletes may be guessed or even brute forced.
- Hardware emulation in 1992 could have seen the content of the encrypted cpu ram..
The attack
The game is fully emulated in MAME for a long time. Source code is available. The game wants a 'WAKE UP! ...' string or it won't boot.
The secure cpu is also fully emulated. There is just some simple opcode obfuscation going on, nothing serious. (first obvious sign of lazyness: Obfuscation is not security.)
I started to look at the ram space for the encrypted cpu to see what the game put there, and what the security cpu was doing. It soon became clear this was going to be a boring job.
- The security cpu creates a page of static data in the shared ram.
- Nothing ever changes in this shared ram.
- Then it sits there idle. Doing nothing.
This could be easier than i thought.
Stupid assembler
I went to look at the rom to see if i was missing any code that the security board might jump to in special cases. There could be some triggers or events i had missed in the main cpu.
Disassembling the obfuscated rom would allow me to see any such hidden surprises. I was really hoping for somekind of a surprise. But not like what i found.
I saw a big issue. Sega had used an assembler that was super sloppy. It had produced a ROM and filled the emptyness with 'random data' from the pc/disk/ram.
Except, it had picked the source code of the V25 encrypted program. Not scrambled. Nicely formatted too.
;------------------------------------------------------------------------------
; SFR INITIAL
;------------------------------------------------------------------------------
INIT PROC
_INIT:
mov aw,0
mov ds0,aw
mov aw,0ff00h
mov ds1,aw
mov cw,9
ldea ix,ITDT
INITLP:
mov iy,word ptr ds0:[ix]
mov dl,byte ptr ds0:[ix+2]
mov byte ptr ds1:[iy],dl
add ix,4
dec cw
bnz INITLP
RET
INIT ENDP
;------------------------------------------------------------------------------
; V25 read/write check
;------------------------------------------------------------------------------
RW22 PROC
_RW22:
mov ch,byte ptr ds1:[ix+1]
cmp ch,20h ; V25 r/w start ?
bne _RW22
mov bw,8 ; counter offset (0008h)
mov dh,byte ptr ds1:[ix+6h] ; add data
mov dl,byte ptr ds1:[ix+7h] ; write start data
LP_22:
call AD_SET
mov byte ptr ds1:[iy],dl ; RAM data write
mov cl,byte ptr ds1:[iy] ; RAM data read
cmp cl,dl
bnz R22_NG
add dl,dh
inc bw
cmp bw,7f0h ;stack area (10h) keep
bnz LP_22
mov ch,22h ; RAM OK data set
call SET_ON
RET
R22_NG:
mov ch,2ah ; RAM NG data set
call SET_ON
RET
RW22 ENDP
;------------------------------------------------------------------------------
; V25 read / V60 write check
;------------------------------------------------------------------------------
RW26 PROC
_RW26:
mov ch,byte ptr ds1:[ix+1]
cmp ch,4fh ; V60 write end ?
bne _RW26
mov bw,8 ; counter offset (0008h)
mov dh,byte ptr ds1:[ix+6h] ; add data
mov dl,byte ptr ds1:[ix+7h] ; write start data
LP_26:
call AD_SET
mov cl,byte ptr ds1:[iy] ; RAM data read
cmp cl,dl
bnz R26_NG
add dl,dh
inc bw
cmp bw,7f0h
bnz LP_26
mov ch,44h ; RAM OK data set
call SET_ON
RET
R26_NG:
mov ch,4ah ; RAM NG data set
call SET_ON
RET
RW26 ENDP
;------------------------------------------------------------------------------
; V60 read / V25 write check
;------------------------------------------------------------------------------
RW62 PROC
_RW62:
mov ch,byte ptr ds1:[ix+1]
cmp ch,50h ; before result write end ?
bne _RW62
mov bw,8 ; counter offset (0008h)
mov dh,byte ptr ds1:[ix+6h] ; add data
mov dl,byte ptr ds1:[ix+7efh] ; write start data
mov byte ptr ds1:[ix+7h],dl ; write start data
LP_62:
call AD_SET
mov byte ptr ds1:[iy],dl ; RAM data write
add dl,dh
inc bw
cmp bw,7f0h
bnz LP_62
mov ch,5fh ; write end code set
call SET_ON
RET
RW62 ENDP
;------------------------------------------------------------------------------
; arabian fight security routin
;------------------------------------------------------------------------------
WRITE_AXE PROC
_RW_AXE:
ldea ix,PLCOL_AX
mov iy,0 ;
mov cw,16 ;loop count
loop:
mov dl,byte ptr ds0:[ix]
mov byte ptr ds1:[iy],dl
add ix,1
add iy,1
dec cw
bnz loop
RET
PLAYCOL1 equ 0000000aH
PLAYCOL2 equ 00000011H
PLAYCOL3 equ 00000018H
PLAYCOL4 equ 0000001fH
ZANZOCOL1 equ 000000c5H
ZANZOCOL2 equ 000000c6H
PLCOL_AXE
dw PLAYCOL1 -- body color
dw ZANZOCOL1 -- zanzoh color
dw PLAYCOL2 -- body color
dw PLAYCOL2 -- zanzoh color
dw PLAYCOL3 -- body color
dw PLAYCOL3 -- zanzoh color
dw PLAYCOL4 -- body color
dw ZANZOCOL2 -- zanzoh color
WRITE_AXE ENDP
;------------------------------------------------------------------------------
; event security routin
;------------------------------------------------------------------------------
;000h~3ffh write buff
;080h~0afh (startup function work)
;400h~7ffh read buff
;------------------------------------------------------------------------------
; start up function
;------------------------------------------------------------------------------
START_FUNC PROC
_ST_FU:
ldea ix,MESS_ST
mov iy,080h ;start function write buff
mov cw,16*3 ;loop count
loop_st:
mov dl,byte ptr ds0:[ix]
mov byte ptr ds1:[iy],dl
add ix,1
add iy,1
dec cw
bnz loop_st
RET
;0123456789abcdef
MESS_ST db 'wake up! GOLDEN ' ;16 byte 1 group
db 'AXE The Revenge ' ;16 byte 1 group
db 'of Death-Adder! ' ;16 byte 1 group
START_FUNC ENDP
;------------------------------------------------------------------------------
; work ram clr
;------------------------------------------------------------------------------
WORK_RAM_CLR PROC
_WO_RA:
mov iy,0000h ;work ram write adr.
mov cw,0400h ;loop count
mov dl,0000h
loop_wc:
mov byte ptr ds1:[iy],dl
add iy,1
dec cw
bnz loop_wc
RET
WORK_RAM_CLR ENDP
;------------------------------------------------------------------------------
; RAM check result set routine
;------------------------------------------------------------------------------
SET_ON PROC
_SET_ON:
mov byte ptr ds1:[ix+1],ch ; check result set
mov cl,byte ptr ds1:[ix+1] ; result set ok ?
cmp ch,cl
bnz _SET_ON
RET
SET_ON ENDP
;------------------------------------------------------------------------------
; V25 address chenge & set routine ix : 0
; aw : chenge address
; bw : address counter
;------------------------------------------------------------------------------
AD_SET PROC
AST_LP:
mov byte ptr ds1:[ix+2],bl ; lower address set (10002h)
mov byte ptr ds1:[ix+3],bh ; upper address set (10004h)
mov cl,byte ptr ds1:[ix+2] ; lower set ok ?
mov ch,byte ptr ds1:[ix+3] ; upper set ok ?
cmp bw,cw
bnz AST_LP
mov iy,bw
RET
AD_SET ENDP
RMCK ENDS
;------------------------------------------------------------------------------
; data table
;------------------------------------------------------------------------------
RMCK SEGMENT
org 1000h
;xxf01=00 --pm0
;xxf02=00 --pmc0
;xxf09=00 --pm1
;xxf0a=08 --pmc1
;xxf11=00 --pm2
;xxf12=00 --pmc2
;xxfe8=00 --wtc
;xxfe9=00 --???
;xxfeb=00 --prc
ITDT dw 0f01h,0,0f02h,0,0f09h,0,0f0ah,8,0f11h,0,0f12h,0
dw 0fe8h,1001h,0fe9h,0,0febh,4ch
RMCK ENDS
;------------------------------------------------------------------------------
; reset vecter
;------------------------------------------------------------------------------
RMCK SEGMENT
org 0fff0h
br FAR PTR START
RMCK ENDS
END
ST_LP:
mov byte ptr ds1:[ix+2],bl ; lower address set (10002h)
mov byte ptr ds1:[ix+3],bh ; upper address set (10004h)
mov cl,byte ptr ds1:[ix+2] ; lower set ok ?
mov ch,byte ptr ds1:[ix+3] ; upper set ok ?
cmp bw,cw
bnz AST_LP
mov iy,bw
RET
AD_SET ENDP
RMCK ENDS
;------------------------------------------------------------------------------
; data table
;------------------------------------------------------------------------------
RMCK SEGMENT
org 1000h
;xxf01=00 --pm0
;xxf02=00 --pmc0
;xxf09=00 --pm1
;xxf0a=08 --pmc1
;xxf11=00 --pm2
;xxf12=00 --pmc2
;xxfe8=00 --wtc
;xxfe9=00 --???
;xxfeb=00 --prc
ITDT dw 0f01h,0,0f02h,0,0f09h,0,0f0ah,8,0f11h,0,0f12h,0
dw 0fe8h,1001h,0fe9h,0,0febh,4ch
RMCK ENDS
-- Sprite table, from the assembly part:
07AF 73696E62617420202020 374 MESS_EV3 db 'sinbat ' ;16 byte 1 group
202020202020
07BF 72616D61796120202020 375 db 'ramaya ' ;16 byte 1 group
202020202020
07CF 676F6C646F7220202020 376 db 'goldor ' ;16 byte 1 group
202020202020
07DF 64617461202020202020 377 db 'data ' ;16 byte 1 group
202020202020
07EF 20202020202020202020 378 db ' ' ;16 byte 1 group
202020202020
07FF 20202020202020202020 379 db ' ' ;16 byte 1 group
202020202020
080F 20202020202020202020 380 db ' ' ;16 byte 1 group
202020202020
081F 20202020202020202020 381 db ' ' ;16 byte 1 group
202020202020
So, whoever assembled this using uPD70320 Assembler V3.10 in SEC mode on 01 Sep 92 12:30:49 on a PC98 with nickname ARAMAWARI made no QA effort.
Also, another lazy sign: They re-used partial Arabian Fight routines, which could help de-obfuscate the sec cpu on that one, the emulation is not 100% on that game yet.
Work done so far:
- Moved the sprite table into ROM
- Bypassed security string
- Tested on real hardware (see here.)
Todo:
- Document the rom types if you want to convert say, F1 super lap.
- De-obfuscate the Arabian Fight sec board?
- Add AF sec emulation to MAME?
- Do the actual Xmas release
I wanted to play Titanfall 2 but wrote this damn wall of text..
And yes, there's a similar situation in Arabian Fight's sec board rom, but there is a lot less source..
First of all thanks for sharing this detailed insight (at the cost of your playing evening )
And LMAO for Sega's epic fail. Keep it coming, man!
OBTW, this belongs in the wiki
My 15kHz cabinet Peplos will never power up, with any item, and I am quite proud of that.