1. 파일 덤프
objdump : object 파일을 덤프하는 명령어이다.
-x --all-headers Display the contents of all headers
-d --disassemble Display assembler contents of executable sections
[root@M4RC0 /root]# objdump -x hello2
두개의 segment header와 두 개의 section header로 이루어져 있다.
프로그램 헤더 쪽을 알아보자.
Program Header:
LOAD off 0x00000000 vaddr 0x08048000 paddr 0x08048000 align 2**12
filesz 0x00000096 memsz 0x00000096 flags r-x
LOAD off 0x00000098 vaddr 0x08049098 paddr 0x08049098 align 2**12
filesz 0x00000011 memsz 0x00000011 flags rw-
off : 파일 오프셋, vaddr : 가상 메모리, align : 할당 크기 (여기선 4kb)
filesz : 파일 크기( 여기선 150byte) -> 실제는 4kb 할당, flag(r-w) : 읽고 실행 가능(Text segment) - 권한을 보고 알 수 있다.
4k 지나서 바로 이어서 다음 segment가 있다. flag(rw-) : 읽고 쓰기 가능(data segment)
filesz : 파일 크기( 여기서 17byte) -> 실제는 4kb 할당, 나머지는 null 패딩
Section 부분을 알아보자.
Sections:
Idx Name Size VMA LMA File off Algn
0 .text 00000016 08048080 08048080 00000080 2**4
CONTENTS, ALLOC, LOAD, READONLY, CODE
1 .data 00000011 08049098 08049098 00000098 2**2
CONTENTS, ALLOC, LOAD, DATA
2 .bss 00000003 080490a9 080490a9 000000a9 2**0
CONTENTS
3 .comment 0000001f 00000000 00000000 000000ac 2**0
CONTENTS, READONLY
크기는 22바이트 (전체 코드의 크기) , vma = entry point, (실제 시작 위치의 주소)
data segment (data, bss, heap 영역 이렇게 크게 3개로 나뉨)
data : 초기화된 데이터, bss : 초기화되지 않은것, heap : malloc 데이터
start adress 0x08048080 - 메모리상의 주소 (여기서부터 파일이 로딩된다.) : 시작 위치
0x00000000
0xbffffffff - 프로세스가 사용
0xc0000000
0xffffffff - 커널이 사용
804808a: b9 98 90 04 08 mov $0x8049098,%ecx // 컴파일시 레이블이 주소로 바뀐다.
2. C언어와 어셈블리어의 차이
1) 데이터 타입
C언어: 숫자(정수, 실수), 문자('), 문자열(")
어셈블리어: 숫자(정수, 실수), 문자, 문자열(',")
2) 레이블 vs 변수
레이블
- 주소
변수
- 값, 주소, 크기
- int var = 10;
3) 데이터의 크기
C언어: char, short, int, long, double, ...
어셈블리어 :
(1) 접두사 : d(.data), res(.bss)
(2) 단위 :
byte unit C
1 (b)byte char
2 (w)word short
4 (d)dword int, float, pointer
8 (q)qword long long, double
12 (t)tenbyte
* char str[] = "Hello, World"; - 얼마만큼의 메모리를 써야하는지 알 수 있다.
char str[]; - 얼마만큼의 메모리를 써야하는지 알 수 없다.
C언어는 상관이 없지만 Assemble은 segment의 분류가 필요하다.
ex)
c언어
int apple = 10;
int orange;
-> nasm(어셈블리어)
segment .data
apple db 10
segment .bss
orange resd 1
3. 소스코드 분석
1 ) 우리가 작성한 hello2.asm을 토대로 분석해보자. (C라이브러리 사용 X)
segment .data
string db 'hello, world!!!', 10(new line[\n]), 00(문자열의 끝은 항상 null) -> "hello, world!!!\n"null
'hello, world!!!'의 주소가 string(레이블)에 들어있다고 생각하면 된다.
레이블의 이름은 중복될 수 없다. db는 nasm에서 사용하는 데이터 타입이다.
db는 총 17바이트 이다.
segment .bss
buffer resd 10244 -> char buffer[1024] // 초기화되지 않은 것
segment .text
global _start
_start: -> entry point (무조건 _start이어야 한다.) - gcc는 main, gcc 이외는 _start
mov eax, 4 이 명령어의 시작주소는 entry point이다.
mov ebx, 1
mov ecx, string
mov edx, 16
int 0x80
2) 우리가 작성한 hello1.asm을 토대로 분석해보자. (C라이브러리 사용 O)
extern printf
segment .data
string db 'hello, world!!', 10, 00
prompt db 'num of apple: %d', 10, 00
apple dd 10
segment .bss
orange resd 1
segment .text
global main
main:
push string -> printf("hello, world!!!\n");
call printf push의 개수는 함수의 인자의 개수와 같다.
push apple(주소) -> printf("num of apple: %d\n", &apple)
push prompt 제대로된 값이 나오지 않는다.
call printf
push dword [apple] -> printf("num of apple: %d\n", apple)
push prompt 제대로된 값이 나온다.
call printf
ex)예제
(0)_(0)(0)_(0)
(=^.^=)(*^.^*)
(_m_m_)(_m_m_) 를 어셈블리로 짜라
extern printf
segment .data
string1 db '(0)_(0)(0)_(0)', 10, 00
string2 db '(=^.^=)(*^.^*)', 10, 00
string3 db '(_m_m_)(_m_m_)', 10, 00
segment .text
global main
main:
push string1
call printf
push string2
call printf
push string3
call printf