본문으로 바로가기

1. 환경 설정


1) Red Hat Linux 6.2

- 부팅시 LILO BOOT에서 linux-up 입력


2) telenet 이용 방법


>> /etc/securetty

pts/0 ~ pts/8 추가


>> /etc/pam.d/login

둘째줄 주석처리

#auth required /lib/security/pam_securetty.so


3) NASM 설치 및 다운로드


#wget http://www.nasm.us/pub/nasm/releasebuilds/0.99.05/nasm-0.99.05.tar.gz

#tar xvfz nasm-0.99.05.tar.gz

#cd nasm-0.99.05.tar.gz

#./configure

#make

#make install

#cp nasm /usr/bin



2. 사용되는 도구들


- C컴파일러: GCC(GNU C Compiler)

- 어셈블러 : GAS(GNU Assembler) - AT&T 문법

NASM(Netwired Assembler) - AT&T, INTER 문법을 지원한다.

- 디버거 : GDB(GNU DeBugger) - 바이너리 분석 디버거


3. C 프로그램(컴파일)


- windows 환경 : visual studio. eclips, ... etc

- IDE : 통합 개발 환경, 주로 컴파일러 + 편집기 + 디버거가 결합된 형태

    (visual studio는 compiler가 아니라 compiler가 포함된 IDE)

- linux 환경: compiler(GCC), editor(VI,VIM), debugger(GDB)

- C 파일이 실행파일이 되는 과정은 아래와 같다.

hello.c -> hello.i -> hello.s(asm) -> hello.o -> hello


간단히 hello.c를 작성해보자.


1
2
3
4
5
6
7
8
#include <stdio.h>
 
int main()
{
        printf("Hello, World!!!\n");
        return 0;
}
 

cs



# gcc hello.c

- 이름 옵션(-o)를 사용하지 않으면 기본 파일면은 a.out으로 나온다.


# ./a.out

Hello, World!!!


4. 컴파일 과정


# gcc -v 소스파일.c : 소스파일 컴파일 과정을 보여준다.


1) 전처리 단계 - cpp(C PreProcess /tmp/ccg9MiUY.i) -save-temps

- hello.c -> hello.i

- 매크로, 해더파일이 처리된다.


2) 컴파일 단계 - cc1

- hello.i -> hello.s

- 어셈블리 언어로 변환

어셈블리 언어로 변환하는 이유는 C언어가 바로 기계어로 변환되지 못하기 때문이다.

바이너리(실행파일)은 0,1로 이루어진 파일이다. 사람이 바이너리 파일을 직접 만드는것은 어렵기 때문에

소스를 작성해 어셈블리 언어로 변환한 후 컴파일러에 의해 자동 기계어로 변환된다.

또한, 어셈블리언어는 기계어에 일대일 대응하기 때문에 사용된다.

GAS는 .s, NASM은 .asm 확장자를 사용한다.


3) 어셈블러 단계 - as(GAS)

- hello.s -> hello.o

- 어셈블리 -> 기계어

- object 파일로만은 라이브러리 파일에 있는 함수를 사용할 수 없다.

- 어셈블리 언어를 바이너리(0,1)형태로 바꿔주는 과정


4) 링크 단계 - collect2, ls, gcc (일반적으로 dynamic-linker 사용)

- hello.o -> hello

- object 파일을 가지고 여러가지 라이브러리를 합쳐서 하나의 바이너리를 만든다.


* 만일 우리가 파일을 C 언어로 작성하지 않고 어셈블리로 작성하면, 1), 2)단계가 생략되고, 3),4)단계만 진행된다.



hello.c 는 단지 C언어로 작성된 파일이기 때문에 text파일이지 실행할수있는 바이너리 파일은 아니다.

hello는 컴파일 후 생긴 바이너리 파일이다. window 환경에서 exe파일을 linux환경에서 ELF 파일이라고 한다.

따라서 hello는 실행할 수 있는 elf 파일이다.


컴파일 과정을 좀 더 자세히 알아보기 위해 hello1.c를 만들어보자.



#define NUMBER 1000이 어떻게 처리되는지 알아보자.


# gcc -E -o hello.i hello.c(전처리 단계)

# gcc -S -o hello.s hello.c(컴파일 단계)

# gcc -c -o hello.o hello.c(어셈블러 단계)

위 명령어를 통해 .i .s .o파일을 만들 수 있다.



전처리 과정을 통해 hello1.i 파일에서 매크로 함수가 처리된것을 확인할 수 있다.



5. 바이너리를 이용해 의사 코드 작성하기



1
2
3
4
5
6
7
8
#include <stdio.h>
 
int main()
{
    pirntf("Hello, World!!!\n");
    return 0;
}
 
cs



1) C 라이브러리를 이용한 어셈블리 프로그램 작성


vi hello.c




======== 분석 ==========


실제 실행되는 코드는 main: 의 두 줄이다.


a) data segment

- 읽기/쓰기 가능한 메모리 영역

- 프로그램 실행에 필요한 데이터


b) text segment

- 실행 가능한 메모리 영역(쓰기 불가)

- 주로 실행할 명령어들이 들어있다.


2) C 라이브러리를 사용하지 않고 프로그램 작성 (original)




위와 같이 C로 작성하지 않고 어셈블리어로 작성하면, 파일 내용을 최소화 할 수 있고,

불필요한것들을 제거할 수 있다. 또한 파일의 실행속도가 빨라진다.

중요한 점은 어셈블리 프로그래밍을 할 때 각각의 세그먼트를 직접 지정해주어야 한다.



5. 기본 지식


- 프로그램이 실행되려면 디스크에 있던 파일을 메모리에 옮겨야한다.

- 모든 실행 중인 파일은 메모리에 상주해 있어야 한다.

- 실행 중인 프로그램을 프로세스라고 한다.

- 메모리에서 해제되면 프로세스가 종료된다 라고 한다.


- 32bit 환경에서 한 프로세스가 사용하는 전체 크기는 4GB이다.

  리눅스의 경우 1G(커널) + 3G(프로세스)로 나눈다.

  3G 프로세스를 크게 text ,data, stack 영역으로 나눈다.

  윈도으ㅜ의 경우 2G(커널) + 2G(프로세스)fh sksnsek.


- segement or pase or section 이라고 부른다.


- 운영체제는 무엇을 보고 segment를 분리할까??

  실행파일 시스템의 구조를 보고 분류한다.

  주로 PE 구조를 보고 확인할 수 있다.

  elf: 리눅스, pe: 윈도우