If you were to read the description when you enter the challenge, one would see the following right at the bottom:
This is Software Revision 02. We have received reports that the prior version of the lock was bypassable without knowing the password. We have fixed this and removed the password from memory.
Lol. Lets take a closer look.
Performing a static analysis of the code, one can see that this time round there is no silly
create_password routine or something similar.
4438 <main> 4438: 3150 9cff add #0xff9c, sp 443c: 3f40 b444 mov #0x44b4 "Enter the password to continue.", r15 4440: b012 6645 call #0x4566 <puts> 4444: 0f41 mov sp, r15 4446: b012 8044 call #0x4480 <get_password> 444a: 0f41 mov sp, r15 444c: b012 8a44 call #0x448a <check_password> 4450: 0f93 tst r15
In fact, just a simple
check_password routine before the
tst r15 call at
0x4450. The call to
get_password just ends up with a syscall, prompting you for a password, so that is not really interesting to us. What is interesting though is
448a <check_password> 448a: bf90 4c7e 0000 cmp #0x7e4c, 0x0(r15) 4490: 0d20 jnz $+0x1c 4492: bf90 2142 0200 cmp #0x4221, 0x2(r15) 4498: 0920 jnz $+0x14 449a: bf90 4522 0400 cmp #0x2245, 0x4(r15) 44a0: 0520 jne #0x44ac <check_password+0x22> 44a2: 1e43 mov #0x1, r14 44a4: bf90 587d 0600 cmp #0x7d58, 0x6(r15) 44aa: 0124 jeq #0x44ae <check_password+0x24> 44ac: 0e43 clr r14 44ae: 0f4e mov r14, r15 44b0: 3041 ret
At first sight it looks like the code does a number of compares to values at an offset from the memory address at
r15. Could these be parts of the actual password? Lets inspect with the debugger. Setting a breakpoint at
0x448a and continuing the CPU (entering a password of test when prompted) until we reach it should help in revealing what is happening.
Hah, so after the first
cmp instruction, the status register is
0x4 (N), meaning the jump 14 bytes onwards to
0x44ac will be taken, effectively ending the
check_password routine prematurely. The bytes in
r15 at the time of the first
cmp instruction was
0x439c, which in turn pointed to
0x7465 in the memory dump (visualised with
read r15 in the debugger). The bytes in memory is clearly the password (test in this case) that I entered when I was prompted.
>>> ' '.join([hex(ord(x)) for x in 'test']) '0x74 0x65 0x73 0x74'
So, lets take the bytes in the three
cmp calls and enter that as the password, keeping our breakpoints and seeing what the CPU does then. The six bytes of interest are:
0x7e 0x4c 0x42 0x21 0x22 0x45.
>>> '7e4c42212245'.decode('hex') '~LB!"E'
Resetting the CPU, entering
~LB!"E as password and continuing untill we hit the breakpoint at
0x448a and then stepping past the first
jnz instructions should now look like this:
Hmm. The value
0x7e4c was at
0x439c (the address
r15 points to), but the
cmp call set the status register to
0x4 (N), ending the
check_password function again. :|
What I think this challenge is supposed to teach you is about the endianness of the CPU which means it stores values in little endian format in memory. What that means for us is that that password values should be provided as
0x4c7e instead of as
0x7e4c like we did. So, lets re-arrange the password we enter, and continue to the breakpoint again.
>>> '4c7e21424522'.decode('hex') 'L~!BE"'
Woohoo. This time the
jnz instruction is not taken as the status register is now
0x3 (CZ) and the next values provided as part of the password checked. By now you might think you have won and decide to just continue the CPU to unlock the lock.
Well, no. See, we missed the part where another
cmp happens just after
0x1 is moved into
This means that when
cmp #0x7d58, 0x6(r15) at
0x44a4 is called, we will be comparing to
0x0 (the bytes at
r15+6), resulting in the jump at
0x44aa not being taken, clearing
r14 before the routine finishes.
So, to prevent that adn as a final password, we need to enter those the bytes
0x7d too to unlock the lock.
>>> '4c7e21424522587d'.decode('hex') 'L~!BE"X}'
Continue the CPU and unlock the lock!
L~!BE"X} as ASCII or
4c7e21424522587d as hex encoded input.
For my other write ups in the microcorruption series, checkout this link.