pwnable.kr(8) - leg
Problem
Points: 2 pt
1 | Daddy told me I should study arm. |
Code
1 |
|
1 | (gdb) disass main |
Thinking
Problem provide C code and ARM asm code, just focus on C code first.
Don’t look around and pay attention on main
.
1 | if( (key1()+key2()+key3()) == key ){ |
The is
tells us the result of key1()
, key2()
and key3()
will be answer to the flag.
Let’s solve some ARM!
Before start on ARM, make sure you understance basic ASM instruction and ARM’s pipline & thumb modes.
Reference at here.
Solution
key1()
1 | (gdb) disass key1 |
In order to use register, first push the register’s value into stack.
So <+0>
make a push of r11, and assign sp
to r11
.
Ofcourse, remember to give value back to register from stack and restore sp,
which <+16>
and <+20>
is doing.
So the code will looks like:
1 | 0x00008cdc <+8>: mov r3, pc |
Here <+8>
move pc into r3, before we do that. We should check pc’s value, and it leads us to check the processor’s status is under ARM
or Thumb
.
In order to check that, we should seek any BX
or BLX
instruction before enter this function in main
, which is nothing we can find! looool.
So, ARM status is default for processor, then we can sure the pc will point to current instruction + 8, and that is 0x00008cdc <+12> + 8 = 0x00008ce4
.
Then move r3
to r0
, which is the function’s return value.
After that, a cool bx lr
back to main
.
BUT! this is a bx
which means it may cause status change.
So we need to check what is in lr
to change mode or node.
The value of lr
is the next instruction address before calling key1()
, and that would be 0x00008d6c
, the last bit of lr
is 0
, so we are still under ARM status
.
key2()
1 | (gdb) disass key2 |
Under ARM status
, r11
stores main’s sp
, and r6
is pc + 1
, which pc
is 0x00008cfc <+12> + 8 + 1 = 0x00008d05
.
And than a bx
to exchange status, r6
‘s last bit is 1
, so change to thumb
mode.
Move pc
into r3
, which r3 = 0x00008d04 + 4 = 0x00008d08
.
After that make a adds
to r3
, so right now r3 = 0x00008d0c
.
blah blah blah. and move r3
to r0
.
So the return is 0x00008d0c
Don’t forget <+44>
, check lr
is 0x00008d74
, cool, still under ARM status
.
key3()
1 | (gdb) disass key3 |
Stll ARM status
, the first thing we found is lr
put into r3
, and lr
is 0x00008d80 <+68>
at main
.
And? not, there is no then, that is the return value, looooooooooool.!
Summation
So key1() + key2() + key3()
= 0x00008ce4 + 0x00008d0c + 0x00008d80
which is 0x0001a770
.
If you noticed….
We seems not care about main’s value, but this is the time we should take a look about it.
After key1()
executed, the return value is 0x00008ce4
, this value have been store at r4
, which shows by 0x00008d6c <+48>
.
Also after key2()
executed, 0x00008d0c
been store at r3
.
Here is funny things at <+60>
in main()
, which is 0x00008d78 <+60>: add r4, r4, r3
.
Now, r4 += r3
, we may need this value later, just put it next to you.
After key3()
executed, the return value is 0x00008d80
, and r3
is already been overwrite to it.
And r2 = r4 + r3
, at this point, the r2
stores summation of all three functions.