18/07/2011

Super nain tant dos

Introduction

Après le reverse de Aladdin dans le dernier post, j'ai voulu jouer avec un autre jeux, Zombies :

zombie_jaq.png

Je crois que ce jeu quand j'étais petit je n'ai jamais réussi à le finir en entier, il est super difficile, mais super fun.

Passwords

Comme dans le jeu Aladdin, tous les 5 levels, on nous file un password pour pouvoir continuer là où on s'est arrêté :

zombie_menu.png

Afin de trouver facilement la routine de vérification des passwords, il m'en fallait un valide, comme ca en tracant le code, je la trouverais facilement, je suis donc allé jusqu'au level 5 :

zombie_passwd.png

Sayez je suis en mesure de pouvoir loguer et meme voir les password que je rentre au sein du debugger :

zombie_w4kf.png

Voici la routine commenté :

$82/B018 AD A0 1E    LDA $1EA0  [$82:1EA0]
$82/B01B C9 42 43    CMP #$4342              ====\
$82/B01E D0 0D       BNE $0D    [$B02D]          |
$82/B020 AD A2 1E    LDA $1EA2  [$82:1EA2]       |
$82/B023 C9 44 46    CMP #$4644                  |  SECRET LEVEL == "BCDF"
$82/B026 D0 05       BNE $05    [$B02D]     =====|
$82/B028 9C 7C 1E    STZ $1E7C  [$82:1E7C]       |
$82/B02B 18          CLC                         |
$82/B02C 6B          RTL                /*RET*/  |
$82/B02D E2 30       SEP #$30               <====/
$82/B02F AE A0 1E    LDX $1EA0  [$82:1EA0]   X = *(0x1EA0)
$82/B032 AD A2 1E    LDA $1EA2  [$82:1EA2]   A = *(0x1EA2)
$82/B035 8D A0 1E    STA $1EA0  [$82:1EA0]   *(0x1EA0) = A
$82/B038 8E A2 1E    STX $1EA2  [$82:1EA2]   *(0x1EA2) = X
$82/B03B C2 30       REP #$30                
$82/B03D A2 00 00    LDX #$0000              X = 0
$82/B040 A9 05 00    LDA #$0005              A = 5
$82/B043 8D 7C 1E    STA $1E7C  [$82:1E7C]   *(0x1E7C) = A 
$82/B046 E2 30       SEP #$30                <======================================\
$82/B048 BC 4B B1    LDY $B14B,x[$82:CC15]   Y = *(0xB14B + x)                       |
$82/B04B B9 78 B1    LDA $B178,y[$82:B17E]   A = *(0xB178 + y)                       |
$82/B04E EB          XBA                     Exchange byte (ex : 4243 -> 43 42)      |
$82/B04F BC 4A B1    LDY $B14A,x[$82:CC14]   Y = *(0xB14A + x)                       |
$82/B052 B9 78 B1    LDA $B178,y[$82:B17E]   A = *(0xB178 + y)                       |
$82/B055 C2 30       REP #$30                                                        |
$82/B057 CD A0 1E    CMP $1EA0  [$82:1EA0]                                           |
$82/B05A F0 1B       BEQ $1B    [$B077]      === First stage Ok =====\               |
$82/B05C EE 7C 1E    INC $1E7C  [$82:1E7C]   \                       |               |
$82/B05F EE 7C 1E    INC $1E7C  [$82:1E7C]   |                       |               |
$82/B062 EE 7C 1E    INC $1E7C  [$82:1E7C]   |--> 0x1E7C += 4        |               |
$82/B065 EE 7C 1E    INC $1E7C  [$82:1E7C]   /                       |               |
$82/B068 E8          INX                     X++;                    |               |
$82/B069 E8          INX                     X++;                    |               | 
$82/B06A E0 1A 00    CPX #$001A              if (A == 0x1A)          |               |
$82/B06D D0 D7       BNE $D7    [$B046]      ========================|===============/
$82/B06F A9 01 00    LDA #$0001                                      |
$82/B072 8D 7C 1E    STA $1E7C  [$82:1E7C]                           |
$82/B075 38          SEC                                             |
$82/B076 6B          RTL                     /* RET == Failed */     |
$82/B077 8E 38 00    STX $0038  [$82:0038]   <=======================|
$82/B07A A2 00 00    LDX #$0000              X = 0
$82/B07D A9 01 00    LDA #$0001              A = 1
$82/B080 8D 3A 00    STA $003A  [$82:003A]   *(0x3A) = A
$82/B083 E2 30       SEP #$30                <======================================\
$82/B085 AC 38 00    LDY $0038  [$82:0038]   Y = *(0x38)                             |
$82/B088 BD 65 B1    LDA $B165,x[$82:CC2F]   A = *(0xB165 + x)                       |
$82/B08B 18          CLC                                                             |
$82/B08C 79 8E B1    ADC $B18E,y[$82:B194]   A += *(0xB18E + y) & 0xff               |
$82/B08F A8          TAY                     Y = A                                   |
$82/B090 B9 78 B1    LDA $B178,y[$82:B17E]   A = *(0xB178 + y)                       |
$82/B093 EB          XBA                     Exchange byte (ex : 4243 -> 43 42)      |
$82/B094 AC 38 00    LDY $0038  [$82:0038]   Y = *(0x38)                             |
$82/B097 BD 64 B1    LDA $B164,x[$82:CC2E]   A = *(0xB164 + x)                       |
$82/B09A 18          CLC                                                             |
$82/B09B 79 8D B1    ADC $B18D,y[$82:B193]   A += *(0xB18D + y) & 0xff               |
$82/B09E A8          TAY                     Y = A                                   |
$82/B09F B9 78 B1    LDA $B178,y[$82:B17E]   A = *(0xB17E + y)                       |
$82/B0A2 C2 30       REP #$30                                                        |
$82/B0A4 CD A2 1E    CMP $1EA2  [$82:1EA2]                                           |
$82/B0A7 F0 12       BEQ $12    [$B0BB]      === JUMP GOOD BOY ===                   |
$82/B0A9 EE 3A 00    INC $003A  [$80:003A]                                           |
$82/B0AC E8          INX                     x++                                     |
$82/B0AD E8          INX                     x++                                     |
$82/B0AE E0 14 00    CPX #$0014              if (x != 0x14)                          |
$82/B0B1 D0 D0       BNE $D0    [$B083]      =======================================/
$82/B0B3 A9 01 00    LDA #$0001              
$82/B0B6 8D 7C 1E    STA $1E7C  [$80:1E7C]
$82/B0B9 38          SEC                  
$82/B0BA 6B          RTL                  /* RET = Failed Password */

