Created
December 9, 2020 13:27
-
-
Save klondi/88a7f1615f13863fe8edf00da54ecfa6 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Show solution to the Hack It 1! From Araba Encounter 07 | |
By klondike of ChaGU | |
Use wasm-decompile from wabt to get the DCMP files (I also used the was2c to get the static sections in a format that worked for python). | |
Find the relevant function: | |
function f_1(a:int):int { | |
var e:int; | |
var d:int; | |
var f:int; | |
var c:int; | |
var b:int = g_a - 48; | |
g_a = b; | |
b[5]:long = 0L; | |
b[4]:long = 0L; | |
b[3]:long = 0L; | |
b[2]:long = 0L; | |
b[1]:long = 0L; | |
b[0]:long = 0L; | |
if (f_d(a) <= 48) { | |
c = b | 2; | |
f_k(b, a); | |
a = b; | |
loop L_b { | |
b[9]:short = (e = b[9]:ushort) + 1; | |
b[4]:short = b[4]:ushort * (b[3]:ushort | 1); | |
b[10]:short = (d = b[10]:ushort) << 11 | d >> 5; | |
b[1]:short = | |
(d = b[1]:ushort) + b[14]:ushort % ((b[5]:ushort & 15) + 1); | |
b[7]:short = (d = d ^ b[7]:ushort); | |
b[13]:short = b[13]:ushort - (b[8]:ushort | (b[15]:ushort ^ d)); | |
b[2]:short = b[2]:ushort + e / ((d & 65535) + 1); | |
var g:long = c[4]:long@2; | |
var h:long = c[8]:long@2; | |
var i:long = c[12]:long@2; | |
var j:long = c[16]:long@2; | |
d = c[20]:int@2; | |
var k:long = c[0]:long@2; | |
e = b[0]:ushort; | |
a[22]:short = c[22]:ushort; | |
a[20]:int@2 = d; | |
a[16]:long@2 = j; | |
a[12]:long@2 = i; | |
a[8]:long@2 = h; | |
a[4]:long@2 = g; | |
a[0]:long@2 = k; | |
b[23]:short = e; | |
f = f + 1; | |
if (f != 1337) continue L_b; | |
} | |
c = eqz(f_l(a)); | |
} | |
g_a = b + 48; | |
return c; | |
} | |
Notice that the other two functions are basically a strcpy (which 0-sets the rest of the memory) and a strcmp which compares against the "hashed" password in memory. | |
function test_pw(a:int):int { | |
var e:int; | |
var d:int; | |
var f:int; | |
var c:int; | |
var b:int = g_a - 48; //Stack | |
g_a = b; | |
b[5]:long = 0L; | |
b[4]:long = 0L; | |
b[3]:long = 0L; | |
b[2]:long = 0L; | |
b[1]:long = 0L; | |
b[0]:long = 0L; | |
if (strlen(a) <= 48) { | |
c = b + 2; //Because it is not aligned | |
//Sets also remaining chars of b to 0 | |
strcpy(b, a); | |
a=b; | |
//Note that all the accesses have to multiply the index by 2 to get the real index | |
loop L_b { | |
b[9]:short = (e = b[9]:ushort) + 1; | |
b[4]:short = b[4]:ushort * (b[3]:ushort | 1); | |
b[10]:short = (d = b[10]:ushort) << 11 | d >> 5; | |
b[1]:short = | |
(d = b[1]:ushort) + b[14]:ushort % ((b[5]:ushort & 15) + 1); | |
b[7]:short = (d = d ^ b[7]:ushort); | |
b[13]:short = b[13]:ushort - (b[8]:ushort | (b[15]:ushort ^ d)); | |
b[2]:short = b[2]:ushort + e / ((d & 65535) + 1); | |
var g:long = c[4]:long@2; | |
var h:long = c[8]:long@2; | |
var i:long = c[12]:long@2; | |
var j:long = c[16]:long@2; | |
d = c[20]:int@2; | |
var k:long = c[0]:long@2; | |
e = b[0]:ushort; | |
a[22]:short = c[22]:ushort; | |
a[20]:int@2 = d; | |
a[16]:long@2 = j; | |
a[12]:long@2 = i; | |
a[8]:long@2 = h; | |
a[4]:long@2 = g; | |
a[0]:long@2 = k; | |
b[23]:short = e; | |
f = f + 1; | |
if (f != 1337) continue L_b; | |
} | |
c = eqz(strcmppwd_48(b)); | |
} | |
g_a = b + 48; | |
return c; | |
} | |
Now start cleaning up the main loop and make indexes clearer to keep track of dependencies | |
function test_pw(a:int):int { | |
var e:int; | |
var d:int; | |
var f:int; | |
var c:int; | |
var b:int = g_a - 48; //Stack | |
g_a = b; | |
if (strlen(a) <= 48) { | |
c = b + 2; //Because it is not aligned | |
//Sets also remaining chars of b to 0 | |
strcpy(b, a); | |
a=b; | |
loop L_b { | |
e = b[18,19]:ushort | |
b[18,19]:short = e + 1; | |
b[8,9]:short = b[8,9]:ushort * (b[6,7]:ushort | 1); | |
d = b[20,21]:ushort | |
b[20,21]:short = d << 11 | d >> 5; | |
d = b[2,3]:ushort | |
b[2,3]:short = d + b[28,29]:ushort % ((b[10,11]:ushort & 15) + 1); | |
d = d ^ b[14,15]:ushort | |
b[14,15]:short = d; | |
b[26,27]:short = b[26,27]:ushort - (b[16,17]:ushort | (b[30,31]:ushort ^ d)); | |
b[4,5]:short = b[4,5]:ushort + e / ((d & 65535) + 1); | |
var g:long = c[8-15]:long@2; | |
var h:long = c[16-23]:long@2; | |
var i:long = c[24-31]:long@2; | |
var j:long = c[32-39]:long@2; | |
d = c[40-43]:int@2; | |
var k:long = c[0-7]:long@2; | |
e = b[0,1]:ushort; | |
a[44,45]:short = c[44,45]:ushort; | |
a[40-43]:int@2 = d; | |
a[32-39]:long@2 = j; | |
a[24-31]:long@2 = i; | |
a[16-23]:long@2 = h; | |
a[8-15]:long@2 = g; | |
a[0-7]:long@2 = k; | |
b[46,47]:short = e; | |
f = f + 1; | |
if (f != 1337) continue L_b; | |
} | |
c = eqz(strcmppwd_48(b)); | |
} | |
g_a = b + 48; | |
return c; | |
} | |
Reorder instructions to avoid unnecessary dependencies so that the hash can be reversed | |
function test_pw(a:int):int { | |
var e:int; | |
var d:int; | |
var f:int; | |
var c:int; | |
var b:int = g_a - 48; //Stack | |
g_a = b; | |
if (strlen(a) <= 48) { | |
c = b + 2; //Because it is not aligned | |
//Sets also remaining chars of b to 0 | |
strcpy(b, a); | |
a=b; | |
loop L_b { | |
# Variable mixing | |
b[8,9]:short *= (b[6,7]:ushort | 1); | |
b[20,21]:short = b[20,21]:ushort << 11 | b[20,21]:ushort >> 5; | |
b[14,15]:short ^= b[2,3]:ushort; | |
b[26,27]:short -= (b[16,17]:ushort | (b[30,31]:ushort ^ b[14,15]:short)); | |
b[2,3]:short += b[28,29]:ushort % ((b[10,11]:ushort & 15) + 1); | |
b[4,5]:short += b[18,19]:ushort / ((b[14,15]:short & 65535) + 1); | |
b[18,19]:short += 1; | |
#Rotate 2 bytes to the left | |
e = b[0,1]:ushort; | |
b[0-7]:long@2 = b[2-9]:long@2; | |
b[8-15]:long@2 = b[10-17]:long@2; | |
b[16-23]:long@2 = b[18-25]:long@2; | |
b[24-31]:long@2 = b[26-33]:long@2; | |
b[32-39]:long@2 = b[34-41]:long@2; | |
b[40-43]:int@2 = b[42-45]:int@2; | |
b[44,45]:short = b[46,47]:ushort; | |
b[46,47]:short = e; | |
f = f + 1; | |
if (f != 1337) continue L_b; # repeat 1337 times exactly | |
} | |
c = eqz(strcmppwd_48(b)); | |
} | |
g_a = b + 48; | |
return c; | |
} | |
#Implement on python fix a ton of bugs an the result becomes this. | |
import struct | |
def gets(i): | |
global c | |
return struct.unpack("<H",c[i:][:2])[0] | |
def sets(i,v): | |
global c | |
c = c[:i] + struct.pack("<H",v&0xffff) + c[i+2:] | |
rvc={} | |
def revmul(a,b): | |
if (a,b) in rvc: | |
return rvc[(a,b)] | |
for i in range(65536): | |
if ((i*b)& 0xffff) == a: | |
rvc[(a,b)] = i | |
return i | |
b = bytes([0x74, 0x35, 0xbb, 0x86, 0xec, 0xa2, 0x2b, 0xa2, 0xc6, 0x59, 0x20, 0xfa, | |
0xf1, 0xba, 0xdb, 0xbe, 0x41, 0x0b, 0x22, 0xc1, 0xfa, 0x2d, 0xb9, 0x25, | |
0x69, 0x70, 0xc1, 0x28, 0xb4, 0xec, 0x31, 0x36, 0xea, 0x21, 0xd2, 0x9b, | |
0xdd, 0x02, 0x3b, 0x27, 0xfd, 0x02, 0x4d, 0x1b, 0xa9, 0x35, 0xf7, 0x37, | |
0x62, 0x6d, 0x6c, 0x6a, 0x5a, 0x53, 0x42, 0x30, 0x63, 0x6e, 0x6b, 0x73, | |
0x49, 0x48, 0x52, 0x79, 0x65, 0x53, 0x42, 0x6f, 0x59, 0x58, 0x4a, 0x6b, | |
0x5a, 0x58, 0x49, 0x4b, 0x00, 0x48, 0x69, 0x21, 0x00, 0x00, 0x00, 0x00, | |
0x58, 0x04]) | |
c=b[:48] | |
for i in range(1337): | |
c=c[46:]+c[:46] | |
sets(18,gets(18)-1) | |
sets(4,gets(4)-(gets(18)//(((gets(14)&65535)+1)&0xffff))) | |
sets(26,gets(26)+(gets(16)|(gets(30)^gets(14)))) | |
sets(2,gets(2)-(gets(28)%(((gets(10)&15)+1)&0xffff))) | |
sets(14,gets(14)^gets(2)) | |
sets(20,((gets(20)>>11)&0xffff)|((gets(20)<<5)&0xffff)) | |
sets(8,revmul(gets(8),gets(6)|1)) | |
print(c) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment