├── AAP.sh ├── AAPFunction ├── LICENSE ├── README.md └── bin └── magiskboot /AAP.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | #by Akina | LuoYan 3 | #2024-06-03 Rewrite 4 | #shellcheck disable=SC2059,SC2086,SC2166 5 | 6 | # TODO: 7 | # - None 8 | 9 | # Check if debug mode is enabled via the APTOOLDEBUG environment variable 10 | if [ -n "${APTOOLDEBUG}" ]; then 11 | if [ ${APTOOLDEBUG} -eq 1 ]; then 12 | printf "\033[1;33m[WARN] $(date "+%H:%M:%S"): Debug mode is on.\033[0m\n" 13 | set -x # Enable command tracing 14 | fi 15 | fi 16 | # Color variables for formatted output 17 | RED="\033[1;31m" # RED 18 | YELLOW="\033[1;33m" # YELLOW 19 | BLUE="\033[40;34m" # BLUE 20 | RESET="\033[0m" # RESET 21 | 22 | # Formatted print for informational messages 23 | msg_info() { 24 | printf "${BLUE}[INFO] $(date "+%H:%M:%S"): ${1}${RESET}\n" 25 | } 26 | # Formatted print for warning messages 27 | msg_warn() { 28 | printf "${YELLOW}[WARN] $(date "+%H:%M:%S"): ${1}${RESET}\n" 29 | } 30 | # Formatted print for error messages 31 | msg_err() { 32 | printf "${RED}[ERROR] $(date "+%H:%M:%S"): ${1}${RESET}\n" 33 | } 34 | # Formatted print for fatal error messages 35 | msg_fatal() { 36 | printf "${RED}[FATAL] $(date "+%H:%M:%S"): ${1}${RESET}\n" 37 | } 38 | # Check the operating system type 39 | if command -v getprop >/dev/null 2>&1; then 40 | OS="android" 41 | else 42 | OS="linux" 43 | fi 44 | # Function to print help message and exit 45 | print_help() { 46 | printf "${BLUE}%s${RESET}\n\n" " 47 | APatch Auto Patch Tool 48 | Written by Akina 49 | Version: 7.0.0 50 | Current DIR: $(pwd) 51 | 52 | -h, -v, print the usage and version. 53 | -i PATH/TO/IMAGE, specify a boot image path. 54 | -k [RELEASE NAME], specify a kernelpatch version [RELEASE NAME]. 55 | -d PATH/TO/DIR, specify a folder containing AAPFunction, kptools and kpimg that we need. 56 | -s \"STRING\", specify a superkey. Use STRING as superkey. 57 | -A [PATH], Download latest APatch CI build to PATH. 58 | -K, Specify the KPMs to be embedded. 59 | -I, directly install to current slot after patch. 60 | -S, Install to another slot (for OTA). 61 | -E [ARGS], Add args [ARGS] to kptools when patching. 62 | -c [COMMANDS], Specifies extra commands to run (developers only)." 63 | TWIDTH=$(tput cols) 64 | TEXTLEN=4 65 | MIDPOS=$(((TWIDTH - TEXTLEN) / 2)) 66 | printf "${BLUE}%*s${RESET}\n" $MIDPOS "NOTE" 67 | printf "${BLUE}%s${RESET}\n" "When arg -I is not specified, the patched boot image will be stored in /storage/emulated/0/patched_boot.img(on android) or \${HOME}/patched_boot.img(on linux). 68 | 69 | When the -s parameter is not specified, uuid will be used to generate an 8-digit SuperKey that is a mixture of alphanumeric characters. 70 | 71 | When the -d parameter is specified, the specified folder should contain AAPFunction, magiskboot, kptools and kpimg, otherwise you will get a fatal error. 72 | 73 | In addition, you can use \`APTOOLDEBUG=1 ${0} [ARGS]\` format to enter verbose mode. 74 | " 75 | exit 0 76 | } 77 | 78 | # Analyze command line arguments 79 | DOWNFILES=true # Flag to indicate if files should be downloaded 80 | while getopts ":hA:vi:k:KIVs:Sd:E:c:" OPT; do 81 | # $OPTARG holds the argument of the current option 82 | case $OPT in 83 | c) 84 | bash -c "$OPTARG" # Execute the provided commands 85 | ;; 86 | h | v) 87 | print_help # Print help message 88 | ;; 89 | A) 90 | DOWNLOAD_ANDROID_VER=true # Flag to download Android version 91 | DOWNLOAD_PATH="$(realpath ${OPTARG})" # Get the real path of the download directory 92 | ;; 93 | d) 94 | MISSINGFILES=0 # Counter for missing files 95 | WORKDIR="$(realpath ${OPTARG})" # Get the real path of the specified working directory 96 | if [ ! -d "${WORKDIR}" ]; then 97 | msg_fatal "${WORKDIR}: No such directory." 98 | exit 1 99 | fi 100 | # Check for required files in the specified directory 101 | for i in AAPFunction magiskboot kptools-${OS} kpimg-android; do 102 | if [ ! -e "${WORKDIR}/${i}" ]; then 103 | msg_fatal "Missing file: ${WORKDIR}/${i}" 104 | MISSINGFILES=$((MISSINGFILES + 1)) 105 | fi 106 | done 107 | # If any required files are missing 108 | if [[ ${MISSINGFILES} -gt 0 ]]; then 109 | unset WORKDIR # Unset the working directory variable 110 | msg_fatal "There are ${MISSINGFILES} files missing, and we need 4 files in total. Please read the instructions in ${0} -h." 111 | msg_info "Omit the -d parameter; the file will be downloaded remotely." 112 | else 113 | DOWNFILES=false # Disable file download 114 | msg_info "The work directory was manually specified: ${WORKDIR}. AAPFunction, kptools and kpimg will not be downloaded again." 115 | fi 116 | ;; 117 | K) 118 | EMBEDKPMS=true # Flag to embed KPMs 119 | msg_info "The -K parameter was received. Will embed KPMs." 120 | ;; 121 | i) 122 | BOOTPATH="$(realpath ${OPTARG})" # Get the real path of the boot image 123 | if [ -e "${BOOTPATH}" ]; then 124 | msg_info "Boot image path specified. Current image path: ${BOOTPATH}" 125 | if [ ! -f "${BOOTPATH}" ]; then 126 | msg_fatal "${BOOTPATH}: Not a file." 127 | exit 1 128 | fi 129 | else 130 | msg_fatal "${BOOTPATH}: The file does not exist." 131 | exit 1 132 | fi 133 | ;; 134 | S) 135 | SAVEROOT="true" # Flag to save root (install to another slot) 136 | msg_info "The -S parameter was received. The patched image will be flashed into another slot if this is a ab partition device." 137 | ;; 138 | I) 139 | if [ "${OS}" = "android" ]; then 140 | INSTALL="true" # Flag to install directly 141 | msg_info "The -I parameter was received. Will install after patching." 142 | else 143 | msg_fatal "Do not use this arg without Android!" 144 | exit 1 145 | fi 146 | ;; 147 | s) 148 | SUPERKEY="${OPTARG}" # Set the superkey from the argument 149 | # Check password length 150 | if [[ ${#SUPERKEY} -lt 8 ]]; then 151 | msg_fatal "The SuperKey is too short! It should be at least eight characters long and contain at least two of the following: numbers, letters, and symbols." 152 | exit 1 153 | fi 154 | # Check for the presence of letters and numbers, letters and symbols, or numbers and symbols 155 | if [[ "$SUPERKEY" =~ [A-Za-z] && "$SUPERKEY" =~ [0-9] ]]; then 156 | ISOK=true 157 | elif [[ "$SUPERKEY" =~ [A-Za-z] && "$SUPERKEY" =~ [\@\#\$\%\^\&\*\(\)\_\+\!\~\-\=] ]]; then 158 | ISOK=true 159 | elif [[ "$SUPERKEY" =~ [0-9] && "$SUPERKEY" =~ [\@\#\$\%\^\&\*\(\)\_\+\!\~\-\=] ]]; then 160 | ISOK=true 161 | else 162 | ISOK=false 163 | fi 164 | case ${ISOK} in 165 | true) msg_info "Valid SuperKey. Current SuperKey: ${SUPERKEY}" ;; 166 | false) msg_fatal "You input a SuperKey that does not meet standards! It should be at least eight characters long and contain at least two of the following: numbers, letters, and symbols." && exit 1 ;; 167 | esac 168 | ;; 169 | k) 170 | KPTOOLVER="${OPTARG}" # Set the kptools version 171 | msg_info "The -k parameter was received. Will use kptool ${KPTOOLVER}." 172 | ;; 173 | E) 174 | EXTRAARGS="${OPTARG}" # Set extra arguments for kptools 175 | msg_info "The -E parameter was received. Current extra args: ${EXTRAARGS}" 176 | ;; 177 | :) 178 | msg_fatal "Option -${OPTARG} requires an argument.." >&2 179 | exit 1 180 | ;; 181 | 182 | ?) 183 | msg_fatal "Invalid option: -${OPTARG}" >&2 184 | exit 1 185 | ;; 186 | esac 187 | done 188 | 189 | # Check if the script is running with root privileges 190 | if [ "$(id -u)" -eq 0 ]; then 191 | ROOT=true 192 | # Check for unsupported Magisk versions on Android 193 | if [ "${OS}" = "android" ]; then 194 | if [ "$(magisk -v | grep "delta")" -o "$(magisk -v | grep "kitsune")" ]; then 195 | msg_fatal "Detected Magisk Deleta/Kitsune: Unsupported environment. Aborted." 196 | exit 114 197 | fi 198 | fi 199 | else 200 | ROOT=false 201 | msg_warn "You are running in unprivileged mode; some functionality may be limited." 202 | fi 203 | # Download latest CI build section 204 | if [[ "${DOWNLOAD_ANDROID_VER}" == "true" ]]; then 205 | if [[ ! -e "${DOWNLOAD_PATH}" ]]; then 206 | msg_fatal "${DOWNLOAD_PATH} do not exist." 207 | exit 1 208 | fi 209 | msg_info "Now downloading..." 210 | curl -L --progress-bar "https://nightly.link/bmax121/APatch/workflows/build/main/APatch.zip" -o "${DOWNLOAD_PATH}/APatch.zip" || ES=$? # Download the zip file 211 | if [[ ${ES} -eq 0 ]]; then 212 | msg_info "Done." 213 | exit 0 214 | else 215 | msg_fatal "Download Failed. Check the err msg above and try again." 216 | exit 1 217 | fi 218 | fi 219 | # Check image path for Linux 220 | if [ "${OS}" = "linux" -a -z "${BOOTPATH}" ]; then 221 | msg_fatal "You are using ${OS}, but there is no image specified by you. Aborted." 222 | exit 1 223 | fi 224 | # Check if the specified boot path is a file 225 | if [ -e "${BOOTPATH}" -a ! -f "${BOOTPATH}" ]; then 226 | msg_fatal "You specified a path, but that path is not a file!" 227 | exit 1 228 | fi 229 | # Exit if no root and no boot image is specified 230 | if [ -z "${BOOTPATH}" -a "${ROOT}" = "false" ]; then 231 | msg_fatal "No root and no boot image is specified. Aborted." 232 | exit 1 233 | fi 234 | # Set the working directory if not already set 235 | if [ -z "${WORKDIR}" ]; then 236 | WORKDIR="$(mktemp -d)" # Create a temporary directory 237 | fi 238 | # Determine if the device uses A/B partitioning and set BOOTSUFFIX accordingly 239 | if [ "${OS}" = "android" ]; then 240 | BYNAMEPATH=$(getprop ro.frp.pst | sed 's/\/frp//g') # Get the by-name path 241 | if [ ! -e "${BYNAMEPATH}/boot" ]; then 242 | BOOTSUFFIX=$(getprop ro.boot.slot_suffix) # Get the current boot slot suffix 243 | fi 244 | else 245 | msg_info "Current OS is not Android. Skip boot slot check." 246 | fi 247 | # Determine the target slot for OTA installation 248 | if [ -n "${SAVEROOT}" -a -n "${BOOTSUFFIX}" -a "${OS}" = "android" ]; then 249 | if [ "${BOOTSUFFIX}" = "_a" ]; then 250 | TBOOTSUFFIX="_b" 251 | else 252 | TBOOTSUFFIX="_a" 253 | fi 254 | msg_warn "You have specified the installation to another slot. Current slot:${BOOTSUFFIX}. Slot to be flashed into:${TBOOTSUFFIX}." 255 | fi 256 | # Generate a SuperKey using uuid if not provided 257 | if [ -z "${SUPERKEY}" ]; then 258 | SUPERKEY="$(cat /proc/sys/kernel/random/uuid | cut -d \- -f1)" 259 | fi 260 | 261 | # Download the AAPFunction file if DOWNFILES is true 262 | if [[ "${DOWNFILES}" == "true" ]]; then 263 | msg_info "Downloading function file from GitHub..." 264 | curl -L --progress-bar "https://raw.githubusercontent.com/AkinaAcct/APatchTool/main/AAPFunction" -o ${WORKDIR}/AAPFunction 265 | EXITSTATUS=$? 266 | if [ $EXITSTATUS != 0 ]; then 267 | msg_fatal "Download failed. Check your Internet connection and try again." 268 | exit 1 269 | fi 270 | fi 271 | 272 | # Backup the boot image if running with root on Android 273 | msg_info "Now backing up the boot image..." 274 | if [ "${ROOT}" == "true" ]; then 275 | if [ "${OS}" == "android" ]; then 276 | msg_info "Backing up boot image..." 277 | dd if=${BYNAMEPATH}/boot${BOOTSUFFIX} of=/storage/emulated/0/stock_boot${BOOTSUFFIX}.img # Backup the current boot image 278 | EXITSTATUS=$? 279 | if [ "${EXITSTATUS}" != "0" ]; then 280 | msg_err "Boot image backup failed." 281 | msg_warn "Skip backing up boot image..." 282 | else 283 | msg_info "Done. Boot image path: /storage/emulated/0/stock_boot${BOOTSUFFIX}.img" 284 | fi 285 | else 286 | msg_info "Currently OS in not Android; Skip backup." 287 | fi 288 | else 289 | msg_warn "No root. Skip back up." 290 | fi 291 | 292 | # Load the AAPFunction script 293 | . ${WORKDIR}/AAPFunction 294 | 295 | # Call functions from AAPFunction to get device boot information, tools, and patch the boot image 296 | get_device_boot 297 | get_tools 298 | patch_boot 299 | # Install the patched boot image if the -I flag was used 300 | if [ -n "${INSTALL}" ]; then 301 | msg_warn "The -I parameter was received. Will install patched image." 302 | flash_boot 303 | else 304 | # Copy the patched boot image to the default location 305 | if [ "${OS}" = "android" ]; then 306 | msg_info "Now copying patched image to /storage/emulated/0/patched_boot.img..." 307 | mv ${WORKDIR}/new-boot.img /storage/emulated/0/patched_boot.img 308 | else 309 | msg_info "Now copying patched image to ${HOME}/patched_boot.img..." 310 | mv ${WORKDIR}/new-boot.img "${HOME}/patched_boot.img" 311 | fi 312 | msg_info "Done. Now deleting tmp files..." 313 | rm -rf ${WORKDIR} # Remove the temporary working directory 314 | msg_info "Done." 315 | fi 316 | # Print the generated or provided SuperKey 317 | print_superkey 318 | -------------------------------------------------------------------------------- /AAPFunction: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | #rewrited 3 | #shellcheck disable=SC2086 4 | get_device_boot() { 5 | msg_info "Getting boot image..." 6 | if [ -z "${BOOTPATH}" ]; then 7 | if [ -n "${BOOTSUFFIX}" ]; then 8 | msg_info "Current boot slot: ${BOOTSUFFIX}" 9 | else 10 | msg_info "Current boot slot: A-Only,no slot." 11 | fi 12 | dd if=${BYNAMEPATH}/boot${BOOTSUFFIX} of=${WORKDIR}/boot${BOOTSUFFIX}.img || EXITSTATUS=$? # Dump boot image from device 13 | if [ $EXITSTATUS != 0 ]; then 14 | msg_fatal "Get boot image from device failed!" 15 | exit 1 16 | fi 17 | else 18 | msg_info "Now copying boot image to workdir..." 19 | cp ${BOOTPATH} "${WORKDIR}/boot${BOOTSUFFIX}.img" # Copy specified boot image to working directory 20 | fi 21 | msg_info "Done." 22 | } 23 | get_tools() { 24 | cd "${WORKDIR}" || exit 1 25 | if [ "${DOWNFILES}" == "true" ]; then 26 | msg_info "Downloading kptools-${OS}..." 27 | if [ -n "${KPTOOLVER}" ]; then 28 | msg_info "Use the specified version: ${KPTOOLVER}" 29 | else 30 | msg_info "Use the latest kptools." 31 | fi 32 | if [ -n "${KPTOOLVER}" ]; then 33 | curl -LO --progress-bar "https://github.com/bmax121/KernelPatch/releases/download/${KPTOOLVER}/kptools-${OS}" # Download specified version of kptools 34 | EXITSTATUS=$? 35 | else 36 | curl -LO --progress-bar "https://github.com/bmax121/KernelPatch/releases/latest/download/kptools-${OS}" # Download latest version of kptools 37 | EXITSTATUS=$? 38 | fi 39 | if [ $EXITSTATUS != 0 ]; then 40 | msg_fatal "Download failed." 41 | msg_fatal "Please check your internet connection." 42 | exit 1 43 | fi 44 | chmod +x kptools-${OS} # Make kptools executable 45 | msg_info "Done." 46 | msg_info "Downloading kpimg-android..." 47 | if [ -n "${KPTOOLVER}" ]; then 48 | curl -LO --progress-bar "https://github.com/bmax121/KernelPatch/releases/download/${KPTOOLVER}/kpimg-android" # Download specified version of kpimg-android 49 | EXITSTATUS=$? 50 | else 51 | curl -LO --progress-bar "https://github.com/bmax121/KernelPatch/releases/latest/download/kpimg-android" # Download latest version of kpimg-android 52 | EXITSTATUS=$? 53 | fi 54 | if [ $EXITSTATUS != 0 ]; then 55 | msg_fatal "Download failed." 56 | msg_fatal "Please check your internet connection." 57 | exit 1 58 | fi 59 | msg_info "Done." 60 | msg_info "Downloading magiskboot..." 61 | curl -LO --progress-bar "https://raw.githubusercontent.com/AkinaAcct/APatchTool/main/bin/magiskboot" # Download magiskboot 62 | EXITSTATUS=$? 63 | if [ $EXITSTATUS != 0 ]; then 64 | msg_fatal "Download failed." 65 | msg_fatal "Please check your internet connection." 66 | exit 1 67 | fi 68 | chmod +x magiskboot # Make magiskboot executable 69 | msg_info "Done." 70 | else 71 | for i in magiskboot kptools-${OS} kpimg-android; do 72 | chmod +x ${WORKDIR}/${i} # Make tools executable in the specified working directory 73 | done 74 | fi 75 | } 76 | analyze_kpms_path() { 77 | unset KPMP # Reset array KPMP 78 | while [[ ${TKPM} != "done" ]]; do 79 | msg_info "Now enter your KPMs' path(Enter \"done\" to finish this operation): " 80 | read -r -a TKPM # Read KPM paths into array TKPM 81 | if [[ ! -f "$(realpath ${TKPM})" ]]; then 82 | msg_err "No such file!" 83 | else 84 | KPMP+=($(realpath ${TKPM})) # Add real path of KPM to array KPMP 85 | fi 86 | msg_info "Current seleted KPMs: ${KPMP[*]}" 87 | msg_info "Total: ${#KPMP[@]}" 88 | done 89 | for i in "${KPMP[@]}"; do 90 | EXTRAARGS+=" --embed-extra-path=$i --extra-type=kpm" # Append KPM paths to EXTRAARGS for kptools 91 | done 92 | msg_info "Current EXTRAARGS: ${EXTRAARGS}" 93 | } 94 | patch_boot() { 95 | if [ "${EMBEDKPMS}" = "true" ]; then 96 | analyze_kpms_path 97 | fi 98 | msg_info "Unpacking image..." 99 | ./magiskboot unpack boot${BOOTSUFFIX}.img # Unpack the boot image 100 | EXITSTATUS=$? 101 | if [ $EXITSTATUS != 0 ]; then 102 | msg_fatal "Unpack failed. Submit a issue with a screenshot of here on github if you are sure that this is not your fault." 103 | exit 1 104 | fi 105 | msg_info "Done." 106 | msg_info "Unpatching current image..." 107 | ./kptools-${OS} --unpatch --image kernel --out kernel || EXITSTATUS=$? # Unpatch the kernel if it was previously patched 108 | if [ ${EXITSTATUS} != 0 ]; then 109 | msg_warn "Unpatch failed. Maybe you are using a unpatched boot image?" 110 | msg_warn "Now skipping unpatching..." 111 | else 112 | msg_info "Done." 113 | fi 114 | msg_info "Patching image...Current Superkey: ${SUPERKEY}" 115 | ./kptools-${OS} --patch --kpimg kpimg-android --skey "${SUPERKEY}" --image kernel --out kernel ${EXTRAARGS} # Patch the kernel with kpimg and superkey 116 | EXITSTATUS=$? 117 | if [ ${EXITSTATUS} != 0 ]; then 118 | msg_fatal "Patch failed. Submit a issue with a screenshot of here on github if you are sure that this is not your fault." 119 | exit 1 120 | fi 121 | msg_info "Done." 122 | msg_info "Repacking..." 123 | ./magiskboot repack boot${BOOTSUFFIX}.img # Repack the boot image 124 | EXITSTATUS=$? 125 | if [ $EXITSTATUS != 0 ]; then 126 | msg_fatal "Repack failed. Submit a issue with a screenshot of here on github if you are sure that this is not your fault." 127 | exit 1 128 | fi 129 | msg_info "Done. Finished paching." 130 | } 131 | 132 | flash_boot() { 133 | if [ "${OS}" = "android" ]; then 134 | if ${ROOT}; then 135 | msg_info "Flashing boot image..." 136 | if [ -n "${TBOOTSUFFIX}" ]; then 137 | msg_warn "You previously specified that you want to install to another slot. Target slot:${TBOOTSUFFIX}." 138 | BOOTSUFFIX=${TBOOTSUFFIX} 139 | fi 140 | dd if=${WORKDIR}/new-boot.img of=${BYNAMEPATH}/boot${BOOTSUFFIX} # Flash the new boot image to the specified slot 141 | EXITSTATUS=$? 142 | if [ ${EXITSTATUS} != 0 ]; then 143 | msg_err "Flash to slot ${BOOTSUFFIX} failed." 144 | msg_fatal "Now trying to restore..." 145 | dd if=${WORKDIR}/boot${BOOTSUFFIX}.img of=${BYNAMEPATH}/boot${BOOTSUFFIX} # Restore the original boot image 146 | EXITSTATUS=$? 147 | if [ ${EXITSTATUS} != 0 ]; then 148 | msg_fatal "Restore failed." 149 | msg_fatal "Even I can't help you now. You can try to restore boot manually." 150 | exit 1 151 | fi 152 | msg_info "Restore Sucessfully." 153 | fi 154 | msg_info "Flash done." 155 | msg_info "Cleaning temporary files..." 156 | rm -rf ${WORKDIR} # Remove temporary working directory 157 | msg_info "Done." 158 | else 159 | msg_fatal "No root. Unable to continue. Aborted." 160 | exit 1 161 | fi 162 | else 163 | msg_fatal "You are trying to change this script. Linux does not require a flashing step. This is the second level of warning." 164 | exit 1 165 | fi 166 | } 167 | 168 | print_superkey() { 169 | cat < [!NOTE] 41 | > This should work. If you encounter any problems, please submit an issue with logs provided by debug mode. 42 | 43 | - Just like in Termux: 44 | 45 | ```sh 46 | cd ${HOME} 47 | curl -LO https://raw.githubusercontent.com/AkinaAcct/APatchAutoPatchTool/main/AAP.sh 48 | chmod +x AAP.sh 49 | ``` 50 | 51 | - Run 52 | 53 | Usage: 54 | 55 | ```sh 56 | ./AAP.sh -h 57 | ``` 58 | 59 | ## Reporting Bugs 60 | 61 | If you have issues or need feedback, please run `AAP.sh` in debug mode. To enable debug mode, run: 62 | 63 | ```sh 64 | APTOOLDEBUG=1 ./AAP.sh [ARGS] | tee AAP_Log_$(date +"%Y-%m-%d_%H:%M:%S").txt 65 | ``` 66 | 67 | Logs will be stored in AAP_Log_\[date]_\[time].txt 68 | Create an issue on github, and upload it as the log. 69 | 70 | --- 71 | 72 | If you encounter any issues, please submit an issue on github. 73 | 74 | --- 75 | 76 | ## Credits 77 | 78 | - [Magisk](https://github.com/topjohnwu/magisk): For magiskboot 79 | 80 | - [KernelPatch](https://github.com/bmax121/KernelPatch): For kptools and kpimg 81 | -------------------------------------------------------------------------------- /bin/magiskboot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CatPlanetOSS/APatchTool/974f9b242eb94e5e05f03108e13175a20bb2cda9/bin/magiskboot --------------------------------------------------------------------------------