본문으로 바로가기

nasm을 이용한 어셈블리 프로그래밍

category 카테고리 없음 2018. 1. 20. 01:00

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