Skip to content

Instantly share code, notes, and snippets.

@skrimix
Last active March 23, 2024 07:52
Show Gist options
  • Save skrimix/cc351cff8c01596ef6babafd0339c854 to your computer and use it in GitHub Desktop.
Save skrimix/cc351cff8c01596ef6babafd0339c854 to your computer and use it in GitHub Desktop.
boot.img repack script for KernelSU. Supports extracting boot.img from factory and OTA images
#!/bin/bash
set -e
# This script creates a patched boot.img with KernelSU GKI kernel and cmdline tweaks
SCRIPT_PATH="$(dirname "$(realpath -s "$0")")"
MAGISKBOOT="$SCRIPT_PATH"/magiskboot
MAGISK_VER="v26.1" # used for downloading magiskboot, newer versions print "unexpected ASN.1 DER tag: expected SEQUENCE, got APPLICATION [1] (primitive)" warning(?)
ANYKERNEL_FILE_NAME="CHANGE_ME" # for downloading from the latest KernelSU github release, e.g. "AnyKernel3-android13-5.10.157_2023-03.zip"
CMDLINE_TWEAKS="" # space separated list of kernel cmdline tweaks, do not use with avbroot
#CMDLINE_TWEAKS="kvm-arm.mode=nvhe" allows to run QEMU
_echo() {
echo -e "\e[1m$1\e[0m"
}
check_command() {
command_name=$1
if ! command -v "$command_name" &> /dev/null; then
_echo "$command_name is not installed"
exit 1
fi
}
print_usage() {
_echo "Usage: $0 <original_file> [kernel_su_anykernel_package]"
_echo "original_file - factory zip, ota zip or boot.img"
_echo "kernel_su_file - KernelSU AnyKernel package to use (if not provided, latest version will be downloaded)"
}
cleanup() {
_echo "Cleaning up"
rm -rf "$SCRIPT_PATH"/tmp
}
download_ksu() {
if [ "$ANYKERNEL_FILE_NAME" = "CHANGE_ME" ]; then
_echo "Please set ANYKERNEL_FILE_NAME variable or provide KernelSU AnyKernel package as the second argument"
exit 1
fi
check_command "wget"
check_command "jq"
check_command "curl"
# download $ANYKERNEL_FILE_NAME from latest KernelSU release at https://github.com/tiann/KernelSU/releases
api_response=$(curl -s https://api.github.com/repos/tiann/KernelSU/releases/latest)
ksu_ver=$(echo "$api_response" | jq -r '.tag_name')
download_url=$(echo "$api_response" | jq -r ".assets[] | select(.name | contains(\"$ANYKERNEL_FILE_NAME\")) | .browser_download_url")
if [ -z "$download_url" ]; then
_echo "Failed to get download url for KernelSU $ksu_ver. Is $ANYKERNEL_FILE_NAME the correct file name?"
exit 1
fi
_echo "Downloading KernelSU $ksu_ver"
wget -q "$download_url" -O "$SCRIPT_PATH"/$ANYKERNEL_FILE_NAME
_echo "Unpacking kernel from $ANYKERNEL_FILE_NAME"
unzip -o -q "$SCRIPT_PATH"/$ANYKERNEL_FILE_NAME Image -d "$SCRIPT_PATH"
}
download_magiskboot() {
check_command "wget"
check_command "jq"
check_command "curl"
# download magiskboot from https://github.com/topjohnwu/Magisk/releases/tag/$MAGISK_VER
api_response=$(curl -s https://api.github.com/repos/topjohnwu/Magisk/releases/tags/$MAGISK_VER)
magisk_apk_url=$(echo "$api_response" | jq -r ".assets[] | select(.name | contains(\"Magisk-$MAGISK_VER.apk\")) | .browser_download_url")
_echo "Downloading Magisk $MAGISK_VER"
wget -q "$magisk_apk_url" -O "$SCRIPT_PATH"/magisk.apk
# unpack magiskboot
_echo "Unpacking magiskboot"
unzip -o -q "$SCRIPT_PATH"/magisk.apk lib/x86_64/libmagiskboot.so -d "$SCRIPT_PATH"
mv "$SCRIPT_PATH"/lib/x86_64/libmagiskboot.so "$MAGISKBOOT"
chmod +x "$MAGISKBOOT"
rm "$SCRIPT_PATH"/magisk.apk && rmdir "$SCRIPT_PATH"/lib/x86_64 && rmdir "$SCRIPT_PATH"/lib
}
handle_ota() {
check_command "payload-dumper-go"
ota_file=$1
_echo "Unpacking payload.bin"
unzip -o -q "$ota_file" payload.bin -d "$SCRIPT_PATH"/tmp
# use payload-dumper-go to extract boot.img from payload
_echo "Extracting boot.img from payload.bin"
payload-dumper-go -o "$SCRIPT_PATH"/tmp -p boot "$SCRIPT_PATH"/tmp/payload.bin
}
handle_factory() {
factory_file=$1
image_zip=$2
_echo "Unpacking image zip"
unzip -o -q "$factory_file" "$image_zip" -d "$SCRIPT_PATH"/tmp
_echo "Extracting boot.img from image zip"
unzip -o -q "$SCRIPT_PATH"/tmp/"$image_zip" boot.img -d "$SCRIPT_PATH"/tmp
}
cmdpatch() {
_echo "Patching cmdline"
for tweak in $CMDLINE_TWEAKS;
do
echo "=== $tweak ==="
local cmdline=$(cat "$SCRIPT_PATH"/tmp/boot/header | grep cmdline=)
[[ "$tweak" != *"$cmdline"* ]] && sed -i "s/cmdline=/cmdline=$tweak /" "$SCRIPT_PATH"/tmp/boot/header
done
}
patch_boot() {
boot_file=$SCRIPT_PATH/tmp/boot.img
if [ ! -f "$boot_file" ] || ! file "$boot_file" | grep -q "Android bootimg"; then
_echo "boot.img not found or not valid"
exit 1
fi
mkdir -p "$SCRIPT_PATH"/tmp/boot
mv "$boot_file" "$SCRIPT_PATH"/tmp/boot/boot.img
cd "$SCRIPT_PATH"/tmp/boot
_echo "Unpacking boot.img"
$MAGISKBOOT unpack -h boot.img
_echo "Getting kernel versions"
ksu_kernel_ver=$(strings -a "$SCRIPT_PATH"/Image | grep -v "%s" | grep -m1 "Linux version" | awk '{print $3}')
orig_kernel_ver=$(strings -a kernel | grep -v "%s" | grep -m1 "Linux version" | awk '{print $3}')
_echo "Original kernel version: $orig_kernel_ver"
_echo "KernelSU kernel version: $ksu_kernel_ver"
_echo "Proceed? (y/n)"
read -r proceed
if [ "$proceed" != "y" ] && [ "$proceed" != "Y" ]; then
_echo "Aborting"
cleanup
exit 1
fi
_echo "Replacing kernel"
mv "$SCRIPT_PATH"/Image kernel
# patch cmdline
cmdpatch
_echo "Repacking boot.img"
$MAGISKBOOT repack boot.img new-boot.img
}
# check if 1st argument is provided
if [ -z "$1" ]; then
print_usage
exit 1
fi
check_command "unzip"
# delete tmp directory if exists
if [ -d "$SCRIPT_PATH"/tmp ]; then
rm -rf "$SCRIPT_PATH"/tmp
fi
# create temp dir
mkdir -p "$SCRIPT_PATH"/tmp
# check if magiskboot exists
if [ ! -f "$MAGISKBOOT" ]; then
_echo "magiskboot not found"
download_magiskboot
else
chmod +x "$MAGISKBOOT"
fi
# if second argument is not provided, download KernelSU
if [ -z "$2" ]; then
download_ksu
else
if [ ! -f "$2" ]; then
_echo "Provided KernelSU AnyKernel package not found"
exit 1
fi
_echo "Unpacking kernel from $2"
unzip -o -q "$2" Image -d "$SCRIPT_PATH"
fi
if [ -f "$1" ]; then
if file "$1" | grep -q "Android bootimg"; then
_echo "boot.img detected"
# if boot.img, copy it to tmp
mkdir -p "$SCRIPT_PATH"/tmp
cp "$1" "$SCRIPT_PATH"/tmp/boot.img
elif unzip -l "$1" | grep -q "payload.bin"; then
_echo "OTA file detected"
handle_ota "$1"
elif unzip -l "$1" | grep -q "image-"; then
_echo "Factory image detected"
handle_factory "$1" "$(unzip -l "$1" | grep "image-" | awk '{print $4}')"
else
_echo "Unrecognized type of original file"
exit 1
fi
else
_echo "Original file not found"
exit 1
fi
patch_boot
file_hash=$(sha256sum "$SCRIPT_PATH"/tmp/boot/new-boot.img | awk '{print $1}' | cut -c1-8)
mkdir -p "$SCRIPT_PATH"/out
cp "$SCRIPT_PATH"/tmp/boot/new-boot.img "$SCRIPT_PATH"/out/boot_patched_"$file_hash".img
cleanup
_echo "New boot.img saved to $SCRIPT_PATH/out/boot_patched_$file_hash.img"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment