ELF 파일 구조

2021. 6. 2. 00:27Layer7/Reverse Engineering

728x90

- ELF 파일

 

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

여기서 ELF는 Executable and Linkable Format의 약자입니다.

(실행, 링킹이 가능한 포멧)

 

ELF 파일은 ELF 헤더, 프로그램 헤더 테이블, 섹션 헤더 테이블로 이루어져있습니다.

 

ELF 헤더는 ELF 파일의 구성을 나타내는 부분입니다.

파일의 가장 첫 부분을 차지하며, 파일의 특성을 알 수 있는 아주 중요한 부분입니다.

 

프로그램 헤더 테이블은 ELF 안의 *세그먼트들에 대한 정보들로

런타임 중에 사용될 메모리 정보

프로세스 이미지를 어떻게 구현해야 할지 나와있는 부분입니다.

 

*섹션 헤더 테이블은 ELF 안에 있는 섹션들에 대한 정보들을 모아둔 부분입니다.

* 실행 파일의 정보가 담긴 공간

 

 

- ELF 헤더

 

ELF 헤더는 xxd 명령어를 이용해 직접 분석을 해보며 정리를 할 생각입니다.

예전에 썼던 C 실행파일 중 test라는 파일이 있으니 그 파일을 hex, 즉 16진수 형식으로 변경하여 설명하겠습니다.

 

#include<stdio.h>

int test(){
	if(num==(100&260)){
    	return 1;
    }
    return 0;
}

void win(){
	printf("good\n");
}

void los(){
	printf("bad\n");
}

int main(){
	int num;
    int res;
    
    printf("Enter Num : ");
    scanf("%d",&num);
    
    res=test(num);
    if(res==1){
    	win(1,2,3,4,5);
    }
    else if(){
    	lose();
    }
    return 0;
}

엄청난 양의 hex 코드! 아래에 더 있습니다

위 사진을 보면 왼쪽에 문자열, 중앙에 4글자씩 끊어진 코드가 있고, 오른쪽에 길게 늘어진 문자들이 있습니다.

왼쪽에 있는 문자열은 *오프셋, 중앙에 있는 코드들은 hex 코드,

* 상대 코드

오른쪽에 있는 문자들은 hex 코드를 영어로 번역한 것입니다.

 

hex 코드의 가장 처음 부분을 보면 7f, 45, 4c, 46 이렇게 4byte의 값들이 있습니다.

이 값들은 ELF 코드를 뜻하는 부분입니다.

 

그보다 아래의 부분들은 하나하나 말하기 보단 표로 정리하는 것이 눈에 더 잘 들어올 것 같으니

표로 정리하여 설명과 함께 적어두도록 하겠습니다.

 

오프셋
0x04 비트 정보. 64비트는 0x02, 32비트는 0x01로 나타난다.
0x05 *Endianness 관한것. *Little Endian일 때는 0x01, *Big Endian일 때는 0x02로 나타난다.
0x06 버전을 나타내는 부분. 항상 0x01로 고정되어있다.
0x07 어떤 운영체제를 위해 제작되었는지 구분. 대상 플랫폼에 따라 값이 달라지지만 종종 0으로 설정된다.
0x08 *ABI 버전. 리눅스 상에서는 특별한 뜻이 없다.
0x09 현재 사용하지 않고 있는 부분. 0으로 채운다.
0x10 현재 파일이 실행, 오브젝트, 공유 라이브러리, 코어 중 어떤것에 속하냐에 따라 1,2,3,4로 결정된다.
0x11 현재 실행파일이 작성된 ISA를 가리킨다. (0x3e : AMD x86-x64)
0x14 ELF의 버전 설정. 0x01로 설정되어있다.
0x18 *엔트리 포인트가 담겨있는 부분.
0x1C, 0x20 프로그램 헤더 테이블을 가리킨다.
0x20, 0x28 섹션 헤더 테이블을 가리킨다.
0x28, 0x34 ELF 헤더의 크기를 보여준다. (메모리 주소 포인트)
0x2A, 0x36 프로그램 헤더 테이블의 크기.
0x2c, 0x38 프로그램 헤더 테이블의 엔트리 수.
0x2E, 0x3A 섹션 헤더 테이블의 크기.
0x30, 0x3C 섹션 헤더 테이블의 엔트리 수.
0x32, 0x3E 섹션 이름들이 있는 섹션 헤더 테이블의 주소.
0x34, 0x40 ELF 헤더 끝

