Layer7 리버싱 2차시

Layer7 리버싱 2차시 과제 정리

수업 내용 정리

Calling Convention

호출 규약은 함수를 호출할 때 인자를 전달하는 방식이다.

호출 규약은 여러 가지가 있는데, 아키텍처마다도 다르다.

x86 : 스택을 사용하여 인자를 전달한다. 예로는 cdecl, stdcall, fastcall 등이 있다.

x64 : 인자로 레지스터를 사용하는 경우가 많고, 인자가 많은 경우에는 스택을 사용한다. 예로는 SYSV, MSCV 등이 있다.


cdecl (x86)

cdecl에서는 함수가 호출되면 인자를 스택에 저장하고, RET를 저장한 뒤 함수 주소로 이동하게 된다. 함수 종료시 Caller로 이동 후 스택을 정리한다.

RET가 스택에 저장되므로 BOF 공격에 이용될 수 있다.


stdcall (x86)

Win32API에서 사용되는 호출 규약으로, Callee가 스택을 정리하기 때문에 안정성이 높지만 가변 인자를 사용할 수 없다.


fastcall (x86)

cdecl과 다르게 fastcall은 인자 2개까지는 ECXEDX에 저장해서 전달할 수 있다. 나머지는 스택을 이용해 전달한다.


SYSV (x64)

리눅스에서 사용되는 호출 규약으로 레지스터 6개까지 인자로 사용할 수 있고(rdi, rsi, rdx, rcx, r8, r9) 나머지는 스택을 사용한다. (스택은 16바이트씩 정렬)




백준 5문제 선택 풀이 후 x86asm으로 풀이


2438 | 별 찍기 - 1


문제

문제 링크

첫째 줄에는 별 1개, 둘째 줄에는 별 2개, N번째 줄에는 별 N개를 찍는 문제


Clang 코드

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
#include <stdio.h>

int main() {

  int n;

  scanf("%d", &n);

  for (int i = 0; i < n; i++) {
    for (int j = 0; j <= i; j++) {
      putchar('*');
    }
    putchar('\n');
  }

  return 0;
}

풀이

이중 반복문으로 간단히 구현할 수 있다. 외부 반복문에서는 개행을 출력하고 내부 반복문에서는 별을 출력하도록 하였다.


x86asm 코드

 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
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
section .data
        star db '*'
        newline db 0x0A
        num db 4 dup(0)

section .text
        global main

main:
        call read
        call str_to_int
        call main_
        mov eax, 0
        ret

read:
        mov eax, 3
        mov ebx, 0
        mov ecx, num
        mov edx, 4
        int 0x80

str_to_int:
        xor ecx, ecx
        mov esi, num
        call .loop      
        ret

.loop:
        movzx edx, byte [esi]
        sub edx, 0x30
        imul ecx, ecx, 10
        add ecx, edx
        inc esi
        cmp byte[esi], 0x0A
        jne .loop
        ret
        
main_:
        xor eax, eax
        call .loop
        ret
        
.loop:
        push ecx
        inc eax
        mov ecx, eax
        push eax
        call .loop_
        call print_newline
        pop eax
        pop ecx
        loop .loop
        ret

.loop_:
        push ecx
        call print_star
        pop ecx
        loop .loop_
        ret

print_star:
        mov eax, 4
        mov ebx, 1
        mov ecx, star
        mov edx, 1
        int 0x80
        ret

print_newline:
        mov eax, 4
        mov ebx, 1
        mov ecx, newline
        mov edx, 1
        int 0x80
        ret

풀이

data section에는 출력할 별과 개행 문자, 숫자를 입력받을 버퍼(3자리 + 개행 문자 = 4byte)를 선언해주었다.

백준 온라인 저지에서는 main 함수에서 0이 반환되어야 정상적으로 종료되기 때문에 시작 함수를 main으로 선언하였다.

main 함수에서는 read, str_to_int, main_ 순으로 호출한 뒤 eax에 0을 저장하여 반환하였다. (return 0;)

read : sys_read()를 호출하여 입력받은 숫자(문자열)를 num에 저장하였다.

str_to_int : 입력받은 문자열을 숫자로 변환하는 함수를 구현하였다. esinum의 포인터를 저장해두고 한 바이트씩 가져와 0x30을 빼서 원래 숫자 값을 구하고 10을 곱해 저장하는 것을 개행 문자까지 반복하였다.

main_ : 외부 반복문에서는 ecx를 카운터로 사용하여 num 만큼 내부 반복문을 호출하고 개행 문자를 출력하는 것을 반복하였다. 내부 반복문에서는 eax를 카운터로 사용하여 ecx에 복사한 뒤 별을 반복하여 출력하도록 하였다.


