Self-Improvement

[pwnable.kr] leg 풀이 (ARM 문제) 본문

ARM

[pwnable.kr] leg 풀이 (ARM 문제)

JoGeun 2020. 6. 23. 15:33

 

소스코드

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)