[Tip] Linux ELF File 구조

오브젝트 파일은 컴파일러가 생성한 중간 단계의 파일을 말하며 기계어 코드만이 아니라, 심볼 테이블, 디버그 정보, 재배치 정보 등 다양한 정보를 포함하고 있다.
이번 포스팅에서는 오브젝트 파일에 포함되는 정보를 추출하는 방법과 오브젝트파일을 조작하는 방법을 소개한다.

ELF 파일
ELF는 Executable and Linking Format의 약자로 실행 가능한 바이너리 또는 오브젝트 파일 등의 형식을 규정한 것이다. ELF 파일은 ELF 헤더가 맨 앞에 위치하고, 프로그램 헤더 테이블과 섹션 헤더 테이블이 그 뒤에 위치한다.
ELF파일의 헤더의 구조는 elf.h에 저장되어 있다.

ELF 헤더
ELF 파일 맨 앞에 반드시 존재하며, 그 부분이 ELF 파일임을 나타낸다. ELF 파일 헤더 내용은 "readelf"의 -h 옵션(--file-header 옵션)을 사용해서 볼 수 있다.






 ELF 파일은 첫 4바이트(파란색)에 "0x7F  0x45  0x4C  0x46"(ASCII "\177ELF") 매직넘버를 가지고 있다. 그다음 바이트(빨간색)는 엔디안을 나타내는데, 리틀 엔디안의 경우 1,빅 엔디안의 경우 2를 사용한다. 그 다음바이트(노란색)는 ELF의 버전과 (보라색)OS,ABI 등의 정보를 나타낸다. 



  • type : 4가지 타입이 존재한다.
    • REL , 바이너리 1, 재배치 가능한 파일
    • EXEC, 바이너리 2, 실행 가능한 파일
    • DYN, 바이너리 3, 공유 오브젝트 파일
    • CORE, 바이너리 4, 코어 파일
  • Machine : 아키텍처 타입을 나타낸다. 
  • entry point address : 이 ELF에서 실행 시작하는 가상 주소이다. 실제 바이너리 안에 있다. 이부분을 이용할 수도 있지 않을까..?

  • 나머지는 그대로 읽으면 알 수 있겠지요...~

프로그램 헤더
ELF 헤더에서 정의되있는 부분을 참고하여 정해진 크기를 갖는 테이블이다.

  • Start of program headers = 지정된 오프셋에서부터 시작
  • Size of program headers = 테이블 내의 프로그램 헤더 크기 
  • Number of program headers = 테이블 내의 프로그램 헤더 개수

즉 프로그램 헤더 테이블의 전체 크기는 Size of program headers * Number of program headers
프로그램 헤더 내용은 "readelf"의 - l 옵션(--program-headers )을 사용해서 볼 수 있다.
Program Headers 의 각 행에 해당하는 Type(파란색)

  • LOAD,  바이너리 1, 로그된 프로그램 세그먼트
  • DYNAMIC, 바이너리 2, 동적 링크 정보
  • INTERP, 바이너리3, 프로그램 인터프리터
  • NOTE, 바이너리 4, 추가 정보
  • PHDR, 바이너리 6, 프로그램 헤더 테이블 자신
  • TLS, 바이너리 7, 스레드 지역 저장소
  • GNU_EH_FRAME, 바이너리 0x6474e550, GNU .eh_frame_hdr 세그먼트
  • GNU_EH_STACK, 바이너리 0x6474e551, 스택 실행 가능성
"Section to Segment mapping"(빨간색) 이후의 행에 나타난 정보는 "Program Headers"의 각 프로그램 헤더에 나타난 세그먼트에 그 세그먼트 메모리 범위를 포함하는 섹션명을 나열하고 있다
  • 최초(인덱스 00) 프로그램 헤더에 표시된 세그먼트는 "PHDR"타입, 속하는 섹션 없음
  • 01 프로그램 헤더에 표시된 세그먼트는 "INTERP"타입, 속하는 섹션 .interp
  • 02 프로그램 헤더에 표시된 세그먼트는 "LOAD"타입, 그 안에 좀 많다..?

섹션 헤더
ELF 헤더의 Start of Section headers로 지정된 오프셋에서 시작한다. 크기와 갯수는 elf헤더를 보면 딱 알 수 있을 것이다.
섹션 헤더 내용은 "readelf"의 -S 옵션(--section-headers)을 사용해서 볼 수 있다.
섹션 타입의 종류
  • PROGBITS, 1,  프로그램 데이터
  • SYMTAB, 2, 심볼 테이블
  • STRTAB, 3, 스트링 테이블
  • RELA, 4, 재배치 엔트리
  • HASH, 5, 심볼 해시 테이블
  • DYNAMIC, 6, 동적 링크 정보
  • NOTE, 7,  notes(호환성 체크를 위한 특별 정호)
  • NOBITS, 8, 파일상에 데이터가 없는 부분(.bss)
  • REL, 9, 재배치 엔트리
  • DYNSYM, 11, 동적 링크에서 사용되는 심볼 테이블
  • INIT_ARRAY, 14, 생성자 배열(.init)
  • FINI_ARRAY, 15, 파괴자 배열(.init)
  • GNU_verdef, 0x6ffffffd, 버전 정의 섹션
  • GNU_verneed, 0x6ffffffe, 버전 중요 섹션
  • GNU_versym, 0x6fffffff, 버전 심볼 테이블



스트링 테이블
스트링 테이블은 단순한 문자열 리스트이다. type부분이 STRTAB인 부분을 한번 보면,
[27] .shstrtab 의 오프셋은 0x1037, 크기는 0xee,이므로 OD를 사용하여 이 부분을 한번 보자
스트링 테이블은 단순히 바이너리파일에서 그대로 긁어오는 것을 알 수 있다.


심볼 테이블
심볼 테이블은 심볼과 그 값 등을 대응시키는 테이블이다. 
섹션 헤더 내용은 "readelf"의 -s 옵션(--sysms)을 사용해서 볼 수 있다.
중략...


ELF 헤더에서 e_ident는 ELF의 매직 넘버(magic number)와 기타 정보를 갖고 있다. 아래 참고 사이트에서 직접 확인해보는 것도 재미있을 것이다.
linux-2.6.39.4-ccs-1.8.3의 경우 elf.h의 elf 헤더 구조


프로그램 헤더의 구조
linux-2.6.39.4-ccs-1.8.3의 경우 elf.h의 프로그램 헤더 구조


섹션 헤더의 구조
linux-2.6.39.4-ccs-1.8.3의 경우 elf.h의 섹션 헤더 구조


[#] Linux의 elf.h 참고: http://tomoyo.sourceforge.jp/cgi-bin/lxr/source/include/linux/elf.h

댓글