Skip to content

Instantly share code, notes, and snippets.

@shuffle2
Created March 25, 2014 00:03
Show Gist options
  • Save shuffle2/59b03053e259144d6ae4 to your computer and use it in GitHub Desktop.
Save shuffle2/59b03053e259144d6ae4 to your computer and use it in GitHub Desktop.
import struct
from array import array
import sys
'''
password getsn looks to be 0x100 long
'''
# microcorruption's emulated dadd DOES NOT TAKE CARRY AS INPUT
def dadd(sr, src, dst):
rv = 0
c = 0
n = (sr >> 2) & 1
for i in range(4):
s = (src >> (i * 4)) & 0xf
d = (dst >> (i * 4)) & 0xf
d += s + c
if d > 10:
if i == 3 and d & 0x8:
n = 1
d -= 10
c = 1
else:
c = 0
rv |= d << (i * 4)
return rv, (n << 2) | c
# dadd actually doesn't adhere to the msp430 spec, so make sure we're behaving like the emulator
# no sr.c as input, no sr.n or sr.z as output
# bcd digits > 0x9 are converted to bcd
assert dadd(0, 0x160e, 0x04a2) == (0x2116, 0), 'rv:%04x sr:%04x' % dadd(0, 0x160e, 0x04a2)
assert dadd(0, 0x3c01, 0x0845) == (0x4a46, 0), 'rv:%04x sr:%04x' % dadd(0, 0x3c01, 0x0845)
assert dadd(0, 0x9999, 0x9999) == (0x9998, 1), 'rv:%04x sr:%04x' % dadd(0, 0x9999, 0x9999)
assert dadd(0, 0x000e, 0x0000) == (0x0014, 0), 'rv:%04x sr:%04x' % dadd(0, 0x000e, 0x0000)
assert dadd(0, 0x0000, 0x0000) == (0x0000, 0), 'rv:%04x sr:%04x' % dadd(0, 0x0000, 0x0000)
assert dadd(0, 0x00ff, 0x00ff) == (0x0154, 0), 'rv:%04x sr:%04x' % dadd(0, 0x00ff, 0x00ff)
assert dadd(0, 0x8000, 0x8000) == (0x6000, 1), 'rv:%04x sr:%04x' % dadd(0, 0x8000, 0x8000)
# dst = dst - src
def sub(src, dst):
src = (~src) & 0xffff
dst &= 0xffff
rv = dst + src + 1
n = 1 if rv & 0x8000 else 0
c = 1 if rv > 0xffff else 0
rv &= 0xffff
z = 1 if rv == 0 else 0
# overflow isn't implemented in emulator
# but we use it to detect a case when n flag is set
v = 0
if (dst ^ (src ^ 0x8000)) & 0x8000:
v = 1 if rv & 0x8000 == ((src ^ 0x8000) & 0x8000) else 0
if n == 0:
n = v
v = 0
#print 'd:%04x s:%04x rv:%05x' % (dst, src, rv)
#print 'v:%x n:%x z:%x c:%x' % (v, n, z, c)
return rv, (v << 8) | (n << 2) | (z << 1) | c
# the flags...barely make sense
assert sub(1234, 0x1000) == (0x0b2e, 1), 'rv:%04x sr:%04x' % sub(1234, 0x1000)
assert sub(1234, 0) == (0xfb2e, 4), 'rv:%04x sr:%04x' % sub(1234, 0)
assert sub(1234, 1234) == (0x0000, 3), 'rv:%04x sr:%04x' % sub(1234, 1234)
assert sub(1234, 0xfb2e) == (0xf65c, 5), 'rv:%04x sr:%04x' % sub(1234, 0xfb2e)
assert sub(1234, 0x8000) == (0x7b2e, 5), 'rv:%04x sr:%04x' % sub(1234, 0x8000)
def add(src, dst):
src &= 0xffff
dst &= 0xffff
rv = src + dst
c = 1 if rv > 0xffff else 0
rv &= 0xffff
z = 1 if rv == 0 else 0
n = 1 if rv & 0x8000 else 0
v = 0
return rv, (v << 8) | (n << 2) | (z << 1) | c
assert add(0x0000, 0x0000) == (0x0000, 2), 'rv:%04x sr:%04x' % add(0x0000, 0x0000)
assert add(0x0000, 0x7fff) == (0x7fff, 0), 'rv:%04x sr:%04x' % add(0x0000, 0x7fff)
assert add(0x7fff, 0x7fff) == (0xfffe, 4), 'rv:%04x sr:%04x' % add(0x7fff, 0x7fff)
assert add(0x8000, 0x8000) == (0x0000, 3), 'rv:%04x sr:%04x' % add(0x8000, 0x8000)
# rra/rrc are so terrible that i've stopped caring about tests
def rra(sr, dst):
dst &= 0xffff
sign = dst & 0x8000
c = sr & 1
rv = sign | (dst >> 1)
z = 0
n = 1 if sign else (sr >> 2) & 1
v = 0
return rv, (v << 8) | (n << 2) | (z << 1) | c
def rrc(sr, dst):
dst &= 0xffff
sign = (sr & 1) << 15
c = dst & 1
rv = sign | (dst >> 1)
z = ((sr >> 1) & 1) if rv == 0 else 0
n = 1 if sign else (sr >> 2) & 1
v = 0
return rv, (v << 8) | (n << 2) | (z << 1) | c
def bswap16(x):
assert x <= 0xffff
return ((x >> 8) & 0xff) | ((x & 0xff) << 8)
def decrypt(crypted, addr):
x, sr = sub(1234, bswap16(addr))
x, sr = add(sr, x)
x, sr = rrc(sr, x)
x, sr = dadd(sr, addr, x)
x, sr = rra(sr, x)
x, sr = rrc(sr, x)
x, sr = dadd(sr, 0x3c01, x)
x, sr = add(sr, x)
x, sr = rrc(sr, x)
x, sr = add(0x100e, x)
x, sr = rrc(sr, x)
x, sr = rrc(sr, x)
return x ^ crypted
assert decrypt(0x0f7d, 0x160c + 2) == 0x8231
data = array('H')
with open(sys.argv[1], 'rb') as f:
f.seek(0x4634 - 0x4400)
data.fromfile(f, 0x1100 / 2)
decrypted = array('H')
for i, b in enumerate(data):
o = 0x1400 + i * 2
d = decrypt(b, o + 2)
decrypted.append(d)
if i == (0x20c / 2):
assert o == 0x160c
assert b == 0x0f7d
assert d == 0x8231
with open(sys.argv[2], 'wb') as fo:
decrypted.tofile(fo)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment