Search

1장 : Introduction: Reverse Engineering

대분류
보안
소분류
기초 리버싱
유형
컴파일러
인터프리터
컴파일
최종 편집 일시
2024/11/02 10:23
생성 일시
2022/09/07 00:35
15 more properties

리버스 엔지니어링(Reverse Engineering) : 역공학

기계어(Machine Language) : 컴퓨터의 언어 →
어셈블러(번역장치) →
어셈블리어(Assembly Language) : 번역된 저급 언어
컴파일러(Compiler)
고급 언어(C, C++, C#…)
바이너리 = 프로그램

컴파일러와 인터프리터

프로그래밍 언어
고급 언어 : C, C++, Go
저급 언어 : 어셈블리어, 기계어
컴파일 : CPU가 수행해야할 명령들을 프로그래밍 언어로 작성한 것(소스코드)를 기계어 형식으로 번역하는 것
인터프리팅 : 사용자의 입력, 또는 사용자가 작성한 스크립트를 그때 그때 번역하여 CPU에 전달하는 것

컴파일 과정

전처리(Preprocessing)

컴파일러가 소스 코드를 어셈블리어로 컴파일하기 전에, 필요한 형식으로 가공하는 과정
1.
주석 제거
주석 : 개발자가 자신과 개발자들의 코드 이해를 돕기위해 작성하는 메모
주석은 프로그램의 동작과 상관이 없으므로 전처리 단계에서 모두 제거
2.
매크로 치환
#define으로 정의한 매크로 : 자주 쓰이는 코드나 상숫값을 단어로 정의한 것
전처리 과정에서 매크로의 이름은 값으로 치환
3.
파일 병합
일반적인 프로그램은 여러 개의 소스와 헤더 파일로 이루어져 있습니다.
컴파일러는 이를 따로 컴파일해 합치기도 하지만, 어떠한 경우는 전처리 단계에서 파일을 합치고 컴파일하기도 함.
// Name: add.c #include "add.h" #define HI 3 int add(int a, int b) { return a + b + HI; } // return a+b
C
복사
// Name: add.h int add(int a, int b);
C
복사
전처리
$ gcc -E add.c > add.i $ cat add.i
Bash
복사
add.i
# 1 "add.c" # 1 "<built-in>" # 1 "<command-line>" # 31 "<command-line>" # 1 "/usr/include/stdc-predef.h" 1 3 4 # 32 "<command-line>" 2 # 1 "add.c" # 1 "add.h" 1 int add(int a, int b); # 2 "add.c" 2 int add(int a, int b) { return a + b + 3; }
Assembly
복사

컴파일(Compile)

C로 작성된 소스 코드를 어셈블리어로 번역하는 것.
이 과정에서 컴파일러는 소스 코드의 문법을 검사하는데, 코드에 문법적 오류가 있다면 컴파일을 멈추고 에러를 출력
// Name: opt.c // Compile: gcc -o opt opt.c -O2 #include <stdio.h> int main() { int x = 0; for (int i = 0; i < 100; i++) x += i; // x에 0부터 99까지의 값 더하기 printf("%d", x); }
C
복사
0x0000000000000560 <+0>: lea rsi,[rip+0x1bd] ; 0x724 0x0000000000000567 <+7>: sub rsp,0x8 0x000000000000056b <+11>: mov edx,0x1356 ; hex((0+99)*50) = '0x1356' = sum(0,1,...,99) 0x0000000000000570 <+16>: mov edi,0x1 0x0000000000000575 <+21>: xor eax,eax 0x0000000000000577 <+23>: call 0x540 <__printf_chk@plt> 0x000000000000057c <+28>: xor eax,eax 0x000000000000057e <+30>: add rsp,0x8 0x0000000000000582 <+34>: ret
Assembly
복사
어셈블리 코드 컴파일 (add.S)
$ gcc -S add.i -o add.S $ cat add.S
Bash
복사
.file "add.c" .intel_syntax noprefix .text .globl add .type add, @function add: .LFB0: .cfi_startproc push rbp .cfi_def_cfa_offset 16 .cfi_offset 6, -16 mov rbp, rsp .cfi_def_cfa_register 6 mov DWORD PTR -4[rbp], edi mov DWORD PTR -8[rbp], esi mov edx, DWORD PTR -4[rbp] mov eax, DWORD PTR -8[rbp] add eax, edx add eax, 3 pop rbp .cfi_def_cfa 7, 8 ret .cfi_endproc .LFE0: .size add, .-add .ident "GCC: (Ubuntu 7.5.0-3ubuntu1~18.04) 7.5.0" .section .note.GNU-stack,"",@progbits
Assembly
복사

어셈블(Assemble)

컴파일로 생성된 어셈블리어 코드를 ELF형식(윈도우는 PE형식)의 목적 파일(Object file)로 변환하는 과정
*ELF : 리눅스의 실행파일 형식
목적파일로 변환 (add.o)
$ gcc -c add.S -o add.o $ file add.o add.o: ELF 64-bit LSB relocatable, x86-64, version 1 (SYSV), not stripped $ hexdump -C add.o 00000000 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00 |.ELF............| 00000010 01 00 3e 00 01 00 00 00 00 00 00 00 00 00 00 00 |..>.............| 00000020 00 00 00 00 00 00 00 00 10 02 00 00 00 00 00 00 |................| 00000030 00 00 00 00 40 00 00 00 00 00 40 00 0b 00 0a 00 |....@.....@.....| 00000040 55 48 89 e5 89 7d fc 89 75 f8 8b 55 fc 8b 45 f8 |UH...}..u..U..E.| 00000050 01 d0 5d c3 00 47 43 43 3a 20 28 55 62 75 6e 74 |..]..GCC: (Ubunt| 00000060 75 20 37 2e 35 2e 30 2d 33 75 62 75 6e 74 75 31 |u 7.5.0-3ubuntu1| 00000070 7e 31 38 2e 30 34 29 20 37 2e 35 2e 30 00 00 00 |~18.04) 7.5.0...| 00000080 14 00 00 00 00 00 00 00 01 7a 52 00 01 78 10 01 |.........zR..x..| 00000090 1b 0c 07 08 90 01 00 00 1c 00 00 00 1c 00 00 00 |................| 000000a0 00 00 00 00 14 00 00 00 00 41 0e 10 86 02 43 0d |.........A....C.| 000000b0 06 4f 0c 07 08 00 00 00 00 00 00 00 00 00 00 00 |.O..............| ...
Bash
복사

링크(Link)

여러 목적 파일들을 연결하여 실행 가능한 바이너리로 만드는 과정
// Name: hello-world.c // Compile: gcc -o hello-world hello-world.c #include <stdio.h> int main() { printf("Hello, world!"); }
C
복사
$ gcc add.o -o add -Xlinker --unresolved-symbols=ignore-in-object-files $ file add add: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/l, ...
Bash
복사