1000 | A+B

문제

문제 링크

두 정수 A와 B를 입력받은 다음, A+B를 출력하는 프로그램을 작성하시오.

Clang 코드

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
#include <stdio.h>

int main() {
    int a, b;
    
    scanf("%d %d", &a, &b);
    printf("%d", a + b);
    
    return 0;
}

풀이

ab를 입력받아 합을 출력하였다.


x86asm 코드

 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
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
section .data
        num db 3 dup(0)
        buf db 2 dup(0)

section .text
        global main
        
main:
        call read
        call main_

        mov eax, 0
        ret

read:
        mov eax, 3
        mov ebx, 0
        mov ecx, num
        mov edx, 3
        int 0x80
        ret

main_:
        movzx eax, byte [num]
        movzx ecx, byte [num+2]
        add eax, ecx
        sub eax, 0x60        

        cmp eax, 10
        jae .tmp

        add eax, 0x30
        mov byte [buf], 0
        mov byte [buf+1], al
        
        mov esi, buf
        inc esi
        
        call print2
        ret

.tmp:
        add eax, 0x26
        mov byte [buf], 0x31
        mov byte [buf+1], al
        
        call print1
        ret

print1:
        mov eax, 4
        mov ebx, 1
        mov ecx, buf
        mov edx, 2
        int 0x80
        ret
        
print2:
        mov eax, 4
        mov ebx, 1
        mov ecx, esi
        mov edx, 1
        int 0x80
        ret

풀이

main 함수에서 read 함수와 main_ 함수를 호출하였다.

read : sys_read()를 호출하도록 하였다.

main_ : 입력받은 3 바이트짜리 버퍼에서 첫 번째 바이트와 마지막 바이트를 가져와 더해주었다. 만약 10 이상이면 두 자리로 바꾸어 출력하고 아니면 한 자리만 출력하도록 하였다.


2557 | Hello World


문제

문제 링크

Hello World!를 출력하시오.


Clang 코드

1
2
3
4
5
6
#include <stdio.h>

int main() {
        printf("Hello World!");
        return 0;
}

풀이

“Hello World!“를 출력하였다.


x86asm 코드

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
section .data
        msg db "Hello World!"

section .text
        global main

main:
        mov eax, 4
        mov ebx, 1
        mov ecx, msg
        mov edx, 12
        int 0x80

        mov eax, 0
        ret

풀이

msg 변수에 “Hello World!“를 저장하고 sys_write를 호출하여 출력하였다.



10171 | 고양이

문제

문제 링크

아래 예제와 같이 고양이를 출력하시오.


Clang 코드

1
2
3
4
5
6
7
8
#include <stdio.h>

int main() {

    printf("\\    /\\\n )  ( ')\n(  /  )\n \\(__)|\n");
    
        return 0;
}

풀이

이스케이프 문자를 통해 특수 문자를 빠짐없이 출력하였다.


x86asm 코드

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
section .data
        msg db "\    /\", 0x0A, " )  ( ')", 0x0A, "(  /  )", 0x0A, " \(__)|"

section .text
        global main

main:
        mov eax, 4
        mov ebx, 1
        mov ecx, msg
        mov edx, 32
        int 0x80

        mov eax, 0
        ret

풀이

개행 문자를 추가하여 sys_write를 호출하였다.


5338 | 마이크로소프트 로고

문제

문제 링크

마이크로소프트 로고를 예제 출력처럼 출력하는 프로그램을 작성하시오.

Clang 코드

1
2
3
4
5
6
7
8
#include <stdio.h>

int main() {

    printf("       _.-;;-._\n'-..-'|   ||   |\n'-..-'|_.-;;-._|\n'-..-'|   ||   |\n'-..-'|_.-''-._|");

    return 0;
}

풀이

개행 문자를 추가하여 한 줄로 출력하였다.


x86asm 코드

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
section .data
        msg db "       _.-;;-._", 0x0A, "'-..-'|   ||   |", 0x0A, "'-..-'|_.-;;-._|", 0x0A, "'-..-'|   ||   |", 0x0A, "'-..-'|_.-''-._|"

section .text
        global main

main:
        mov eax, 4
        mov ebx, 1
        mov ecx, msg
        mov edx, 83
        int 0x80

        xor eax, eax
        ret

풀이

개행 문자의 아스키 코드인 0x0A를 추가하여 msg에 저장한 뒤, sys_write를 호출하였다




Dreamhack x86-assembly-2 학습