pwnable.kr-leg

题目描述:

Daddy told me I should study arm.
But I prefer to study my leg!

Download : http://pwnable.kr/bin/leg.c
Download : http://pwnable.kr/bin/leg.asm

ssh [email protected] -p2222 (pw:guest)

这题的描述比较有意思,这题主要考察arm的汇编指令,当然此ARM非彼arm(胳膊),leg.c的代码:

#include <stdio.h>
#include <fcntl.h>
int key1(){
 asm("mov r3, pc\n");
}
int key2(){
 asm(
 "push {r6}\n"
 "add r6, pc, $1\n"
 "bx r6\n"
 ".code 16\n"
 "mov r3, pc\n"
 "add r3, $0x4\n"
 "push {r3}\n"
 "pop {pc}\n"
 ".code 32\n"
 "pop {r6}\n"
 );
}
int key3(){
 asm("mov r3, lr\n");
}
int main(){
 int key=0;
 printf("Daddy has very strong arm! : ");
 scanf("%d", &key);
 if( (key1()+key2()+key3()) == key ){
 printf("Congratz!\n");
 int fd = open("flag", O_RDONLY);
 char buf[100];
 int r = read(fd, buf, 100);
 write(0, buf, r);
 }
 else{
 printf("I have strong leg :P\n");
 }
 return 0;
}

leg.asm的代码:

