【pwnable.kr】leg

题目描述

#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;
}
(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) 

思路

主要是两个小问题,一个是arm中pc寄存器中存的并不是执行指令的地址,而是取址指令的地址,一般是当前指令处+8/+4的地址。当pc的值被直接改变时,流水线中的预取的指令被清空,重新开始流水线。

在执行第一条指令时,PC寄存器应指向第三条指令。也即,当处理器为三级流水线结构时,PC寄存器总是指向随后的第三条指令。
当处理器处于ARM状态时,每条ARM指令为4个字节,所以PC寄存器的值为当前指令地址 + 8字节
当处理器处于Thumb状态时,每条Thumb指令为2字节,所以PC寄存器的值为当前指令地址 + 4字节
此外,在ARM9中,采用了五级流水线结构,是在ARM7的三级流水线结构后面添加了两个新的过程。因此,指令的执行过程和取指过程还是相隔一个译码过程,因而PC还是指向当前指令随后的第三条指令。

第二个问题就是在key2函数中的pc+1是什么意思。

ARM指令是字对齐(指令的地址后两位为[1:0]=0b00),Thumb是半字对齐(指令的地址后两位为[1:0]=0bx0,x为0或1)。指令的地址的最后一位必为0。
因此bx(不管往ARM还是往Thumb跳转)的跳转指令必须保证指令地址的最后一位为0,上例中bx指令能自动地将目标地址值置为r4的值和0xFFFFFFFE的与后的结果,就会使指令地址的最后一位必为0了。
那么delay+1的这个1不就被0与掉了么,就没有什么作用了?其实,在执行bx指令时,它是首先判断指令地址的后一位为0或1(这样就知道要跳转的地方是ARM还是Thumb指令。0跳转arm,1跳转thumb。),然后再PC=r4 AND 0xFFFFFFFE。这样,当我们需要要跳转到Thumb指令处执行时,必须将指令地址的最后以为置1。而bx再跳转到ARM指令时就无需考虑这些了,就不用像上面的+1处理了。

至于lr寄存器存储的即为返回值。
了解了如上三点很容易计算得到flag。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值