Skip to content

Reversing

Yeong-won Seo edited this page May 28, 2024 · 4 revisions

Introduction (2024.04.03)

IDA 설치

yay -S ida-free

분석해보기

discord에 올라온 샘플을 분석해보자

Stack/Memory (2024.05.22)

int a;
while (true)
{
    int b;
}
int c;

이 세 변수는 메모리에 어떻게 저장될까?

선형적으로 4바이트씩 할당되어도 좋겠지만, 그랬다가는 가운데의 int b가 무한정 할당될것만 같아 두렵다.

이를 해결하기위해 메모리 스코프스택의 개념을 도입하자.

메모리 스코프

구조적 프로그래밍을 도입하며, 변수를 효과적으로 관리하기 위한 수단으로 메모리 스코프가 등장했다.

C언어 이전 옛 언어들의 문법에는 다음과 같은 구조가 드러난다:

BEGIN
    { do stuff... }
END

위의 BEGINEND로 구성된 쌍은 절 내부의 것들이 절 외부에서 참조되지 못하도록 역할하는데, 같은 역할을 구현하기위해 C언어에는 중괄호가 도입되었다.

int a;
{
    int c;
}
int b;

중괄호 절 외부에서 중괄호 내부에 접근하지 못하기 때문에, int c는 중괄호 절을 벗어났을때, 할당이 해제되는 것이 효율적일 것이다.

또한 중괄호를 사용함으로서 스코프가 열리고 닫히는 구조가 스택의 형태를 띄기 때문에, 이러한 할당을 스택을 통해 관리하면 좋을 것이다.

따라서, C언어에서 (또한 수많은 현대 언어들에서) 변수에 대한 메모리 할당은 다음과 같이 일어난다:

  1. 최외각 스코프의 int a, b가 처음 스택에 push된다.
  2. int c가 포함된 스코프에 진입했을때, 스택에 int c를 push한다.
  3. 스코프를 벗어나면, 스택에서 pop한다.
int a = 0xDEADBEEF;
{
    int c = 0xDEADCAFE;
}
int b = 0xDEADC0DE;

따라서, 위의 코드에 따르면 스택은 다음과 같이 변화한다.

- 1
0 | DEADBEEF
4 | DEADC0DE

- 2
0 | DEADBEEF
4 | DEADC0DE
8 | DEADCAFE

- 3
0 | DEADBEEF
4 | DEADC0DE

Calling Convention

메모리 스코프의 구현, 스택 계산기등을 생각해보면 스택 방식의 언어를 설계한것은 매우 타당해보인다.

그렇다면, 함수의 호출 또한 스택 방식으로 설명해볼 수 있을까?

https://en.wikipedia.org/wiki/Calling_convention

Example

  1. 이 프로그램이 어떤 일을 수행하는지 분석하고 문서화하기
  2. 메모리 할당과 해제를 분석하고 문서화하기
  3. 컴파일된 바이너리를 분석하고 2번의 결과와 비교하여 문서화
  4. 컴파일러 안쓰고 직접 어셈블리로 바꿔보기

할 수 있는 한 높은 단계에 도전해보자!

#include <stdio.h>

int main(void)
{
    while (1)
    {
        int x = 0;
        int y = 1;
        do
        {
            printf("%d\n", x);

            int z = x + y;
            x = y;
            y = z;
        } while (x < 255);
    }
}

Assembly Language (2024.05.29)

NASM 설치하기

$ yay -S nasm

Hello, World!

        section .data
hello:  db 'Hello, World!', 10

        section .text
        global  _start
_start: mov     eax, 4      ; 'write' syscall
        mov     ebx, 1
        mov     ecx, hello
        mov     edx, 14
        int     80h

        mov     eax, 1      ; 'exit' syscall
        mov     ebx, 0
        int     80h
$ nasm -f elf64 hello.asm -o hello.o
$ ld hello.o -o hello
$ ./hello
Hello, World!

Jump

        section .data
hello:  db 'Hello, World!', 10

        section .text
        global  _start
_start: mov     eax, 4      ; 'write' syscall
        mov     ebx, 1
        mov     ecx, hello
        mov     edx, 14
        int     80h
        jmp     _start
$ nasm -f elf64 hello.asm -o hello.o
$ ld hello.o -o hello
$ ./hello
Hello, World!
Hello, World!
Hello, World!
Hello, World!
Hello, World!
Hello, World!
...

Branch

        section .data
hello:  db 'Hello, World!', 10

        section .text
        global  _start
        mov     esi, 0

_start: cmp     esi, 3
        ja      exit

        mov     eax, 4      ; 'write' syscall
        mov     ebx, 1
        mov     ecx, hello
        mov     edx, 14
        int     80h

        inc     esi
        jmp     _start

exit:   mov     eax, 1      ; 'exit' syscall
        mov     ebx, 0
        int     80h
$ nasm -f elf64 hello.asm -o hello.o
$ ld hello.o -o hello
$ ./hello
Hello, World!
Hello, World!
Hello, World!
Hello, World!

Subroutine

        section .data
hello:  db 'Hello, World!', 10

        section .text
        global  _start
_start: call phello
        call phello
        call phello

        mov     eax, 1      ; 'exit' syscall
        mov     ebx, 0
        int     80h

phello: mov     eax, 4      ; 'write' syscall
        mov     ebx, 1
        mov     ecx, hello
        mov     edx, 14
        int     80h
        ret
$ nasm -f elf64 hello.asm -o hello.o
$ ld hello.o -o hello
$ ./hello
Hello, World!
Hello, World!
Hello, World!

See also

Homework

  • 별찍기 (피라미드)
  • 입력이 주어졌을때, 해당 정수를 높이로 가지는 피라미드 출력해보기!