(gdb) disass main
Dump of assembler code for function main:
 0x00008d3c <+0>: push {r4, r11, lr}
 0x00008d40 <+4>: add r11, sp, #8
 0x00008d44 <+8>: sub sp, sp, #12
 0x00008d48 <+12>: mov r3, #0
 0x00008d4c <+16>: str r3, [r11, #-16]
 0x00008d50 <+20>: ldr r0, [pc, #104] ; 0x8dc0 <main+132>
 0x00008d54 <+24>: bl 0xfb6c <printf>
 0x00008d58 <+28>: sub r3, r11, #16
 0x00008d5c <+32>: ldr r0, [pc, #96] ; 0x8dc4 <main+136>
 0x00008d60 <+36>: mov r1, r3
 0x00008d64 <+40>: bl 0xfbd8 <__isoc99_scanf>
 0x00008d68 <+44>: bl 0x8cd4 <key1>
 0x00008d6c <+48>: mov r4, r0
 0x00008d70 <+52>: bl 0x8cf0 <key2>
 0x00008d74 <+56>: mov r3, r0
 0x00008d78 <+60>: add r4, r4, r3
 0x00008d7c <+64>: bl 0x8d20 <key3>
 0x00008d80 <+68>: mov r3, r0
 0x00008d84 <+72>: add r2, r4, r3
 0x00008d88 <+76>: ldr r3, [r11, #-16]
 0x00008d8c <+80>: cmp r2, r3
 0x00008d90 <+84>: bne 0x8da8 <main+108>
 0x00008d94 <+88>: ldr r0, [pc, #44] ; 0x8dc8 <main+140>
 0x00008d98 <+92>: bl 0x1050c <puts>
 0x00008d9c <+96>: ldr r0, [pc, #40] ; 0x8dcc <main+144>
 0x00008da0 <+100>: bl 0xf89c <system>
 0x00008da4 <+104>: b 0x8db0 <main+116>
 0x00008da8 <+108>: ldr r0, [pc, #32] ; 0x8dd0 <main+148>
 0x00008dac <+112>: bl 0x1050c <puts>
 0x00008db0 <+116>: mov r3, #0
 0x00008db4 <+120>: mov r0, r3
 0x00008db8 <+124>: sub sp, r11, #8
 0x00008dbc <+128>: pop {r4, r11, pc}
 0x00008dc0 <+132>: andeq r10, r6, r12, lsl #9
 0x00008dc4 <+136>: andeq r10, r6, r12, lsr #9
 0x00008dc8 <+140>: ; <UNDEFINED> instruction: 0x0006a4b0
 0x00008dcc <+144>: ; <UNDEFINED> instruction: 0x0006a4bc
 0x00008dd0 <+148>: andeq r10, r6, r4, asr #9
End of assembler dump.
(gdb) disass key1
Dump of assembler code for function key1:
 0x00008cd4 <+0>: push {r11} ; (str r11, [sp, #-4]!)
 0x00008cd8 <+4>: add r11, sp, #0
 0x00008cdc <+8>: mov r3, pc
 0x00008ce0 <+12>: mov r0, r3
 0x00008ce4 <+16>: sub sp, r11, #0
 0x00008ce8 <+20>: pop {r11} ; (ldr r11, [sp], #4)
 0x00008cec <+24>: bx lr
End of assembler dump.
(gdb) disass key2
Dump of assembler code for function key2:
 0x00008cf0 <+0>: push {r11} ; (str r11, [sp, #-4]!)
 0x00008cf4 <+4>: add r11, sp, #0
 0x00008cf8 <+8>: push {r6} ; (str r6, [sp, #-4]!)
 0x00008cfc <+12>: add r6, pc, #1
 0x00008d00 <+16>: bx r6
 0x00008d04 <+20>: mov r3, pc
 0x00008d06 <+22>: adds r3, #4
 0x00008d08 <+24>: push {r3}
 0x00008d0a <+26>: pop {pc}
 0x00008d0c <+28>: pop {r6} ; (ldr r6, [sp], #4)
 0x00008d10 <+32>: mov r0, r3
 0x00008d14 <+36>: sub sp, r11, #0
 0x00008d18 <+40>: pop {r11} ; (ldr r11, [sp], #4)
 0x00008d1c <+44>: bx lr
End of assembler dump.
(gdb) disass key3
Dump of assembler code for function key3:
 0x00008d20 <+0>: push {r11} ; (str r11, [sp, #-4]!)
 0x00008d24 <+4>: add r11, sp, #0
 0x00008d28 <+8>: mov r3, lr
 0x00008d2c <+12>: mov r0, r3
 0x00008d30 <+16>: sub sp, r11, #0
 0x00008d34 <+20>: pop {r11} ; (ldr r11, [sp], #4)
 0x00008d38 <+24>: bx lr
End of assembler dump.
(gdb) 

这题的代码其实很简单,我们输入的key,需要让他满足其值为key1(), key2(), key3()三个函数返回值的和,这里需要对三个函数分别进行分析:

首先是key1:

Dump of assembler code for function key1:
 0x00008cd4 <+0>: push {r11} ; (str r11, [sp, #-4]!)
 0x00008cd8 <+4>: add r11, sp, #0
 0x00008cdc <+8>: mov r3, pc
 0x00008ce0 <+12>: mov r0, r3
 0x00008ce4 <+16>: sub sp, r11, #0
 0x00008ce8 <+20>: pop {r11} ; (ldr r11, [sp], #4)
 0x00008cec <+24>: bx lr

在ARM汇编中,子函数通常是通过寄存器r0返回函数的返回值,所以这里我们看r0的值,r0等于r3,r3等于pc的值,关于pc的说明,请见:http://blog.sina.com.cn/s/blog_bcdac52b0101nf7j.html

所以这里r0也就是key1的值为0x8cdc+8

接着是key2:

Dump of assembler code for function key2:
 0x00008cf0 <+0>: push {r11} ; (str r11, [sp, #-4]!)
 0x00008cf4 <+4>: add r11, sp, #0
 0x00008cf8 <+8>: push {r6} ; (str r6, [sp, #-4]!)
 0x00008cfc <+12>: add r6, pc, #1
 0x00008d00 <+16>: bx r6
 0x00008d04 <+20>: mov r3, pc
 0x00008d06 <+22>: adds r3, #4
 0x00008d08 <+24>: push {r3}
 0x00008d0a <+26>: pop {pc}
 0x00008d0c <+28>: pop {r6} ; (ldr r6, [sp], #4)
 0x00008d10 <+32>: mov r0, r3
 0x00008d14 <+36>: sub sp, r11, #0
 0x00008d18 <+40>: pop {r11} ; (ldr r11, [sp], #4)
 0x00008d1c <+44>: bx lr
End of assembler dump.

key2中r0的值也是来自r3,r3等于偏移20处的pc的值,然后下一行再加上4,这里需要注意的是,这里有一个bx,关于bx,请见:http://blog.csdn.net/liuchao1986105/article/details/6539728

在c代码中我们也可以看到.code的伪指令,来表明是ARM指令和thumb指令之间的切换,所以这里的pc统统都变成了当前地址+4,因为指令集由ARM的32位的指令变成16指令,对应的指令长度变成了原来的一半,所以这里r0也就是key2的值为0x8d04+4+4

最后是key3:

Dump of assembler code for function key3:
 0x00008d20 <+0>: push {r11} ; (str r11, [sp, #-4]!)
 0x00008d24 <+4>: add r11, sp, #0
 0x00008d28 <+8>: mov r3, lr
 0x00008d2c <+12>: mov r0, r3
 0x00008d30 <+16>: sub sp, r11, #0
 0x00008d34 <+20>: pop {r11} ; (ldr r11, [sp], #4)
 0x00008d38 <+24>: bx lr
End of assembler dump.

这里r0等于r3就是等于lr的值,关于lr指令,一般它的值等于:1、子函数的返回地址;2、发生异常时pc-4,这里lr保证了程序能够正常运行,由于这里程序并没有异常,所以这里保存的是key3()函数的返回地址,也就是:0x8d80

所以最终key的值应该为0x8cdc+8+0x8d04+4+4+0x8d80=108400

然后输入这个key,就能成功获得flag:

/ $ ./leg
Daddy has very strong arm! : 108400
Congratz!
My daddy has a lot of ARMv5te muscle!

最终的flag为:

My daddy has a lot of ARMv5te muscle!

About the Author

admin

Leave a Reply

Your email address will not be published. Required fields are marked *