
원시 커널에서 커널 심볼 테이블(kallsyms)을 추출하여 완전히 분석 가능한 .ELF를 복구하는 도구
이 도구는 vmlinux/vmlinuz/bzImage/zImage 커널 이미지(원시 바이너리 블롭 또는 이미 존재하지만 심볼이 제거된 .ELF 파일)에서 함수 및 변수 심볼을 복구하여 완전히 분석 가능한 .ELF 파일을 얻을 수 있게 해 줍니다.
이를 위해 이 도구는 커널에서 커널 심볼 테이블(kallsyms)을 스캔합니다. kallsyms는 거의 모든 커널에 대부분 변경되지 않은 채로 존재하는 압축된 심볼 테이블입니다.
해당 심볼 테이블은 원래 압축되어 있기 때문에 원본 바이너리에는 보이지 않는 문자열도 복구할 수 있습니다.
이 도구는 IDA Pro 및 Ghidra로 분석할 수 있는 .ELF 파일을 생성합니다. 따라서 임베디드 시스템 리버스 엔지니어링에 유용합니다.
사용법:
# Command line:
vmlinux-to-elf <input_kernel.bin> <output_kernel.elf>
# Command line, list symbol addresses only:
kallsyms-finder <input_kernel.bin> # If installed with uv
vmlinux-to-elf.kallsyms-finder # If installed with snap
# Command line, just decompress the kernel:
vmlinuz-decompressor <input_kernel.bin> <output_kernel.bin> # If installed with uv
vmlinux-to-elf.vmlinuz-decompressor # If installed with snap
# Graphical:
vmlinux-to-elf-gui # If installed with uv
vmlinux-to-elf.gui # If installed with snap
flatpak run re.fossplant.vmlinux-to-elf # If installed with flatpak
설치:
# Install CLI+GUI with Snap (recommended on Ubuntu)
sudo snap install vmlinux-to-elf
# Install CLI+GUI with yay (recommended on Arch, Manjaro)
yay -S vmlinux-to-elf libadwaita python-gobject
# Install CLI+GUI with uv (example with Fedora)
sudo dnf install -y uv glib2-devel libadwaita-devel gtk4-devel \
gobject-introspection-devel python3-gobject-devel \
python3-devel cairo-devel @development-tools
uv tool install vmlinux-to-elf[gui]
vmlinux-to-elf-gui --install-metadata # Install .desktop file
# Install CLI with uv and GUI with Flatpak (recommended on
# distributions with libadwaita < 1.6)
sudo dnf install -y uv flatpak @development-tools
uv tool install vmlinux-to-elf
flatpak remote-add --if-not-exists flathub https://flathub.org/repo/flathub.flatpakrepo
flatpak install re.fossplant.vmlinux-to-elf
로컬 개발 환경 설정:
sudo snap install --classic astral-uv
sudo apt install git
git clone [email protected]:marin-m/vmlinux-to-elf.git
# Dependencies for the GTK-4 GUI
sudo apt install libgirepository-2.0-dev libadwaita-1-dev \
gir1.2-adw-1 gir1.2-gtk-4.0 python3-dev blueprint-compiler
cd vmlinux-to-elf
cp -a .github/hooks/* .git/hooks/
# Download Python modules and initialize virtualenv (creates ".venv",
# call "source .venv/bin/activate" to set up)
uv sync --extra gui
# Add vmlinux-to-elf to $PATH, so that the commands are callable
# system-wide (creates a symlink to the source in "~/.local/bin")
uv tool install -e .[gui]
ANDROID! 또는 UNCOMPRESSED_IMG 매직으로 시작하는 특정 유형의 Android boot.img 파일 해제 [OK]"kallsyms" 심볼 테이블에 대한 간략한 역사는 "kallsyms.py" 파일 상단에서 확인할 수 있습니다. 간단히 말하면, 이 테이블은 2004년경 Linux 커널에 현재의 형태로 도입되었으며, 무엇보다도 "Kernel oops" 메시지를 출력하는 데 사용됩니다.
여기에는 "심볼 이름", "심볼 주소", "심볼 유형"의 튜플이 포함됩니다(심볼 유형은 nm 유틸리티와 유사하게 단일 문자로 지정됩니다). 이 정보는 간단한 압축 알고리즘으로 빽빽하게 패킹되어 있습니다.
아래 스키마는 이 정보가 커널에 직렬화되는 방식을 보여줍니다. 각 구조체의 오프셋은 vmlinux-to-elf가 휴리스틱을 통해 감지합니다.
| 배열 이름 | 설명 | 샘플 내용 |
|---|---|---|
kallsyms_addresses (or kallsyms_offsets + kallsyms_relative_base) | 각 심볼의 주소(또는 최신 커널에서는 베이스에 대한 상대 오프셋)를 배열로 저장 | 80 82 00 C0 80 82 00 C0 80 82 00 C0 0C 84 00 C0 B4 84 00 C0 5C 85 00 C0 60 85 00 C0 60 85 00 C0 ... |
kallsyms_num_syms | 전체 심볼 수를 정수로 저장 (엔디안, 정렬, 심볼 테이블의 올바른 디코딩 여부를 확인하는 데 유용) | 54 D4 00 00 |
kallsyms_names | 압축되고 길이로 구분된 심볼 이름 자체. 압축된 심볼 문자열의 각 바이트는 "kallsyms_token_index" 배열의 인덱스를 참조하며, 이 인덱스는 다시 "kallsyms_token_table" 배열의 문자 또는 문자열 조각의 오프셋을 참조합니다. | 09 54 64 6F 5F E1 F1 66 F5 25 05 54 F3 74 AB 74 0E 54 FF AB ... |
kallsyms_markers | "kallsyms_names"에서 압축된 심볼 이름의 대략적인 오프셋을 빠르게 찾는 데 사용되는 룩업 테이블: 256개 심볼마다 "kallsyms_names"의 해당 심볼에 대한 오프셋이 long 형식으로 이 테이블에 추가됩니다. | 00 00 00 00 03 0C 00 00 0C 18 00 00 1B 24 00 00 0F 31 00 00 DA 3D 00 00 CF 4A 00 00 ... |
kallsyms_seqs_of_names | 이 룩업 테이블(6.2+ 커널에만 존재)은 패킹된 3바이트 정수의 배열 시퀀스를 포함하며, 배열 인덱스는 특정 심볼 이름의 영숫자 순서와 일치하고 배열 값은 kallsyms_addresses 및 kallsyms_names 배열의 해당 엔트리 인덱스와 일치합니다. | |
kallsyms_token_table | 커널 심볼 이름에 포함될 수 있는 널 종료 문자열 조각 또는 문자. 최대 256개의 문자열 조각 또는 문자를 포함할 수 있습니다. 실제로 커널 심볼에서 사용되는 ASCII 코드 포인트에 해당하는 인덱스는 해당 ASCII 문자에 대응하며, 나머지 위치에는 통계적으로 선택된 문자열 조각이 포함됩니다. 이 도구는 kallsyms 심볼 테이블을 찾기 위해 먼저 전달된 파일 전체에서 이 배열을 휴리스틱하게 찾으려고 시도합니다. | 73 69 00 67 70 00 74 74 00 79 6E 00 69 6E 74 5F 00 66 72 00 ... |
kallsyms_token_index | 256개의 워드로, 각각 "kallsyms_token_table"의 해당 인덱스가 지정하는 문자 또는 문자열 조각의 오프셋에 매핑됩니다. | 00 00 03 00 06 00 09 00 0C 00 11 00 14 00 1B 00 1E 00 22 00 2C 00 30 00 35 00 38 00 ... |
이 필드들은 정렬과 필드 크기가 가변적입니다. 필드 크기는 아키텍처와 커널 버전에 따라 달라질 수도 있습니다. 이러한 이유로 vmlinux-to-elf는 다양한 사례에 대해 테스트되었습니다.
OpenWRT는 2013년부터 기본적으로 kallsyms 테이블의 압축을 제거하는 패치를 보유하고 있습니다(사용자가 빌드 시 kallsyms를 활성화한 경우). 이는 LZMA를 사용하여 커널을 다시 압축할 때 공간을 절약하기 위한 것입니다.
즉, kallsyms_token_table 및 kallsyms_token_address 엔트리가 사라지고, 심볼 이름이 일반 텍스트 ASCII를 대신 사용하게 됩니다. 이 경우도 지원됩니다.
표준 Linux 6.2 커널에서 kallsyms 배열은 다음 순서로 인코딩됩니다:
kallsyms_addresses (or kallsyms_offsets + kallsyms_relative_base)kallsyms_num_symskallsyms_nameskallsyms_markerskallsyms_seqs_of_names (6.2+ 전용)kallsyms_token_tablekallsyms_token_indexLinux 6.4+ 커널에서는 이 레이아웃이 다음과 같이 변경됩니다:
kallsyms_num_symskallsyms_nameskallsyms_markerskallsyms_token_tablekallsyms_token_indexkallsyms_addresses (또는 kallsyms_offsets + kallsyms_relative_base)kallsyms_seqs_of_names한편 vmlinux-to-elf의 파싱 알고리즘은 이를 다음 순서로 파싱합니다:
kallsyms_token_table (끝에서 두 번째 구조)kallsyms_token_index (마지막 구조, 순방향)kallsyms_markers (역방향)kallsyms_names (다시 역방향)kallsyms_num_syms (다시 역방향)kallsyms_addresses (또는 kallsyms_offsets + kallsyms_relative_base) (다시 역방향)2.6.10(2004년 12월)부터 현재 6.4(2023년 8월 기준)까지의 커널을 지원합니다. CONFIG_KALLSYMS 없이 명시적으로 구성된 커널만 지원되지 않습니다. 빌드 시 이 커널 구성 변수가 설정되지 않은 경우 KallsymsNotFoundException: No embedded symbol table found in this kernel 오류가 발생합니다.