首先看 。
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 leg@pwnable.kr -p2222 (pw:guest)
那就首先下载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;
}
首先看
代码啥意思。。。
int key=0; #这里定义int
printf("Daddy has very strong arm! : ");
scanf("%d", &key); #输入key 值
if( (key1()+key2()+key3()) == key ){
printf("Congratz!\n"); #如果 函数 key 1,2,3 的和为key值。则读取flag
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;
也就说,这道题重点是考3个函数的理解
首先看 函数1
int key1(){
asm("mov r3, pc\n");
}
没啥作用啊。那就只有去看它给的汇编代码了。好难,想放弃
(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 # r3 = pc
0x00008ce0 <+12>: mov r0, r3 # r0= r3
0x00008ce4 <+16>: sub sp, r11, #0 #弹栈
0x00008ce8 <+20>: pop {r11} ; (ldr r11, [sp], #4) #弹出
0x00008cec <+24>: bx lr #返回
End of assembler dump.
也就是说,返回的参数是 r0 =r3=pc = 0x00008cdc +8 =36068
然后是 key2()
这里我看不懂了。。所以场外求助百度。。地址 https://blog.csdn.net/lee_ham/article/details/78398551
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"
);
}
(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
###pc+8+1的值赋给r6,即r6=0x00008cfc+8+1;
0x00008d00 <+16>: bx r6
###有bx指令,这条指令表示r6是跳转的目的地址,并且根据地址的最低位确定是否状态切换。如果末尾是1则切###换到thumb状态,否则保留在asm状态;当前状态下是应该切换到thumb状态
0x00008d04 <+20>: mov r3, pc
### r3=pc
0x00008d06 <+22>: adds r3, #4
### r3=r3+4 ==> r3=0x00008d04+4+4
0x00008d08 <+24>: push {r3}
0x00008d0a <+26>: pop {pc}
0x00008d0c <+28>: pop {r6} ; (ldr r6, [sp], #4)
0x00008d10 <+32>: mov r0, r3 #r0=r3
### PS r0 都是最后的返回值
0x00008d14 <+36>: sub sp, r11, #0
0x00008d18 <+40>: pop {r11} ; (ldr r11, [sp], #4)
0x00008d1c <+44>: bx lr
End of assembler dump.
也就是说 key2()=0x00008d04+4+4=36108
key3 ()
(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(link register)的值赋值给r3,r0;
而lr寄存器中存储的是子函数的返回地址,那么应该在main()函数的反汇编代码中找key3()函数返回后下一条指令地址:
0x00008d7c <+64>: bl 0x8d20 <key3>
也就说 key3()=0x00008d7c <+64>=0x00008d80=36224
加起来
36224+36108+36068=108400
成功
emmm 我记住了。。Dump中 r0是返回参数的寄存器