ELF (Executable and Linking Format) 포맷에 대해 알아보자.
리눅스, 유닉스 환경에서 구동되는 프로그램의 바이너리 파일, 오브젝트 파일의 형식을 나타내는 것이다.
윈도우로 치면 PE포맷임.
오브젝트 파일 포스트에서 ELF 포맷을 공부하기 위해
오브젝트 파일의 몇가지 분류에 대해 설명했다.
ELF 포맷도 마찬가지로 용도가 조금 다르다.
다시 한번 설명함..
1. 실행 가능한 오브젝트 파일 (Executable object file)
-> 말 그대로 실행 가능한 파일
2. 공유 오브젝트 파일 (Shared object file)
-> 다른 공유 오브젝트 파일이나 재배치 가능한 오브젝트 파일과 링크하여 새 오브젝트파일을 만듦
3. 재배치 가능한 오브젝트 파일 (Relocatable object file)
-> 다른 오브젝트 파일과 링크되어 위에 두가지 오브젝트 파일을 생성할 수 있는 파일
이렇게 오브젝트 파일은 용도에 따라 구분이 3가지로 된다. 그래서 ELF 포맷도 형태가 나뉜다.
링킹 관점과 실행 관점.. 형태는 거의 비슷하다. 일단 그림을 보자.
두가지 관점 모두 기본 형태는 같다.
[ELF 헤더] [프로그램 헤더 테이블] [섹션 헤더 테이블] 로 구성되어 있다.
근데 중요한건 링킹 관점에서는 프로그램 헤더 테이블이 없을 수도 있다.
ELF 헤더만 맨 앞에 올 뿐, 나머지는 저 순서대로 있는 것은 아님
공유 오브젝트 파일은 두가지 형태 모두 가진다.(프로그램 헤더, 섹션 헤더)
자세한 설명은 각 항목별로 나누어 하겠음.
1. ELF Header
ELF 파일의 가장 처음 부분에 있다.
readelf 명령에 -h 프레그를 달면 elf헤더 내용을 확인할 수 있다.
오.. 뭔가 많은 설정 값들이 나온다. 대충 보면 알것 같기도 하지만 정확하게 알아야지.
설명에 들어가기 전에 ELF Header의 구조부터 확인해보자.
구조에 대응시켜 위 그림의 값들을 설명하겠음.
각각 32비트(위 구조체) 64비트(아래 구조체) 환경에서
사용하는 ELF 헤더 구조이다. ABC도 모르는 사람이 아니라면 주석보고 무슨 뜻인지 알 수 있다.
제일 처음 보이는 e_ident에 설정된 값은 매직 넘버와 여타 정보들이 들어있는 변수다.
매직 넘버의 제일 처음 4 바이트 0x7f 0x45 0x4c 0x46 으로 설정되어 있는데,
문자열로 변환시키면 (DEL) E L F 이다. ELF 파일이라는 것을 나타내주는 것.
뒤에 0x01과 0x00 값이 나오는데,
첫 번째 바이트는 ELFCLASS. 32비트는 0x01, 64비트는 0x02의 값을 갖는다.
두 번째 바이트는 엔디안. 리틀엔디안 0x01, 빅엔디안은 0x02
세 번째 바이트부터는 ELF 버젼, OS정보, ABI (Application Binary Interface) 등의 정보를 1바이트씩 사용하여 표기한다.
다음 e_type은 오브젝트 파일이 어떤 형식인지(위에 설명했듯이) 표기하는 부분.
오브젝트 파일에 여러가지 형식이 있듯이 값도 여러가지로 설정될 수 있다.
그리고 그 뒤에 나와있는 값들도 각자 자기 역할이 있겠지.
상대적으로 앞에 있는 내용보다 중요도가 떨어지므로 한번에 표에 정리하겠다.
요기 까지가 ELF Header에 대한 설명이다. 헤더 내용들에 대한 좀더 자세한 것들은
검색을 통해서 알아보시길.. 저기 있는 값들 하나하나 깊게 들어가면 너무 길어진다.
자 이제 Program Header를 알아보자.
2. Program Header
ELF 헤더에서 언급했던 프로그램 헤더 테이블 위치에 관련된e_phoff 에 지정된 값에서 시작하고
e_phentsize(사이즈), e_phnum(헤더 갯수) 로 헤더를 나타낸다.
readelf 에 -l 플레그 옵션을 주면 프로그램 헤더의 내용을 알 수 있다.
실행 파일에서 가지는 헤더 부분이다.
아까 그림에서 설명했듯이 실행관점에서 봤을때 생기는 헤더가 프로그램 헤더.
프로그램 헤더도 마찬가지로 elf.h 에 구조가 정의되어 있다.
[Section to Segment mapping:] 밑에 적힌 내용들은
실행파일 관점의 "Segment(세그먼트)" 이름과
한번 보면서 매칭시켜 보겠음.
이것도 마찬가지로 32비트와 64비트 환경에서 다른 구조체가 선언되어 있다. (숫자만 다름..)
자 그럼 이제 프로그램 헤더 구조체 인자들을 하나씩 파헤쳐보자.
먼저 p_type이다. 이녀석은 해당 세그먼트의 종류를 나타내는 것이다.
p_type에는 아래와 같이 여러가지 내용이 있다.
그리고 p_type 뒤에 나오는 내용들은 각각 헤더의 세그먼트들이 포함된 섹션의 이름을 나열하고 있는거임.
인덱스에 따라 다른 내용을 갖고 있다. 이것 또한 표로 정리..
이 부분은 사실 이해가 잘 가지않아서 계속 찾아봤는데.. 아직도 잘 모르겠다 -_-
후에 더 자세하게 알게되면 수정하겠음.
3. Section Header
이번엔 링킹 관점에서의 오브젝트 파일들에 대한 섹션헤더를 보도록 하자.
프로그램 헤더와 마찬가지로 ELF 헤더에 지정되어 있는 섹션 헤더 값들을 토대로 구성된다.
e_shoff 에 지정된 값에서 시작하고 e_shentsize(사이즈), e_shnum(헤더 갯수) 로 헤더를 나타낸다.
readelf 에 -S 플레그 옵션을 주면 프로그램 헤더의 내용을 알 수 있다.
일단 이거만 봐선 너도 나도 무슨 말인지 모른다.
방금 말한 프로그램 헤더의 세그먼트에 포함된 세션에 대한 내용이 여기 나와있는 모양이다.
일단 섹션헤더의 구조부터 보자.
위 구조는 readelf -S로 확인한 각 행 섹션에 대한 구성 내용이다.
먼저 sh_name (섹션 이름)을 보면, 뒤에 괄호로 string tbl index 라고 되어 있다.
스트링 테이블 인덱스?
위에 ELF 헤더에서 구성 항목을 알아볼 때 나왔는데.. 기억 안난다고 우길게 분명하니 캡쳐하겟음
이것은 ELF헤더에 있는 값이라고 했다.
스트링 테이블이란 건 그냥 단순히 문자열 리스트이다.
지금 우리가 보고있는 /bin/ls 의 readelf -h(ELF 헤더) 와 readelf -S(섹션 헤더) 내용을 살펴보면
이건 readelf -h 이다.
섹션 헤더 스트링 테이블 인덱스가 23이라고 나와 있다. 그럼 readelf -S 를 열어 23번 인덱스를 한번 보자.
오 이게 스트링 테이블 인덱스 23.
offset과 사이즈를 알 수 있다.
offset은 0x00a380, size는 0x0000ce
od 명령을 이용하여 .shstrtab 을 열어보자.
섹션헤더에 나왔던 섹션들의 이름 문자열이 나열되어 있는 것을 확인할 수 있다.
다음 세션 타입을 나타내는 sh_type 에 대해 알아보자.
말그대로 세션의 타입 별로 값을 주어 구분하게 되어 있음.
표에다 정리해보겠다.
그 외 헤더 내용들을 보겠다.
sh_flag : 섹션의 세부적인 특성을 나타냄. 1비트의 플레그 지원.
sh_addr : 만약 프로그램이 실행될 때 이 섹션이 실행을 위해 메모리에 적재된다면
섹션의 첫 바이트가 위치하는 바이트 옵셋을 가르킨다.
sh_offset : 이 섹션의 첫바이트가 위치하는 상대적인 바이트 옵셋 값을 가짐.
sh_size : 섹션의 크기를 바이트 단위로 나타냄.
sh_link : 섹션 헤더 테이블 인덱스의 링크.
sh_info : 섹션의 부가적인 정보가 들어있음.
sh_addralign : 주소 정렬 제한에 대한 제어 값을 가지고 있다. (자세한 내용은 후에 보충하겠음.)
sh_entsize : 섹션들은 모두 고정된 크기를 갖는데, 이 때 그 엔트리의 크기를 나타낸다.
내용은 후에 좀더 보충하도록 하겠음...
'IT 그리고 정보보안 > Knowledge base' 카테고리의 다른 글
오브제트 파일 관련 명령어 (objdump, objcopy, nm) (0) | 2021.04.18 |
---|---|
ldd (List Dynamic Dependencies) (0) | 2021.04.18 |
od(octal dump) (0) | 2021.04.18 |
C언어 컴파일 과정 (0) | 2021.04.18 |
Shell 실행 함수 종류 (0) | 2021.04.18 |