kr_offset.sh
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
#!/system/bin/sh | |
# Copyright (C) MIT License 2024 Nicholas Bissell (TheFreeman193) | |
NL=" | |
" | |
SYSNMLN=65 | |
showHeader() { | |
echo " | |
========= Kernel release offset finder ========= | |
Buy me a coffee: https://ko-fi.com/nickbissell | |
===================== v1.0 ===================== | |
" >&2 | |
} | |
showUsage() { | |
showHeader 2>&1 | |
echo "Usage: | |
$0 --auto [--hex] [--quiet] | |
$0 [--kernel] kernel_file [--hex] [--quiet] | |
$0 --image boot_img [--hex] [--quiet] | |
$0 --boot boot_part [--hex] [--quiet] | |
--auto -a Detect boot partition and extract automatically | |
--kernel -k Get offset from an uncompressed kernel file (kernel) | |
--image -i Get offset from a boot image file (boot.img) | |
--boot -b Get offset from a boot partition (/dev/block/...) | |
--hex -x Return offset in hexadecimal format | |
--quiet -q Quiet operation - don't print operations to stderr | |
kernel_file An uncompressed Linux kernel extracted with magiskboot | |
boot_img A boot image file containing the Linux kernel | |
boot_part A path to the boot partition of the device | |
" | |
exit 0 | |
} | |
[ $# -eq 0 ] || [ -z "$1" ] && showUsage | |
if [ ! -f /data/adb/magisk/busybox ] || [ ! -f /data/adb/magisk/magiskboot ]; then | |
echo "ERROR: Critical Magisk components not found. Make sure magisk is installed and this is a root shell." >&2 | |
exit 2 | |
fi | |
readUtsFieldHex() { | |
[ -z "$SYSNMLN" ] && SYSNMLN=65 | |
dd if="$1" skip="$2" count="$SYSNMLN" iflag="skip_bytes,count_bytes" status=none | /data/adb/magisk/busybox xxd -p -c "$SYSNMLN" | |
} | |
toUtsFieldHex() { | |
[ -z "$SYSNMLN" ] && SYSNMLN=65 | |
hexSYSNMLN="$((SYSNMLN * 2))" | |
hexPad="$(dd if=/dev/zero iflag=count_bytes count="$SYSNMLN" status=none | /data/adb/magisk/busybox xxd -p -c "$SYSNMLN")" | |
echo "$(printf %s "$1" | /data/adb/magisk/busybox xxd -p -c "$SYSNMLN")$hexPad" | cut -b "-$hexSYSNMLN" | |
} | |
findStringsInBin() { | |
/data/adb/magisk/busybox strings -t d "$1" | grep -F "$2" | sed -r 's/^[[:space:]]*([0-9]+)[[:space:]]+.+$/\1/g' | grep -E "^[0-9]+$" | |
} | |
findUtsFieldOffset() { | |
file="$1" | |
value="$2" | |
[ -z "$SYSNMLN" ] && SYSNMLN=65 | |
[ $quietMode -eq 0 ] && echo "${NL}Looking for instances of '$value' in '$file'..." >&2 | |
curSys="$(uname -s | cut -b "-$SYSNMLN")" | |
curMachine="$(uname -m | cut -b "-$SYSNMLN")" | |
hexValue="$(toUtsFieldHex "$value")" | |
hexCurSys="$(toUtsFieldHex "$curSys")" | |
hexCurMachine="$(toUtsFieldHex "$curMachine")" | |
potentialOffsets="$(findStringsInBin "$file" "$value")" | |
validOffsets="" | |
[ $asHex -eq 0 ] && offsetFormat="%s%s... " || offsetFormat="%s0x%x... " | |
for offset in $potentialOffsets; do | |
[ $quietMode -eq 0 ] && printf "$offsetFormat" " Checking match at offset " "$offset" >&2 | |
if [ "$(readUtsFieldHex "$file" "$offset")" == "$hexValue" ]; then | |
found="" | |
sysOffset="$((offset - SYSNMLN * 5))" | |
endOffset="$((offset + SYSNMLN * 5))" | |
while [ "$sysOffset" -lt "$endOffset" ]; do | |
curHex="$(readUtsFieldHex "$file" "$sysOffset")" | |
if [ "$curHex" == "$hexCurSys" ]; then | |
found="sysname" | |
break 1 | |
elif [ "$curHex" == "$hexCurMachine" ]; then | |
found="machine" | |
break 1 | |
fi | |
sysOffset="$((sysOffset + SYSNMLN))" | |
done | |
if [ -n "$found" ]; then | |
validOffsets+="$offset$NL" | |
[ $quietMode -eq 0 ] && echo "Found UTS $found field!" >&2 | |
else | |
[ $quietMode -eq 0 ] && echo "Not a complete UTS structure" >&2 | |
fi | |
else | |
[ $quietMode -eq 0 ] && echo "Partial match/not UTS" >&2 | |
fi | |
done | |
if [ -n "$validOffsets" ]; then | |
echo "$validOffsets" | sed '/^$/d' | |
else | |
echo "${NL}No offsets with UTS format found for '$curRelease'" >&2 | |
return 1 | |
fi | |
} | |
findBootPath() { | |
[ $quietMode -eq 0 ] && echo "${NL}Detecting boot partition path..." >&2 | |
bootPath="/dev/block/bootdevice/by-name" | |
if [ ! -d "$bootPath/" ]; then | |
echo "ERROR: Boot partition directory not found." >&2 | |
exit 1 | |
fi | |
if [ -e "$bootPath/boot" ]; then | |
echo "$bootPath/boot" | |
elif [ -e "$bootPath/boot_a" ] && [ -e "$bootPath/boot_b" ]; then | |
slot_suffix="$(getprop ro.boot.slot_suffix)" | |
if [ -n "$slot_suffix" ]; then | |
echo "$bootPath/boot$slot_suffix" | |
return 0 | |
fi | |
current_slot="$(getprop current-slot)" | |
if [ -n "$current_slot" ]; then | |
echo "$bootPath/boot$current_slot" | |
return 0 | |
fi | |
command -v bootctl && slot_number="$(bootctl get-current-slot)" | |
[ -n "$slot_number" ] && slot_suffix="$(bootctl get-suffix "$slot_number")" | |
if [ -n "$slot_suffix" ]; then | |
echo "$bootPath/boot$slot_suffix" | |
return 0 | |
fi | |
slot_suffix="$(cat /proc/cmdline | sed 's/ /\n/g' | grep -Ei 'slot_suffix|current-slot' | sed -r 's/.+=//')" | |
if [ -n "$slot_suffix" ]; then | |
echo "$bootPath/boot$slot_suffix" | |
return 0 | |
fi | |
echo "ERROR: Cannot get active slot." >&2 | |
exit 1 | |
else | |
echo "ERROR: Unexpected boot partition configuration." >&2 | |
exit 1 | |
fi | |
} | |
newStage() { | |
lastDir="$PWD" | |
stageDir="/data/local/tmp/$(uuidgen)" | |
mkdir "$stageDir" | |
if [ ! -d "$stageDir" ]; then | |
echo "ERROR: Couldn't create temporary directory '$stageDir'" >&2 | |
exit 5 | |
fi | |
cd "$stageDir" | |
} | |
cleanupQuit() { | |
if [ -n "$stageDir" ] && [ -d "$stageDir" ]; then | |
[ -n "$lastDir" ] && [ -d "$lastDir" ] && cd "$lastDir" | |
rm -rf "$stageDir" | |
fi | |
[ -n "$1" ] && exit $1 || exit 0 | |
} | |
kernelFile="" | |
imageFile="" | |
bootPath="" | |
autoExtract=0 | |
asHex=0 | |
quietMode=0 | |
while [ $# -gt 0 ]; do | |
param="$1" | |
hasShifted=0 | |
case "$param" in | |
-h|-\?|--help) | |
showUsage | |
;; | |
--kernel|-k|-[aqx]*k) | |
kernelFile="$(readlink -f "$2")" | |
shift; shift; hasShifted=1 | |
;; | |
--image|-i|-[aqx]*i) | |
imageFile="$(readlink -f "$2")" | |
shift; shift; hasShifted=1 | |
;; | |
--boot|-b|-[aqx]*b) | |
bootPath="$2" | |
shift; shift; hasShifted=1 | |
;; | |
--auto|-a) | |
autoExtract=1 | |
shift; continue | |
;; | |
--quiet|-q) | |
quietMode=1 | |
shift; continue | |
;; | |
--hex|-x) | |
asHex=1 | |
shift; continue | |
;; | |
*) | |
if echo "$1" | grep -Eqv '^-'; then | |
kernelFile="$(readlink -f "$1")" | |
shift; continue | |
fi | |
;; | |
esac | |
echo "$param" | grep -Eq '^-[qx]*a[qx]*[kib]$' && autoExtract=1 | |
echo "$param" | grep -Eq '^-[qa]*x[qa]*[kib]$' && asHex=1 | |
echo "$param" | grep -Eq '^-[ax]*q[ax]*[kib]$' && quietMode=1 | |
[ $hasShifted -eq 1 ] && continue | |
echo "ERROR: Couldn't parse parameter '$1'." >&2 | |
exit 1 | |
done | |
[ $quietMode -eq 0 ] && showHeader | |
primArgs=0 | |
mode=0 | |
[ -n "$kernelFile" ] && mode=1 && primArgs=$((primArgs + 1)) | |
[ -n "$imageFile" ] && mode=2 && primArgs=$((primArgs + 1)) | |
[ -n "$bootPath" ] && mode=3 && primArgs=$((primArgs + 1)) | |
[ $autoExtract -eq 1 ] && mode=4 && primArgs=$((primArgs + 1)) | |
if [ $primArgs -gt 1 ]; then | |
echo "ERROR: Too many parameters ($primArgs) - only 1 of --kernel, --image, --boot, --auto allowed." >&2 | |
exit 2 | |
fi | |
if [ $mode -eq 0 ]; then | |
echo "ERROR: You must either pass a kernel file, boot image, partition path, or use --auto." | |
exit 3 | |
fi | |
[ $mode -ge 4 ] && bootPath="$(findBootPath)" | |
[ $mode -ge 2 ] && newStage | |
if [ $mode -ge 3 ]; then | |
if [ ! -e "$bootPath" ]; then | |
echo "ERROR: Boot partition path '$bootPath' not found." >&2 | |
cleanupQuit 4 | |
fi | |
imageFile="boot.img" | |
[ $quietMode -eq 0 ] && echo "${NL}Extracting boot image '$bootPath'..." >&2 | |
dd if="$bootPath" of="$imageFile" status=none | |
if [ ! -f "$imageFile" ]; then | |
echo "ERROR: Failed to extract boot image." >&2 | |
cleanupQuit 6 | |
fi | |
fi | |
if [ $mode -ge 2 ]; then | |
kernelFile="kernel" | |
[ $quietMode -eq 0 ] && echo "${NL}Unpacking boot image '$imageFile'..." | |
/data/adb/magisk/magiskboot unpack "$imageFile" 2>/dev/null | |
if [ ! -f "$kernelFile" ]; then | |
echo "ERROR: Failed to unpack boot image." >&2 | |
cleanupQuit 7 | |
fi | |
fi | |
if [ $mode -eq 1 ] && [ ! -f "$kernelFile" ]; then | |
echo "ERROR: Failed to unpack boot image." >&2 | |
cleanupQuit 8 | |
fi | |
curRelease="$(uname -r | cut -b "-$SYSNMLN")" | |
releaseOffsets="$(findUtsFieldOffset "$kernelFile" "$curRelease")" | |
if [ -n "$releaseOffsets" ]; then | |
[ $quietMode -eq 0 ] && echo "" >&2 | |
[ $asHex -eq 1 ] && printf "0x%x\n" "$releaseOffsets" || echo "$releaseOffsets" | |
[ $quietMode -eq 0 ] && echo "" >&2 | |
fi | |
cleanupQuit 0 |