'오브젝트 파일'에 해당되는 글 2건

  1. 2011.07.03 [Hack #10] objdump - (2) 오브젝트 파일 역어셈블
  2. 2011.07.01 [Hack #5] Object file - ELF 파일
2011. 7. 3. 02:54

[ objdump를 이용한 오브젝트 파일 역어셈블 ]

 

♧ 역어셈블 관련 옵션

옵션 [ 긴 옵션 ]

설명

-d | --disassemble

오브젝트 파일을 기계어로 역어셈블 (실행 코드가 있는 섹션)

-D | --disassemble-all

모든 섹션을 대상으로 역어셈블

--[no-]show-raw-insn

코드와 바이트열 제거/출력 [디폴트=보여줌]

--prefix-address

코드의 주소를 심볼에서의 상대주소로 표시

-j section | --section=section

특정 섹션 지정

-l | --line-numbers

각각의 코드에 대응하는 소스코드의 행에 관한 정보 출력.

-S | --source

행 번호에 해당하는 소스코드가 그 위치에 삽입되어 출력.

   

   

▶ -d 옵션을 사용한 일반적인 역어셈블

▷ -d 옵션을 사용해 역어셈블 할 때는 통상 실행 코드가 있는 섹션(.text등)을 역어셈블 대상으로 삼는다.

   

▶-D 옵션을 사용해 모든 섹션을 대상으로 역어셈블

길어서 pass~

   

▷ 일반적인 역어셈블 결과는 다음과 같은 형식으로 출력.

주소 <심볼>:

  주소: 코드의 바이트열 역어셈블 코드

   

▶ 『--no-show-raw-insn』 옵션을 사용하여 코드의 바이트 제거하여 출력.

   

▶ 『--prefix-address』 옵션을 사용하여 코드 주소를 심볼에서의 상대 주소로 표시

   

▷ 『--prefix-address』 옵션을 사용하면 디폴트로 코드의 바이트열은 출력되지 않음으로,

출력하고자 할 경우에는 『--show-raw-insn』 옵션을 함께 사용.

   

▶ 덤프할 때와 마찬가지로 -j 옵션을 사용하여 특정 섹션 지정 출력

   

▶ 덤프할 때와 마찬가지로 주소 범위 지정 출력

전 챕터(Hack #9)에서 했으므로 패스~

   

▶ -l옵션을 사용하여 가각의 코드에 대응하는 소스코드의 행에 관한 정보도 출력.

   

▶ -S옵션을 사용하여 -l 옵션의 행 번호에 대응하는 소스코드를 삽입하여 출력.

▷ -S옵션과 -l옵션 동시 사용 가능

▷ -S옵션과 -l옵션은 오브젝트 파일에 디버그 정보가 포함되어 있어야 함. (gcc –g)

   

▷ 오브젝트 파일의 디버그 정보로는 소스코드 경로명과 행 번호만 포함되므로

해당 경로에 소스 파일이 존재해야 한다. 만약 소스 파일이 없다면 소스는 출력되지 않으며

다른 소스 파일이 존재한다면 엉뚱한 소스가 출력될 것이다.

▶ 소스 파일명을 변경후, -S옵션을 사용하였음에도 소스코드는 출력 되지 않음.

   

   

▷ 링크하기 전의 오브젝트 파일에서는 재배치되는 주소가 0임에 주의해야 한다.

▷ 위 예에서는 "Hello World!!!\n"을 가리키는 포인터는 12~15 사이의

4바이트에 채워져 있어야 하지만, 링크하기 전이므로 0인 채로 남아 있다.

   

▶ 링크 후 생성된 실행 파일에서는 해당하는 부분에 다음과 같이 주소가 채워져 있다.

  

 

Posted by devanix
2011. 7. 1. 15:50

♧ ELF :: Executable and Linking Format 의 약자로,

실행 가능한 바이너리 또는 오브젝트 파일 등의 형식을 규정한 것.

▷ ELF 파일은 ELF헤더가 맨 앞에 위치.

▷ 프로그램 헤더 테이블과 섹션 헤더 테이블이 그 뒤에 위치.

▷ 이러한 헤더의 구조는 elf.h 참조

   

   

   

:: ELF 에서 사용하는 자료형

▷ ELF 바이너리에는 32bit와 64비트, 두 가지가 있다.

자료형

N = 32

N = 64

설명

ElfN_Half

uint16_t

uint16_t

부호 없는 16비트 값

ElfN_Word

uint32_t

uint32_t

부호 없는 32비트 값

ElfN_Sword

int32_t

int32_t

부호 있는 32비트 값

ElfN_Xword

uint64_t

uint64_t

부호 없는 64비트 값

ElfN_Sxword

int64_t

int64_t

부호 있는 64비트 값

ElfN_Addr

uint32_t

uint64_t

주소

ElfN_Off

uint32_t

uint64_t

오프셋

ElfN_Section

uint16_t

uint16_t

섹션 인덱스

ElfN_Versym

uint16_t

uint16_t

버전 심볼 정보

  

   

   

:: [ ELF 헤더 ] readelf 의 -h옵션 (--file-header)

▷ ELF헤더는 ELF파일 맨 앞에 반드시 존재하며, 그 파일이 ELF 파일임을 나타냄.

   

[ ELF헤더 구조 ] (/usr/include/elf.h)

   

▷ e_ident::

ELF의 매직 넘버(MAGIC NUMBER)와 기타 정보를 갖고 있다.

ELF 파일은 첫 4바이트에 다음과 같은 매직 넘버를 갖는다

| 0x7F | 0x45 | 0x4c | 0x46 | → "\177ELF"가 된다.

그 다음 바이트는 32비트인 경우 ELFCLASS32(1), 64바이트인 경우 ELFCLASS(2)가 된다.

다음 바이트는 엔디안을 나타냄.(리틀 엔디안인=ELFDATA2LSB(1),빅 엔디안인=ELFDATA2MSB(2))

나머지 바이트는 ELF버전과 OS, ABI 등의 정보를 1바이트씩을 사용해 나타냄.

   

▷ e_type:: 다음 타입 중 하나를 나타낸다.

타입

설명

ET_REL

1

재배치 가능한 파일

ET_EXEC

2

실행 가능한 파일

ET_DYN

3

공유 오브젝트 파일

ET_CORE

4

코어 파일

   

▷ e_machine:: 아키텍처 타입을 타나낸다. (EM_으로 시작하는 상수로 정의되어 있음.)

▷ e_version:: ELF 버전을 나타낸다. (위 예(/bin/ls)는 EV_CURRENT(1)이다)

▷ e_entry:: 이 ELF에서 실행 시작하는 가상 주소.

▷ e_ehsize:: ELF 헤더 자체의 크기.

▷ e_phoff, e_phentsize, e_phnum:: 프로그램 헤더 테이블의 위치, 크기, 헤더 개수.

▷ e_shoff, e_shentsize, e_shnum:: 섹션 헤더 테이블의 위치, 크기, 개수.

▷ e_shstrndx:: 섹션명의 스트링 테이블을 갖는 섹션 헤더 인덱스를 나타냄.

   

   

:: [ 프로그램 헤더 ] readelf의 -l 옵션 (--program-headers)

▷ 프로그램 헤더 테이블은 ELF 헤더의 e_phoff로 지정된 오프셋에서 시작.

▷ e_phentsize(헤더크기)와 e_phnum(프로그램 헤더 개수)으로 정해진 크기를 갖는 테이블.

(※ 즉, 프로그램 헤더 테이블의 전체 크기 = e_phentsize * e_phnum)

   

 [ 프로그램 헤더 구조 ]

   

▷ 『Program Headers:』의 각 행에 해당.

▷ p_type:: 다음과 같다.

p_type

설명

PT_LOAD

1

로드된 프로그램 세그먼트

PT_DYNAMIC

2

동적 링크 정보

PT_INTERP

3

프로그램 인터프리터

PT_NOTE

4

추가 정보

PT_PHDR

6

프로그램 헤더 테이블 자신

PT_TLS

7

스레드 지역 저장소

PT_GNU_EH_FRAME

0x6474e550

GNU .eh_frame_hdr 세그먼트

PT_GNU_STACK

0x6474e551

스택 실행 가능성

   

▷ 『Section to Segment mapping:』 이후의 행에 나타난 정보는

『Program Headers:』의 각 프로그램 헤더에 나타난 세그먼트에

그 세그먼트 메모리 범위를 포함하는 섹션명을 나열하고 있다.

   

(인덱스 00) 프로그램 헤더에 표시된 세그먼트는 PHDR 타입이고 그에 속하는 섹션은 없다.

(인덱스 01) 프로그램 헤더에 표시된 세그먼트는 INTERP 타입이고 그에 속하는 섹션은 .interp가 있다.

(인덱스 02) 프로그램 헤더에 표시된 세그먼트는 LOAD 타입이고 그 안에는 .interp, .note.ABI-tag, ...등등

▷ 『Section to Segment mapping:』 ↔ 『Program Headers:』 이 둘을 연결해서 봄.

type

segment

section

PHDR

00

없음.

INTERP

01

.interp

LOAD

02

.interp , .note.ABI-tag , .note.gnu.build-id, .hash ...[등등]

  

   

   

:: [ 섹션 헤더 ] readelf의 -S 옵션 (--section-headers)

▷ 섹션 헤더 테이블은 ELF 헤더의 e_shoff로 지정된 오프셋에서 시작.

▷ e_shentsize(섹션 헤더 크기)와 e_shnum(섹션 헤더 개수)으로 정해진 크기를 갖는 테이블.

(※ 즉, 섹션 헤더 테이블의 전체 크기 = e_shentsize * e_shnum)

   

[ 섹션 헤더 구조 ]

▷ 『Section Headers:』의 각 행에 해당.

▷ 섹션명(Section name)은

ELF 헤더의 e_shstrndx로 지정된 섹션에 포함된 스트링 테이블의 인덱스로 지정.

▷ 위의 /bin/ls 예의 경우,

e_shstrndx는 28이므로, 28번째 섹션 헤더가 그 스트링 테이블을 갖는 섹션이 된다.

- sh_offset이 '0x0192d4' 이고, 크기가 '0x0000f2' 바이트인 스트링 테이블(STRTAB)임을 알 수 있다.

   

▷ 섹션 타입(sh_type):

 섹션 타입

 값 

 설명

 SHT_PROGBITS

 1

 프로그램 데이터

 SHT_STRTAB

 2

 심볼 테이블

 SHT_STRTAB

 3

 스트링 테이블

 SHT_RELA

 4

 재배치 엔트리

 SHT_HASH

 5

 심볼 해시 테이블

 SHT_DYNAMIC

 6

 동적 링크 정보

 SHT_NOTE

 7

 Notes (호환 체크정보)

 SHT_NOBITS

 8

파일상에  데이터가 없는 부분 (.bss)

 SHT_REL

 9

 재배치 엔트리

 SHT_DYNSYM

 11

 동적 링크의 심볼테이블

 SHT_INIT_ARRAY

 14

 생성자 배열 (.init) 

 SHT_FINI_ARRAY

 15

 소멸자 배열 (.fini)

 SHT_GNU_verdef

 0x6ffffffd

 버전 정의 섹션

 SHT_GNU_verneed 

 0x6ffffffe

 필요한 버전 섹션

 SHT_GNU_versym

 0x6fffffff

 버전 심볼 테이블

  

   

   

:: [ 스트링 테이블 ]

▷ 스트링 테이블은 단순한 문자열 리스트이다.

▷ /bin/ls의 경우 다음 섹션이 스트링 테이블이다.

▷ 예를 들어 [28] .shstrtab의 오프셋은 '0x0192d4', 크기는 '0xf2'이므로

od를 사용하여 테이블을 확인하자.

# od --skip-bytes 0x192d4 --read-bytes 0xf2 -t x1z /bin/ls

▷ 이 경우 스트링 테이블은 다음과 같이 되어 있다.

인덱스

문자열

1

.shstrtab

11

.interp

19

.note.ABI-tag

즉, .shstrtab의 맨 앞부터의 오프셋이 스트링 테이블의 인섹스가 된다.

   

   

:: [ 심볼 테이블 ] readelf의 -s 옵션 (--syms)

▷ 심볼 테이블은 심볼과 그 값 등을 대응시키는 테이블이다.

▷ /bin/ls의 경우 strip되어 있으므로 동적 심볼 테이블만 있다.

...(중략)...

▷ 이를 ELF 헤더로부터 찾아 보자.

우선 섹션 헤더에서 .dynsym이라는 심볼 테이블이 있다는 것을 알 수 있다.

▷ 덤프해 보면 다음과 같다.

...(중략)...

▷ 심볼 테이블은 다음과 같은 구조 테이블이다.

32비트와 64비트 ELF 바이너리에서는 st_value의 정렬 순서에 따라 변한다.

▷ st_name=스트링 테이블의 인덱스, st_value=심볼 값, st_size=심볼크기.

▷ st_info의 하위 4비트는 심볼 테이블 등의 정보로 다음과 같은 것이 있다.

심볼 타입

설명

STT_OBJECT

1

데이터 오브젝트

STT_FUNC

2

실행 코드

STT_SECTION

3

섹션 관련

STT_FILE

4

오브젝트 관련 소스코드 파일

STT_COMMON

5

일반 데이터

STT_TLS

6

스레드 지역 저장 데이터

▷ 또한 st_info의 상위 4비트는 그 심볼의 바인딩 방법을 타나낸다.

심볼 바인딩

설명

STB_LOCAL

0

지역 심볼

STB_GLOBAL

1

전역 심볼

STB_WEAK

2

WEAK

   

▷ st_shndx는 관련된 섹션을 나타낸다.

섹션

설명

SHN_UNDEF

0

미정의

SHN_ABS

0xfff1

절대값을 갖는 심볼

SHN_COMMON

0xfff2

일반적인 심볼

   

/bin/ls의 예를 보자. 0번째 심볼 정보는 다음과 같이 비어 있다.

▷ /bin/ls의 위의 예에서 맨 마지막에 있는 심볼 정보를 알아 보자.

주소 0006104 부터 시작하는 이 바이트 열은 다음과 같은 의미를 갖는다.

( ※ 아키텍처(x86) 리틀 엔디안 이기 때문에 반대로 읽는다)

st_name = 0x2db

st_value = 0x08061320

st_size = 0x4

st_intfo = 0x11 = (STB_GLOBAL | STT_OBJECT)

st_other = 0

st_shndx = 0x1a = 26

   

▷ 여기서 심볼명을 가리키는 오프셋 값 st_name은 '0x2db'로 되어 있다.

.dynstr 섹션을 보면 스트링 테이블은 시작 위치로부터 '0xc54' 바이트 떨어진 위치에서 시작한다.

- 여기서 '0xc54'에 0x2db(st_name)를 더한 값인 '0xf2f' 위치에서 시작하는 문자열을 보면,

' optarg'라는 문자열을 찾을 수 있다.

- 이와 같이 st_name = '0x2db'에 해당하는 심볼은 'optarg'임을 알 수 있다.

   

▷ 이는 readelf -s 출력 결과에서 위의 심볼 정보를 확인 할 수 있다.

  

   

   

:: [ 재배치 정보 ]

▷ SHT_RELA 또는 SHT_REL 타입의 섹션은 재배치 정보를 갖는다.

▷ SHT_RELA는 다음과 같은 Rela 구조의 테이블을 갖는다.

   

▷ SHT_REL의 경우는 다음과 같이 r_addend가 없는 Rel 구조의 테이블을 갖는다.

   

▷ r_offset은 재배치를 해야 하는 위치를 가리키는, 섹션 첫 위치로부터의 오프셋이다.

▷ r_info는 재배치 타입 또는 심볼테이블의 인덱스 등의 정보를 포함한다.

▷ Rela의 경우 재배치할 경우에 항상 더해야 할 값을 r_addend로 갖고 있다.

  

Posted by devanix