Skip to content

Commit

Permalink
change_os_version: scan os_patch_level on boot/recovery images
Browse files Browse the repository at this point in the history
Signed-off-by: Denis Efremov <[email protected]>
  • Loading branch information
evdenis committed Apr 20, 2020
1 parent 779a0ee commit c946906
Show file tree
Hide file tree
Showing 3 changed files with 319 additions and 0 deletions.
73 changes: 73 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
cmake_minimum_required(VERSION 3.12)

if (NOT DEFINED NDK_ROOT)
if (DEFINED ENV{NDK_ROOT})
set(NDK_ROOT "$ENV{NDK_ROOT}")
else ()
message(FATAL_ERROR "Please define NDK_ROOT to point to your NDK path!")
endif ()
endif ()

find_program(ZIP NAMES zip)

# Set the tool chain file
set(CMAKE_TOOLCHAIN_FILE ${NDK_ROOT}/build/cmake/android.toolchain.cmake)
set(ANDROID_ABI arm64-v8a)
set(ANDROID_PLATFORM latest)
set(ANDROID_STL none)
set(ANDROID_LD lld)

add_compile_options(-Wall -Wextra -pedantic -Werror)

set(DEFAULT_FUTURE_DATE "2099-12" CACHE STRING "Select os_patch_level date.")
option(SELF_PACK_EXECUTABLES "Self-pack executables." ON)

set(UPDATE_ZIP "backtothefuture-${DEFAULT_FUTURE_DATE}.zip")

project(BackToTheFuture)

set(CMAKE_C_FLAGS_RELEASE "-O2 -flto")
set(ANDROID_PIE FALSE)
link_libraries("-static")

add_executable(change_os_version change_os_version.c)

if (CMAKE_BUILD_TYPE STREQUAL Release)
add_custom_command(
TARGET change_os_version
POST_BUILD
COMMAND "${ANDROID_TOOLCHAIN_PREFIX}strip" --strip-all change_os_version
COMMENT "Stripping the executables"
VERBATIM
)
if (SELF_PACK_EXECUTABLES)
include("${CMAKE_ROOT}/Modules/FindSelfPackers.cmake")
if (SELF_PACKER_FOR_EXECUTABLE)
add_custom_command(
TARGET change_os_version
POST_BUILD
COMMAND ${SELF_PACKER_FOR_EXECUTABLE} -9q ${SELF_PACKER_FOR_EXECUTABLE_FLAGS} change_os_version
COMMENT "Packing the executables"
VERBATIM
)
endif ()
endif ()
endif ()

if (NOT CMAKE_CURRENT_BINARY_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR)
add_custom_command(
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/META-INF/com/google/android/update-binary
COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/META-INF/com/google/android/update-binary
${CMAKE_CURRENT_BINARY_DIR}/META-INF/com/google/android/update-binary
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/META-INF/com/google/android/update-binary
)
endif ()

add_custom_target(zip
DEPENDS change_os_version
DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/META-INF/com/google/android/update-binary
COMMAND ${ZIP} ${UPDATE_ZIP} change_os_version META-INF/com/google/android/update-binary
COMMENT "Preparing ${UPDATE_ZIP}"
VERBATIM
)

91 changes: 91 additions & 0 deletions META-INF/com/google/android/update-binary
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
#!/sbin/sh

