해당 게시물은 드림핵의 강좌 내용을 정리한 것이다. 예제 코드는 포함하지 않았다.
Ⅰ. 서론
기계어(Machine Language) : 컴퓨터에게 명령을 내리기 위한 언어
어셈블리어(Assembly Language) : 0과 1을 대신한 사람이 이해하기 쉬운 언어
어셈블러(Assembler) : 어셈블리어를 기계어로 번역해주는 프로그램
컴파일러(Compiler) : C, C++, GO, Rust과 같은 어셈블리어보다 이해하기 쉬운 언어들을 번역해주는 프로그램
고급 언어(High-Level Language) : 사람이 이해하기 쉬운 언어
저급 언어(Low-Level Language) : 컴퓨터가 이해하기 쉬운 언어
Ⅱ. 프로그램과 컴파일
▶ 프로그램(Program) : 연산 장치가 수행해야 하는 동작을 정의한 일종의 문서
사용자가 정의한 프로그램을 해석하여 명령어를 처리할 수 있는 연산 장치를 programmable 하다고 한다.
→ 현대의 컴퓨터 : programmable 연산 장치
→ 일반 계산기 : non-programmable 연산 장치
과거에는 프로그램을 내부 저장 장치에 저장이 불가능 했음
→ 사람이 전선을 직접 연결해 컴퓨터로 전달
→ 천공 카드(Punched card)에 프로그램을 기록해 재사용
애니악(ENIAC) : 전자의 방식을 사용한 컴퓨터. 프로그램이 바뀔 때마다 배선을 재배치해야 했으므로 매우 비효율적이었고, 크기가 큰 프로그램 사용에도 어려움이 있었음.
Stored-Program Computer : 애니악의 단점을 해결한 컴퓨터. 프로그램을 메모리에 전자적 / 광학적으로 저장할 수 있음.
→ 프로그램 저장 공간과 저장된 프로그램의 사용이 더 간편해짐. 따라서 컴퓨터의 대부분이 Stored-Program Computer의 형태로 개발되기 시작함.
많은 정보 분야의 엔지니어들이 프로그램을 바이너리(Binary)라고 부름.
→ Stored-Program Computer에서 프로그램이 저장 장치에 이진(Binay) 형태로 저장되기 때문.
※ 텍스트가 아닌 다른 데이터들도 바이너리라고 불리긴 하나, 대부분 바이너리라고 하면 프로그램을 의미함.
▶ 컴파일러와 인터프리터
프로그래밍 언어(Programming Language) : 프로그램을 개발하기 위해 사용하는 언어
소스 코드(Source Code) : CPU가 수행해야 할 명령들을 프로그래밍 언어로 작성한 것
컴파일(compile) : 소스 코드를 컴퓨터가 이해할 수 있는 기계어 형식으로 번역하는 것
인터프리팅(Interpreting) : 사용자가 작성한 스크립트를 그때그때 번역하는 것
인터프리터(Interpreter) : 인터프리팅을 처리해주는 프로그램
종류 | 속도 | 장/단점 |
컴파일 | 느림 | 한 번 번역하면 또 번역하지 않아도 됨 |
인터프리팅 | 빠름 | 실행할 때마다 번역해야 함 |
▶ 컴파일 과정
C언어로 작성된 코드는 일반적으로
전처리(Preprocess) → 컴파일(Compile) → 어셈블(Assemble) → 링크(Link)
의 과정을 거쳐 바이너리로 번역됨
▶ 전처리
전처리(Preprocessing) : 컴파일러가 소스 코드를 어셈블리어로 컴파일하기 전, 필요한 형식으로 가공하는 과정
> 전처리 과정
- 주석 제거 : 주석은 프로그램의 동작과 상관이 없으므로 모두 제거됨
- 매크로 치환 : #define으로 정의한 매크로의 이름은 값으로 치환됨
- 파일 병합 : 여러 개의 소스와 헤더 파일로 이루어진 프로그램을 합치고 컴파일 하기도 함
▶ 컴파일
컴파일(Compile) : C로 작성된 소스 코드를 어셈블리어로 번역하는 것.
컴파일 과정에서 소스 코드의 문법을 검사해 문법적 오류가 있다면 에러를 출력해주고, 몇몇 조건을 만족하면 최적화 기술을 통해 효율적인 어셈블리 코드를 생성해줌
▶ 어셈블
어셈블(Assemble) : 컴파일로 생성된 어셈블리어 코드를 ELF형식의 목적 파일(Object file)로 변환하는 과정
ELF : 리눅스 실행파일 형식
윈도우에서 어셈블 한다면 목적 파일은 PE형식을 가짐
목적 파일로 변환되고 나면 어셈블리 코드가 기계어로 번역 되어 사람이 해석하기 어려워짐
▶ 링크
링크(Link) : 여러 목적 파일들을 연결해 실행 가능한 바이너리로 만드는 과정
c언어의 printf 함수의 경우 직접 printf 함수를 선언하지 않음.
이 함수의 정의는 libc라는 공유 라이브러리에 존재함.
libc는 gcc의 기본 라이브러리 경로에 있는데, 링커는 바이너리가 printf를 호출하면 libc의 함수가 실행되도록 연결해줌.
Ⅲ. 디스어셈블과 디컴파일
▶ 디스어셈블
디스어셈블(Disassemble) : 어셈블의 역과정
▶ 디컴파일
디컴파일러(Decompiler) : 어셈블리어보다 고급 언어로 바이너리를 번역하는 프로그램
어셈블리어와 기계어는 거의 1:1로 대응되어 오차가 없음.
그러나 고급 언어와 어셈블리어 사이에서는 대응 관계가 없고
컴파일 과정에서 작성한 코드가 변형된다.
'Reverse Engineering' 카테고리의 다른 글
스택 프레임(Stack Frame) (0) | 2022.08.28 |
---|---|
Dreamhack | Reverse Engineering | Stage 2 | Background: Static Analysis vs. Dynamic Analysis (0) | 2022.07.09 |