Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
184 changes: 184 additions & 0 deletions Tools/lk_img_analyzer.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,184 @@
#!/usr/bin/env python3
# MediaTek LK (Little Kernel) image analyzer
# Extracts fastboot commands, OEM commands, getvar variables,
# and valid configuration values from lk.img binaries.
import struct
import sys
import os


def extract_strings(data, min_length=4):
"""Extract printable ASCII strings from binary data."""
result = []
current = []
for byte in data:
if 0x20 <= byte < 0x7f:
current.append(chr(byte))
else:
if len(current) >= min_length:
result.append("".join(current))
current = []
if len(current) >= min_length:
result.append("".join(current))
return result


def parse_mtk_header(data):
"""Parse MediaTek image header."""
info = {}
if len(data) < 0x200:
return info
magic = struct.unpack("<I", data[0:4])[0]
size = struct.unpack("<I", data[4:8])[0]
name = data[8:40].split(b"\x00")[0].decode("ascii", errors="replace")
info["magic"] = f"0x{magic:08X}"
info["size"] = size
info["name"] = name
return info


def find_fastboot_commands(strings_list):
"""Identify standard fastboot protocol commands."""
commands = set()
# Only match exact protocol-level commands
exact_cmds = [
"boot", "continue", "download:", "erase:", "flash:",
"getvar:", "reboot-bootloader", "reboot-fastboot",
"reboot-recovery", "set_active:", "upload",
"flashing lock", "flashing unlock", "flashing get_unlock_ability",
]
for s in strings_list:
stripped = s.strip()
if stripped in exact_cmds:
commands.add(stripped)
return sorted(commands)


def find_oem_commands(strings_list):
"""Extract fastboot oem commands."""
oem_cmds = set()
for s in strings_list:
stripped = s.strip()
if stripped.startswith("oem ") and len(stripped) > 4:
oem_cmds.add(stripped)
return sorted(oem_cmds)


def find_getvar_variables(strings_list):
"""Extract getvar variable names."""
# Only match exact known variable names
exact_vars = [
"version-bootloader", "version-baseband", "version-preloader",
"product", "serialno", "secure", "unlocked", "variant",
"max-download-size", "current-slot", "slot-count",
"slot-successful:a", "slot-successful:b",
"slot-unbootable:a", "slot-unbootable:b",
"slot-retry-count:a", "slot-retry-count:b",
"has-slot:", "has-slot:preloader",
"partition-type:", "partition-size:",
"battery-voltage", "battery-soc-ok", "battery-sn",
"erase-block-size", "logical-block-size",
"is-userspace", "off-mode-charge",
"hw-revision", "warranty", "securestate",
"battery-manager",
]
variables = set()
for s in strings_list:
stripped = s.strip()
if stripped in exact_vars:
variables.add(stripped)
return sorted(variables)


def find_partitions(strings_list):
"""Extract partition names."""
known_parts = {
"boot", "recovery", "system", "vendor", "dtbo", "vbmeta",
"lk", "preloader", "logo", "md1img", "spmfw", "sspm",
"tee", "scp", "cache", "userdata", "metadata", "super",
"misc", "persist", "protect", "nvcfg", "nvdata", "proinfo",
"para", "expdb", "frp", "sec1", "seccfg", "efuse", "otp",
"init_boot", "gz", "mcupm", "vcp",
}
found = set()
for s in strings_list:
if s.strip().lower() in known_parts:
found.add(s.strip().lower())
return sorted(found)


def analyze_lk_image(filepath):
"""Main analysis function for lk.img."""
with open(filepath, "rb") as f:
data = f.read()

header = parse_mtk_header(data)
strings_list = extract_strings(data)

fastboot_cmds = find_fastboot_commands(strings_list)
oem_cmds = find_oem_commands(strings_list)
getvar_vars = find_getvar_variables(strings_list)
partitions = find_partitions(strings_list)

results = {
"header": header,
"file_size": len(data),
"fastboot_commands": fastboot_cmds,
"oem_commands": oem_cmds,
"getvar_variables": getvar_vars,
"partitions": partitions,
}
return results


def print_report(results):
"""Print analysis report to stdout."""
print("=" * 70)
print("MediaTek LK Image Analysis Report")
print("=" * 70)

hdr = results["header"]
print(f"\nFile size: {results['file_size']} bytes "
f"({results['file_size'] / 1024:.1f} KB)")
if hdr:
print(f"MTK Header magic: {hdr.get('magic', 'N/A')}")
print(f"Image name: {hdr.get('name', 'N/A')}")
print(f"Payload size: {hdr.get('size', 'N/A')} bytes")

print(f"\n{'=' * 70}")
print("Fastboot Protocol Commands")
print("=" * 70)
for cmd in results["fastboot_commands"]:
print(f" {cmd}")

print(f"\n{'=' * 70}")
print("Fastboot OEM Commands")
print("=" * 70)
for cmd in results["oem_commands"]:
print(f" fastboot {cmd}")

print(f"\n{'=' * 70}")
print("Getvar Variables")
print("=" * 70)
for var in results["getvar_variables"]:
print(f" fastboot getvar {var}")

print(f"\n{'=' * 70}")
print("Flashable Partitions")
print("=" * 70)
for part in results["partitions"]:
print(f" {part}")

print()


if __name__ == "__main__":
if len(sys.argv) < 2:
print(f"Usage: {sys.argv[0]} <lk.img>")
sys.exit(1)
filepath = sys.argv[1]
if not os.path.isfile(filepath):
print(f"Error: file not found: {filepath}")
sys.exit(1)
results = analyze_lk_image(filepath)
print_report(results)
Loading