commit
0d43238b29
11 changed files with 53574 additions and 0 deletions
@ -0,0 +1,20 @@ |
|||||
|
all: game.gbc |
||||
|
|
||||
|
%.2bpp: %.png |
||||
|
rgbgfx --colors embedded -o $@ $< |
||||
|
|
||||
|
%.1bpp: %.png |
||||
|
rgbgfx -d 1 -o $@ $< |
||||
|
|
||||
|
game.o: game.asm bank_*.asm |
||||
|
rgbasm -o game.o game.asm |
||||
|
|
||||
|
game.gbc: game.o |
||||
|
rgblink --tiny -n game.sym -m game.map -o $@ $< |
||||
|
rgbfix -v -p 255 $@ |
||||
|
|
||||
|
@if which md5sum &>/dev/null; then md5sum $@; else md5 $@; fi |
||||
|
|
||||
|
clean: |
||||
|
rm -f game.o game.gbc game.sym game.map |
||||
|
find . \( -iname '*.1bpp' -o -iname '*.2bpp' \) -exec rm {} + |
File diff suppressed because it is too large
@ -0,0 +1,7 @@ |
|||||
|
; Disassembly of "fools.sav" |
||||
|
; This file was created with: |
||||
|
; mgbdis v2.0 - Game Boy ROM disassembler by Matt Currie and contributors. |
||||
|
; https://github.com/mattcurrie/mgbdis |
||||
|
|
||||
|
INCLUDE "hardware.inc" |
||||
|
INCLUDE "bank_000.asm" |
File diff suppressed because it is too large
File diff suppressed because it is too large
@ -0,0 +1,27 @@ |
|||||
|
Breakpoint at S02:A9E2, modify register A |
||||
|
|
||||
|
00: F4660888 (invalid) |
||||
|
01: 88509D53 |
||||
|
02: 536A1248 |
||||
|
03: 48975C04 |
||||
|
04: 04CAE9E3 |
||||
|
05: E31DE75F |
||||
|
06: 5F29D022 |
||||
|
07: 22AFCABB |
||||
|
08: BB40762A |
||||
|
09: 2AA8AE76 |
||||
|
0a: 768BA8FE |
||||
|
0b: FE76C776 |
||||
|
0c: 76B17639 |
||||
|
0d: 39A82376 |
||||
|
0e: 76C2A823 |
||||
|
0f: 23A8C3A8 |
||||
|
10: A86F767B |
||||
|
11: 7BA88DB0 |
||||
|
12: B0AA5BFD |
||||
|
13: FD4CCC0A |
||||
|
14: 0A51BCE1 |
||||
|
15: E1CB6D7D |
||||
|
16: 7DA1357C |
||||
|
17: 7C9D0BCE |
||||
|
18: CE729EFB (invalid) |
@ -0,0 +1,3 @@ |
|||||
|
Stand outside of bill's house |
||||
|
Address 07:68ff write 06 0B |
||||
|
Enter the house, don't move and talk to the gem |
@ -0,0 +1,88 @@ |
|||||
|
#include <stdint.h> |
||||
|
#include <stdbool.h> |
||||
|
#include <stdio.h> |
||||
|
#include <string.h> |
||||
|
|
||||
|
struct hash { |
||||
|
uint16_t hl; |
||||
|
uint16_t bc; |
||||
|
}; |
||||
|
|
||||
|
struct hash hashpass(uint8_t *password) |
||||
|
{ |
||||
|
uint8_t c, b, c1; |
||||
|
|
||||
|
#define swap(x) (((x & 0x0f) << 4) | ((x & 0xf0) >> 4)) |
||||
|
c = password[0] & 0xf; |
||||
|
b = swap(password[0]) & 0x03; |
||||
|
c = ((password[1] & 0xf) + swap(c)) & 0xff; |
||||
|
b = ((swap(password[1]) & 0x03) + ((b << 2) & 0xff)) & 0xff; |
||||
|
c1 = c; |
||||
|
c = password[2] & 0xf; |
||||
|
b = ((swap(password[2]) & 0x03) + ((b << 2) & 0xff)) & 0xff; |
||||
|
c = ((password[3] & 0xf) + swap(c)) & 0xff; |
||||
|
b = ((swap(password[3]) & 0x03) + ((b << 2) & 0xff)) & 0xff; |
||||
|
#undef swap |
||||
|
|
||||
|
return (struct hash){.hl = (password[4] << 8) | b, .bc = (c << 8) | c1}; |
||||
|
} |
||||
|
|
||||
|
bool validpass(struct hash password) |
||||
|
{ |
||||
|
if ((password.hl & 0xe000) != 0) return false; |
||||
|
if ((password.hl & 0x0007) != 0) return false; |
||||
|
return true; |
||||
|
} |
||||
|
|
||||
|
char *passchars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789?!"; |
||||
|
|
||||
|
void convpass(char *password, uint8_t *out) |
||||
|
{ |
||||
|
for (int x = 0; x < 5; x++) { |
||||
|
*out++ = strchr(passchars, *password++) - passchars; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
void hex_dump(const unsigned char *buf, unsigned size) |
||||
|
{ |
||||
|
for (unsigned i = 0; i < size; i += 0x10) { |
||||
|
printf(" "); |
||||
|
for (unsigned x = i; x < i + 0x10 && x < size; x++) { |
||||
|
printf(" %02X", buf[x]); |
||||
|
} |
||||
|
printf("\n"); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
int main(int argc, char *argv[]) |
||||
|
{ |
||||
|
if (argc > 1 && strcmp(argv[1], "valid") == 0) { |
||||
|
for (char **arg = argv + 2; arg < argv + argc; arg++) { |
||||
|
uint8_t pwd[5]; |
||||
|
convpass(*arg, pwd); |
||||
|
hex_dump(pwd, sizeof(pwd)); |
||||
|
struct hash hash = hashpass(pwd); |
||||
|
printf("0x%04x 0x%04x\n", hash.hl, hash.bc); |
||||
|
if (validpass(hash)) { |
||||
|
printf("%s\n", *arg); |
||||
|
} |
||||
|
} |
||||
|
return 0; |
||||
|
} |
||||
|
|
||||
|
for (uint64_t x = 0; x < 0x40000000; x++) { |
||||
|
uint8_t pwd[5]; |
||||
|
uint64_t val = x; |
||||
|
for (uint8_t *c = pwd; c < pwd + 5; c++) { |
||||
|
*c = val % 64; |
||||
|
val /= 64; |
||||
|
} |
||||
|
struct hash hash = hashpass(pwd); |
||||
|
if (validpass(hash)) { |
||||
|
for (uint8_t *c = pwd; c < pwd + 5; c++) { |
||||
|
putchar_unlocked(passchars[*c]); |
||||
|
} |
||||
|
putchar_unlocked('\n'); |
||||
|
} |
||||
|
} |
||||
|
} |
@ -0,0 +1,169 @@ |
|||||
|
#!/usr/bin/env python3 |
||||
|
|
||||
|
class RNG: |
||||
|
def __init__(self): |
||||
|
self.rng = [0xe3, 0x34, 0xad, 0x30] |
||||
|
|
||||
|
def next(self): |
||||
|
self.rng[0] += 1 |
||||
|
self.rng[0] &= 0xff |
||||
|
|
||||
|
self.rng[1] ^= self.rng[0] |
||||
|
self.rng[1] ^= self.rng[3] |
||||
|
self.rng[2] += self.rng[1] |
||||
|
self.rng[2] &= 0xff |
||||
|
self.rng[3] += (self.rng[2] >> 1) ^ self.rng[1] |
||||
|
self.rng[3] &= 0xff |
||||
|
return self.rng[3] |
||||
|
|
||||
|
class FunnyCode: |
||||
|
def __init__(self): |
||||
|
self.code = self.gencode() |
||||
|
self.cache = {} |
||||
|
|
||||
|
def __str__(self): |
||||
|
return " ".join(map(lambda x: "%02x" % x, self.code)) |
||||
|
|
||||
|
def gencode(self): |
||||
|
rng = RNG() |
||||
|
code = [] |
||||
|
for x in range(0x400): |
||||
|
val1 = rng.next() |
||||
|
while val1 == 0: |
||||
|
val1 = rng.next() |
||||
|
|
||||
|
val2 = rng.next() |
||||
|
while True: |
||||
|
val2 &= 0xf8 |
||||
|
if val2 in [0x00, 0x08, 0xf8]: |
||||
|
val2 = rng.next() |
||||
|
continue |
||||
|
break |
||||
|
|
||||
|
code.append(0x0e) # ld c, n8 |
||||
|
code.append(val1) |
||||
|
code.append(0x09) # add hl, bc |
||||
|
code.append(0x15) # dec d |
||||
|
code.append(0xc8) # ret z |
||||
|
code.append(0x1d) # dec e |
||||
|
|
||||
|
if x < 0x14: |
||||
|
code.append(0x20) # jr nz, o8 |
||||
|
code.append(val2 & 0x7f) |
||||
|
elif x >= 0x400 - 0x14: |
||||
|
code.append(0x18) # jr o8 |
||||
|
code.append((val2 & 0x7f) + 0x80) |
||||
|
else: |
||||
|
code.append(0x20) # jr nz, o8 |
||||
|
code.append(val2) |
||||
|
|
||||
|
return code |
||||
|
|
||||
|
def runcode(self, offset, de): |
||||
|
key = offset << 16 | de |
||||
|
if key in self.cache: |
||||
|
return self.cache[key] |
||||
|
|
||||
|
hl = 0 |
||||
|
bc = 0 |
||||
|
d = de >> 8 |
||||
|
e = de & 0xff |
||||
|
while True: |
||||
|
# de = d << 8 | e |
||||
|
# print("0x%04x"%offset, "bc=0x%04x"%bc, "de=0x%04x"%de, "hl=0x%04x"%hl) |
||||
|
c = self.code[offset + 1] |
||||
|
bc = (bc & 0xff00) | c |
||||
|
hl = (hl + bc) & 0xffff |
||||
|
d -= 1 |
||||
|
d &= 0xff |
||||
|
if d == 0: break |
||||
|
e -= 1 |
||||
|
e &= 0xff |
||||
|
if self.code[offset + 6] == 0x20 and e == 0: |
||||
|
offset += 8 |
||||
|
else: |
||||
|
jr = self.code[offset + 7] |
||||
|
if jr >= 0x80: jr -= 0x100 |
||||
|
offset = (offset + 8) + jr |
||||
|
|
||||
|
self.cache[key] = hl |
||||
|
return hl |
||||
|
|
||||
|
class PasswordHash: |
||||
|
def __init__(self, password): |
||||
|
self.hash = self.hashpass(password) |
||||
|
self.valid = True |
||||
|
if (self.hash[0] & 0xe000) != 0: |
||||
|
self.valid = False |
||||
|
if (self.hash[0] & 0x0007) != 0: |
||||
|
self.valid = False |
||||
|
|
||||
|
def swap(self, val): |
||||
|
vl = (val & 0xf0) >> 4 |
||||
|
vh = (val & 0x0f) << 4 |
||||
|
return vh | vl |
||||
|
|
||||
|
def hashpass(self, password): |
||||
|
c = password[0] & 0xf |
||||
|
b = self.swap(password[0]) & 0x03 |
||||
|
c = ((password[1] & 0xf) + self.swap(c)) & 0xff |
||||
|
b = ((self.swap(password[1]) & 0x03) + ((b << 2) & 0xff)) & 0xff |
||||
|
c1 = c |
||||
|
c = password[2] & 0xf |
||||
|
b = ((self.swap(password[2]) & 0x03) + ((b << 2) & 0xff)) & 0xff |
||||
|
c = ((password[3] & 0xf) + self.swap(c)) & 0xff |
||||
|
b = ((self.swap(password[3]) & 0x03) + ((b << 2) & 0xff)) & 0xff |
||||
|
|
||||
|
return (password[4] << 8) | b, (c << 8) | c1 |
||||
|
|
||||
|
passchars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789?!" |
||||
|
def convpass(password): |
||||
|
return bytearray(passchars.index(x) for x in password) |
||||
|
|
||||
|
if __name__ == "__main__": |
||||
|
wanted = [ |
||||
|
0xadaa, |
||||
|
0xac39, |
||||
|
0x002f |
||||
|
] |
||||
|
|
||||
|
from sys import argv |
||||
|
if len(argv) > 1 and argv[1] == "valid": |
||||
|
for x in argv[2:]: |
||||
|
pwd = convpass(x) |
||||
|
password = PasswordHash(pwd) |
||||
|
print(*map(hex, password.hash)) |
||||
|
if password.valid: |
||||
|
print(x) |
||||
|
exit() |
||||
|
if len(argv) > 1 and argv[1] == "run": |
||||
|
code = FunnyCode() |
||||
|
for x in argv[2:]: |
||||
|
pwd = convpass(x) |
||||
|
password = PasswordHash(pwd) |
||||
|
result = code.runcode(*password.hash) |
||||
|
if result in wanted: |
||||
|
print(hex(result), x) |
||||
|
exit() |
||||
|
|
||||
|
code = FunnyCode() |
||||
|
|
||||
|
pwd = convpass("BEPISBEPISBEPIS") |
||||
|
password = PasswordHash(pwd) |
||||
|
print(password.hash) |
||||
|
if not password.valid: |
||||
|
print("Password invalid!") |
||||
|
exit(1) |
||||
|
print(hex(code.runcode(*password.hash))) |
||||
|
|
||||
|
# val = code.runcode(0, 0) |
||||
|
# print(hex(val)) |
||||
|
# if val != 0x1a51: |
||||
|
# exit(1) |
||||
|
|
||||
|
# val = code.runcode(0x1200, 0xf814) |
||||
|
# print(hex(val)) |
||||
|
# if val != 0x4031: |
||||
|
# exit(1) |
||||
|
|
||||
|
# print("success") |
@ -0,0 +1,4 @@ |
|||||
|
#!/bin/sh |
||||
|
set -e |
||||
|
cc -O3 password.c |
||||
|
./a.out | xargs -P$(nproc) ./password.py run |
Loading…
Reference in new issue