[pwnable.kr] leg

이동화·2025년 7월 21일


ARM 아키텍처의 어셈블리로 코드를 구성했다.

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");
}

사용된 레지스터
LR (R14) : subroutine 이후 돌아갈 리턴 주소를 저장
PC (R15) : x86의 것과 다르게, 현재 fetch되고 있는 명령의 주소를 가리킨다. 즉 현재 실행되는 명령어의 다음 주소 (+8)을 의미한다.
SP (R13) : stack pointer
R0~R12 : 함수 호출 인자를 전달
R0 : eax같은 함수 리턴 값 저장

사용된 명령어들은 intel의 어셈과 크게 다른것은 없어보이지만,
bx 명령어는 서브 루틴에서 복귀하며 LR의 값을 PC에 저장하여 복귀하는 명령어 (asm<->thumb 모드 오갈때 쓰이는듯)
.code 명령어는 code section을 어떤 모드로 조합할지를 지정해주는 역할로, ARM에는 thumb-16 모드와 ARM-32 모드가 있다고 하여 그 둘을 오갈 때 저걸 붙여주는 것 같다.

이를 바탕으로, 리턴값들을 알아야 하기 때문에 r0에 들어가는 값을 위주로 key 함수들의 반환값을 살펴보면,

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

0x8cdc + 8 = 0x8ce4

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

r6 = 0x8cf8 + 8 + 1
r3 = 0x8d04+4+4

최종적으로 r0에 들어가는 값은 r3이기 때문에 0x8d0c

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

LR = 함수가 돌아갈 리턴 주소이기 때문에 main 함수를 보면

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

0x8d80이다.

셋을 전부 더하면 108400이고, 이를 입력으로 넣어주면 flag를 얻을 수 있다.

key2 함수에서 r6 레지스터의 값을 조작하는 부분이 있는데, 이는 thumb 모드로 전환하면서 branch 대상 주소의 최하위 비트를 1로 세팅해서 CPU에서 thumb 모드로 전환했음을 알리기 위한 신호를 구현하는 과정이다. CPU는 주소에서 lsb가 1인 것으로 모드를 판별하기 때문에 bx 이후가 실질적인 코드이다.

daddy_has_lot_of_ARM_muscl3

profile
notion이 나은듯

0개의 댓글