Super nain tant dos
Introduction
Après le reverse de Aladdin dans le dernier post, j'ai voulu jouer avec un autre jeux, Zombies :
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é :
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 :
Sayez je suis en mesure de pouvoir loguer et meme voir les password que je rentre au sein du debugger :
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 :
Tous les autres passwords sont aussi fonctionnels, Have fun :]
Retour en enfance
Introduction
C'est en voyant des vidéos du site le joueur du grenier où le mec délire à finir un paquet de jeux old-school, ou encore voir des speed run sur speeddemosarchive, qu'une envie de ressortir les vieilles consoles prend le dessus.
C'est pour ça que je décide de m'amuser avec une vieille rom d'un jeu que j'ai pas mal apprécié, Aladdin :
C'est l'occasion aussi de tester ce que vaut un tracer/debugger pour SNES.
Passwords
Dans le jeu Aladdin, tous les 2 - 3 levels, on nous donne un password à rentrer pour pouvoir revenir là où on en était la dernièere fois :
Chaque password est une combinaison de 6 personnages du jeu :
- Aladdin
- Jafar
- Sultan
- Apu (singe)
- Génie
- Jasmine
J'étaits en mesure de pouvoir tracer le programme avec cette outil :
A partir de là le logiciel me crée des fichiers de logs : Aladdin0000.log, et en sortant les couteaux suisses : sort, uniq, cut en loguant quand le password est valide ou non, je fus en mesure de trouver la routine de vérification des password :
$84/ADE4 A0 00 LDY #$00
$84/ADE6 B6 A6 LDX $A6,y [$00:00A6]
$84/ADE8 8A TXA
$84/ADE9 D1 AA CMP ($AA),y[$00:5555]
$84/ADEB F0 18 BEQ $18 [$AE05]
$84/ADED C2 21 REP #$21
$84/ADEF A5 AA LDA $AA [$00:00AA]
$84/ADF1 69 04 00 ADC #$0004
$84/ADF4 85 AA STA $AA [$00:00AA]
$84/ADF6 E2 20 SEP #$20
$84/ADF8 EE 0C 00 INC $000C [$00:000C]
$84/ADFB AD 0C 00 LDA $000C [$00:000C]
$84/ADFE C9 08 CMP #$08
$84/AE00 D0 E2 BNE $E2 [$ADE4]
$84/AE02 4C 7B AE JMP $AE7B [$00:AE7B]
$84/AE05 C8 INY
$84/AE06 C0 04 CPY #$04
$84/AE08 D0 DC BNE $DC [$ADE6]
$84/AE0A AD 0C 00 LDA $000C [$00:000C]
$84/AE0D AA TAX
$84/AE0E BD D6 FD LDA $FDD6,x[$00:FDD6]
$84/AE11 8D 05 00 STA $0005 [$00:0005]
$84/AE14 8D 5C 03 STA $035C [$00:035C]
$84/AE17 9C 5D 03 STZ $035D [$00:035D]
$84/AE1A 22 0A 81 80 JSL $80810A[$80:810A]
$84/AE1E 4C 71 AE JMP $AE71 [$00:AE71]
$84/AE21 89 08 BIT #$08
$84/AE23 F0 0E BEQ $0E [$AE33]
$84/AE25 A6 A5 LDX $A5 [$00:00A5]
Bon j'ai du apprendre vite fait l'assembleur du cpu de la SNES : 65c816, afin de comprendre comment retrouver tous les passwords sans trop de difficulté.
C'est à l'adresse 0xA6 que nos choix de password sont stockés, on voit meme à quelle valeur correspond tel personnage :
- Jafar : 5
- Sultant : 4
- Apu : 3
- Génie : 2
- Jasmine : 1
- Aladdin : 0
Revenons sur le code précédent, je vais le réecrire en pseudo-code pour ce qui ont du mal :
int *pass_valid = 0xFD75;
cpt = 0;
begin:
y = 0;
test:
a = input[y]; /* (0xA6) */
if (a == *(pass_valid + y))
y++;
if (y != 4)
goto test;
else
goto pass_valid;
pass_valid += 4;
cpt += 1;
if (cpt != 8)
goto begin;
else
/* Password failed : Restart du jeu */
En fait il y a 7 passwords possible qu'on va gentiment dumper :
Attention ils se lisent à l'envers ;) :
- Génie, Apu, Aladdin, Sultan
- Jafar, Apu, Jasmine, Génie
- Génie, Jafar, Aladdin, Apu
- Apu, Aladdin, Génie, Jasmine
- Jafar, Jasmine, Aladdin, Jafar
- Jasmine, Jafar, Sultan, Jasmine
- Aladdin, Jasmine, Apu, Sultan
Voilà on a tous les passwords, bon on s'est quand meme bien fait chier car suffisait de google : "Password Aladdin SNES".
Mais bon le but c'était de s'amuser :]
Pages : 1