리눅스 바이너리 실행의 비밀, ELF와 동적 링킹을 파헤치다!

by DD
1개월 전
조회수 38

저자는 25년간의 리눅스 내부 경험을 바탕으로 ELF(Executable and Linkable Format) 파일 형식을 심층 분석함

동적 링킹(Dynamic Linking)의 동작 원리를 상세히 설명하며, GOT/PLT, 재배치(Relocations) 과정을 다룸

실행 시점(Runtime)에 메모리 매핑, 시스템 콜(Syscalls), 동적 로더(Dynamic Loader)의 역할을 파악

LD_PRELOAD를 활용한 실행 파일 가로채기(Interception)를 통해 시스템 보안 취약점 및 공격 기법을 제시

ELF 파일 구조와 실행 과정

저자는 ELF 파일이 단순한 실행 파일이 아닌, 컴파일된 코드, 시스템 로더, 메모리 간의 계약(Contract)이라고 정의한다. ELF 헤더(ELF Header), 프로그램 헤더(Program Headers), 섹션 헤더(Section Headers)로 구성되며, 각 헤더는 실행 파일의 로딩과 실행에 필요한 정보를 담고 있다. 특히, 프로그램 헤더는 메모리 매핑(Memory Mapping)에, 섹션 헤더는 링커 및 분석 도구에 활용된다는 점을 강조한다.

동적 링킹과 PLT/GOT의 역할

본문에서는 동적 링킹의 핵심 메커니즘인 PLT(Procedure Linkage Table)와 GOT(Global Offset Table)를 상세히 설명한다. PLT는 외부 함수 호출을 위한 작은 점프 테이블(Tiny Trampolines) 역할을 하며, GOT는 실제 함수 주소를 저장한다. Lazy Binding 방식을 통해 초기 실행 시 모든 의존성을 해결하는 대신, 필요할 때만 함수 주소를 찾아 GOT를 업데이트하여 성능을 최적화한다.

LD_PRELOAD를 이용한 런타임 가로채기

저자는 LD_PRELOAD 환경 변수를 활용하여 동적 링킹 과정(Dynamic Linking Process)을 가로채는 방법을 제시한다. LD_PRELOAD를 통해 라이브러리를 먼저 로드하면, 링커가 해당 라이브러리의 함수를 먼저 사용하게 된다. 이를 통해 printf와 같은 함수를 가로채어 실행 흐름을 변경하고, 시스템 보안 취약점을 악용하는 루트킷(Rootkit)을 구현할 수 있음을 보여준다.

스택, 힙, 그리고 메모리 매핑

실행 파일이 메모리에 로드된 후, 스택(Stack), 힙(Heap)과 같은 메모리 영역이 생성된다. 저자는 섹션(Sections)이 디스크 상의 프로그램 구조를 나타내고, 세그먼트(Segments)가 메모리 상의 프로그램 구조를 정의한다고 설명한다. /proc//maps 파일을 통해 메모리 매핑 정보를 직접 확인할 수 있으며, ASLR(Address Space Layout Randomization)과 PIE(Position Independent Executable) 컴파일을 통해 보안을 강화할 수 있다.

How Linux executes binaries: ELF and dynamic linking explained