Self-Improvement
[pwnable.kr] leg 풀이 (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;
}
|
cs |
ARM 리버싱 문제이면서 main에서 각 key1, key2, key3에 대한 반환 값을 더하여 입력 값과 비교하게 된다.
각 key 별로 어셈블 코드도 따로 주어짐으로 자세히 확인해 본다.
Key1
각 함수들의 반환 값은 r0 레지스터에 저장되어 진다.
0x8cdc 라인의 "mov r3, pc"로 arm에서의 pc는 현재 실행(execute)중인 코드 주소가 아닌 fetch 중인 주소를 나타내고 있다. fetch(0x8ce4) -> decode(0x8ce0) -> execute(0x8cdc)
그리하여 Key1의 반환 값은 0x8ce4
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.
|
cs |
참고 : http://recipes.egloos.com/4982170
Key2
여기서도 마지막 부분 0x8d10에서 "mov r0, r3"이 이루어짐으로 r3에 관해서만 집중적으로 본다.
0x8d04에서 "mov r3, pc"로 pc의 값 0x8d08이 r3에 저장되어 진다.
0x8d06에서 "adds r3, #4"로 r3에 4를 더하게 되어 0x8D0C
마지막으로 0x8d10에서 r3의 값이 r0에 저장되어 최종 반환 값은 0x8d0c
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.
|
cs |
Key3
0x8d28의 "mov r3, lr"에서 lr은 함수종료 시 복귀할 주소를 나타낸다고 한다.
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.
|
cs |
lr은 main에서 Key3()함수가 종료된 다음 주소를 확인하면 된다.
Key3의 반환 값은 0x8d80
풀이
각 Key들의 반환 값을 더해서 10진수로 입력해주면 해결 된다.
0x8ce4 + 0x8d0c + 0x8d80 = 0x1A770 (108400)
'ARM' 카테고리의 다른 글
ARM의 함수 포인터(function pointer) 예제 (0) | 2021.01.12 |
---|---|
ARM의 포인터(pointer) 사용예제 [R3] (0) | 2021.01.11 |
IDA에서 ARM의 SUB "-" 부분과 스택(stack) 부분 (0) | 2021.01.11 |
ARM - Socket( bind, socket ) 코드 분석 (htons, htonl) (0) | 2020.12.03 |
ARM 기초 (레지스터 종류, 명령어 등, LDR, STR) (0) | 2020.08.05 |