pwnable.kr [Toddler's Bottle] - 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 下面的函数调用与 x86 下面的函数调用有着相似之处,例如都要保护返回地址、进入子函数执行、执行完成后根据返回地址返回等一系列操作,但是它们有着许多的不同。

关于ARM寄存器结构的基本内容详见我的另外两篇文章:
ARM状态结构小记
ARM寄存器结构小记

ARM属于RISC指令集,不同于 x86 CISC指令集的堆栈传参,ARM 在函数调用时倾向于寄存器传参。一般地,当参数不超过4个时,系统会使用 R0-R4 寄存器进行参数传递,超过四个才会借助堆栈。

ARM的PC永远指向当前执行指令之后的第二条指令,即处于流水线取指阶段的指令,而 x86 的 PC 指向的是当前执行的指令。

调用子函数也和 x86 不同,x86下是使用 CALL 指令,ARM下是使用 BL (带链接跳转,即当前执行指令的下一条指令保存到 R14,并跳转,进入子函数后会将 R14 的值入栈)指令。

关于返回值,x86 使用 EAX 寄存器传递返回值,ARM 使用 R0 传递返回值。

掌握上述基础知识后,这题就迎刃而解了。
先放上题目源码:

#include 
#include 
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;
}
(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 
   0x00008d54 <+24>:    bl  0xfb6c 
   0x00008d58 <+28>:    sub r3, r11, #16
   0x00008d5c <+32>:    ldr r0, [pc, #96]   ; 0x8dc4 
   0x00008d60 <+36>:    mov r1, r3
   0x00008d64 <+40>:    bl  0xfbd8 <__isoc99_scanf>
   0x00008d68 <+44>:    bl  0x8cd4 
   0x00008d6c <+48>:    mov r4, r0
   0x00008d70 <+52>:    bl  0x8cf0 
   0x00008d74 <+56>:    mov r3, r0
   0x00008d78 <+60>:    add r4, r4, r3
   0x00008d7c <+64>:    bl  0x8d20 
   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 
   0x00008d94 <+88>:    ldr r0, [pc, #44]   ; 0x8dc8 
   0x00008d98 <+92>:    bl  0x1050c 
   0x00008d9c <+96>:    ldr r0, [pc, #40]   ; 0x8dcc 
   0x00008da0 <+100>:   bl  0xf89c 
   0x00008da4 <+104>:   b   0x8db0 
   0x00008da8 <+108>:   ldr r0, [pc, #32]   ; 0x8dd0 
   0x00008dac <+112>:   bl  0x1050c 
   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>:           ;  instruction: 0x0006a4b0
   0x00008dcc <+144>:           ;  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) 

可以清楚地看到,key1 函数返回值为 PC:0x00008ce4;key2 函数返回值为 PC + 4: 0x00008d08 + 4 = 0x00008d0c;key3 函数返回值为LR:0x00008d80。
这三个数相加后结果为 0x0001a770 = 108400(d) 。
输入后即可看到flag:

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

你可能感兴趣的:(pwnable.kr [Toddler's Bottle] - leg)