'readelf'에 해당되는 글 2건

  1. 2011.07.02 [Hack #8] readelf - ELF 파일 정보 보기
  2. 2011.07.01 [Hack #5] Object file - ELF 파일
2011. 7. 2. 18:44

♧ readelf는 BFD 라이브러리를 이용하지 않고 직접 ELF를 읽기 위한 툴.

▷ BFD에 의존적이지 않은 프로그램도 존재하므로 ELF 파일의 문제인지 BFD의 문제인지 쉽게 구분.

▷ readelf는 BFD를 경유하지 않고 ELF 파일을 읽어내므로 objdump보다 상세한 정보를 얻을 수 있다.

▷ 예를 들면 DWARF 디버그 정보를 검사할 수도 있다.

▷ readelf 명령은 하나 이상의 옵션을 사용해야 함. (옵션을 지정하지 않으면 기본 사용법 출력)

(※ BFD 라이브러리(Birnary Descriptor Library):

다양한 형식의 오브젝트 파일의 호환성을 위한 GNU 프로젝트의 주 매커니즘.)

   

 

[ ELF 헤더 출력 ]

헤더 종류

옵션

긴 옵션

ELF 파일 헤더

-h

--file-header

프로그램 헤더

-l (엘)

--program-headers, --segments

섹션 헤더

-S

--section-headers, --sections

위 세가지 헤더

-e

--headers

 

 

[ ELF 정보 출력 ]

종보 종류

옵션

긴 옵션

심볼 테이블

-s

--syms, --symbols

재배치 정보

-r

--relocs

동적 세그먼트

-d

--dynamic

버전 섹션

-V

--version-info

아키텍처 의존정보

-A

--arch-specific

버킷 리스트 길이 히스토그램

-I(아이)

--histogram

모든 헤더 및 정보

-a

--all

코어 노트(core notes)

-n

--notes

unwind 정보

-u

--unwind

▷ 일반적으로 심볼 정보는 심볼 섹션에 있는 심볼 정보를 이용하지만,

-D 옵션 (--use-dynamic 옵션)을 사용하면 동적 섹션에 있는 심볼 정보를 이용하게 됨.

   

   

[ ELF 섹션 덤프 ]

-x 옵션 (--hex-dump 옵션)을 이용해 지정한 섹션의 내용을 덤프.

(섹션은 섹션 번호로 표시하고, -S 옵션으로 출력된 섹션 헤더에 섹션 번호가 표시된다.)
 

▶ 사용 예)

  

 

 

[ DWARF2 디버그 섹션 출력 ]

-w 옵션(--debug-dump 옵션)으로 DWARF2 디버그 섹션 정보를 출력.

-w

--debug-dump=

섹션

l

line

.debug_line

i

info

.debug_info

a

abbrev

.debug_abbrev

p

pubnames

.debug_pubnames

r

aranges

.debug_aranges

R

Ranges

.debug_ranges

m

macro

.debug_macinfo

f

frames

.debug_frame

F

frames-interp

.debug_frame

s

str

.debug_str

o

loc

.debug_loc

 

[ 긴 이름의 심볼 출력 ]

-W 옵션 (--wide 옵션)을 사용하면 80문자 이상의 행도 출력이 가능

(기본적으로 긴 이름의 심볼은 1행 이내에 출력되도록 뒷부분이 잘린다.)

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