avatar

pwnable.kr-leg-arm基础

分析

题目说是arm相关,并给出了源代码与程序,我们来看一看

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
#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;
}

逻辑很简单,就是三个函数的返回值相加要等于我们输入的key,使用了c语言内联arm汇编,同时题目给出了用gdb整出来的反汇编文件http://pwnable.kr/bin/leg.asm

基础知识可以参考ARM架构简介

key1

1
2
3
4
5
6
7
8
9
10
(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.

这里我们可以发现光有基础知识还不够,所以补充知识

寄存器pc(r15)在arm状态下(指令长度为4,RISC等长指令集),总是指向当前指令(正在执行)+8处

故分析可得,执行 0x00008cdc 后,r3内的值为 0x00008ce4

可得返回值r0的值为 0x00008ce4

key2

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
(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.

这里 +8 的地方熟悉保存一波 r6,然后 +12 指令实际上是 r6 = pc+1,需要注意的是bx跳转的时候是跳转到 +20,因为指令地址会先和0xFFFFFFFE进行按位与,因为最后一位肯定是0,因此最后一位用于做标志位,bx执行时如果地址最后一位是0,表示跳到arm状态,1则跳到thumb态,而在thumb态下,每条指令2字节长,故 +20 执行后,r3的值为 0x00008d08 ,然后 r3+=4 并传值给r0

故返回值r0 = 0x00008d0c

key3

1
2
3
4
5
6
7
8
9
10
(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.

这里需要关注的是lr寄存器,而lr用于保存子程序的返回地址

1
2
0x00008d7c <+64>:	bl	0x8d20 <key3>
0x00008d80 <+68>: mov r3, r0

故此时 lr 的值为 0x00008d80

可得返回值r0 = 0x00008d80

exp

可得 0x00008ce4 + 0x00008d0c + 0x00008d80 = 0x1a770 = 108400

直接输入即可

参考:

文章作者: 0bs3rver
文章链接: http://yoursite.com/2021/04/24/pwnable-kr-leg-arm%E5%9F%BA%E7%A1%80/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 0bs3rver的小屋