Last active
March 23, 2024 07:52
-
-
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
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/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