乱七八糟的pwn入门(九)——8.leg

  • 审题

    首先看题目:

    他说让学习arm,那么问题来了,arm是啥?首先排除字面意思“胳膊”。又看到他给了汇编代码,emmm,可能跟汇编有关系。

    那先放一放这个问题,看看提供的代码吧。

    首先是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;
}

    然后是汇编代码:

(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) 

    从C的代码不难看出,只要输入的key值跟key1、key2、key3函数返回值之和相等即可。而key1/2/3的内容都是汇编。那么接下来就要解决一开始的问题,arm和汇编的关系。

  • arm汇编

    把arm和汇编放一起搜一下,确实有这么个东西,叫arm汇编。我真是个小天才。

    arm同intel一样也是一种处理器,但是arm的不同在于,它包含的指令集更小,但寄存器更多。

    我就学了一些与本题相关的知识点,列举如下:

    arm寄存器

    首先需要弄明白它都有哪些寄存器,每个寄存器都是干嘛的,有大佬列了个表,我就直接截图放下面了,参考链接见最后。

    然后是

    arm寄存器与intel寄存器的对照

    关于这道题,需要知道的就是R0寄存器存放的是函数返回值,LR寄存器存放的是函数返回地址,R1-R10都是通用寄存器,PC寄存器放的是下一条指令的地址就可以了。

    但是,重点来了!PC寄存器存放的并不是当前指令的下一条指令的地址。这是因为arm处理器采用了三级流水线结构,包括执行(execute)、译码(decode)、取指(fetch)三级。当前指令处在执行级,下一条指令处在译码级,再下一条指令处在取指级。而PC寄存器存放的是处于取指级指令的地址,也就是当前指令的下下一条指令的地址。

    arm汇编指令:

    除了寄存器以外,还需要知道arm汇编的指令含义,如下表:

    arm模式和thumb模式:

    arm处理器有两种主要的操作状态,分别是arm模式和thumb模式。

    这道题需要知道的主要就是,arm模式的指令集宽度是32位,thumb模式的指令集宽度是16位;

    还有就是如果要从arm模式切换到thumb模式时,可以使用BX或BLX指令,将目的寄存器最低位置1。

    掌握了以上的基础知识,基本就可以解这道题了,一共三个函数,一个一个看。

    这里面主要是看R0寄存器存放了哪些内容,这个内容就是返回值。

    key1很好理解,就是把PC寄存器的值传给R3,再把R3的值传给R0,所以返回的就是传PC值时,PC的值,也就是当前指令的下下一条指令的地址。传PC值指令的地址为0x00008cdc,它下下一条指令的地址就是0x00008ce4;

    key2,这里就用到了arm模式和thumb模式的切换,开头三条指令就是将BX的目的寄存器最低位置1,从而从arm模式切换到thumb模式。这一点可以从C代码中的“.code 16”看出,以及从汇编中BX指令后的指令宽度从4字节变成2字节看出。然后看到R0寄存器存放的是R3的值,所以只需看后面对R3寄存器的操作即可。可以看出,R3寄存器首先存放了PC的值0x00008d08,又在此基础上加了4。所以key2的返回值就是0x00008d0c。

    key3是将LR寄存器的内容传给了R0,已经知道LR寄存器存的是函数的返回地址,也就是函数调用指令的后一条指令的地址,这里就是0x00008d80。

    综上,key1+key2+key3=0x0001a770,转化成十进制就是108400。

    运行程序,输入108400,拿到flag,搞定!

  • 参考链接

    https://www.cnblogs.com/hilfloser/p/10516610.html

    https://etenal.me/archives/972#C9

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值