* 컴퓨터의 메모리와 같은 1차원의 공간에 여러 개의 연속된 대상을 배열하는 방법

* 작은 단위가 앞에 나오는 Endianness

* 큰 단위가 앞에 나오는 Endianness

* 응용 프로그램 이진 인터페이스

* 제어가 운영 체제에서 컴퓨터 프로그램으로 이동하는 것

 

간결하게 정리된 위 표의 내용을 볼 수 있는 명령어가 있습니다.

-> readelf -h ./[파일명]

명령어 입력 결과

각종 정보들이 한줄로 정리되어 나오게 됩니다.

 

 

- 프로그램 헤더 테이블

 

프로그램 헤더 테이블 역시 간결하게 정리된 내용을 볼 수 있는 명령어가 있습니다.

-> readelf -l ./[파일명]

 

명령어 입력 결과

시스템은 프로그램 헤더 테이블을 참조하여 프로세스 메모리를 구성합니다.

 

 

- 섹션 헤더 테이블

 

이 부분에는 여러가지 섹션들이 있습니다.

그 중에서도 아래의 4가지 섹션들은 중요한 섹션이므로 알아두면 좋습니다.

 

  • .test : 프로그램의 실행 가능한 명령어들이 위치.
  • .data : 초기화된 전역, 정적 변수들이 위치.
  • .bss : 초기화가 되지 않은 전역, 정적 변수들이 위치. 시작시에 0으로 자동 초기화 하는 특징이 있다.
  • .rodata : 읽기 전용 데이터 섹션 (읽기만 가능. 나머지는 권한 X). 문자열, 상수가 위치.

 

- 심볼 테이블

 

심볼 테이블이란 함수의 이름들에 대한 정보를 가지고 있는 테이블입니다.

 

심볼 테이블을 확인하려면 아래와 같은 명령어를 사용하면 됩니다.

-> readelf -s ./[파일명]

 

명령어 처리 결과. 아래에 더 많은 심볼 테이블이 존재

여기서 dynsym, dynstr는 사용하는 공유 라이브러리 함수에 대한 *심볼을 가집니다.

* 함수명

그리고 symtab, strtab는 해당 프로그램에서 사용하는 모든 함수들에 대한 심볼을 가집니다.

(symtab 결과가 dynsym 결과보다 많은 것도 위와 같은 이유 때문입니다)

 

또한 위의 섹션들은 Dynamic Linking, 즉 동적 링킹을 할 때 필요합니다.

 

 

- PLT & GOT

 

PLT는 Procedure Linkage Table의 약자이고

GOT는 Global Offset Table의 약자입니다.

 

PLT는 외부 라이브러리 함수의 주소와 연결하기 위해 있는 테이블입니다.GOT는 외부 라이브러리에 있는 함수의 주소를 가지는 테이블입니다.

 

이렇게 정의만 말하면 이해가 잘 안될 수도 있으니아래 사진으로 예시를 들면서 설명을 적어보도록 하겠습니다.

 

PLT, GOT의 상호 관계

"call printf@plt"라는 부분은 printf 함수를 호출하는 부분입니다.

 

우선 PLT에게 가고 GOT로 점프를 합니다.

 

GOT로 이동을 했으면 라이브러리를 참조하게 됩니다.

이 라이브러리에는 printf의 주소가 담겨져있고, GOT가 그 주소를 반환합니다.

728x90