#!/usr/bin/env python3 # Small script to print all options available inside a built kernel. # fmt: off import sys from elftools.elf.elffile import ELFFile SIZEOF_PTR = 8 SIZEOF_STRUCT = 40 ENDIAN = "little" if __name__ == "__main__": if len(sys.argv) < 2: print("Provide a path to the kernel binary to use") sys.exit(1) with open(sys.argv[1], "rb") as elffile: file = ELFFile(elffile) section = file.get_section_by_name(".cmdline") if section == None: sys.exit(1) cmdline_data = section.data() num_options = int(section.data_size / SIZEOF_PTR) print(f"Kernel contains {num_options} options:") for i in range(num_options): # Read "struct cmdline_option*" addr = int.from_bytes(cmdline_data[(i * SIZEOF_PTR) :][:SIZEOF_PTR], byteorder=ENDIAN) elffile.seek(next(file.address_offsets(start=addr))) option = elffile.read(SIZEOF_STRUCT) # Name name = "" name_ptr = int.from_bytes(option[0:][:SIZEOF_PTR], byteorder=ENDIAN) elffile.seek(next(file.address_offsets(start=name_ptr))) while True: b = int.from_bytes(elffile.read(1)) if b == 0: break name += chr(b) # Description desc = "" desc_ptr = int.from_bytes(option[8:][:SIZEOF_PTR], byteorder=ENDIAN) elffile.seek(next(file.address_offsets(start=desc_ptr))) while True: b = int.from_bytes(elffile.read(1)) if b == 0: break desc += chr(b) # Type kind_str = "unknown" kind = int.from_bytes(option[16:][:4], byteorder=ENDIAN) match kind: case 0: kind_str = "string" case 1: kind_str = "bool" case 2: kind_str = "integer" case 2: kind_str = "unsigned integer" # Skip function pointer # Allowed values limit = "" limit_ptr = int.from_bytes(option[32:][:SIZEOF_PTR], byteorder=ENDIAN) if limit_ptr != 0: elffile.seek(next(file.address_offsets(start=limit_ptr))) match kind: case 0: limit = [] i = 0 while True: ptr = next(file.address_offsets(start=limit_ptr + i * SIZEOF_PTR)) elffile.seek(ptr) str_ptr = int.from_bytes(elffile.read(SIZEOF_PTR), byteorder=ENDIAN) if str_ptr == 0: break strstr_off = next(file.address_offsets(start=str_ptr)) val = "" elffile.seek(strstr_off) while True: b = int.from_bytes(elffile.read(1)) if b == 0: break val += chr(b) i += 1 limit.append(val) case 2: min = int.from_bytes(elffile.read(SIZEOF_PTR), byteorder=ENDIAN, signed=True) max = int.from_bytes(elffile.read(SIZEOF_PTR), byteorder=ENDIAN) limit = f"[{min}, {max}]" case 3: min = int.from_bytes(elffile.read(SIZEOF_PTR), byteorder=ENDIAN) max = int.from_bytes(elffile.read(SIZEOF_PTR), byteorder=ENDIAN) limit = f"[{min}, {max}]" print(f"- {name}:\t{desc} ({kind_str}) {limit if len(limit) != 0 else ""}")