Elle peut paraitre un peu longue mais en fait il y a une subtilité marrante, pour chaque password, il y en a 10 de possible, chacun d'eux donnera un nombre de victimes différents lorsque vous partirez du niveau désiré.
J'ai ecrit un petit code en python pour les générer:

stage = "HNCVWBXKGZTDLFPSRYJMQ"
B14A_offset =    [0x10, 0x00, 0x08, 0x05, 0x02,
                  0x0D, 0x11, 0x07, 0x05, 0x06,
                  0x0C, 0x11, 0x09, 0x0C, 0x14,
                  0x12, 0x03, 0x09, 0x0E, 0x10,
                  0x00, 0x0C, 0x12, 0x04, 0x0F,
                  0x0B, 0x04, 0x07]

B18D_offset = [0x00, 0xFE, 0xFE, 0xFF, 0x02,
                  0x00, 0x01, 0x02, 0xFF, 0xFE,
                  0x02, 0x02, 0x02, 0x01, 0x00,
                  0x00, 0x01, 0x01, 0x01, 0x00,
                  0xFF, 0xFF, 0x00, 0xFF, 0x00,
                  0x01, 0x18, 0x69, 0x8F]

B164_offset =    [0x04, 0x07, 0x0F, 0x0A, 0x0C,
                  0x12, 0x10, 0x09, 0x0E, 0x10,
                  0x03, 0x05, 0x0D, 0x08, 0x08,
                  0x0C, 0x0A, 0x0E, 0x06, 0x11]

x = 0
y = 0
print "Nb victims \t 1\t 2\t 3\t 4\t 5\t 6\t 7\t 8\t 9\t 10"
while (x < 0x1a):
    second = stage[B14A_offset[x + 1]]
    third = stage[B14A_offset[x]]
    y = 0
    lvl = "Lvl X\t\t"
    while (y < 0x14):
        a = B164_offset[y + 1]
        a += B18D_offset[x + 1]
        a &= 0xff
        fourth = stage[a]
        a = B164_offset[y]
        a += B18D_offset[x]
        a &= 0xff
        first = stage[a]
        lvl += first + second + third + fourth + "\t"
        y += 2
    print lvl
    x += 2
print "Secret Level : BCDF"

Voici l'output :

Nb victims 1	  2	  3	  4	  5	  6	  7	  8	  9	 10
Lvl X	WHRB	 SHRG	 LHRR	 RHRK	 PHRP	 VHRV	 FHRX	 GHRT	 THRL	XHRS	
Lvl X	CBGX	 FBGZ	 TBGY	 PBGG	 LBGS	 NBGW	 DBGK	 XBGD	 GBGF	WBGR	
Lvl X	XFCK	 YFCT	 PFCJ	 JFCZ	 RFCR	 BFCB	 SFCG	 TFCL	 LFCP	GFCY	
Lvl X	BKYZ	 RKYL	 FKYQ	 YKYD	 SKYJ	 WKYK	 PKYT	 ZKYP	 DKYR	KKYM 
Lvl X	VXBB	 PXBG	 DXBR	 SXBK	 FXBP	 CXBV	 LXBX	 KXBT	 ZXBL   BXBS 
Lvl X	XYLZ	 YYLL	 PYLQ	 JYLD	 RYLJ	 BYLK	 SYLT	 TYLP    LYLR   GYLM 
Lvl X	XLZG	 YLZD	 PLZM	 JLZT	 RLZY	 BLZX	 SLZZ    TLZF    LLZS   GLZJ 
Lvl X	WJQK	 SJQT	 LJQJ	 RJQZ	 PJQR	 VJQB    FJQG    GJQL    TJQP   XJQY 
Lvl X	BZVG	 RZVD	 FZVM	 YZVT	 SZVY    WZVX    PZVZ    ZZVF    DZVS   KZVJ 
Lvl X	BRPK	 RRPT	 FRPJ	 YRPZ    SRPR    WRPB    PRPG    ZRPL    DRPP   KRPY 
Lvl X	VLHX	 PLHZ	 DLHY    SLHG    FLHS    CLHW    LLHK    KLHD    ZLHF   BLHR 
Lvl X	WWJX	 SWJZ    LWJY    RWJG    PWJS    VWJW    FWJK    GWJD    TWJF	XWJR 
Lvl X	WDSG     SDSD    LDSM    RDST    PDSY    VDSX    FDSZ    GDSF	 TDSS   XDSJ 
Secret Level : BCDF

On teste le secret level and it works :

zombie_bonus.png

Tous les autres passwords sont aussi fonctionnels, Have fun :]