ZIPFILE=$3
ZIPNAME=${ZIPFILE##*/}
OUTFD=$2

scr_wdth=50

# Detect real $OUTFD
#
if readlink /proc/$$/fd/$OUTFD 2>/dev/null | grep /tmp >/dev/null; then
OUTFD=0
for FD in $( ls /proc/$$/fd ); do
if readlink /proc/$$/fd/$FD 2>/dev/null | grep pipe >/dev/null; then
if ps | grep " 3 $FD " | grep -v grep >/dev/null; then
OUTFD=$FD
break
fi
fi
done
fi

ui_print() {
echo -ne "ui_print $1\n" >> /proc/self/fd/$OUTFD
echo -ne "ui_print\n" >> /proc/self/fd/$OUTFD
}

print_full_bar() {
ui_print "$(printf '%*s\n' $scr_wdth | tr ' ' '=')"
}

print_justified() {
local str="$1"
local str_len=${#str}
local padding_len=$(( ($scr_wdth - $str_len - 2) / 2))
local ljust="$(printf '%*s' $padding_len)"
local rjust="$(printf '%*s' $(($padding_len + $str_len % 2)))"

ui_print "=$ljust$str$rjust="
}


ui_print " "
print_full_bar
print_justified "Back to the Future"
print_justified "OS Patch level changer v1.0"
print_justified "of boot and recovery partitions"
print_justified "for Samsung S10/Note10 devices."
print_justified "https://github.com/CruelKernel/"
print_full_bar
ui_print " "

bl=$(getprop ro.boot.bootloader)

# Device is first 5 characters of bootloader string.
#
device=${bl:0:$((${#bl} - 8))}

if echo $device | grep -Ev 'G97([035][FN0]|7[BN])|N97([05][FN0]|6[BN0]|1N)' >/dev/null; then
ui_print " - Unsupported device detected. Installation aborted."
ui_print " "
exit 1
fi

date="$(echo $ZIPNAME | sed 's/^.*-\(2[0-9]\{3\}-[01][0-9]\).zip$/\1/')"

if [ "$date" = "$ZIPNAME" ]; then
date="2127-12"
ui_print " - Can't determine os_patch_level date"
ui_print " - from filename '$ZIPNAME'."
ui_print " - Max possible date $date will be used."
else
ui_print " - Detected date from zip filename: $date."
fi

unzip -d /tmp -o $ZIPFILE change_os_version
chmod +x /tmp/change_os_version

ui_print " - Patching boot ..."
/tmp/change_os_version /dev/block/by-name/boot same $date 2>&1 |
sed 's/^\(.*\)$/ui_print - - \1\n/' >> /proc/self/fd/$OUTFD
ui_print " "
ui_print " - Patching recovery ..."
/tmp/change_os_version /dev/block/by-name/recovery same $date 2>&1 |
sed 's/^\(.*\)$/ui_print - - \1\n/' >> /proc/self/fd/$OUTFD

rm -f /tmp/change_os_version

ui_print " "
ui_print " - Finished."
ui_print " "
155 changes: 155 additions & 0 deletions change_os_version.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
#include <errno.h>
#include <stdbool.h>
#include <stdint.h>
#include <ctype.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <stdarg.h>
#include <stdio.h>
#include <string.h>

#define BOOT_IMAGE_HEADER_V1_SIZE 1648
#define BOOT_IMAGE_HEADER_V2_SIZE 1660

typedef union __attribute__((packed)) {
uint32_t version;
struct {
unsigned os_patch_level:11;
unsigned os_version:21;
};
struct {
unsigned month:4;
unsigned year:7;
unsigned c:7;
unsigned b:7;
unsigned a:7;
};
} os_version_t;


static inline void check(bool cond, const char *message, ...)
{
if (cond) {
va_list args;
va_start(args, message);
vfprintf(stderr, message, args);
va_end(args);
exit(EXIT_FAILURE);
}
}

int main(int argc, char *argv[])
{
int fd;
uint32_t *addr;
const char *file, *os_version, *os_patch_level;
char *delim = NULL;
int year, month;
int a, b, c;
os_version_t curv, newv;
bool preserve_os_version = false;
bool preserve_os_patch_level = false;

check(argc != 4, "Usage: %s <file> <os_version|same> <os_patch_level|same>\n", argv[0]);
file = argv[1];
os_version = argv[2];
os_patch_level = argv[3];

if (!strcmp(os_version, "same")) {
preserve_os_version = true;
} else {
// Format: a.b.c
for (const char *p = os_version; *p != '\0'; ++p) {
check(!(isdigit(*p) || *p == '.'),
"Incorrect os_version '%s'. Format: a.b.c\n", os_version);
}
a = strtol(os_version, &delim, 10);
check(*delim != '.', "Incorrect os_version '%s'. Format: a.b.c\n", os_version);
b = strtol(delim + 1, &delim, 10);
check(*delim != '.', "Incorrect os_version '%s'. Format: a.b.c\n", os_version);
c = strtol(delim + 1, NULL, 10);
check(!(0 <= a && a <= 127 &&
0 <= b && b <= 127 &&
0 <= c && c <= 127),
"Incorrect os_version '%s'. Format: a.b.c\n", os_version);
}


if (!strcmp(os_patch_level, "same")) {
preserve_os_patch_level = true;
} else {
// Format: YYYY-MM
check(strlen(os_patch_level) != 7 ||
os_patch_level[4] != '-' ||
!isdigit(os_patch_level[0]) ||
!isdigit(os_patch_level[1]) ||
!isdigit(os_patch_level[2]) ||
!isdigit(os_patch_level[3]) ||
!isdigit(os_patch_level[5]) ||
!isdigit(os_patch_level[6]),
"Incorrent os_patch_level '%s'. Format: YYYY-MM\n", os_patch_level);

year = atoi(os_patch_level);
month = atoi(os_patch_level + 5);

check(!(2000 <= year && year <= 2127),
"Incorrect year: %ld (2000 <= year <= 2127)\n", year);
check(!(1 <= month && month <= 12),
"Incorrect month: %ld (01 <= month <= 12)\n", month);
}

fd = open(file, O_RDWR);
check(fd < 0, "open %s failed: %s\n", file, strerror(errno));

addr = mmap(NULL, BOOT_IMAGE_HEADER_V1_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
check(addr == MAP_FAILED, "mmap %s failed: %s\n", file, strerror(errno));

check(strncmp((const char *)addr, "ANDROID!", 8),
"Incorrect magic number, not a boot file.\n");

curv.version = *(addr + 11);
printf("Current OS version:\t%u.%u.%u %u-%02u\n",
curv.a, curv.b, curv.c,
curv.year + 2000, curv.month);

if (preserve_os_version) {
newv.os_version = curv.os_version;
} else {
newv.a = a;
newv.b = b;
newv.c = c;
}

if (preserve_os_patch_level) {
newv.os_patch_level = curv.os_patch_level;
} else {
newv.year = (year - 2000);
newv.month = month;
}

if (curv.version != newv.version) {
printf("New OS version:\t\t%u.%u.%u %u-%02u\n",
newv.a, newv.b, newv.c,
newv.year + 2000, newv.month);

if (curv.os_version > newv.os_version) {
fprintf(stderr, "warn: new os_version is lower than current\n");
}

if (curv.os_patch_level > newv.os_patch_level) {
fprintf(stderr, "warn: new os_patch_level version is lower than current\n");
}

*(addr + 11) = newv.version;
check(msync(addr, BOOT_IMAGE_HEADER_V1_SIZE, MS_SYNC) < 0, "msync failed: %s\n", strerror(errno));
} else {
printf("The dates are the same. Nothing to be done.\n");
}

check(munmap(addr, BOOT_IMAGE_HEADER_V1_SIZE) < 0, "munmap failed: %s\n", strerror(errno));
check(close(fd) < 0, "close failed: %s\n", strerror(errno));

return 0;
}

0 comments on commit c946906

Please sign in to comment.