1. objdump 를 이용해 elf 파일 내부를 자세히 보자.
objdump -x 옵션을 모든 이용가능한 헤더 정보를 준다.
아래 그림을 보고 이해해보자.
굉장히 복잡해 보이지만 차근 차근 하나씩 알아보도록 하자.
hello2: file format elf32-i386 //파일 형식이 elf라는것을 알 수 있다.
architecture: i386, flags 0x00000112 //하드웨어 타입을 알 수 있다.
start address 0x08048080 //메모리 상의 주소( 여기부터 프로세스가 올라간다.)
LOAD off 0x00000000 vaddr 0x08048000 paddr 0x08048000 align 2**12(4kb) // off(파일 오프셋), vaddr(가상 메모리)
filesz 0x00000096 memsz 0x00000096 flags r-x
0x96은 150byte이지만 실제 4kb가 할당된다. flag - 읽고 실행가능 (권한을 보고 이 부분이 text segment임을 알 수 있다.)
LOAD off 0x00000098 vaddr 0x08049098 paddr 0x08049098 align 2**12(4kb) // 4kb 지나서 다음 segment 존재
filesz 0x00000011 memsz 0x00000011 flags rw-
Sections:
Idx Name Size VMA LMA File off Algn
0 .text 00000016 08048080 08048080 00000080 2**4 // size 는 코드의 전체 크기 이다.(22byte)
CONTENTS, ALLOC, LOAD, READONLY, CODE // vma = entry point 실제 시작 위치 주소
1 .data 00000011 08049098 08049098 00000098 2**2 // data segment(data, bss, heap 영역)
CONTENTS, ALLOC, LOAD, DATA // data 초기화된 데이터, bss 초기화 되지 않은 데이터
2 .bss 00000003 080490a9 080490a9 000000a9 2**0
CONTENTS
3 .comment 0000001f 00000000 00000000 000000ac 2**0
2. red hat 6.2
최근에 나온 ubuntu, centos 등 여러 OS는 최신의 메모리 보호 기법이 적용되어 있다.
하지만 처음 시작하는 입장에서 이러한 메모리 보호 기법이 적용되어 있으면 공부하기 너무 어렵다.
따라서 메모리 보호기법이 적용되어있지 않은 red hat 6.2를 사용한다.
주로 0x00000000 ~ 0xbfffffff 공간은 프로세스가 사용하고, 0xc000000~0xffffffff 공간은 커널이 사용한다.
hello2 elf 파일을 대상으로 분석해보자.
start address는 0x08048080 -- 이 주소가 파일이 로딩되는 시작 위치이다.
1번에서 objdump -x 옵션을 통해 헤더 정보를 확인했지만, 이번에는 objdump -d 옵션을 통해 disassemble을 해보자.
또한 xxd 명령을 통해 hexadump를 할 수 있다. 우선 지금 단계에서는 이를 통해 elf 파일임을 확인 가능하다.
3. 어셈블리와 C언어
1) 데이터 타입
assembly와 C 모두 숫자(정수, 실수), 문자('), 문자열(")을 데이터 타입으로 갖는다.
2) 레이블 vs 변수
assembly는 레이블, C언어는 변수라는 개념을 사용한다.
레이블은 이름표라고 생각하는 주소이다.
변수는 값, 주소, 크기를 모두 갖는다.
3) 데이터 크기 (assembly)
a. 접두사 : d(data), res(bss)
b. 단위:
byte unit c
1 (b)byte char
2 (w)word short
4 (d)dword int, float, pointer
8 (q)qword long long, double
10 (t)tenbyte x
4) 어셈블리는 반드시 segment 분류가 필요하다.
C언어
int apple = 10;
int orange;
nasm
segment .data
apple dd 10
segment .bss
orange resd 1
4. 어셈블리 프로그래밍 및 이해
1) C라이브러리를 사용하지 않고 프로그래밍 하기
segment .data
string db 'hello, world!!!', 10(new line), 00(문자열의 끝에 항상 null 문자가 들어가야햔다.)
- "hello, world!!!\"null 로 생각하면 쉽다.
- 'hello, world!!!'의 주소가 string(레이블)에 들어가 있다고 생각하면 된다.
- 레이블의 이름은 중복될 수 없다.
- db는 nasm에서 사용하는 데이터 타입니다.
- 현제 db는 총 17바이트이다.
- C언어로 비유를 들면 char stirng[] = 'hello, world!!!\nNULL'
segment .bss
buffer resb 1024 // char buffer[1024]; 초기화 되지 않았다.
segment .text
global _start
_start: // entry point(gcc는 main, gcc 이외는 _start로 시작한다.)
mov eax, 4
mov ebx, 1
mov ecx, string
mov edx, 16
int 0x80
출력값으로 string에 저장된 문자열이 그대로 나오는것을 확인할 수 있다.
하지만 system call 관련 이야기를 해야하므로 추후에 더 얘기하기로 하고 프로그래밍 관점에서 보자.
dword []를 통해 주소에 있는 값에 접근 할 수 있다. C언어에서의 포인터 개념과 유사하다
5. 연습문제
C라이브러리를 이용하여
(0)_(0)(0)_(0)
(=^.^=)(*^.^*)
(_m_m_)(_m_m_) 를 어셈블리로 짜라
초기화 되지 않고 사용되는 데이터가 없어서 .bss 세그먼트를 이용하지 않고 프로그래밍 하였다.
'Pwnable' 카테고리의 다른 글
어셈블리 프로그래밍 심화3 (0) | 2018.07.19 |
---|---|
어셈블리 프로그래밍 심화2 (0) | 2018.07.12 |
어셈블리 프로그래밍 심화 및 CPU 구조 (0) | 2018.07.04 |
Understanding of the running process of a program made with C language (0) | 2018.07.02 |
C언어로 만들어진 프로그램의 실행과정의 이해 (0) | 2018.01.18 |