실습 환경 세팅 / 컴파일 과정 / ELF 섹션(ELF Section) / 어셈블 프로그래밍에 대해서 정리한다.
- 실습 환경
- Red Hat Linux 6.2
* 부팅시마다 LILO BOOT에서 linux-up을 입력해줘야 한다.
- 원격접속 설정
1). /etc/securetty
pts/0
pts/1
pts/2
..
pts/8
* 위 내용을 해당 파일에 추가 시켜주기만 하면 다음 부팅시부터 Telnet을 이용한 원격접속이 가능하다.
2). PAM: /etc/pam.d/login
- 두번째 라인을 주석 처리
- # auth required /lib/security/pam_securetty.so
- 사용하는 도구
* C 컴파일러 : GCC ( GNU C Complier)
* 어셈블러 : GAS( GNU Assembler ): AT&T 문법
NASM( Netwired Assembler ): AT&T, INTEL 문법을 지원
* 디버거 : GDB( GNU DeBugger ): 바이너리 분석 도구
- 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
#> ./configure
#> make
#> make install
#> cp nasm /usr/bin
* 실습환경 운영체제를 Red Hat Linux6.2를 사용하기 때문에 nasm은 제일 낮은 버전인 0.99.05를 설치했다.
! C 컴파일
- windows: visual studio, eclipse, ...
- IDE: 개발환경( 컴파일러 + 편집기 + 디버거 + ... )
- 실습에는 컴파일러: GCC, 편집기: VI, 디버거: GDB를 사용한다.
* 컴파일러를 이용해서 c언어를 컴파일 할때는 .c 확장자를 붙여준다.
* gcc 컴파일러를 이용해서 컴파일하게 되면 실행 가능한 프로그램(바이너리) 파일 하나가 나오게 된다.
* 생성할 파일 이름을 지정하지 않으면 default 파일 이름으로 a.out이 나온다.
( 같은 이름의 프로그램이 있는 경우에는 내용을 덮어쓴다 )
* 컴파일시 생성되는 파일 이름을 지정하려면 -o 옵션을 이용해서 지정해준다.
( 예를 들어서 gcc -o hello hello.c를 하게 되면 hello라는 이름으로 프로그램이 생성된다 )
* 컴파일 과정
hello.c -> hello.i -> hello.s( .asm ) -> hello.o -> hello
1. 컴파일 과정
1). 전처리 과정: cpp
- hello.c -> hello.i
* 전처리 과정에는 해당 되는 지시문들을 치환해서 가져온다.
( c언어를 예로 들면 #include, #define 등의 지시문들을 치환해서 가져온다 )
2). 컴파일 과정: cc1
- hello.i -> hello.s
- c 코드를 어셈블 코드로 바꿔주는 과정
- GAS는 .s 확장자를 사용하고 nasm은 .asm 확장자를 사용한다.
3). 어셈블리 과정: as(GAS)
- hello.s -> hello.o
- 어셈블 코드를 바이너리 형태로 바꿔주는 과정
4). 링킹 과정: ld, collect2( GCC )
- hello.o -> hello
- 여러개의 목적파일(object file)을 묶어서 하나의 프로그램을 만드는 과정
* 리눅스에서 xxd 명령어를 이용하면 object file 내용을 16진수와 ASCII 형태로 볼수 있다.
! 실행파일 구조
- 리눅스 : ELF ( 파일 시그니처: ELF (7f45 4c46) )
- 윈도우즈 : PE ( 파일 시그니처: MZ )
- 유닉스: COFF
* 각 운영체제별로 실행파일의 구조가 다르다.
그렇기 때문에 리눅스 운영체제에서 만든 실행파일을 윈도우 운영체제에서 실행 할 수 없다.
* 악성코드를 분석할때 실행파일 구조 파악은 필수!!
* ELF 구조
( 실행파일을 실행할때는 ELF 헤더에 들어있는 내용을 보고 해당 섹션들을 실행한다 )
! 프로그램 & 프로세스
1. 프로그램
- 실행중이지 않은 상태
- 디스크상에 파일 형태로 존재
2. 프로세스
- 실행중인 상태
- 운영체제가 관리하는 작업의 단위
- 파일이 메모리에 존재
* 리눅스에서는 objdump -x 명령을 이용해서 ELF 파일에 모든 헤더들을 읽어드릴수 있다.
* objdump -d를 이용하면 object file에 바이너리 내용을 어셈블러로 변환시켜 볼 수 있다.
- section
1. text 섹션(세그먼트)
- 실행코드가 존재하는 영역
- 읽기전용
- 실행가능한 메모리 영역
2. DATA 섹션(세그먼트)
- 읽기/쓰기 가능한 메모리 영역
- 초기화된 데이터 영역
3. BSS 섹션(세그먼트)
- 읽기/쓰기 가능한 메모리 영역
- 초기화 되지 않은 데이터 영역
4. 스택
- 파일상에서는 나타나지 않는다.
예) 전역변수는 실행시에 스택 영역을 사용
software engineering( 소프트웨어 공학 )
- 소프트웨어를 만드는 전체 과정
- 기획 -> 설계 -> 구현 -> 배포 -> 유지보수
* 리버싱은 배포단계를 구현단계로 되돌리는 엔지니어링 기법이다.
( 컴파일 단계에서 보면 4단계에서 3단계, 즉 프로그램에서 바이너리 코드로 되돌려 어셈블리어로 변환이 가능해진다 )
어셈블 프로그래밍
- 각 섹션(세그먼트)들을 직접 정의
- ;(세미콜론)은 어셈블 프로그래밍을 할때 주석으로 사용된다.
- extern을 이용해서 외부 라이브러리를 가져오고 call 명령을 이용해서 사용할 수 있다.
* 시스템 콜을 이용하면 외부 라이브러리 없이 어셈블리어로만 프로그램을 작성 할 수 있다.
( 순수 어셈블리어로 프로그램을 작성하게 되면 성능적인 면에서도 c언어를 사용할때보다 더 좋다는
태생적인 장점이 있다 )
* nasm에 대한 사용법은 공식홈페이지에 문서를 참고하면 된다.
nasm 공식 홈페이지: http://www.nasm.us/
! 32bit 메모리 운영체제 기준으로 가상메모리를 4GB 사용한다.
( 1GB는 kernel이 사용하고 나머지 3GB를 사용 )
* kernel이 사용하는 메모리는 접근 불가능
* 64bit 메모리의 경우에는 개념은 같고 32bit에 비해 가상메모리의 크기가 확장될뿐이다.
댓글