Esta herramienta permite obtener un archivo .elf totalmente analizable de una imagen de kernel vmlinux/vmlinuz/bzimage/zimage (una mancha binaria sin procesar o un archivo .elf preexistente pero eliminado), con función recuperada y símbolos variables.
Para esto, escanea su núcleo para una tabla de símbolos del núcleo (kallsyms), una tabla de símbolos comprimido que está presente en casi todos los kernel, en su mayoría inalterados.
Debido a que la tabla de símbolos en cuestión se comprime originalmente, debe recuperar cadenas que no son visibles en el binario original.
Produce un archivo .elf que puede analizar utilizando IDA Pro y Ghidra. Esta herramienta es, por lo tanto, útil para la ingeniería inversa de sistemas integrados.
Uso:
./vmlinux-to-elf < input_kernel.bin > < output_kernel.elf > Instalación de todo el sistema (el segundo comando puede no ser necesario ya que PIP debe encontrar las dependencias dentro del archivo setup.py ):
sudo apt install python3-pip liblzo2-dev
sudo pip3 install --upgrade lz4 zstandard git+https://github.com/clubby789/python-lzo@b4e39df
sudo pip3 install --upgrade git+https://github.com/marin-m/vmlinux-to-elfboot.img , ¡comenzando con un ANDROID! o UNCOMPRESSED_IMG magia [OK]Se puede encontrar una breve historia de la tabla de símbolos "Kallsyms" en la parte superior del archivo "kallsyms_finder.py". Brevemente, esto se introdujo alrededor de 2004 en el núcleo de Linux en su forma actual y se utiliza para imprimir los mensajes "Kernel Oops", entre otras cosas.
Contiene tuplas de "nombre del símbolo", "dirección del símbolo", "tipo de símbolo" (los tipos de símbolos que se designan con una sola letra de una manera similar a la utilidad nm ), esta información está bien llena de un algoritmo de compresión simple.
El siguiente esquema muestra cómo esta información se serializa en el núcleo, el desplazamiento de cada estructura respectiva detectada por vmlinux-to-elf a través de la heurística:
| Nombre de la matriz | Descripción | Muestra de contenido |
|---|---|---|
kallsyms_addresses (o kallsyms_offsets + kallsyms_relative_base ) | Las direcciones (o compensaciones en relación con una base, en núcleos recientes) de cada símbolo, como una matriz | 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 | El número total de símbolos, como entero (útil para verificar la endianness, la alineación, la decodificación correcta de la tabla de símbolos) | 54 D4 00 00 |
kallsyms_names | Los símbolos comprimidos y separados por longitud. Cada byte en las cadenas de símbolos comprimidos hace referencia a un índice en la matriz "kallsyms_token_index", que en sí misma hace referencia al desplazamiento de un fragmento de carácter o cadena en la matriz "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 | Una tabla de búsqueda que sirve para encontrar rápidamente el desplazamiento aproximado de un nombre de símbolo comprimido en "kallsyms_names": cada 256 símbolos, un desplazamiento al símbolo preocupado en "kallsyms_names" se agrega como una tabla larga. | 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 | Esta tabla de búsqueda (presente solo en 6.2+ núcleos) contiene una secuencia de matriz de enteros de 3 bytes empaquetados, donde los índices de matriz coinciden con el orden alfanumérico para un nombre de símbolo dado, y los valores de matriz coinciden con los índices de entrada correspondientes en kallsyms_addresses y kallsyms_names Arrays Arrays | |
kallsyms_token_table | Fragmentos de cuerda o caracteres de cadena nulo que pueden estar contenidos en los nombres de símbolos del núcleo. Esto puede contener como máximo 256 fragmentos o caracteres de cadena. Los índices correspondientes a los puntos de código ASCII que realmente se utilizan en cualquier símbolo del núcleo corresponderán al carácter ASCII en cuestión, otras posiciones contendrán un fragmento de cadena estadísticamente elegido. Esta herramienta intenta encontrar heurísticamente esta matriz a través del archivo aprobado primero para encontrar la tabla de símbolos 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 palabras, cada mapeo a las compensaciones de los caracteres o fragmentos de cadena designados por sus respectivos índices en "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 ... |
Estos campos tienen alineación variable y tamaño de campo. Los tamaños de campo también pueden variar sobre la arquitectura y la versión del núcleo. Por esta razón, vmlinux-to-elf se ha probado en una variedad de casos.
OpenWRT desde 2013 tiene un parche que elimina la compresión sobre la tabla kallsyms de forma predeterminada (cuando el usuario ha habilitado la construcción kallsyms ). Hacen esto para ahorrar espacio al volver a comprimir el núcleo con LZMA.
Esto significa que las entradas kallsyms_token_table y kallsyms_token_address desaparecen, y que los nombres de símbolos usan texto plano ASCII en su lugar. Este caso también es compatible.
En los núcleos estándar de Linux 6.2, las matrices kallsyms están codificadas en el siguiente orden:
kallsyms_addresses (o kallsyms_offsets + kallsyms_relative_base )kallsyms_num_symskallsyms_nameskallsyms_markerskallsyms_seqs_of_names (solo 6.2+)kallsyms_token_tablekallsyms_token_indexPara los núcleos de Linux 6.4+, este diseño se cambia a:
kallsyms_num_symskallsyms_nameskallsyms_markerskallsyms_token_tablekallsyms_token_indexkallsyms_addresses (o kallsyms_offsets + kallsyms_relative_base )kallsyms_seqs_of_names Mientras que estos se analizan en el siguiente orden por el algoritmo de análisis de vmlinux-to-elf :
kallsyms_token_table (estructura anterior)kallsyms_token_index (última estructura, hacia adelante)kallsyms_markers (al revés)kallsyms_names (hacia atrás de nuevo)kallsyms_num_syms (hacia atrás de nuevo)kallsyms_addresses (o kallsyms_offsets + kallsyms_relative_base ) (hacia atrás nuevamente) Debe admitir núcleos de la versión 2.6.10 (diciembre de 2004), hasta el actual 6.4 (a agosto de 2023). Solo los kernels configurados explícitamente sin CONFIG_KALLSYMS no deben ser compatibles. Si esta variable de configuración del núcleo no se estableció en la compilación, obtendrá: KallsymsNotFoundException: No embedded symbol table found in this kernel .
Para los núcleos crudos, se pueden detectar las siguientes arquitecturas (usando Magics de Binwalk): Mipsel, Mipseb, Armel, Armeb, PowerPC, SPARC, X86, X86-64, ARM64, MIPS64, Superh, Arco.
Los siguientes formatos de compresión del núcleo se pueden detectar automáticamente: XZ, LZMA, GZIP, BZ2, LZ4, LZO y ZSTD.
También puede obtener una salida de solo texto de los nombres, direcciones y tipos de símbolos del núcleo mediante el uso de la utilidad kallsyms-finder , también inclinada con esta herramienta. El formato de su salida será similar al archivo /proc/kallsyms PROCFS.
Algunos parámetros que deben ser inferidos automáticamente por la herramienta (como el conjunto de instrucciones o la dirección base) pueden ser anulados en caso de emisión. La especificación completa de los argumentos que permiten hacer eso se presenta a continuación:
$ vmlinux-to-elf -h
usage: vmlinux-to-elf [-h] [--e-machine DECIMAL_NUMBER] [--bit-size BIT_SIZE]
[--file-offset HEX_NUMBER] [--base-address HEX_NUMBER]
input_file output_file
Turn a raw or compressed kernel binary, or a kernel ELF without symbols, into
a fully analyzable ELF whose symbols were extracted from the kernel symbol
table
positional arguments:
input_file Path to the
vmlinux/vmlinuz/zImage/bzImage/kernel.bin/kernel.elf
file to make into an analyzable .ELF
output_file Path to the analyzable .ELF to output
optional arguments:
-h, --help show this help message and exit
--e-machine DECIMAL_NUMBER
Force overriding the output ELF "e_machine" field with
this integer value (rather than auto-detect)
--bit-size BIT_SIZE Force overriding the input kernel bit size, providing
32 or 64 bit (rather than auto-detect)
--file-offset HEX_NUMBER
Consider that the raw kernel starts at this offset of
the provided raw file or compressed stream (rather
than 0, or the beginning of the ELF sections if an ELF
header was present in the input)
--base-address HEX_NUMBER
Force overriding the output ELF base address field
with this integer value (rather than auto-detect)
$ kallsyms-finder -h
usage: kallsyms-finder [-h] [--bit-size BIT_SIZE] input_file
Find the kernel's embedded symbol table from a raw or stripped ELF kernel
file, and print these to the standard output with their addresses
positional arguments:
input_file Path to the kernel file to extract symbols from
optional arguments:
-h, --help show this help message and exit
--bit-size BIT_SIZE Force overriding the input kernel bit size, providing
32 or 64 bit (rather than auto-detect)
No dude en abrir un problema para cualquier sugerencia de mejora.