There is a familiar face here: sym.string_length. Recall in phase 1 I glazed over sym.string_not_equal which had buried inside a call to sym.string_length - if you've been following along at home this is not a surprise. The result of this call (which expects our input string as an argument) should be 6.
cmp eax, 0x6
This is our first clue to solving the riddle.
Peeking ahead a little there are two memory locations referenced directly: sym.array.123 and str.giants. Before we get too far into the details of sym.phase_5 lets look at what each of these contain. Using the memory printing capabilities of radare2 we can do this with: px @ sym.array.123 and ps @ str.giants to get the hex and ASCII representations, respectively.
Not surprisingly str.giants contains the string 'giants' and the content of sym.array.123 is listed below:
Alright, now that we've got some context lets continue with the code.
lea ecx, [ebp-0x8] ; load an empty local array
mov esi, sym.array.123 ; set a pointer to the first element of the memory above
mov al, [edx+ebx] ; target of the jump below
and al, 0xf
movsx eax, al
mov al, [eax+esi]
mov [edx+ecx], al
inc edx
cmp edx, 0x5
jle 0x8048d57
After loading the address of a local array the code enters a loop from 0 to 5 (for the six characters of our input). The body of that loop does the following:
Selects the nth byte from the user input string, masks off the bottom 4 bits, and then uses that as an index into sym.array.123. The byte at that index is then copied to the local array.
mov al, [edx+ebx]
and al, 0xf
movsx eax, al
mov al, [eax+esi]
mov [edx+ecx], al
In C, that might look similar to
char array123[] = "isrveawhobpnutfg", local[6] = {0}, *input = ...;
int i = 0;
for (; i < 6; ++i)
local[i] = array123[input[i] & 0xf];
After the loop the local array is null terminated and compared against str.giants; matching strings avoids triggering the bomb. Now all we need is to determine what indices from sym.array.123 yield the string 'giants.'
Recall the memory stored in sym.array.123 - isrveawhobpnutfg. The necessary index sequence then becomes: 0xf, 0x0, 0x5, 0xb, 0xd, 0x1. Since our ASCII input is masked we need to find ASCII strings with lower-order bits matching these values. I list the valid combinations (for printable ASCII) below:
0xf : / ? O _ o 0x0 : 0 @ P ` p 0x5 : % 5 E U e u 0xb : + ; K [ k { 0xd : - = M ] m } 0x1 : ! 1 A Q a q
Any combination of those values should be a valid input to solve this stage. Let's try one: 'opekma'
Sweet, almost there. Next up is phase 6 the [supposed] last stage...
No comments :
Post a Comment