mirror of
https://github.com/topjohnwu/Magisk.git
synced 2025-08-14 17:45:23 +00:00
Compare commits
133 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
d53f33bed8 | ||
![]() |
02e039d792 | ||
![]() |
9f9333315e | ||
![]() |
0d10b812fe | ||
![]() |
b4fe4f3d10 | ||
![]() |
ba93fcbda0 | ||
![]() |
88d19a4ca4 | ||
![]() |
af7b9ea898 | ||
![]() |
09cd0468cf | ||
![]() |
529aa754f5 | ||
![]() |
3c7e865555 | ||
![]() |
7877ac0c3b | ||
![]() |
1442e29d0e | ||
![]() |
9a7e9b736e | ||
![]() |
c421e45fa0 | ||
![]() |
8833d21ac3 | ||
![]() |
1a3c522c94 | ||
![]() |
c55aa92d4f | ||
![]() |
212a303347 | ||
![]() |
3f3568d8af | ||
![]() |
1e3bcfc8cd | ||
![]() |
a4ce9f6f05 | ||
![]() |
65dc99744e | ||
![]() |
c6d4740b0c | ||
![]() |
9f91c8b59d | ||
![]() |
2b3b087c29 | ||
![]() |
e08d46aa76 | ||
![]() |
feccc97a14 | ||
![]() |
77eec3d21d | ||
![]() |
ecaafd1b70 | ||
![]() |
0d51997e46 | ||
![]() |
463cbceb07 | ||
![]() |
1437c5c63f | ||
![]() |
52f1d50902 | ||
![]() |
a839cb787e | ||
![]() |
f621fb2060 | ||
![]() |
2ccd8b8838 | ||
![]() |
7ef0746c52 | ||
![]() |
6f609f0dd7 | ||
![]() |
ee2a30470a | ||
![]() |
e11fb2c09e | ||
![]() |
c6e9270590 | ||
![]() |
3e2e171407 | ||
![]() |
332f531a10 | ||
![]() |
bae2c9bc63 | ||
![]() |
5ac68f8df8 | ||
![]() |
06d3b94804 | ||
![]() |
e7c314fefc | ||
![]() |
faab79b41a | ||
![]() |
14204c9bfc | ||
![]() |
45dbd4464b | ||
![]() |
472255924a | ||
![]() |
6d3ac2aa55 | ||
![]() |
9ad03994d1 | ||
![]() |
35228f80b8 | ||
![]() |
69ded881c6 | ||
![]() |
d9bce45db4 | ||
![]() |
5e92b4faa9 | ||
![]() |
db501822ef | ||
![]() |
ef9948a967 | ||
![]() |
298f09402f | ||
![]() |
d4149d4b7a | ||
![]() |
3315228a90 | ||
![]() |
f72205c401 | ||
![]() |
11862bbaee | ||
![]() |
8d846993ee | ||
![]() |
1f84626278 | ||
![]() |
b4cfe6e9c0 | ||
![]() |
94a861e318 | ||
![]() |
1421e775d2 | ||
![]() |
f8eab72c7a | ||
![]() |
2afd2f0d3b | ||
![]() |
2b72f40cec | ||
![]() |
ff5c0d6361 | ||
![]() |
198b14e5fc | ||
![]() |
f9fea265cf | ||
![]() |
668601ca23 | ||
![]() |
99406f2099 | ||
![]() |
632b3cb9ae | ||
![]() |
0bf04c04f9 | ||
![]() |
dc29018ec0 | ||
![]() |
b6412afe96 | ||
![]() |
4e88186903 | ||
![]() |
f387378b69 | ||
![]() |
f894e6b4ea | ||
![]() |
e33f5996f3 | ||
![]() |
8f7f1ff7dd | ||
![]() |
54a0e52e05 | ||
![]() |
b2431b982f | ||
![]() |
8d6d619eed | ||
![]() |
70e332b9e8 | ||
![]() |
0a53c42a8a | ||
![]() |
0ccc92dc1e | ||
![]() |
c9157cc13b | ||
![]() |
2b1270381d | ||
![]() |
cdb8ee3946 | ||
![]() |
1e3586621b | ||
![]() |
c07e9ac29d | ||
![]() |
6e3bb48574 | ||
![]() |
16d7ae62bd | ||
![]() |
eea3cb32a5 | ||
![]() |
670fe8590c | ||
![]() |
30c048723c | ||
![]() |
85dc669ddf | ||
![]() |
397c1a1c2b | ||
![]() |
f1d3e35aac | ||
![]() |
0e69201f05 | ||
![]() |
f8fdaf5c1f | ||
![]() |
1f3b81338c | ||
![]() |
5921d3a42a | ||
![]() |
dbbc85719e | ||
![]() |
0ddb6c3f10 | ||
![]() |
e13281726c | ||
![]() |
0ddf4355a1 | ||
![]() |
7c8a3ca1a8 | ||
![]() |
3068738a70 | ||
![]() |
cfa0d8b7c0 | ||
![]() |
7ac41652f7 | ||
![]() |
24a510bc2e | ||
![]() |
0498540439 | ||
![]() |
da94c2e1e5 | ||
![]() |
bcdd74514f | ||
![]() |
1d0c36a0ab | ||
![]() |
a34ea8f131 | ||
![]() |
7fbfa6a52b | ||
![]() |
799ef3380d | ||
![]() |
d5087858ca | ||
![]() |
d9fc5650b8 | ||
![]() |
9ea028f5ab | ||
![]() |
aa309087fd | ||
![]() |
57bdd9d3bf | ||
![]() |
dc9871fe5b | ||
![]() |
3255ca3ea4 |
16
.gitattributes
vendored
Normal file
16
.gitattributes
vendored
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
# Set the default behavior, in case people don't have core.autocrlf set.
|
||||||
|
* text eol=lf
|
||||||
|
|
||||||
|
# Explicitly declare text files you want to always be normalized and converted
|
||||||
|
# to native line endings on checkout.
|
||||||
|
# *.c text
|
||||||
|
# *.h text
|
||||||
|
|
||||||
|
# Declare files that will always have CRLF line endings on checkout.
|
||||||
|
*.cmd text eol=crlf
|
||||||
|
|
||||||
|
# Denote all files that are truly binary and should not be modified.
|
||||||
|
binaries/** binary
|
||||||
|
*.jar binary
|
||||||
|
*.exe binary
|
||||||
|
*.apk binary
|
23
.gitignore
vendored
23
.gitignore
vendored
@@ -1,3 +1,22 @@
|
|||||||
obj
|
obj/
|
||||||
libs
|
libs/
|
||||||
*.zip
|
*.zip
|
||||||
|
|
||||||
|
# Copied binaries
|
||||||
|
zip_static/arm/*
|
||||||
|
zip_static/arm64/*
|
||||||
|
zip_static/x86/*
|
||||||
|
zip_static/x64/*
|
||||||
|
zip_static/chromeos/*
|
||||||
|
uninstaller/arm/*
|
||||||
|
uninstaller/arm64/*
|
||||||
|
uninstaller/x86/*
|
||||||
|
uninstaller/x64/*
|
||||||
|
uninstaller/chromeos/*
|
||||||
|
ziptools/zipadjust
|
||||||
|
|
||||||
|
# Generated scripts
|
||||||
|
uninstaller/common/
|
||||||
|
zip_static/common/*.sh
|
||||||
|
zip_static/common/*.rc
|
||||||
|
zip_static/META-INF/com/google/android/update-binary
|
||||||
|
18
.gitmodules
vendored
18
.gitmodules
vendored
@@ -1,6 +1,12 @@
|
|||||||
[submodule "selinux"]
|
[submodule "jni/selinux"]
|
||||||
path = selinux
|
path = jni/selinux
|
||||||
url = https://github.com/topjohnwu/selinux
|
url = https://github.com/topjohnwu/selinux.git
|
||||||
[submodule "jni/sepolicy-inject"]
|
[submodule "jni/su"]
|
||||||
path = jni/sepolicy-inject
|
path = jni/su
|
||||||
url = https://github.com/topjohnwu/sepolicy-inject
|
url = https://github.com/topjohnwu/MagiskSU.git
|
||||||
|
[submodule "jni/ndk-compression"]
|
||||||
|
path = jni/ndk-compression
|
||||||
|
url = https://github.com/topjohnwu/ndk-compression.git
|
||||||
|
[submodule "jni/magiskpolicy"]
|
||||||
|
path = jni/magiskpolicy
|
||||||
|
url = https://github.com/topjohnwu/magiskpolicy.git
|
||||||
|
10
README.MD
10
README.MD
@@ -1,3 +1,11 @@
|
|||||||
# Magisk
|
# Magisk
|
||||||
Static binaries included:
|
###Static binaries included:
|
||||||
* Busybox: http://forum.xda-developers.com/android/software-hacking/tool-busybox-flashable-archs-t3348543
|
* Busybox: http://forum.xda-developers.com/android/software-hacking/tool-busybox-flashable-archs-t3348543
|
||||||
|
|
||||||
|
###How to build Magisk
|
||||||
|
1. Download and install NDK
|
||||||
|
2. Add the NDK directory into PATH
|
||||||
|
To check if the PATH is set correctly, try calling `which ndk-build` (`where ndk-build` on Windows) and see if it shows the NDK directory
|
||||||
|
3. Unix-like users (e.g. Linux & MacOS) please execute `build.sh` through shell
|
||||||
|
Windows users please execute `build.cmd` through cmd
|
||||||
|
4. The scripts will show you further details
|
||||||
|
BIN
binaries/busybox-arm
Normal file
BIN
binaries/busybox-arm
Normal file
Binary file not shown.
BIN
binaries/busybox-arm64
Normal file
BIN
binaries/busybox-arm64
Normal file
Binary file not shown.
BIN
binaries/busybox-x64
Normal file
BIN
binaries/busybox-x64
Normal file
Binary file not shown.
BIN
binaries/busybox-x86
Normal file
BIN
binaries/busybox-x86
Normal file
Binary file not shown.
182
build.cmd
Normal file
182
build.cmd
Normal file
@@ -0,0 +1,182 @@
|
|||||||
|
@ECHO OFF
|
||||||
|
SETLOCAL ENABLEEXTENSIONS
|
||||||
|
SET me=%~nx0
|
||||||
|
SET parent=%~dp0
|
||||||
|
SET tab=
|
||||||
|
SET OK=
|
||||||
|
|
||||||
|
CD %parent%
|
||||||
|
|
||||||
|
call :%~1 "%~2"
|
||||||
|
IF NOT DEFINED OK CALL :usage
|
||||||
|
|
||||||
|
EXIT /B %ERRORLEVEL%
|
||||||
|
|
||||||
|
:usage
|
||||||
|
ECHO %me% all ^<version name^>
|
||||||
|
ECHO %tab%Build binaries, zip, and sign Magisk
|
||||||
|
ECHO %tab%This is equlivant to first ^<build^>, then ^<zip^>
|
||||||
|
ECHO %me% clean
|
||||||
|
ECHO %tab%Cleanup compiled / generated files
|
||||||
|
ECHO %me% build
|
||||||
|
ECHO %tab%Build the binaries with ndk
|
||||||
|
ECHO %me% zip ^<version name^>
|
||||||
|
ECHO %tab%Zip and sign Magisk
|
||||||
|
ECHO %me% uninstaller
|
||||||
|
ECHO %tab%Zip and sign the uninstaller
|
||||||
|
EXIT /B 1
|
||||||
|
|
||||||
|
:all
|
||||||
|
SET OK=y
|
||||||
|
IF [%~1] == [] (
|
||||||
|
CALL :error "Missing version number"
|
||||||
|
CALL :usage
|
||||||
|
EXIT /B %ERRORLEVEL%
|
||||||
|
)
|
||||||
|
CALL :build
|
||||||
|
CALL :zip "%~1"
|
||||||
|
EXIT /B %ERRORLEVEL%
|
||||||
|
|
||||||
|
:build
|
||||||
|
SET OK=y
|
||||||
|
ECHO ************************
|
||||||
|
ECHO * Building binaries
|
||||||
|
ECHO ************************
|
||||||
|
FOR /F "tokens=* USEBACKQ" %%F IN (`where ndk-build`) DO (
|
||||||
|
IF [%%F] == [] (
|
||||||
|
CALL :error "Please add ndk-build to PATH!"
|
||||||
|
EXIT /B 1
|
||||||
|
)
|
||||||
|
)
|
||||||
|
CALL ndk-build -j4 || CALL :error "Magisk binary tools build failed...."
|
||||||
|
IF %ERRORLEVEL% NEQ 0 EXIT /B %ERRORLEVEL%
|
||||||
|
ECHO ************************
|
||||||
|
ECHO * Copying binaries
|
||||||
|
ECHO ************************
|
||||||
|
CALL :mkcp libs\armeabi-v7a\* zip_static\arm
|
||||||
|
CALL :mkcp libs\arm64-v8a\* zip_static\arm64
|
||||||
|
CALL :mkcp libs\x86\* zip_static\x86
|
||||||
|
CALL :mkcp libs\x86_64\* zip_static\x64
|
||||||
|
CALL :mkcp libs\armeabi-v7a\magiskboot uninstaller\arm
|
||||||
|
CALL :mkcp libs\arm64-v8a\magiskboot uninstaller\arm64
|
||||||
|
CALL :mkcp libs\x86\magiskboot uninstaller\x86
|
||||||
|
CALL :mkcp libs\x86_64\magiskboot uninstaller\x64
|
||||||
|
EXIT /B %ERRORLEVEL%
|
||||||
|
|
||||||
|
:clean
|
||||||
|
SET OK=y
|
||||||
|
ECHO ************************
|
||||||
|
ECHO * Cleaning up
|
||||||
|
ECHO ************************
|
||||||
|
CALL ndk-build clean
|
||||||
|
2>NUL RMDIR /S /Q zip_static\arm
|
||||||
|
2>NUL RMDIR /S /Q zip_static\arm64
|
||||||
|
2>NUL RMDIR /S /Q zip_static\x86
|
||||||
|
2>NUL RMDIR /S /Q zip_static\x64
|
||||||
|
2>NUL RMDIR /S /Q zip_static\chromeos
|
||||||
|
2>NUL DEL zip_static\META-INF\com\google\android\update-binary
|
||||||
|
2>NUL DEL zip_static\common\*.sh
|
||||||
|
2>NUL DEL zip_static\common\*.rc
|
||||||
|
2>NUL RMDIR /S /Q uninstaller\common
|
||||||
|
2>NUL RMDIR /S /Q uninstaller\arm
|
||||||
|
2>NUL RMDIR /S /Q uninstaller\arm64
|
||||||
|
2>NUL RMDIR /S /Q uninstaller\x86
|
||||||
|
2>NUL RMDIR /S /Q uninstaller\x64
|
||||||
|
2>NUL RMDIR /S /Q uninstaller\chromeos
|
||||||
|
EXIT /B 0
|
||||||
|
|
||||||
|
:zip
|
||||||
|
SET OK=y
|
||||||
|
IF [%~1] == [] (
|
||||||
|
CALL :error "Missing version number"
|
||||||
|
CALL :usage
|
||||||
|
EXIT /B %ERRORLEVEL%
|
||||||
|
)
|
||||||
|
IF NOT EXIST "zip_static\arm\magiskboot" CALL :error "Missing binaries! Please run '%me% build' before zipping!"
|
||||||
|
IF %ERRORLEVEL% NEQ 0 EXIT /B %ERRORLEVEL%
|
||||||
|
ECHO ************************
|
||||||
|
ECHO * Adding version info
|
||||||
|
ECHO ************************
|
||||||
|
powershell.exe -nologo -noprofile -command "(gc -Raw scripts\flash_script.sh) -replace 'MAGISK_VERSION_STUB', 'Magisk v%~1 Boot Image Patcher' | sc zip_static\META-INF\com\google\android\update-binary"
|
||||||
|
powershell.exe -nologo -noprofile -command "(gc -Raw scripts\magic_mask.sh) -replace 'MAGISK_VERSION_STUB', 'setprop magisk.version \"%~1\"' | sc zip_static\common\magic_mask.sh"
|
||||||
|
ECHO ************************
|
||||||
|
ECHO * Copying Files
|
||||||
|
ECHO ************************
|
||||||
|
COPY /Y scripts\ramdisk_patch.sh zip_static\common\ramdisk_patch.sh
|
||||||
|
COPY /Y scripts\init.magisk.rc zip_static\common\init.magisk.rc
|
||||||
|
COPY /Y binaries\busybox-arm zip_static\arm\busybox
|
||||||
|
COPY /Y binaries\busybox-arm64 zip_static\arm64\busybox
|
||||||
|
COPY /Y binaries\busybox-x86 zip_static\x86\busybox
|
||||||
|
COPY /Y binaries\busybox-x64 zip_static\x64\busybox
|
||||||
|
CALL :mkcp binaries\chromeos zip_static\chromeos
|
||||||
|
ECHO ************************
|
||||||
|
ECHO * Zipping Magisk v%~1
|
||||||
|
ECHO ************************
|
||||||
|
CD zip_static
|
||||||
|
2>NUL DEL "..\Magisk-v%~1.zip"
|
||||||
|
..\ziptools\win_bin\zip "..\Magisk-v%~1.zip" -r .
|
||||||
|
CD ..\
|
||||||
|
CALL :sign_zip "Magisk-v%~1.zip"
|
||||||
|
EXIT /B %ERRORLEVEL%
|
||||||
|
|
||||||
|
:uninstaller
|
||||||
|
SET OK=y
|
||||||
|
IF NOT EXIST "uninstaller\arm\magiskboot" CALL :error "Missing binaries! Please run '%me% build' before zipping!"
|
||||||
|
IF %ERRORLEVEL% NEQ 0 EXIT /B %ERRORLEVEL%
|
||||||
|
ECHO ************************
|
||||||
|
ECHO * Copying Files
|
||||||
|
ECHO ************************
|
||||||
|
CALL :mkcp scripts\magisk_uninstaller.sh uninstaller\common
|
||||||
|
COPY /Y binaries\busybox-arm uninstaller\arm\busybox
|
||||||
|
COPY /Y binaries\busybox-arm64 uninstaller\arm64\busybox
|
||||||
|
COPY /Y binaries\busybox-x86 uninstaller\x86\busybox
|
||||||
|
COPY /Y binaries\busybox-x64 uninstaller\x64\busybox
|
||||||
|
CALL :mkcp binaries\chromeos uninstaller\chromeos
|
||||||
|
ECHO ************************
|
||||||
|
ECHO * Zipping uninstaller
|
||||||
|
ECHO ************************
|
||||||
|
FOR /F "tokens=* USEBACKQ" %%F IN (`ziptools\win_bin\date "+%%Y%%m%%d"`) DO (set timestamp=%%F)
|
||||||
|
CD uninstaller
|
||||||
|
2>NUL DEL "../Magisk-uninstaller-%timestamp%.zip"
|
||||||
|
..\ziptools\win_bin\zip "../Magisk-uninstaller-%timestamp%.zip" -r .
|
||||||
|
CD ..\
|
||||||
|
CALL :sign_zip "Magisk-uninstaller-%timestamp%.zip"
|
||||||
|
EXIT /B %ERRORLEVEL%
|
||||||
|
|
||||||
|
:sign_zip
|
||||||
|
IF NOT EXIST "ziptools\win_bin\zipadjust.exe" (
|
||||||
|
ECHO ************************
|
||||||
|
ECHO * Compiling ZipAdjust
|
||||||
|
ECHO ************************
|
||||||
|
gcc -o ziptools\win_bin\zipadjust ziptools\src\*.c -lz || CALL :error "ZipAdjust Build failed...."
|
||||||
|
IF %ERRORLEVEL% NEQ 0 EXIT /B %ERRORLEVEL%
|
||||||
|
)
|
||||||
|
SET basename="%~1"
|
||||||
|
SET basename="%basename:.zip=%"
|
||||||
|
ECHO ************************
|
||||||
|
ECHO * First sign %~1
|
||||||
|
ECHO ************************
|
||||||
|
java -jar "ziptools\signapk.jar" "ziptools\test.certificate.x509.pem" "ziptools\test.key.pk8" "%~1" "%basename:"=%-firstsign.zip"
|
||||||
|
ECHO ************************
|
||||||
|
ECHO * Adjusting %~1
|
||||||
|
ECHO ************************
|
||||||
|
ziptools\win_bin\zipadjust "%basename:"=%-firstsign.zip" "%basename:"=%-adjusted.zip"
|
||||||
|
ECHO ************************
|
||||||
|
ECHO * Final sign %~1
|
||||||
|
ECHO ************************
|
||||||
|
java -jar "ziptools\minsignapk.jar" "ziptools\test.certificate.x509.pem" "ziptools\test.key.pk8" "%basename:"=%-adjusted.zip" "%basename:"=%-signed.zip"
|
||||||
|
|
||||||
|
MOVE /Y "%basename:"=%-signed.zip" "%~1"
|
||||||
|
DEL "%basename:"=%-adjusted.zip" "%basename:"=%-firstsign.zip"
|
||||||
|
EXIT /B %ERRORLEVEL%
|
||||||
|
|
||||||
|
:mkcp
|
||||||
|
2>NUL MKDIR "%~2"
|
||||||
|
2>NUL COPY /Y "%~1" "%~2"
|
||||||
|
EXIT /B 0
|
||||||
|
|
||||||
|
:error
|
||||||
|
ECHO.
|
||||||
|
ECHO ! %~1
|
||||||
|
ECHO.
|
||||||
|
EXIT /B 1
|
172
build.sh
Executable file
172
build.sh
Executable file
@@ -0,0 +1,172 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
usage() {
|
||||||
|
echo "$0 all <version name>"
|
||||||
|
echo -e "\tBuild binaries, zip, and sign Magisk"
|
||||||
|
echo -e "\tThis is equlivant to first <build>, then <zip>"
|
||||||
|
echo "$0 clean"
|
||||||
|
echo -e "\tCleanup compiled / generated files"
|
||||||
|
echo "$0 build"
|
||||||
|
echo -e "\tBuild the binaries with ndk"
|
||||||
|
echo "$0 zip <version name>"
|
||||||
|
echo -e "\tZip and sign Magisk"
|
||||||
|
echo "$0 uninstaller"
|
||||||
|
echo -e "\tZip and sign the uninstaller"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
cleanup() {
|
||||||
|
echo "************************"
|
||||||
|
echo "* Cleaning up"
|
||||||
|
echo "************************"
|
||||||
|
ndk-build clean 2>/dev/null
|
||||||
|
rm -rfv zip_static/arm
|
||||||
|
rm -rfv zip_static/arm64
|
||||||
|
rm -rfv zip_static/x86
|
||||||
|
rm -rfv zip_static/x64
|
||||||
|
rm -rfv zip_static/chromeos
|
||||||
|
rm -rfv zip_static/META-INF/com/google/android/update-binary
|
||||||
|
rm -rfv zip_static/common/*.sh
|
||||||
|
rm -rfv zip_static/common/*.rc
|
||||||
|
rm -rfv uninstaller/common
|
||||||
|
rm -rfv uninstaller/arm
|
||||||
|
rm -rfv uninstaller/arm64
|
||||||
|
rm -rfv uninstaller/x86
|
||||||
|
rm -rfv uninstaller/x64
|
||||||
|
rm -rfv uninstaller/chromeos
|
||||||
|
}
|
||||||
|
|
||||||
|
mkcp() {
|
||||||
|
[ ! -d "$2" ] && mkdir -p "$2"
|
||||||
|
cp -afv $1 $2
|
||||||
|
}
|
||||||
|
|
||||||
|
error() {
|
||||||
|
echo -e "\n! $1\n"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
build_bin() {
|
||||||
|
echo "************************"
|
||||||
|
echo "* Building binaries"
|
||||||
|
echo "************************"
|
||||||
|
[ -z `which ndk-build` ] && error "Please add ndk-build to PATH!"
|
||||||
|
ndk-build -j4 || error "Magisk binary tools build failed...."
|
||||||
|
echo "************************"
|
||||||
|
echo "* Copying binaries"
|
||||||
|
echo "************************"
|
||||||
|
mkcp "libs/armeabi-v7a/*" zip_static/arm
|
||||||
|
mkcp libs/armeabi-v7a/magiskboot uninstaller/arm
|
||||||
|
mkcp "libs/arm64-v8a/*" zip_static/arm64
|
||||||
|
mkcp libs/arm64-v8a/magiskboot uninstaller/arm64
|
||||||
|
mkcp "libs/x86/*" zip_static/x86
|
||||||
|
mkcp libs/x86/magiskboot uninstaller/x86
|
||||||
|
mkcp "libs/x86_64/*" zip_static/x64
|
||||||
|
mkcp libs/x86_64/magiskboot uninstaller/x64
|
||||||
|
}
|
||||||
|
|
||||||
|
zip_package() {
|
||||||
|
[ ! -f "zip_static/arm/magiskboot" ] && error "Missing binaries!! Please run '$0 build' before zipping"
|
||||||
|
echo "************************"
|
||||||
|
echo "* Adding version info"
|
||||||
|
echo "************************"
|
||||||
|
sed "s/MAGISK_VERSION_STUB/Magisk v$1 Boot Image Patcher/g" scripts/flash_script.sh > zip_static/META-INF/com/google/android/update-binary
|
||||||
|
sed "s/MAGISK_VERSION_STUB/setprop magisk.version \"$1\"/g" scripts/magic_mask.sh > zip_static/common/magic_mask.sh
|
||||||
|
echo "************************"
|
||||||
|
echo "* Copying files"
|
||||||
|
echo "************************"
|
||||||
|
cp -afv scripts/ramdisk_patch.sh zip_static/common/ramdisk_patch.sh
|
||||||
|
cp -afv scripts/init.magisk.rc zip_static/common/init.magisk.rc
|
||||||
|
cp -afv binaries/busybox-arm zip_static/arm/busybox
|
||||||
|
cp -afv binaries/busybox-arm64 zip_static/arm64/busybox
|
||||||
|
cp -afv binaries/busybox-x86 zip_static/x86/busybox
|
||||||
|
cp -afv binaries/busybox-x64 zip_static/x64/busybox
|
||||||
|
cp -afv binaries/chromeos/. zip_static/chromeos
|
||||||
|
echo "************************"
|
||||||
|
echo "* Zipping Magisk v$1"
|
||||||
|
echo "************************"
|
||||||
|
cd zip_static
|
||||||
|
find . -type f -exec chmod 644 {} \;
|
||||||
|
find . -type d -exec chmod 755 {} \;
|
||||||
|
rm -rf "../Magisk-v$1.zip"
|
||||||
|
zip "../Magisk-v$1.zip" -r .
|
||||||
|
cd ../
|
||||||
|
sign_zip "Magisk-v$1.zip"
|
||||||
|
}
|
||||||
|
|
||||||
|
zip_uninstaller() {
|
||||||
|
[ ! -f "uninstaller/arm/magiskboot" ] && error "Missing binaries!! Please run '$0 build' before zipping"
|
||||||
|
echo "************************"
|
||||||
|
echo "* Copying files"
|
||||||
|
echo "************************"
|
||||||
|
mkcp scripts/magisk_uninstaller.sh uninstaller/common
|
||||||
|
cp -afv binaries/busybox-arm uninstaller/arm/busybox
|
||||||
|
cp -afv binaries/busybox-arm64 uninstaller/arm64/busybox
|
||||||
|
cp -afv binaries/busybox-x86 uninstaller/x86/busybox
|
||||||
|
cp -afv binaries/busybox-x64 uninstaller/x64/busybox
|
||||||
|
cp -afv binaries/chromeos/. zip_static/chromeos
|
||||||
|
echo "************************"
|
||||||
|
echo "* Zipping uninstaller"
|
||||||
|
echo "************************"
|
||||||
|
mkcp scripts/magisk_uninstaller.sh uninstaller/common
|
||||||
|
cd uninstaller
|
||||||
|
find . -type f -exec chmod 644 {} \;
|
||||||
|
find . -type d -exec chmod 755 {} \;
|
||||||
|
TIMESTAMP=`date "+%Y%m%d"`
|
||||||
|
rm -rf "../Magisk-uninstaller-$TIMESTAMP.zip"
|
||||||
|
zip "../Magisk-uninstaller-$TIMESTAMP.zip" -r .
|
||||||
|
cd ../
|
||||||
|
sign_zip "Magisk-uninstaller-$TIMESTAMP.zip"
|
||||||
|
}
|
||||||
|
|
||||||
|
sign_zip() {
|
||||||
|
if [ ! -f "ziptools/zipadjust" ]; then
|
||||||
|
echo "************************"
|
||||||
|
echo "* Compiling ZipAdjust"
|
||||||
|
echo "************************"
|
||||||
|
gcc -o ziptools/zipadjust ziptools/src/*.c -lz || error "ZipAdjust Build failed...."
|
||||||
|
chmod 755 ziptools/zipadjust
|
||||||
|
fi
|
||||||
|
echo "************************"
|
||||||
|
echo "* First sign $1"
|
||||||
|
echo "************************"
|
||||||
|
java -jar "ziptools/signapk.jar" "ziptools/test.certificate.x509.pem" "ziptools/test.key.pk8" "$1" "${1%.*}-firstsign.zip"
|
||||||
|
echo "************************"
|
||||||
|
echo "* Adjusting $1"
|
||||||
|
echo "************************"
|
||||||
|
ziptools/zipadjust "${1%.*}-firstsign.zip" "${1%.*}-adjusted.zip"
|
||||||
|
echo "************************"
|
||||||
|
echo "* Final sign $1"
|
||||||
|
echo "************************"
|
||||||
|
java -jar "ziptools/minsignapk.jar" "ziptools/test.certificate.x509.pem" "ziptools/test.key.pk8" "${1%.*}-adjusted.zip" "${1%.*}-signed.zip"
|
||||||
|
|
||||||
|
mv "${1%.*}-signed.zip" "$1"
|
||||||
|
rm "${1%.*}-adjusted.zip" "${1%.*}-firstsign.zip"
|
||||||
|
}
|
||||||
|
|
||||||
|
DIR="$(cd "$(dirname "$0")"; pwd)"
|
||||||
|
cd "$DIR"
|
||||||
|
|
||||||
|
case $1 in
|
||||||
|
"all" )
|
||||||
|
[ -z "$2" ] && echo -e "! Missing version number\n" && usage
|
||||||
|
build_bin
|
||||||
|
zip_package $2
|
||||||
|
;;
|
||||||
|
"clean" )
|
||||||
|
cleanup
|
||||||
|
;;
|
||||||
|
"build" )
|
||||||
|
build_bin
|
||||||
|
;;
|
||||||
|
"zip" )
|
||||||
|
[ -z "$2" ] && echo -e "! Missing version number\n" && usage
|
||||||
|
zip_package $2
|
||||||
|
;;
|
||||||
|
"uninstaller" )
|
||||||
|
zip_uninstaller
|
||||||
|
;;
|
||||||
|
* )
|
||||||
|
usage
|
||||||
|
;;
|
||||||
|
esac
|
@@ -1,35 +1,7 @@
|
|||||||
my_path := $(call my-dir)
|
LOCAL_PATH := $(call my-dir)
|
||||||
|
|
||||||
LOCAL_PATH := $(my_path)
|
include jni/magiskboot/Android.mk
|
||||||
|
include jni/magiskhide/Android.mk
|
||||||
include $(CLEAR_VARS)
|
include jni/resetprop/Android.mk
|
||||||
LOCAL_MODULE := magiskhide
|
include jni/magiskpolicy/Android.mk
|
||||||
LOCAL_MODULE_TAGS := optional
|
include jni/su/Android.mk
|
||||||
LOCAL_FORCE_STATIC_EXECUTABLE := true
|
|
||||||
LOCAL_LDFLAGS := -static
|
|
||||||
LOCAL_STATIC_LIBRARIES := libc libcutils
|
|
||||||
LOCAL_SRC_FILES := magiskhide.c
|
|
||||||
include $(BUILD_EXECUTABLE)
|
|
||||||
|
|
||||||
include $(CLEAR_VARS)
|
|
||||||
LOCAL_MODULE := bootimgtools
|
|
||||||
LOCAL_MODULE_TAGS := optional
|
|
||||||
LOCAL_FORCE_STATIC_EXECUTABLE := true
|
|
||||||
LOCAL_LDFLAGS := -static
|
|
||||||
LOCAL_STATIC_LIBRARIES := libc libcutils
|
|
||||||
LOCAL_SRC_FILES := bootimgtools.c extract.c repack.c hexpatch.c
|
|
||||||
LOCAL_CFLAGS += -std=gnu11
|
|
||||||
include $(BUILD_EXECUTABLE)
|
|
||||||
|
|
||||||
include $(CLEAR_VARS)
|
|
||||||
LOCAL_MODULE := sepolicy-inject
|
|
||||||
LOCAL_MODULE_TAGS := optional
|
|
||||||
LOCAL_FORCE_STATIC_EXECUTABLE := true
|
|
||||||
LOCAL_LDFLAGS := -static
|
|
||||||
LOCAL_STATIC_LIBRARIES := libc libcutils libsepol
|
|
||||||
LOCAL_SRC_FILES := sepolicy-inject/sepolicy-inject.c sepolicy-inject/builtin_rules.c
|
|
||||||
LOCAL_C_INCLUDES := selinux/libsepol/include/
|
|
||||||
LOCAL_CFLAGS += -std=gnu11
|
|
||||||
include $(BUILD_EXECUTABLE)
|
|
||||||
|
|
||||||
include selinux/libsepol/Android.mk
|
|
||||||
|
@@ -1,3 +1,3 @@
|
|||||||
APP_ABI := x86 armeabi
|
APP_ABI := x86 x86_64 armeabi-v7a arm64-v8a
|
||||||
APP_PIE = true
|
|
||||||
APP_PLATFORM := android-21
|
APP_PLATFORM := android-21
|
||||||
|
APP_CPPFLAGS += -std=c++11
|
||||||
|
@@ -1,45 +0,0 @@
|
|||||||
#include <getopt.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
|
|
||||||
#include "bootimgtools.h"
|
|
||||||
|
|
||||||
/********************
|
|
||||||
Patch Boot Image
|
|
||||||
*********************/
|
|
||||||
|
|
||||||
int usage(char *arg0) {
|
|
||||||
fprintf(stderr, "Boot Image Unpack/Repack Tool\n");
|
|
||||||
fprintf(stderr, "%s --extract <bootimage>\n", arg0);
|
|
||||||
fprintf(stderr, " Unpack <bootimage> into current directory\n\n");
|
|
||||||
fprintf(stderr, "%s --repack <bootimage>\n", arg0);
|
|
||||||
fprintf(stderr, " Repack kernel, dt, ramdisk... from current directory to new-image.img\n <bootimage> is the image you've just unpacked\n\n");
|
|
||||||
fprintf(stderr, "%s --hexpatch <bootimage> <hexpattern1> <hexpattern2>\n", arg0);
|
|
||||||
fprintf(stderr, " Search <hexpattern1> in <bootimage>, and replace with <hexpattern2>\n\n");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
int main(int argc, char *argv[])
|
|
||||||
{
|
|
||||||
char ch;
|
|
||||||
struct option long_options[] = {
|
|
||||||
{"extract", required_argument, NULL, 'e'},
|
|
||||||
{"repack", required_argument, NULL, 'r'},
|
|
||||||
{"hexpatch", required_argument, NULL, 'p'},
|
|
||||||
{NULL, 0, NULL, 0}
|
|
||||||
};
|
|
||||||
while ((ch = getopt_long(argc, argv, "e:r:p:", long_options, NULL)) != -1) {
|
|
||||||
switch (ch) {
|
|
||||||
case 'e':
|
|
||||||
return extract(optarg);
|
|
||||||
case 'r':
|
|
||||||
return repack(optarg);
|
|
||||||
case 'p':
|
|
||||||
if (argc < 5) return usage(argv[0]);
|
|
||||||
optind += 2;
|
|
||||||
return hexpatch(argv[optind - 3], argv[optind - 2], argv[optind - 1]);
|
|
||||||
default:
|
|
||||||
return usage(argv[0]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
148
jni/extract.c
148
jni/extract.c
@@ -1,148 +0,0 @@
|
|||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <sys/types.h>
|
|
||||||
#include <sys/stat.h>
|
|
||||||
#include <sys/sendfile.h>
|
|
||||||
#include <sys/mman.h>
|
|
||||||
#include <fcntl.h>
|
|
||||||
#include <assert.h>
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
#include "bootimgtools.h"
|
|
||||||
|
|
||||||
void dump(uint8_t *ptr, size_t size, char* filename) {
|
|
||||||
unlink(filename);
|
|
||||||
int ofd = open(filename, O_WRONLY|O_CREAT, 0644);
|
|
||||||
assert(ofd >= 0);
|
|
||||||
int ret = write(ofd, ptr, size);
|
|
||||||
assert(ret == size);
|
|
||||||
close(ofd);
|
|
||||||
}
|
|
||||||
|
|
||||||
//TODO: Search for other header types
|
|
||||||
void dump_ramdisk(uint8_t *ptr, size_t size) {
|
|
||||||
//GZip header
|
|
||||||
if(memcmp(ptr, "\x1f\x8b\x08\x00", 4) == 0) {
|
|
||||||
dump(ptr, size, "ramdisk.gz");
|
|
||||||
//MTK header
|
|
||||||
} else if(memcmp(ptr, "\x88\x16\x88\x58", 4) == 0) {
|
|
||||||
if(memcmp(ptr+4, "RECOVERY", 8)==0) {
|
|
||||||
dump(ptr, 0, "ramdisk-mtk-recovery");
|
|
||||||
} else if(memcmp(ptr+4, "ROOTFS\0\0", 8)==0) {
|
|
||||||
dump(ptr, 0, "ramdisk-mtk-boot");
|
|
||||||
} else {
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
dump(ptr, 0, "ramdisk-mtk"); //Create an mtk flag
|
|
||||||
dump_ramdisk(ptr+512, size-512);
|
|
||||||
} else {
|
|
||||||
//Since our first aim is to extract/repack ramdisk
|
|
||||||
//Stop if we can't find it
|
|
||||||
//Still dump it for debug purposes
|
|
||||||
dump(ptr, size, "ramdisk");
|
|
||||||
|
|
||||||
fprintf(stderr, "Unknown ramdisk type\n");
|
|
||||||
abort();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void search_security_hdr(uint8_t *buf, size_t size) {
|
|
||||||
if(memcmp(buf, "CHROMEOS", 8) == 0) {
|
|
||||||
dump(buf, 0, "chromeos");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int search_security(uint8_t *buf, size_t size, int pos) {
|
|
||||||
//Rockchip signature
|
|
||||||
if(memcmp(buf+1024, "SIGN", 4) == 0) {
|
|
||||||
//Rockchip signature AT LEAST means the bootloader will check the crc
|
|
||||||
dump(buf, 0, "rkcrc"); //Create an flag to tell it
|
|
||||||
|
|
||||||
//And it's possible there is a security too
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
//If we didn't parse the whole file, it is highly likely there is a boot signature
|
|
||||||
if(pos < size) {
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* TODO:
|
|
||||||
* - At the moment we dump kernel + ramdisk + second + DT, it's likely we only want ramdisk
|
|
||||||
* - Error-handling via assert() is perhaps not the best
|
|
||||||
*/
|
|
||||||
int extract(char *image) {
|
|
||||||
|
|
||||||
int fd = open(image, O_RDONLY);
|
|
||||||
off_t size = lseek(fd, 0, SEEK_END);
|
|
||||||
lseek(fd, 0, SEEK_SET);
|
|
||||||
uint8_t *orig = mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0);
|
|
||||||
uint8_t *base = orig;
|
|
||||||
assert(base);
|
|
||||||
|
|
||||||
search_security_hdr(base, size);
|
|
||||||
|
|
||||||
//We're searching for the header in the whole file, we could stop earlier.
|
|
||||||
//At least HTC and nVidia have a signature header
|
|
||||||
while(base<(orig+size)) {
|
|
||||||
if(memcmp(base, BOOT_MAGIC, BOOT_MAGIC_SIZE) == 0)
|
|
||||||
break;
|
|
||||||
//We're searching every 256bytes, is it ok?
|
|
||||||
base += 256;
|
|
||||||
}
|
|
||||||
assert(base < (orig+size));
|
|
||||||
|
|
||||||
struct boot_img_hdr *hdr = (struct boot_img_hdr*) base;
|
|
||||||
assert(
|
|
||||||
hdr->page_size == 2048 ||
|
|
||||||
hdr->page_size == 4096 ||
|
|
||||||
hdr->page_size == 16384
|
|
||||||
);
|
|
||||||
|
|
||||||
long pos = hdr->page_size;
|
|
||||||
dump(base+pos, hdr->kernel_size, "kernel");
|
|
||||||
pos += hdr->kernel_size + hdr->page_size-1;
|
|
||||||
pos &= ~(hdr->page_size-1L);
|
|
||||||
|
|
||||||
dump_ramdisk(base+pos, hdr->ramdisk_size);
|
|
||||||
pos += hdr->ramdisk_size + hdr->page_size-1;
|
|
||||||
pos &= ~(hdr->page_size-1L);
|
|
||||||
|
|
||||||
if(hdr->second_size) {
|
|
||||||
assert( (pos+hdr->second_size) <= size);
|
|
||||||
dump(base+pos, hdr->second_size, "second");
|
|
||||||
pos += hdr->second_size + hdr->page_size-1;
|
|
||||||
pos &= ~(hdr->page_size-1L);
|
|
||||||
}
|
|
||||||
|
|
||||||
//This is non-standard, so we triple check
|
|
||||||
if( hdr->unused[0] &&
|
|
||||||
pos < size &&
|
|
||||||
(pos+hdr->unused[0]) <= size) {
|
|
||||||
|
|
||||||
if(memcmp(base+pos, "QCDT", 4) == 0 ||
|
|
||||||
memcmp(base+pos, "SPRD", 4) == 0 ||
|
|
||||||
memcmp(base+pos, "DTBH", 4) == 0
|
|
||||||
) {
|
|
||||||
dump(base+pos, hdr->unused[0], "dt");
|
|
||||||
pos += hdr->unused[0] + hdr->page_size-1;
|
|
||||||
pos &= ~(hdr->page_size-1L);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//If we think we find some security-related infos in the boot.img
|
|
||||||
//create a "secure" flag to warn the user it is dangerous
|
|
||||||
if(search_security(base, size, pos)) {
|
|
||||||
dump(base, 0, "secure");
|
|
||||||
}
|
|
||||||
|
|
||||||
munmap(orig, size);
|
|
||||||
close(fd);
|
|
||||||
return 0;
|
|
||||||
}
|
|
@@ -1,66 +0,0 @@
|
|||||||
#include <getopt.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <sys/types.h>
|
|
||||||
#include <sys/stat.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <fcntl.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
#include "bootimgtools.h"
|
|
||||||
|
|
||||||
int hex2int(char c) {
|
|
||||||
int first = c / 16 - 3;
|
|
||||||
int second = c % 16;
|
|
||||||
int result = first * 10 + second;
|
|
||||||
if(result > 9) result--;
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
int hex2ascii(char c, char d) {
|
|
||||||
int high = hex2int(c) * 16;
|
|
||||||
int low = hex2int(d);
|
|
||||||
return high+low;
|
|
||||||
}
|
|
||||||
|
|
||||||
void hexstr2str(char *hex, char *str) {
|
|
||||||
char buf = 0;
|
|
||||||
for(int i = 0, length = strlen(hex); i < length; ++i){
|
|
||||||
if(i % 2){
|
|
||||||
str[i / 2] = hex2ascii(buf, hex[i]);
|
|
||||||
} else{
|
|
||||||
buf = hex[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int hexpatch(char * image, char *from, char *to) {
|
|
||||||
int fd = open(image, O_RDWR), patternsize = strlen(from) / 2, patchsize = strlen(to) / 2;
|
|
||||||
off_t filesize = lseek(fd, 0, SEEK_END);
|
|
||||||
char *file, *pattern, *patch, *start;
|
|
||||||
file = malloc(sizeof (char) * filesize);
|
|
||||||
pattern = malloc(sizeof (char) * patternsize);
|
|
||||||
patch = malloc(sizeof (char) * patchsize);
|
|
||||||
lseek(fd, 0, SEEK_SET);
|
|
||||||
read(fd, file, filesize);
|
|
||||||
hexstr2str(from, pattern);
|
|
||||||
hexstr2str(to, patch);
|
|
||||||
for (off_t i = 0; i < filesize;) {
|
|
||||||
int j;
|
|
||||||
for (j = 0; j < patternsize; ++j) {
|
|
||||||
if(file[i + j] != pattern[j]) break;
|
|
||||||
}
|
|
||||||
if (j == patternsize) {
|
|
||||||
fprintf(stderr, "Pattern %s found!\nPatching to %s\n", from, to);
|
|
||||||
lseek(fd, i, SEEK_SET);
|
|
||||||
write(fd, patch, patchsize);
|
|
||||||
}
|
|
||||||
if(j == 0) j = 1;
|
|
||||||
i += j;
|
|
||||||
}
|
|
||||||
free(file);
|
|
||||||
free(pattern);
|
|
||||||
free(patch);
|
|
||||||
close(fd);
|
|
||||||
return 0;
|
|
||||||
}
|
|
19
jni/magiskboot/Android.mk
Normal file
19
jni/magiskboot/Android.mk
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
LOCAL_PATH := $(call my-dir)
|
||||||
|
|
||||||
|
include $(CLEAR_VARS)
|
||||||
|
LOCAL_MODULE := magiskboot
|
||||||
|
LOCAL_STATIC_LIBRARIES := libz liblzma liblz4 libbz2
|
||||||
|
LOCAL_C_INCLUDES := \
|
||||||
|
jni/ndk-compression/zlib/ \
|
||||||
|
jni/ndk-compression/xz/src/liblzma/api/ \
|
||||||
|
jni/ndk-compression/lz4/lib/ \
|
||||||
|
jni/ndk-compression/bzip2/
|
||||||
|
|
||||||
|
LOCAL_SRC_FILES := main.c unpack.c repack.c hexpatch.c parseimg.c compress.c utils.c cpio.c sha1.c
|
||||||
|
LOCAL_CFLAGS += -DZLIB_CONST
|
||||||
|
include $(BUILD_EXECUTABLE)
|
||||||
|
|
||||||
|
include jni/ndk-compression/zlib/Android.mk
|
||||||
|
include jni/ndk-compression/xz/src/liblzma/Android.mk
|
||||||
|
include jni/ndk-compression/lz4/lib/Android.mk
|
||||||
|
include jni/ndk-compression/bzip2/Android.mk
|
@@ -43,7 +43,14 @@ struct boot_img_hdr
|
|||||||
|
|
||||||
uint32_t tags_addr; /* physical addr for kernel tags */
|
uint32_t tags_addr; /* physical addr for kernel tags */
|
||||||
uint32_t page_size; /* flash page size we assume */
|
uint32_t page_size; /* flash page size we assume */
|
||||||
uint32_t unused[2]; /* future expansion: should be 0 */
|
uint32_t dt_size; /* device tree in bytes */
|
||||||
|
|
||||||
|
/* operating system version and security patch level; for
|
||||||
|
* version "A.B.C" and patch level "Y-M-D":
|
||||||
|
* ver = A << 14 | B << 7 | C (7 bits for each of A, B, C)
|
||||||
|
* lvl = ((Y - 2000) & 127) << 4 | M (7 bits for Y, 4 bits for M)
|
||||||
|
* os_version = ver << 11 | lvl */
|
||||||
|
uint32_t os_version;
|
||||||
|
|
||||||
uint8_t name[BOOT_NAME_SIZE]; /* asciiz product name */
|
uint8_t name[BOOT_NAME_SIZE]; /* asciiz product name */
|
||||||
|
|
||||||
@@ -66,10 +73,13 @@ struct boot_img_hdr
|
|||||||
** +-----------------+
|
** +-----------------+
|
||||||
** | second stage | o pages
|
** | second stage | o pages
|
||||||
** +-----------------+
|
** +-----------------+
|
||||||
|
** | device tree | p pages
|
||||||
|
** +-----------------+
|
||||||
**
|
**
|
||||||
** n = (kernel_size + page_size - 1) / page_size
|
** n = (kernel_size + page_size - 1) / page_size
|
||||||
** m = (ramdisk_size + page_size - 1) / page_size
|
** m = (ramdisk_size + page_size - 1) / page_size
|
||||||
** o = (second_size + page_size - 1) / page_size
|
** o = (second_size + page_size - 1) / page_size
|
||||||
|
** p = (dt_size + page_size - 1) / page_size
|
||||||
**
|
**
|
||||||
** 0. all entities are page_size aligned in flash
|
** 0. all entities are page_size aligned in flash
|
||||||
** 1. kernel and ramdisk are required (size != 0)
|
** 1. kernel and ramdisk are required (size != 0)
|
||||||
@@ -83,8 +93,10 @@ struct boot_img_hdr
|
|||||||
** else: jump to kernel_addr
|
** else: jump to kernel_addr
|
||||||
*/
|
*/
|
||||||
|
|
||||||
int extract(char *image);
|
typedef struct mtk_hdr {
|
||||||
int repack(char *image);
|
uint8_t magic[4]; /* MTK magic */
|
||||||
int hexpatch(char *image, char *from, char *to);
|
uint32_t size; /* Size of the content */
|
||||||
|
uint8_t name[32]; /* The type of the header */
|
||||||
|
} mtk_hdr;
|
||||||
|
|
||||||
#endif
|
#endif
|
479
jni/magiskboot/compress.c
Normal file
479
jni/magiskboot/compress.c
Normal file
@@ -0,0 +1,479 @@
|
|||||||
|
#include <zlib.h>
|
||||||
|
#include <lzma.h>
|
||||||
|
#include <lz4frame.h>
|
||||||
|
#include <bzlib.h>
|
||||||
|
|
||||||
|
#include "magiskboot.h"
|
||||||
|
|
||||||
|
static void write_file(const int fd, const void *buf, const size_t size, const char *filename) {
|
||||||
|
if (write(fd, buf, size) != size)
|
||||||
|
error(1, "Error in writing %s", filename);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void report(const int mode, const char* filename) {
|
||||||
|
switch(mode) {
|
||||||
|
case 0:
|
||||||
|
printf("Decompressing to [%s]\n\n", filename);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
printf("Compressing to [%s]\n\n", filename);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mode: 0 = decode; 1 = encode
|
||||||
|
void gzip(int mode, const char* filename, const unsigned char* buf, size_t size) {
|
||||||
|
size_t ret = 0, flush, have, pos = 0;
|
||||||
|
z_stream strm;
|
||||||
|
unsigned char out[CHUNK];
|
||||||
|
|
||||||
|
report(mode, filename);
|
||||||
|
int fd = open_new(filename);
|
||||||
|
|
||||||
|
strm.zalloc = Z_NULL;
|
||||||
|
strm.zfree = Z_NULL;
|
||||||
|
strm.opaque = Z_NULL;
|
||||||
|
|
||||||
|
switch(mode) {
|
||||||
|
case 0:
|
||||||
|
ret = inflateInit2(&strm, windowBits | ZLIB_GZIP);
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
ret = deflateInit2(&strm, 9, Z_DEFLATED, windowBits | ZLIB_GZIP, memLevel, Z_DEFAULT_STRATEGY);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
error(1, "Unsupported gzip mode!");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ret != Z_OK)
|
||||||
|
error(1, "Unable to init zlib stream");
|
||||||
|
|
||||||
|
do {
|
||||||
|
strm.next_in = buf + pos;
|
||||||
|
if (pos + CHUNK >= size) {
|
||||||
|
strm.avail_in = size - pos;
|
||||||
|
flush = Z_FINISH;
|
||||||
|
} else {
|
||||||
|
strm.avail_in = CHUNK;
|
||||||
|
flush = Z_NO_FLUSH;
|
||||||
|
}
|
||||||
|
pos += strm.avail_in;
|
||||||
|
|
||||||
|
do {
|
||||||
|
strm.avail_out = CHUNK;
|
||||||
|
strm.next_out = out;
|
||||||
|
switch(mode) {
|
||||||
|
case 0:
|
||||||
|
ret = inflate(&strm, flush);
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
ret = deflate(&strm, flush);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (ret == Z_STREAM_ERROR)
|
||||||
|
error(1, "Error when running gzip");
|
||||||
|
|
||||||
|
have = CHUNK - strm.avail_out;
|
||||||
|
write_file(fd, out, have, filename);
|
||||||
|
|
||||||
|
} while (strm.avail_out == 0);
|
||||||
|
|
||||||
|
} while(pos < size);
|
||||||
|
|
||||||
|
switch(mode) {
|
||||||
|
case 0:
|
||||||
|
inflateEnd(&strm);
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
deflateEnd(&strm);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
close(fd);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Mode: 0 = decode xz/lzma; 1 = encode xz; 2 = encode lzma
|
||||||
|
void lzma(int mode, const char* filename, const unsigned char* buf, size_t size) {
|
||||||
|
size_t have, pos = 0;
|
||||||
|
lzma_ret ret = 0;
|
||||||
|
lzma_stream strm = LZMA_STREAM_INIT;
|
||||||
|
lzma_options_lzma opt;
|
||||||
|
lzma_action action;
|
||||||
|
unsigned char out[BUFSIZ];
|
||||||
|
|
||||||
|
report(mode, filename);
|
||||||
|
int fd = open_new(filename);
|
||||||
|
|
||||||
|
// Initialize preset
|
||||||
|
lzma_lzma_preset(&opt, LZMA_PRESET_DEFAULT);
|
||||||
|
lzma_filter filters[] = {
|
||||||
|
{ .id = LZMA_FILTER_LZMA2, .options = &opt },
|
||||||
|
{ .id = LZMA_VLI_UNKNOWN, .options = NULL },
|
||||||
|
};
|
||||||
|
|
||||||
|
switch(mode) {
|
||||||
|
case 0:
|
||||||
|
ret = lzma_auto_decoder(&strm, UINT64_MAX, 0);
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
ret = lzma_stream_encoder(&strm, filters, LZMA_CHECK_CRC64);
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
ret = lzma_alone_encoder(&strm, &opt);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
error(1, "Unsupported lzma mode!");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (ret != LZMA_OK)
|
||||||
|
error(1, "Unable to init lzma stream");
|
||||||
|
|
||||||
|
do {
|
||||||
|
strm.next_in = buf + pos;
|
||||||
|
if (pos + BUFSIZ >= size) {
|
||||||
|
strm.avail_in = size - pos;
|
||||||
|
action = LZMA_FINISH;
|
||||||
|
} else {
|
||||||
|
strm.avail_in = BUFSIZ;
|
||||||
|
action = LZMA_RUN;
|
||||||
|
}
|
||||||
|
pos += strm.avail_in;
|
||||||
|
|
||||||
|
do {
|
||||||
|
strm.avail_out = BUFSIZ;
|
||||||
|
strm.next_out = out;
|
||||||
|
ret = lzma_code(&strm, action);
|
||||||
|
have = BUFSIZ - strm.avail_out;
|
||||||
|
write_file(fd, out, have, filename);
|
||||||
|
} while (strm.avail_out == 0 && ret == LZMA_OK);
|
||||||
|
|
||||||
|
if (ret != LZMA_OK && ret != LZMA_STREAM_END)
|
||||||
|
error(1, "LZMA error %d!", ret);
|
||||||
|
|
||||||
|
} while (pos < size);
|
||||||
|
|
||||||
|
lzma_end(&strm);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mode: 0 = decode; 1 = encode
|
||||||
|
void lz4(int mode, const char* filename, const unsigned char* buf, size_t size) {
|
||||||
|
LZ4F_decompressionContext_t dctx;
|
||||||
|
LZ4F_compressionContext_t cctx;
|
||||||
|
LZ4F_frameInfo_t info;
|
||||||
|
|
||||||
|
size_t outCapacity, avail_in, ret = 0, pos = 0;
|
||||||
|
size_t have, read;
|
||||||
|
unsigned char *out = NULL;
|
||||||
|
|
||||||
|
report(mode, filename);
|
||||||
|
int fd = open_new(filename);
|
||||||
|
|
||||||
|
// Initialize context
|
||||||
|
switch(mode) {
|
||||||
|
case 0:
|
||||||
|
ret = LZ4F_createDecompressionContext(&dctx, LZ4F_VERSION);
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
ret = LZ4F_createCompressionContext(&cctx, LZ4F_VERSION);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
error(1, "Unsupported lz4 mode!");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (LZ4F_isError(ret))
|
||||||
|
error(1, "Context creation error: %s\n", LZ4F_getErrorName(ret));
|
||||||
|
|
||||||
|
// Allocate out buffer
|
||||||
|
switch(mode) {
|
||||||
|
case 0:
|
||||||
|
// Read header
|
||||||
|
read = CHUNK;
|
||||||
|
ret = LZ4F_getFrameInfo(dctx, &info, buf, &read);
|
||||||
|
if (LZ4F_isError(ret))
|
||||||
|
error(1, "LZ4F_getFrameInfo error: %s\n", LZ4F_getErrorName(ret));
|
||||||
|
switch (info.blockSizeID) {
|
||||||
|
case LZ4F_default:
|
||||||
|
case LZ4F_max64KB: outCapacity = 1 << 16; break;
|
||||||
|
case LZ4F_max256KB: outCapacity = 1 << 18; break;
|
||||||
|
case LZ4F_max1MB: outCapacity = 1 << 20; break;
|
||||||
|
case LZ4F_max4MB: outCapacity = 1 << 22; break;
|
||||||
|
default:
|
||||||
|
error(1, "Impossible unless more block sizes are allowed\n");
|
||||||
|
}
|
||||||
|
pos += read;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
outCapacity = LZ4F_compressBound(CHUNK, NULL) + LZ4_HEADER_SIZE + LZ4_FOOTER_SIZE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
out = malloc(outCapacity);
|
||||||
|
if (!out)
|
||||||
|
error(1, "LZ4 malloc error!");
|
||||||
|
|
||||||
|
// Write header
|
||||||
|
if (mode == 1) {
|
||||||
|
have = ret = LZ4F_compressBegin(cctx, out, size, NULL);
|
||||||
|
if (LZ4F_isError(ret))
|
||||||
|
error(1, "Failed to start compression: error %s\n", LZ4F_getErrorName(ret));
|
||||||
|
write_file(fd, out, have, filename);
|
||||||
|
}
|
||||||
|
|
||||||
|
do {
|
||||||
|
if (pos + CHUNK >= size) {
|
||||||
|
avail_in = size - pos;
|
||||||
|
} else {
|
||||||
|
avail_in = CHUNK;
|
||||||
|
}
|
||||||
|
|
||||||
|
do {
|
||||||
|
switch(mode) {
|
||||||
|
case 0:
|
||||||
|
have = outCapacity, read = avail_in;
|
||||||
|
ret = LZ4F_decompress(dctx, out, &have, buf + pos, &read, NULL);
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
read = avail_in;
|
||||||
|
have = ret = LZ4F_compressUpdate(cctx, out, outCapacity, buf + pos, avail_in, NULL);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (LZ4F_isError(ret))
|
||||||
|
error(1, "LZ4 coding error: %s\n", LZ4F_getErrorName(ret));
|
||||||
|
|
||||||
|
write_file(fd, out, have, filename);
|
||||||
|
// Update status
|
||||||
|
pos += read;
|
||||||
|
avail_in -= read;
|
||||||
|
} while(avail_in != 0 && ret != 0);
|
||||||
|
|
||||||
|
} while(pos < size && ret != 0);
|
||||||
|
|
||||||
|
switch(mode) {
|
||||||
|
case 0:
|
||||||
|
LZ4F_freeDecompressionContext(dctx);
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
have = ret = LZ4F_compressEnd(cctx, out, outCapacity, NULL);
|
||||||
|
if (LZ4F_isError(ret))
|
||||||
|
error(1, "Failed to end compression: error %s\n", LZ4F_getErrorName(ret));
|
||||||
|
|
||||||
|
write_file(fd, out, have, filename);
|
||||||
|
|
||||||
|
LZ4F_freeCompressionContext(cctx);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
free(out);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mode: 0 = decode; 1 = encode
|
||||||
|
void bzip2(int mode, const char* filename, const unsigned char* buf, size_t size) {
|
||||||
|
size_t ret = 0, action, have, pos = 0;
|
||||||
|
bz_stream strm;
|
||||||
|
char out[CHUNK];
|
||||||
|
|
||||||
|
report(mode, filename);
|
||||||
|
int fd = open_new(filename);
|
||||||
|
|
||||||
|
strm.bzalloc = NULL;
|
||||||
|
strm.bzfree = NULL;
|
||||||
|
strm.opaque = NULL;
|
||||||
|
|
||||||
|
switch(mode) {
|
||||||
|
case 0:
|
||||||
|
ret = BZ2_bzDecompressInit(&strm, 0, 0);
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
ret = BZ2_bzCompressInit(&strm, 9, 0, 0);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
error(1, "Unsupported bzip2 mode!");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ret != BZ_OK)
|
||||||
|
error(1, "Unable to init bzlib stream");
|
||||||
|
|
||||||
|
do {
|
||||||
|
strm.next_in = (char *) buf + pos;
|
||||||
|
if (pos + CHUNK >= size) {
|
||||||
|
strm.avail_in = size - pos;
|
||||||
|
action = BZ_FINISH;
|
||||||
|
} else {
|
||||||
|
strm.avail_in = CHUNK;
|
||||||
|
action = BZ_RUN;
|
||||||
|
}
|
||||||
|
pos += strm.avail_in;
|
||||||
|
|
||||||
|
do {
|
||||||
|
strm.avail_out = CHUNK;
|
||||||
|
strm.next_out = out;
|
||||||
|
switch(mode) {
|
||||||
|
case 0:
|
||||||
|
ret = BZ2_bzDecompress(&strm);
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
ret = BZ2_bzCompress(&strm, action);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
have = CHUNK - strm.avail_out;
|
||||||
|
write_file(fd, out, have, filename);
|
||||||
|
|
||||||
|
} while (strm.avail_out == 0);
|
||||||
|
|
||||||
|
} while(pos < size);
|
||||||
|
|
||||||
|
switch(mode) {
|
||||||
|
case 0:
|
||||||
|
BZ2_bzDecompressEnd(&strm);
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
BZ2_bzCompressEnd(&strm);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
close(fd);
|
||||||
|
}
|
||||||
|
|
||||||
|
int decomp(file_t type, const char *to, const unsigned char *from, size_t size) {
|
||||||
|
switch (type) {
|
||||||
|
case GZIP:
|
||||||
|
gzip(0, to, from, size);
|
||||||
|
break;
|
||||||
|
case XZ:
|
||||||
|
lzma(0, to, from, size);
|
||||||
|
break;
|
||||||
|
case LZMA:
|
||||||
|
lzma(0, to, from, size);
|
||||||
|
break;
|
||||||
|
case BZIP2:
|
||||||
|
bzip2(0, to, from, size);
|
||||||
|
break;
|
||||||
|
case LZ4:
|
||||||
|
lz4(0, to, from, size);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
// Unsupported
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Output will be to.ext
|
||||||
|
int comp(file_t type, const char *to, const unsigned char *from, size_t size) {
|
||||||
|
char name[PATH_MAX];
|
||||||
|
const char *ext = strrchr(to, '.');
|
||||||
|
if (ext == NULL) ext = to;
|
||||||
|
strcpy(name, to);
|
||||||
|
switch (type) {
|
||||||
|
case GZIP:
|
||||||
|
if (strcmp(ext, ".gz") != 0)
|
||||||
|
sprintf(name, "%s.%s", to, "gz");
|
||||||
|
gzip(1, name, from, size);
|
||||||
|
break;
|
||||||
|
case XZ:
|
||||||
|
if (strcmp(ext, ".xz") != 0)
|
||||||
|
sprintf(name, "%s.%s", to, "xz");
|
||||||
|
lzma(1, name, from, size);
|
||||||
|
break;
|
||||||
|
case LZMA:
|
||||||
|
if (strcmp(ext, ".lzma") != 0)
|
||||||
|
sprintf(name, "%s.%s", to, "lzma");
|
||||||
|
lzma(2, name, from, size);
|
||||||
|
break;
|
||||||
|
case BZIP2:
|
||||||
|
if (strcmp(ext, ".bz2") != 0)
|
||||||
|
sprintf(name, "%s.%s", to, "bz2");
|
||||||
|
bzip2(1, name, from, size);
|
||||||
|
break;
|
||||||
|
case LZ4:
|
||||||
|
if (strcmp(ext, ".lz4") != 0)
|
||||||
|
sprintf(name, "%s.%s", to, "lz4");
|
||||||
|
lz4(1, name, from, size);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
// Unsupported
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void decomp_file(char *from, const char *to) {
|
||||||
|
int ok = 1;
|
||||||
|
unsigned char *file;
|
||||||
|
size_t size;
|
||||||
|
mmap_ro(from, &file, &size);
|
||||||
|
file_t type = check_type(file);
|
||||||
|
char *ext;
|
||||||
|
ext = strrchr(from, '.');
|
||||||
|
if (ext == NULL)
|
||||||
|
error(1, "Bad filename extention");
|
||||||
|
|
||||||
|
// File type and extension should match
|
||||||
|
switch (type) {
|
||||||
|
case GZIP:
|
||||||
|
if (strcmp(ext, ".gz") != 0)
|
||||||
|
ok = 0;
|
||||||
|
break;
|
||||||
|
case XZ:
|
||||||
|
if (strcmp(ext, ".xz") != 0)
|
||||||
|
ok = 0;
|
||||||
|
break;
|
||||||
|
case LZMA:
|
||||||
|
if (strcmp(ext, ".lzma") != 0)
|
||||||
|
ok = 0;
|
||||||
|
break;
|
||||||
|
case BZIP2:
|
||||||
|
if (strcmp(ext, ".bz2") != 0)
|
||||||
|
ok = 0;
|
||||||
|
break;
|
||||||
|
case LZ4:
|
||||||
|
if (strcmp(ext, ".lz4") != 0)
|
||||||
|
ok = 0;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
error(1, "Provided file \'%s\' is not a supported archive format", from);
|
||||||
|
}
|
||||||
|
if (ok) {
|
||||||
|
// If all match, strip out the suffix
|
||||||
|
if (!to) {
|
||||||
|
*ext = '\0';
|
||||||
|
to = from;
|
||||||
|
}
|
||||||
|
decomp(type, to, file, size);
|
||||||
|
if (to == from) {
|
||||||
|
*ext = '.';
|
||||||
|
unlink(from);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
error(1, "Bad filename extention \'%s\'", ext);
|
||||||
|
}
|
||||||
|
munmap(file, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
void comp_file(const char *method, const char *from, const char *to) {
|
||||||
|
file_t type;
|
||||||
|
if (strcmp(method, "gzip") == 0) {
|
||||||
|
type = GZIP;
|
||||||
|
} else if (strcmp(method, "xz") == 0) {
|
||||||
|
type = XZ;
|
||||||
|
} else if (strcmp(method, "lzma") == 0) {
|
||||||
|
type = LZMA;
|
||||||
|
} else if (strcmp(method, "lz4") == 0) {
|
||||||
|
type = LZ4;
|
||||||
|
} else if (strcmp(method, "bzip2") == 0) {
|
||||||
|
type = BZIP2;
|
||||||
|
} else {
|
||||||
|
error(1, "Only support following methods: " SUP_LIST);
|
||||||
|
}
|
||||||
|
unsigned char *file;
|
||||||
|
size_t size;
|
||||||
|
mmap_ro(from, &file, &size);
|
||||||
|
if (!to)
|
||||||
|
to = from;
|
||||||
|
comp(type, to, file, size);
|
||||||
|
munmap(file, size);
|
||||||
|
if (to == from)
|
||||||
|
unlink(from);
|
||||||
|
}
|
||||||
|
|
480
jni/magiskboot/cpio.c
Normal file
480
jni/magiskboot/cpio.c
Normal file
@@ -0,0 +1,480 @@
|
|||||||
|
#include "magiskboot.h"
|
||||||
|
#include "cpio.h"
|
||||||
|
|
||||||
|
static uint32_t x8u(char *hex) {
|
||||||
|
uint32_t val, inpos = 8, outpos;
|
||||||
|
char pattern[6];
|
||||||
|
|
||||||
|
while (*hex == '0') {
|
||||||
|
hex++;
|
||||||
|
if (!--inpos) return 0;
|
||||||
|
}
|
||||||
|
// Because scanf gratuitously treats %*X differently than printf does.
|
||||||
|
sprintf(pattern, "%%%dx%%n", inpos);
|
||||||
|
sscanf(hex, pattern, &val, &outpos);
|
||||||
|
if (inpos != outpos) error(1, "bad cpio header");
|
||||||
|
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void cpio_free(cpio_file *f) {
|
||||||
|
if (f) {
|
||||||
|
free(f->filename);
|
||||||
|
free(f->data);
|
||||||
|
free(f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void cpio_vec_insert(vector *v, cpio_file *n) {
|
||||||
|
cpio_file *f, *t;
|
||||||
|
int shift = 0;
|
||||||
|
// Insert in alphabet order
|
||||||
|
vec_for_each(v, f) {
|
||||||
|
if (shift) {
|
||||||
|
vec_entry(v)[_i] = t;
|
||||||
|
t = f;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
t = f;
|
||||||
|
if (strcmp(f->filename, n->filename) == 0) {
|
||||||
|
// Replace, then all is done
|
||||||
|
cpio_free(f);
|
||||||
|
vec_entry(v)[_i] = n;
|
||||||
|
return;
|
||||||
|
} else if (strcmp(f->filename, n->filename) > 0) {
|
||||||
|
// Insert, then start shifting
|
||||||
|
vec_entry(v)[_i] = n;
|
||||||
|
t = f;
|
||||||
|
shift = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (shift)
|
||||||
|
vec_push_back(v, t);
|
||||||
|
else
|
||||||
|
vec_push_back(v, n);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int cpio_compare(const void *a, const void *b) {
|
||||||
|
return strcmp((*(cpio_file **) a)->filename, (*(cpio_file **) b)->filename);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse cpio file to a vector of cpio_file
|
||||||
|
static void parse_cpio(const char *filename, vector *v) {
|
||||||
|
printf("Loading cpio: [%s]\n\n", filename);
|
||||||
|
int fd = open(filename, O_RDONLY);
|
||||||
|
if (fd < 0)
|
||||||
|
error(1, "Cannot open %s", filename);
|
||||||
|
cpio_newc_header header;
|
||||||
|
cpio_file *f;
|
||||||
|
while(read(fd, &header, 110) == 110) {
|
||||||
|
f = calloc(sizeof(*f), 1);
|
||||||
|
// f->ino = x8u(header.ino);
|
||||||
|
f->mode = x8u(header.mode);
|
||||||
|
f->uid = x8u(header.uid);
|
||||||
|
f->gid = x8u(header.gid);
|
||||||
|
// f->nlink = x8u(header.nlink);
|
||||||
|
// f->mtime = x8u(header.mtime);
|
||||||
|
f->filesize = x8u(header.filesize);
|
||||||
|
// f->devmajor = x8u(header.devmajor);
|
||||||
|
// f->devminor = x8u(header.devminor);
|
||||||
|
// f->rdevmajor = x8u(header.rdevmajor);
|
||||||
|
// f->rdevminor = x8u(header.rdevminor);
|
||||||
|
f->namesize = x8u(header.namesize);
|
||||||
|
// f->check = x8u(header.check);
|
||||||
|
f->filename = malloc(f->namesize);
|
||||||
|
read(fd, f->filename, f->namesize);
|
||||||
|
file_align(fd, 4, 0);
|
||||||
|
if (strcmp(f->filename, ".") == 0 || strcmp(f->filename, "..") == 0) {
|
||||||
|
cpio_free(f);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (strcmp(f->filename, "TRAILER!!!") == 0) {
|
||||||
|
cpio_free(f);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (f->filesize) {
|
||||||
|
f->data = malloc(f->filesize);
|
||||||
|
read(fd, f->data, f->filesize);
|
||||||
|
file_align(fd, 4, 0);
|
||||||
|
}
|
||||||
|
vec_push_back(v, f);
|
||||||
|
}
|
||||||
|
close(fd);
|
||||||
|
// Sort by name
|
||||||
|
vec_sort(v, cpio_compare);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void dump_cpio(const char *filename, vector *v) {
|
||||||
|
printf("\nDump cpio: [%s]\n\n", filename);
|
||||||
|
int fd = open_new(filename);
|
||||||
|
unsigned inode = 300000;
|
||||||
|
char header[111];
|
||||||
|
cpio_file *f;
|
||||||
|
vec_for_each(v, f) {
|
||||||
|
if (f->remove) continue;
|
||||||
|
sprintf(header, "070701%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x",
|
||||||
|
inode++, // f->ino
|
||||||
|
f->mode,
|
||||||
|
f->uid,
|
||||||
|
f->gid,
|
||||||
|
1, // f->nlink
|
||||||
|
0, // f->mtime
|
||||||
|
f->filesize,
|
||||||
|
0, // f->devmajor
|
||||||
|
0, // f->devminor
|
||||||
|
0, // f->rdevmajor
|
||||||
|
0, // f->rdevminor
|
||||||
|
f->namesize,
|
||||||
|
0 // f->check
|
||||||
|
);
|
||||||
|
write(fd, header, 110);
|
||||||
|
write(fd, f->filename, f->namesize);
|
||||||
|
file_align(fd, 4, 1);
|
||||||
|
if (f->filesize) {
|
||||||
|
write(fd, f->data, f->filesize);
|
||||||
|
file_align(fd, 4, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Write trailer
|
||||||
|
sprintf(header, "070701%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x", inode++, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 11, 0);
|
||||||
|
write(fd, header, 110);
|
||||||
|
write(fd, "TRAILER!!!\0", 11);
|
||||||
|
file_align(fd, 4, 1);
|
||||||
|
close(fd);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void cpio_vec_destroy(vector *v) {
|
||||||
|
// Free each cpio_file
|
||||||
|
cpio_file *f;
|
||||||
|
vec_for_each(v, f) {
|
||||||
|
cpio_free(f);
|
||||||
|
}
|
||||||
|
vec_destroy(v);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void cpio_rm(int recursive, const char *entry, vector *v) {
|
||||||
|
cpio_file *f;
|
||||||
|
vec_for_each(v, f) {
|
||||||
|
if ((recursive && strncmp(f->filename, entry, strlen(entry)) == 0)
|
||||||
|
|| (strcmp(f->filename, entry) == 0) ) {
|
||||||
|
if (!f->remove) {
|
||||||
|
printf("Remove [%s]\n", entry);
|
||||||
|
f->remove = 1;
|
||||||
|
}
|
||||||
|
if (!recursive) return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void cpio_mkdir(mode_t mode, const char *entry, vector *v) {
|
||||||
|
cpio_file *f = calloc(sizeof(*f), 1);
|
||||||
|
f->mode = S_IFDIR | mode;
|
||||||
|
f->namesize = strlen(entry) + 1;
|
||||||
|
f->filename = malloc(f->namesize);
|
||||||
|
memcpy(f->filename, entry, f->namesize);
|
||||||
|
cpio_vec_insert(v, f);
|
||||||
|
printf("Create directory [%s] (%04o)\n",entry, mode);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void cpio_add(mode_t mode, const char *entry, const char *filename, vector *v) {
|
||||||
|
int fd = open(filename, O_RDONLY);
|
||||||
|
if (fd < 0)
|
||||||
|
error(1, "Cannot open %s", filename);
|
||||||
|
cpio_file *f = calloc(sizeof(*f), 1);
|
||||||
|
f->mode = S_IFREG | mode;
|
||||||
|
f->namesize = strlen(entry) + 1;
|
||||||
|
f->filename = malloc(f->namesize);
|
||||||
|
memcpy(f->filename, entry, f->namesize);
|
||||||
|
f->filesize = lseek(fd, 0, SEEK_END);
|
||||||
|
lseek(fd, 0, SEEK_SET);
|
||||||
|
f->data = malloc(f->filesize);
|
||||||
|
read(fd, f->data, f->filesize);
|
||||||
|
close(fd);
|
||||||
|
cpio_vec_insert(v, f);
|
||||||
|
printf("Add entry [%s] (%04o)\n", entry, mode);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void cpio_test(vector *v) {
|
||||||
|
int ret = 0;
|
||||||
|
cpio_file *f;
|
||||||
|
vec_for_each(v, f) {
|
||||||
|
if (strcmp(f->filename, "sbin/launch_daemonsu.sh") == 0) {
|
||||||
|
if (!ret) ret = 2;
|
||||||
|
} else if (strcmp(f->filename, "init.magisk.rc") == 0) {
|
||||||
|
ret = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cpio_vec_destroy(v);
|
||||||
|
exit(ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int check_verity_pattern(const char *s) {
|
||||||
|
int pos = 0;
|
||||||
|
if (s[0] == ',') ++pos;
|
||||||
|
if (strncmp(s + pos, "verify", 6) != 0) return -1;
|
||||||
|
pos += 6;
|
||||||
|
if (s[pos] == '=') {
|
||||||
|
while (s[pos] != ' ' && s[pos] != '\n' && s[pos] != ',') ++pos;
|
||||||
|
}
|
||||||
|
return pos;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void cpio_dmverity(vector *v) {
|
||||||
|
cpio_file *f;
|
||||||
|
size_t read, write;
|
||||||
|
int skip;
|
||||||
|
vec_for_each(v, f) {
|
||||||
|
if (strstr(f->filename, "fstab") != NULL && S_ISREG(f->mode)) {
|
||||||
|
for (read = 0, write = 0; read < f->filesize; ++read, ++write) {
|
||||||
|
skip = check_verity_pattern(f->data + read);
|
||||||
|
if (skip > 0) {
|
||||||
|
printf("Remove pattern [%.*s] in [%s]\n", (int) skip, f->data + read, f->filename);
|
||||||
|
read += skip;
|
||||||
|
}
|
||||||
|
f->data[write] = f->data[read];
|
||||||
|
}
|
||||||
|
f->filesize = write;
|
||||||
|
} else if (strcmp(f->filename, "verity_key") == 0) {
|
||||||
|
f->remove = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void cpio_forceencrypt(vector *v) {
|
||||||
|
cpio_file *f;
|
||||||
|
size_t read, write;
|
||||||
|
#define ENCRYPT_LIST_SIZE 2
|
||||||
|
const char *ENCRYPT_LIST[ENCRYPT_LIST_SIZE] = { "forceencrypt", "forcefdeorfbe" };
|
||||||
|
vec_for_each(v, f) {
|
||||||
|
if (strstr(f->filename, "fstab") != NULL && S_ISREG(f->mode)) {
|
||||||
|
for (read = 0, write = 0; read < f->filesize; ++read, ++write) {
|
||||||
|
for (int i = 0 ; i < ENCRYPT_LIST_SIZE; ++i) {
|
||||||
|
if (strncmp(f->data + read, ENCRYPT_LIST[i], strlen(ENCRYPT_LIST[i])) == 0) {
|
||||||
|
memcpy(f->data + write, "encryptable", 11);
|
||||||
|
printf("Replace [%s] with [%s] in [%s]\n", ENCRYPT_LIST[i], "encryptable", f->filename);
|
||||||
|
write += 11;
|
||||||
|
read += strlen(ENCRYPT_LIST[i]);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
f->data[write] = f->data[read];
|
||||||
|
}
|
||||||
|
f->filesize = write;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void cpio_extract(const char *entry, const char *filename, vector *v) {
|
||||||
|
cpio_file *f;
|
||||||
|
vec_for_each(v, f) {
|
||||||
|
if (strcmp(f->filename, entry) == 0 && S_ISREG(f->mode)) {
|
||||||
|
printf("Extracting [%s] to [%s]\n\n", entry, filename);
|
||||||
|
int fd = open_new(filename);
|
||||||
|
write(fd, f->data, f->filesize);
|
||||||
|
fchmod(fd, f->mode);
|
||||||
|
fchown(fd, f->uid, f->gid);
|
||||||
|
close(fd);
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
error(1, "Cannot find the file entry [%s]", entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void cpio_backup(const char *orig, vector *v) {
|
||||||
|
vector o_body, *o = &o_body, bak;
|
||||||
|
cpio_file *m, *n, *dir, *rem;
|
||||||
|
char chk1[21], chk2[21], buf[PATH_MAX];
|
||||||
|
int res, doBak;
|
||||||
|
|
||||||
|
dir = calloc(sizeof(*dir), 1);
|
||||||
|
rem = calloc(sizeof(*rem), 1);
|
||||||
|
vec_init(o);
|
||||||
|
vec_init(&bak);
|
||||||
|
// First push back the directory and the rmlist
|
||||||
|
vec_push_back(&bak, dir);
|
||||||
|
vec_push_back(&bak, rem);
|
||||||
|
parse_cpio(orig, o);
|
||||||
|
// Remove possible backups in original ramdisk
|
||||||
|
cpio_rm(1, ".backup", o);
|
||||||
|
cpio_rm(1, ".backup", v);
|
||||||
|
|
||||||
|
// Init the directory and rmlist
|
||||||
|
dir->filename = strdup(".backup");
|
||||||
|
dir->namesize = strlen(dir->filename) + 1;
|
||||||
|
dir->mode = S_IFDIR;
|
||||||
|
rem->filename = strdup(".backup/.rmlist");
|
||||||
|
rem->namesize = strlen(rem->filename) + 1;
|
||||||
|
rem->mode = S_IFREG;
|
||||||
|
|
||||||
|
// Start comparing
|
||||||
|
size_t i = 0, j = 0;
|
||||||
|
while(i != vec_size(o) || j != vec_size(v)) {
|
||||||
|
doBak = 0;
|
||||||
|
if (i != vec_size(o) && j != vec_size(v)) {
|
||||||
|
m = vec_entry(o)[i];
|
||||||
|
n = vec_entry(v)[j];
|
||||||
|
res = strcmp(m->filename, n->filename);
|
||||||
|
} else if (i == vec_size(o)) {
|
||||||
|
n = vec_entry(v)[j];
|
||||||
|
res = 1;
|
||||||
|
} else if (j == vec_size(v)) {
|
||||||
|
m = vec_entry(o)[i];
|
||||||
|
res = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (res < 0) {
|
||||||
|
// Something is missing in new ramdisk, backup!
|
||||||
|
++i;
|
||||||
|
doBak = 1;
|
||||||
|
printf("Entry [%s] is missing\n", m->filename);
|
||||||
|
} else if (res == 0) {
|
||||||
|
++i; ++j;
|
||||||
|
if (m->filesize == n->filesize && memcmp(m->data, n->data, m->filesize) == 0)
|
||||||
|
continue;
|
||||||
|
// Not the same!
|
||||||
|
doBak = 1;
|
||||||
|
printf("Entry [%s] missmatch\n", m->filename);
|
||||||
|
} else {
|
||||||
|
// Someting new in ramdisk, record in rem
|
||||||
|
++j;
|
||||||
|
if (n->remove) continue;
|
||||||
|
rem->data = realloc(rem->data, rem->filesize + n->namesize);
|
||||||
|
memcpy(rem->data + rem->filesize, n->filename, n->namesize);
|
||||||
|
rem->filesize += n->namesize;
|
||||||
|
printf("Entry [%s] is new\n", n->filename);
|
||||||
|
}
|
||||||
|
if (doBak) {
|
||||||
|
m->namesize += 8;
|
||||||
|
m->filename = realloc(m->filename, m->namesize);
|
||||||
|
strcpy(buf, m->filename);
|
||||||
|
sprintf(m->filename, ".backup/%s", buf);
|
||||||
|
vec_push_back(&bak, m);
|
||||||
|
// NULL the original entry, so it won't be freed
|
||||||
|
vec_entry(o)[i - 1] = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add the backup files to the original ramdisk
|
||||||
|
vec_for_each(&bak, m) {
|
||||||
|
vec_push_back(v, m);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Don't include if empty
|
||||||
|
if (rem->filesize == 0) {
|
||||||
|
rem->remove = 1;
|
||||||
|
if (bak.size == 2)
|
||||||
|
dir->remove = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sort
|
||||||
|
vec_sort(v, cpio_compare);
|
||||||
|
|
||||||
|
// Cleanup
|
||||||
|
cpio_vec_destroy(o);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int cpio_restore(vector *v) {
|
||||||
|
cpio_file *f, *n;
|
||||||
|
int ret = 1;
|
||||||
|
vec_for_each(v, f) {
|
||||||
|
if (strstr(f->filename, ".backup") != NULL) {
|
||||||
|
ret = 0;
|
||||||
|
f->remove = 1;
|
||||||
|
if (strcmp(f->filename, ".backup") == 0) continue;
|
||||||
|
if (strcmp(f->filename, ".backup/.rmlist") == 0) {
|
||||||
|
for (int pos = 0; pos < f->filesize; pos += strlen(f->data + pos) + 1)
|
||||||
|
cpio_rm(0, f->data + pos, v);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
n = calloc(sizeof(*n), 1);
|
||||||
|
memcpy(n, f, sizeof(*f));
|
||||||
|
n->namesize -= 8;
|
||||||
|
n->filename = malloc(n->namesize);
|
||||||
|
memcpy(n->filename, f->filename + 8, n->namesize);
|
||||||
|
n->data = malloc(n->filesize);
|
||||||
|
memcpy(n->data, f->data, n->filesize);
|
||||||
|
n->remove = 0;
|
||||||
|
printf("Restoring [%s] -> [%s]\n", f->filename, n->filename);
|
||||||
|
cpio_vec_insert(v, n);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Some known stuff we can remove
|
||||||
|
cpio_rm(0, "sbin/magic_mask.sh", v);
|
||||||
|
cpio_rm(0, "init.magisk.rc", v);
|
||||||
|
cpio_rm(0, "magisk", v);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int cpio_commands(const char *command, int argc, char *argv[]) {
|
||||||
|
int recursive = 0, ret = 0;
|
||||||
|
command_t cmd;
|
||||||
|
char *incpio = argv[0];
|
||||||
|
++argv;
|
||||||
|
--argc;
|
||||||
|
if (strcmp(command, "test") == 0) {
|
||||||
|
cmd = TEST;
|
||||||
|
} else if (strcmp(command, "patch-dmverity") == 0) {
|
||||||
|
cmd = DMVERITY;
|
||||||
|
} else if (strcmp(command, "patch-forceencrypt") == 0) {
|
||||||
|
cmd = FORCEENCRYPT;
|
||||||
|
} else if (strcmp(command, "restore") == 0) {
|
||||||
|
cmd = RESTORE;
|
||||||
|
} else if (argc == 1 && strcmp(command, "backup") == 0) {
|
||||||
|
cmd = BACKUP;
|
||||||
|
} else if (argc > 0 && strcmp(command, "rm") == 0) {
|
||||||
|
cmd = RM;
|
||||||
|
if (argc == 2 && strcmp(argv[0], "-r") == 0) {
|
||||||
|
recursive = 1;
|
||||||
|
++argv;
|
||||||
|
--argc;
|
||||||
|
}
|
||||||
|
} else if (argc == 2 && strcmp(command, "extract") == 0) {
|
||||||
|
cmd = EXTRACT;
|
||||||
|
} else if (argc == 2 && strcmp(command, "mkdir") == 0) {
|
||||||
|
cmd = MKDIR;
|
||||||
|
} else if (argc == 3 && strcmp(command, "add") == 0) {
|
||||||
|
cmd = ADD;
|
||||||
|
} else {
|
||||||
|
cmd = NONE;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
vector v;
|
||||||
|
vec_init(&v);
|
||||||
|
parse_cpio(incpio, &v);
|
||||||
|
switch(cmd) {
|
||||||
|
case TEST:
|
||||||
|
cpio_test(&v);
|
||||||
|
break;
|
||||||
|
case DMVERITY:
|
||||||
|
cpio_dmverity(&v);
|
||||||
|
break;
|
||||||
|
case FORCEENCRYPT:
|
||||||
|
cpio_forceencrypt(&v);
|
||||||
|
break;
|
||||||
|
case RESTORE:
|
||||||
|
ret = cpio_restore(&v);
|
||||||
|
break;
|
||||||
|
case BACKUP:
|
||||||
|
cpio_backup(argv[0], &v);
|
||||||
|
case RM:
|
||||||
|
cpio_rm(recursive, argv[0], &v);
|
||||||
|
break;
|
||||||
|
case EXTRACT:
|
||||||
|
cpio_extract(argv[0], argv[1], &v);
|
||||||
|
break;
|
||||||
|
case MKDIR:
|
||||||
|
cpio_mkdir(strtoul(argv[0], NULL, 8), argv[1], &v);
|
||||||
|
break;
|
||||||
|
case ADD:
|
||||||
|
cpio_add(strtoul(argv[0], NULL, 8), argv[1], argv[2], &v);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
// Never happen
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
dump_cpio(incpio, &v);
|
||||||
|
cpio_vec_destroy(&v);
|
||||||
|
exit(ret);
|
||||||
|
}
|
42
jni/magiskboot/cpio.h
Normal file
42
jni/magiskboot/cpio.h
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
#ifndef _CPIO_H_
|
||||||
|
#define _CPIO_H_
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
typedef struct cpio_file {
|
||||||
|
// uint32_t ino;
|
||||||
|
uint32_t mode;
|
||||||
|
uint32_t uid;
|
||||||
|
uint32_t gid;
|
||||||
|
// uint32_t nlink;
|
||||||
|
// uint32_t mtime;
|
||||||
|
uint32_t filesize;
|
||||||
|
// uint32_t devmajor;
|
||||||
|
// uint32_t devminor;
|
||||||
|
// uint32_t rdevmajor;
|
||||||
|
// uint32_t rdevminor;
|
||||||
|
uint32_t namesize;
|
||||||
|
// uint32_t check;
|
||||||
|
char *filename;
|
||||||
|
char *data;
|
||||||
|
int remove;
|
||||||
|
} cpio_file;
|
||||||
|
|
||||||
|
typedef struct cpio_newc_header {
|
||||||
|
char magic[6];
|
||||||
|
char ino[8];
|
||||||
|
char mode[8];
|
||||||
|
char uid[8];
|
||||||
|
char gid[8];
|
||||||
|
char nlink[8];
|
||||||
|
char mtime[8];
|
||||||
|
char filesize[8];
|
||||||
|
char devmajor[8];
|
||||||
|
char devminor[8];
|
||||||
|
char rdevmajor[8];
|
||||||
|
char rdevminor[8];
|
||||||
|
char namesize[8];
|
||||||
|
char check[8];
|
||||||
|
} cpio_newc_header;
|
||||||
|
|
||||||
|
#endif
|
151
jni/magiskboot/elf.h
Normal file
151
jni/magiskboot/elf.h
Normal file
@@ -0,0 +1,151 @@
|
|||||||
|
|
||||||
|
#ifndef _ELF_H_
|
||||||
|
#define _ELF_H_
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
** ELF structure
|
||||||
|
**
|
||||||
|
** +-----------------+
|
||||||
|
** | ELF magic | | 4 bytes
|
||||||
|
** +------------ +
|
||||||
|
** | ELF class | | 1 byte
|
||||||
|
** +------------ +
|
||||||
|
** | ELF header |
|
||||||
|
** +-----------------+
|
||||||
|
** ~
|
||||||
|
** +-----------------+
|
||||||
|
** | program header | kernel info
|
||||||
|
** +-----------------+
|
||||||
|
** | program header | ramdisk info
|
||||||
|
** +-----------------+
|
||||||
|
** | program header | dtb info
|
||||||
|
** +-----------------+
|
||||||
|
** | program header | (possible) cmdline info
|
||||||
|
** +-----------------+
|
||||||
|
** ~
|
||||||
|
** +-----------------+
|
||||||
|
** | section header | cmdline info
|
||||||
|
** +-----------------+
|
||||||
|
** ~
|
||||||
|
** +-----------------+
|
||||||
|
** | |
|
||||||
|
** | Data |
|
||||||
|
** | |
|
||||||
|
** +-----------------+
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
typedef uint32_t elf32_addr;
|
||||||
|
typedef uint16_t elf32_half;
|
||||||
|
typedef uint32_t elf32_off;
|
||||||
|
typedef uint32_t elf32_word;
|
||||||
|
|
||||||
|
typedef uint64_t elf64_addr;
|
||||||
|
typedef uint16_t elf64_half;
|
||||||
|
typedef uint64_t elf64_off;
|
||||||
|
typedef uint32_t elf64_word;
|
||||||
|
typedef uint64_t elf64_xword;
|
||||||
|
|
||||||
|
#define ELF_MAGIC "\x7f""ELF"
|
||||||
|
#define ELF_MAGIC_SIZE 4
|
||||||
|
|
||||||
|
#define EI_CLASS 4
|
||||||
|
#define EI_DATA 5
|
||||||
|
#define EI_VERSION 6
|
||||||
|
#define EI_OSABI 7
|
||||||
|
#define EI_PAD 8
|
||||||
|
|
||||||
|
#define ELFCLASSNONE 0
|
||||||
|
#define ELFCLASS32 1
|
||||||
|
#define ELFCLASS64 2
|
||||||
|
#define ELFCLASSNUM 3
|
||||||
|
|
||||||
|
#define ET_EXEC 2
|
||||||
|
#define EM_ARM 40
|
||||||
|
#define EI_NIDENT 16
|
||||||
|
|
||||||
|
typedef struct elf32_ehdr {
|
||||||
|
unsigned char e_ident[EI_NIDENT];
|
||||||
|
elf32_half e_type;
|
||||||
|
elf32_half e_machine;
|
||||||
|
elf32_word e_version;
|
||||||
|
elf32_addr e_entry; /* Entry point */
|
||||||
|
elf32_off e_phoff;
|
||||||
|
elf32_off e_shoff;
|
||||||
|
elf32_word e_flags;
|
||||||
|
elf32_half e_ehsize;
|
||||||
|
elf32_half e_phentsize;
|
||||||
|
elf32_half e_phnum;
|
||||||
|
elf32_half e_shentsize;
|
||||||
|
elf32_half e_shnum;
|
||||||
|
elf32_half e_shstrndx;
|
||||||
|
} elf32_ehdr;
|
||||||
|
|
||||||
|
typedef struct elf64_ehdr {
|
||||||
|
unsigned char e_ident[EI_NIDENT]; /* ELF "magic number" */
|
||||||
|
elf64_half e_type;
|
||||||
|
elf64_half e_machine;
|
||||||
|
elf64_word e_version;
|
||||||
|
elf64_addr e_entry; /* Entry point virtual address */
|
||||||
|
elf64_off e_phoff; /* Program header table file offset */
|
||||||
|
elf64_off e_shoff; /* Section header table file offset */
|
||||||
|
elf64_word e_flags;
|
||||||
|
elf64_half e_ehsize;
|
||||||
|
elf64_half e_phentsize;
|
||||||
|
elf64_half e_phnum;
|
||||||
|
elf64_half e_shentsize;
|
||||||
|
elf64_half e_shnum;
|
||||||
|
elf64_half e_shstrndx;
|
||||||
|
} elf64_ehdr;
|
||||||
|
|
||||||
|
typedef struct elf32_phdr {
|
||||||
|
elf32_word p_type;
|
||||||
|
elf32_off p_offset;
|
||||||
|
elf32_addr p_vaddr;
|
||||||
|
elf32_addr p_paddr;
|
||||||
|
elf32_word p_filesz;
|
||||||
|
elf32_word p_memsz;
|
||||||
|
elf32_word p_flags;
|
||||||
|
elf32_word p_align;
|
||||||
|
} elf32_phdr;
|
||||||
|
|
||||||
|
typedef struct elf64_phdr {
|
||||||
|
elf64_word p_type;
|
||||||
|
elf64_word p_flags;
|
||||||
|
elf64_off p_offset; /* Segment file offset */
|
||||||
|
elf64_addr p_vaddr; /* Segment virtual address */
|
||||||
|
elf64_addr p_paddr; /* Segment physical address */
|
||||||
|
elf64_xword p_filesz; /* Segment size in file */
|
||||||
|
elf64_xword p_memsz; /* Segment size in memory */
|
||||||
|
elf64_xword p_align; /* Segment alignment, file & memory */
|
||||||
|
} elf64_phdr;
|
||||||
|
|
||||||
|
typedef struct elf32_shdr {
|
||||||
|
elf32_word s_name;
|
||||||
|
elf32_word s_type;
|
||||||
|
elf32_word s_flags;
|
||||||
|
elf32_addr s_addr;
|
||||||
|
elf32_off s_offset;
|
||||||
|
elf32_word s_size;
|
||||||
|
elf32_word s_link;
|
||||||
|
elf32_word s_info;
|
||||||
|
elf32_word s_addralign;
|
||||||
|
elf32_word s_entsize;
|
||||||
|
} elf32_shdr;
|
||||||
|
|
||||||
|
typedef struct elf64_shdr {
|
||||||
|
elf64_word s_name; /* Section name, index in string tbl */
|
||||||
|
elf64_word s_type; /* Type of section */
|
||||||
|
elf64_xword s_flags; /* Miscellaneous section attributes */
|
||||||
|
elf64_addr s_addr; /* Section virtual addr at execution */
|
||||||
|
elf64_off s_offset; /* Section file offset */
|
||||||
|
elf64_xword s_size; /* Size of section in bytes */
|
||||||
|
elf64_word s_link; /* Index of another section */
|
||||||
|
elf64_word s_info; /* Additional section information */
|
||||||
|
elf64_xword s_addralign; /* Section alignment */
|
||||||
|
elf64_xword s_entsize; /* Entry size if section holds table */
|
||||||
|
} elf64_shdr;
|
||||||
|
|
||||||
|
#endif
|
32
jni/magiskboot/hexpatch.c
Normal file
32
jni/magiskboot/hexpatch.c
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
#include "magiskboot.h"
|
||||||
|
|
||||||
|
static void hex2byte(const char *hex, unsigned char *str) {
|
||||||
|
char high, low;
|
||||||
|
for (int i = 0, length = strlen(hex); i < length; i += 2) {
|
||||||
|
high = toupper(hex[i]) - '0';
|
||||||
|
low = toupper(hex[i + 1]) - '0';
|
||||||
|
str[i / 2] = ((high > 9 ? high - 7 : high) << 4) + (low > 9 ? low - 7 : low);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void hexpatch(const char *image, const char *from, const char *to) {
|
||||||
|
int patternsize = strlen(from) / 2, patchsize = strlen(to) / 2;
|
||||||
|
size_t filesize;
|
||||||
|
unsigned char *file, *pattern, *patch;
|
||||||
|
mmap_rw(image, &file, &filesize);
|
||||||
|
pattern = malloc(patternsize);
|
||||||
|
patch = malloc(patchsize);
|
||||||
|
hex2byte(from, pattern);
|
||||||
|
hex2byte(to, patch);
|
||||||
|
for (size_t i = 0; i < filesize - patternsize; ++i) {
|
||||||
|
if (memcmp(file + i, pattern, patternsize) == 0) {
|
||||||
|
printf("Pattern %s found!\nPatching to %s\n", from, to);
|
||||||
|
memset(file + i, 0, patternsize);
|
||||||
|
memcpy(file + i, patch, patchsize);
|
||||||
|
i += patternsize - 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
munmap(file, filesize);
|
||||||
|
free(pattern);
|
||||||
|
free(patch);
|
||||||
|
}
|
127
jni/magiskboot/magiskboot.h
Normal file
127
jni/magiskboot/magiskboot.h
Normal file
@@ -0,0 +1,127 @@
|
|||||||
|
#ifndef _MAGISKBOOT_H_
|
||||||
|
#define _MAGISKBOOT_H_
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <sys/sendfile.h>
|
||||||
|
#include <sys/mman.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "bootimg.h"
|
||||||
|
#include "sha1.h"
|
||||||
|
|
||||||
|
#define windowBits 15
|
||||||
|
#define ZLIB_GZIP 16
|
||||||
|
#define memLevel 8
|
||||||
|
#define CHUNK 0x40000
|
||||||
|
|
||||||
|
#define LZ4_HEADER_SIZE 19
|
||||||
|
#define LZ4_FOOTER_SIZE 4
|
||||||
|
|
||||||
|
#define CHROMEOS_MAGIC "CHROMEOS"
|
||||||
|
#define CHROMEOS_MAGIC_SIZE 8
|
||||||
|
|
||||||
|
#define KERNEL_FILE "kernel"
|
||||||
|
#define RAMDISK_FILE "ramdisk.cpio"
|
||||||
|
#define SECOND_FILE "second"
|
||||||
|
#define DTB_FILE "dtb"
|
||||||
|
#define NEW_BOOT "new-boot.img"
|
||||||
|
|
||||||
|
#define SUP_LIST "gzip, xz, lzma, lz4, bzip2"
|
||||||
|
#define SUP_NUM 5
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
UNKNOWN,
|
||||||
|
CHROMEOS,
|
||||||
|
AOSP,
|
||||||
|
ELF,
|
||||||
|
GZIP,
|
||||||
|
LZOP,
|
||||||
|
XZ,
|
||||||
|
LZMA,
|
||||||
|
BZIP2,
|
||||||
|
LZ4,
|
||||||
|
MTK,
|
||||||
|
QCDT,
|
||||||
|
} file_t;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
NONE,
|
||||||
|
RM,
|
||||||
|
MKDIR,
|
||||||
|
ADD,
|
||||||
|
EXTRACT,
|
||||||
|
TEST,
|
||||||
|
DMVERITY,
|
||||||
|
FORCEENCRYPT,
|
||||||
|
BACKUP,
|
||||||
|
RESTORE
|
||||||
|
} command_t;
|
||||||
|
|
||||||
|
extern char *SUP_EXT_LIST[SUP_NUM];
|
||||||
|
extern file_t SUP_TYPE_LIST[SUP_NUM];
|
||||||
|
// Cannot declare in header, but place a copy here for convenience
|
||||||
|
// char *SUP_EXT_LIST[SUP_NUM] = { "gz", "xz", "lzma", "bz2", "lz4" };
|
||||||
|
// file_t SUP_TYPE_LIST[SUP_NUM] = { GZIP, XZ, LZMA, BZIP2, LZ4 };
|
||||||
|
|
||||||
|
// Vector
|
||||||
|
typedef struct vector {
|
||||||
|
size_t size;
|
||||||
|
size_t cap;
|
||||||
|
void **data;
|
||||||
|
} vector;
|
||||||
|
void vec_init(vector *v);
|
||||||
|
void vec_push_back(vector *v, void *p);
|
||||||
|
void vec_sort(vector *v, int (*compar)(const void *, const void *));
|
||||||
|
void vec_destroy(vector *v);
|
||||||
|
|
||||||
|
#define vec_size(v) (v)->size
|
||||||
|
#define vec_cap(v) (v)->cap
|
||||||
|
#define vec_entry(v) (v)->data
|
||||||
|
// vec_for_each(vector *v, void *e)
|
||||||
|
#define vec_for_each(v, e) \
|
||||||
|
e = (v)->data[0]; \
|
||||||
|
for (size_t _i = 0; _i < (v)->size; ++_i, e = (v)->data[_i])
|
||||||
|
|
||||||
|
// Global variables
|
||||||
|
extern unsigned char *kernel, *ramdisk, *second, *dtb, *extra;
|
||||||
|
extern boot_img_hdr hdr;
|
||||||
|
extern file_t boot_type, ramdisk_type, dtb_type;
|
||||||
|
extern int mtk_kernel, mtk_ramdisk;
|
||||||
|
|
||||||
|
// Main entries
|
||||||
|
void unpack(const char *image);
|
||||||
|
void repack(const char* orig_image, const char* out_image);
|
||||||
|
void hexpatch(const char *image, const char *from, const char *to);
|
||||||
|
void error(int rc, const char *msg, ...);
|
||||||
|
void parse_img(unsigned char *orig, size_t size);
|
||||||
|
int cpio_commands(const char *command, int argc, char *argv[]);
|
||||||
|
void cleanup();
|
||||||
|
|
||||||
|
// Compressions
|
||||||
|
void gzip(int mode, const char* filename, const unsigned char* buf, size_t size);
|
||||||
|
void lzma(int mode, const char* filename, const unsigned char* buf, size_t size);
|
||||||
|
void lz4(int mode, const char* filename, const unsigned char* buf, size_t size);
|
||||||
|
void bzip2(int mode, const char* filename, const unsigned char* buf, size_t size);
|
||||||
|
int comp(file_t type, const char *to, const unsigned char *from, size_t size);
|
||||||
|
void comp_file(const char *method, const char *from, const char *to);
|
||||||
|
int decomp(file_t type, const char *to, const unsigned char *from, size_t size);
|
||||||
|
void decomp_file(char *from, const char *to);
|
||||||
|
|
||||||
|
// Utils
|
||||||
|
void mmap_ro(const char *filename, unsigned char **buf, size_t *size);
|
||||||
|
void mmap_rw(const char *filename, unsigned char **buf, size_t *size);
|
||||||
|
file_t check_type(const unsigned char *buf);
|
||||||
|
void write_zero(int fd, size_t size);
|
||||||
|
void mem_align(size_t *pos, size_t align);
|
||||||
|
void file_align(int fd, size_t align, int out);
|
||||||
|
int open_new(const char *filename);
|
||||||
|
void print_info();
|
||||||
|
|
||||||
|
#endif
|
104
jni/magiskboot/main.c
Normal file
104
jni/magiskboot/main.c
Normal file
@@ -0,0 +1,104 @@
|
|||||||
|
#include "magiskboot.h"
|
||||||
|
|
||||||
|
/********************
|
||||||
|
Patch Boot Image
|
||||||
|
*********************/
|
||||||
|
|
||||||
|
static void usage(char *arg0) {
|
||||||
|
fprintf(stderr, "%s --unpack <bootimg>\n", arg0);
|
||||||
|
fprintf(stderr, " Unpack <bootimg> to kernel, ramdisk.cpio, (second), (dtb) into the\n current directory\n");
|
||||||
|
fprintf(stderr, "\n");
|
||||||
|
|
||||||
|
fprintf(stderr, "%s --repack <origbootimg> [outbootimg]\n", arg0);
|
||||||
|
fprintf(stderr, " Repack kernel, ramdisk.cpio[.ext], second, dtb... from current directory\n");
|
||||||
|
fprintf(stderr, " to [outbootimg], or new-boot.img if not specified.\n");
|
||||||
|
fprintf(stderr, " It will compress ramdisk.cpio with the same method used in <origbootimg>\n");
|
||||||
|
fprintf(stderr, " if exists, or attempt to find ramdisk.cpio.[ext], and repack\n");
|
||||||
|
fprintf(stderr, " directly with the compressed ramdisk file\n");
|
||||||
|
fprintf(stderr, "\n");
|
||||||
|
|
||||||
|
fprintf(stderr, "%s --hexpatch <file> <hexpattern1> <hexpattern2>\n", arg0);
|
||||||
|
fprintf(stderr, " Search <hexpattern1> in <file>, and replace with <hexpattern2>\n");
|
||||||
|
fprintf(stderr, "\n");
|
||||||
|
|
||||||
|
fprintf(stderr, "%s --cpio-<cmd> <incpio> [flags...] [params...]\n", arg0);
|
||||||
|
fprintf(stderr, " Do cpio related cmds to <incpio> (modifications are done directly)\n Supported commands:\n");
|
||||||
|
fprintf(stderr, " --cpio-rm <incpio> [-r] <entry>\n Remove entry from cpio, flag -r to remove recursively\n");
|
||||||
|
fprintf(stderr, " --cpio-mkdir <incpio> <mode> <entry>\n Create directory as an <entry>\n");
|
||||||
|
fprintf(stderr, " --cpio-add <incpio> <mode> <entry> <infile>\n Add <infile> as an <entry>; replaces <entry> if already exists\n");
|
||||||
|
fprintf(stderr, " --cpio-extract <incpio> <entry> <outfile>\n Extract <entry> to <outfile>\n");
|
||||||
|
fprintf(stderr, " --cpio-test <incpio>\n Return value: 0/not patched 1/Magisk 2/SuperSU\n");
|
||||||
|
fprintf(stderr, " --cpio-patch-dmverity <incpio>\n Remove dm-verity\n");
|
||||||
|
fprintf(stderr, " --cpio-patch-forceencrypt <incpio>\n Change forceencrypt flag to encryptable\n");
|
||||||
|
fprintf(stderr, " --cpio-backup <incpio> <origcpio>\n Create ramdisk backups into <incpio> from <origcpio>\n");
|
||||||
|
fprintf(stderr, " --cpio-restore <incpio>\n Restore ramdisk from ramdisk backup within <incpio>\n");
|
||||||
|
fprintf(stderr, "\n");
|
||||||
|
|
||||||
|
fprintf(stderr, "%s --compress[=method] <infile> [outfile]\n", arg0);
|
||||||
|
fprintf(stderr, " Compress <infile> with [method](default: gzip), optionally to [outfile]\n Supported methods: " SUP_LIST "\n");
|
||||||
|
fprintf(stderr, "\n");
|
||||||
|
|
||||||
|
fprintf(stderr, "%s --decompress <infile> [outfile]\n", arg0);
|
||||||
|
fprintf(stderr, " Detect method and decompress <infile>, optionally to [outfile]\n Supported methods: " SUP_LIST "\n");
|
||||||
|
fprintf(stderr, "\n");
|
||||||
|
|
||||||
|
fprintf(stderr, "%s --sha1 <file>\n", arg0);
|
||||||
|
fprintf(stderr, " Print the SHA1 checksum for <file>\n");
|
||||||
|
fprintf(stderr, "\n");
|
||||||
|
|
||||||
|
fprintf(stderr, "%s --cleanup\n", arg0);
|
||||||
|
fprintf(stderr, " Cleanup the current working directory\n");
|
||||||
|
fprintf(stderr, "\n");
|
||||||
|
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void error(int rc, const char *msg, ...) {
|
||||||
|
va_list ap;
|
||||||
|
va_start(ap, msg);
|
||||||
|
vfprintf(stderr, msg, ap);
|
||||||
|
fprintf(stderr,"\n\n");
|
||||||
|
va_end(ap);
|
||||||
|
exit(rc);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char *argv[]) {
|
||||||
|
printf("MagiskBoot (by topjohnwu) - Boot Image Modification Tool\n\n");
|
||||||
|
|
||||||
|
if (argc > 1 && strcmp(argv[1], "--cleanup") == 0) {
|
||||||
|
cleanup();
|
||||||
|
} else if (argc > 2 && strcmp(argv[1], "--sha1") == 0) {
|
||||||
|
char sha1[21], *buf;
|
||||||
|
size_t size;
|
||||||
|
mmap_ro(argv[2], (unsigned char **) &buf, &size);
|
||||||
|
SHA1(sha1, buf, size);
|
||||||
|
for (int i = 0; i < 20; ++i)
|
||||||
|
printf("%02x", sha1[i]);
|
||||||
|
printf("\n");
|
||||||
|
munmap(buf, size);
|
||||||
|
} else if (argc > 2 && strcmp(argv[1], "--unpack") == 0) {
|
||||||
|
unpack(argv[2]);
|
||||||
|
} else if (argc > 2 && strcmp(argv[1], "--repack") == 0) {
|
||||||
|
repack(argv[2], argc > 3 ? argv[3] : NEW_BOOT);
|
||||||
|
} else if (argc > 2 && strcmp(argv[1], "--decompress") == 0) {
|
||||||
|
decomp_file(argv[2], argc > 3 ? argv[3] : NULL);
|
||||||
|
} else if (argc > 2 && strncmp(argv[1], "--compress", 10) == 0) {
|
||||||
|
char *method;
|
||||||
|
method = strchr(argv[1], '=');
|
||||||
|
if (method == NULL) method = "gzip";
|
||||||
|
else method++;
|
||||||
|
comp_file(method, argv[2], argc > 3 ? argv[3] : NULL);
|
||||||
|
} else if (argc > 4 && strcmp(argv[1], "--hexpatch") == 0) {
|
||||||
|
hexpatch(argv[2], argv[3], argv[4]);
|
||||||
|
} else if (argc > 2 && strncmp(argv[1], "--cpio", 6) == 0) {
|
||||||
|
char *command;
|
||||||
|
command = strchr(argv[1] + 2, '-');
|
||||||
|
if (command == NULL) usage(argv[0]);
|
||||||
|
else ++command;
|
||||||
|
if (cpio_commands(command, argc - 2, argv + 2)) usage(argv[0]);
|
||||||
|
} else {
|
||||||
|
usage(argv[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
252
jni/magiskboot/parseimg.c
Normal file
252
jni/magiskboot/parseimg.c
Normal file
@@ -0,0 +1,252 @@
|
|||||||
|
#include "bootimg.h"
|
||||||
|
#include "elf.h"
|
||||||
|
#include "magiskboot.h"
|
||||||
|
|
||||||
|
unsigned char *kernel, *ramdisk, *second, *dtb, *extra;
|
||||||
|
boot_img_hdr hdr;
|
||||||
|
int mtk_kernel = 0, mtk_ramdisk = 0;
|
||||||
|
file_t boot_type, ramdisk_type, dtb_type;
|
||||||
|
|
||||||
|
static void check_headers() {
|
||||||
|
// Check ramdisk compression type
|
||||||
|
ramdisk_type = check_type(ramdisk);
|
||||||
|
|
||||||
|
// Check MTK
|
||||||
|
if (check_type(kernel) == MTK) {
|
||||||
|
printf("MTK header found in kernel\n");
|
||||||
|
mtk_kernel = 1;
|
||||||
|
}
|
||||||
|
if (check_type(ramdisk) == MTK) {
|
||||||
|
printf("MTK header found in ramdisk\n");
|
||||||
|
mtk_ramdisk = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check dtb if ELF boot
|
||||||
|
if (boot_type == ELF && hdr.dt_size) {
|
||||||
|
dtb_type = check_type(dtb);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Print info
|
||||||
|
print_info();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void elf_header_check(void *elf, int is64) {
|
||||||
|
|
||||||
|
size_t e_size, mach, ver, p_size, p_num, s_size, s_num;
|
||||||
|
size_t r_e_size, r_p_size, r_s_size;
|
||||||
|
|
||||||
|
if (is64) {
|
||||||
|
e_size = ((elf64_ehdr *) elf)->e_ehsize;
|
||||||
|
mach = ((elf64_ehdr *) elf)->e_machine;
|
||||||
|
ver = ((elf64_ehdr *) elf)->e_version;
|
||||||
|
p_size = ((elf64_ehdr *) elf)->e_phentsize;
|
||||||
|
p_num = ((elf64_ehdr *) elf)->e_phnum;
|
||||||
|
s_size = ((elf64_ehdr *) elf)->e_shentsize;
|
||||||
|
s_num = ((elf64_ehdr *) elf)->e_shnum;
|
||||||
|
r_e_size = sizeof(elf64_ehdr);
|
||||||
|
r_p_size = sizeof(elf64_phdr);
|
||||||
|
r_s_size = sizeof(elf64_shdr);
|
||||||
|
} else {
|
||||||
|
e_size = ((elf32_ehdr *) elf)->e_ehsize;
|
||||||
|
mach = ((elf32_ehdr *) elf)->e_machine;
|
||||||
|
ver = ((elf32_ehdr *) elf)->e_version;
|
||||||
|
p_size = ((elf32_ehdr *) elf)->e_phentsize;
|
||||||
|
p_num = ((elf32_ehdr *) elf)->e_phnum;
|
||||||
|
s_size = ((elf32_ehdr *) elf)->e_shentsize;
|
||||||
|
s_num = ((elf32_ehdr *) elf)->e_shnum;
|
||||||
|
r_e_size = sizeof(elf32_ehdr);
|
||||||
|
r_p_size = sizeof(elf32_phdr);
|
||||||
|
r_s_size = sizeof(elf32_shdr);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (e_size != r_e_size)
|
||||||
|
error(1, "Header size not %d", r_e_size);
|
||||||
|
|
||||||
|
if (mach != EM_ARM)
|
||||||
|
error(1, "ELF machine is not ARM");
|
||||||
|
|
||||||
|
if (ver != 1)
|
||||||
|
error(1, "Unknown ELF version");
|
||||||
|
|
||||||
|
if (p_size != r_p_size)
|
||||||
|
error(1, "Program header size not %d", r_p_size);
|
||||||
|
|
||||||
|
if (p_num < 2 || p_num > 4)
|
||||||
|
error(1, "Unexpected number of elements: %d", p_num);
|
||||||
|
|
||||||
|
if (s_num && s_size != r_s_size)
|
||||||
|
error(1, "Section header size not %d", r_s_size);
|
||||||
|
|
||||||
|
if (s_num > 1)
|
||||||
|
error(1, "More than one section header");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void elf_set(int i, unsigned char *base, size_t size, size_t offset, size_t addr) {
|
||||||
|
if (size <= 4096) {
|
||||||
|
// Possible cmdline
|
||||||
|
memset(hdr.cmdline, 0, BOOT_ARGS_SIZE);
|
||||||
|
strncpy((char *) hdr.cmdline, (char *) (base + offset), BOOT_ARGS_SIZE);
|
||||||
|
hdr.cmdline[strcspn((char*) hdr.cmdline, "\n")] = '\0';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
switch(i) {
|
||||||
|
case 0:
|
||||||
|
// kernel
|
||||||
|
kernel = base + offset;
|
||||||
|
hdr.kernel_size = size;
|
||||||
|
hdr.kernel_addr = addr;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
// ramdisk
|
||||||
|
ramdisk = base + offset;
|
||||||
|
hdr.ramdisk_size = size;
|
||||||
|
hdr.ramdisk_addr = addr;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
// dtb
|
||||||
|
dtb = base + offset;
|
||||||
|
hdr.dt_size = size;
|
||||||
|
hdr.tags_addr = addr;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void parse_elf(unsigned char *base) {
|
||||||
|
|
||||||
|
// Reset boot image header
|
||||||
|
memset(&hdr, 0, sizeof(hdr));
|
||||||
|
|
||||||
|
// Hardcode header magic and pagesize
|
||||||
|
memcpy(hdr.magic, BOOT_MAGIC, BOOT_MAGIC_SIZE);
|
||||||
|
hdr.page_size = 4096;
|
||||||
|
|
||||||
|
switch(base[EI_CLASS]) {
|
||||||
|
|
||||||
|
case ELFCLASS32: {
|
||||||
|
|
||||||
|
elf32_ehdr *elf32;
|
||||||
|
elf32_phdr *ph32;
|
||||||
|
elf32_shdr *sh32;
|
||||||
|
|
||||||
|
printf("IMAGE [ELF32]\n");
|
||||||
|
|
||||||
|
elf32 = (elf32_ehdr *) base;
|
||||||
|
|
||||||
|
elf_header_check(elf32, 0);
|
||||||
|
|
||||||
|
ph32 = (elf32_phdr *) (base + elf32->e_phoff);
|
||||||
|
sh32 = (elf32_shdr *) (base + elf32->e_shoff);
|
||||||
|
|
||||||
|
for (int i = 0; i < elf32->e_phnum; ++i) {
|
||||||
|
elf_set(i, base, ph32[i].p_filesz, ph32[i].p_offset, ph32[i].p_paddr);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (elf32->e_shnum) {
|
||||||
|
// cmdline
|
||||||
|
memset(hdr.cmdline, 0, BOOT_ARGS_SIZE);
|
||||||
|
strncpy((char *) hdr.cmdline, (char *) (base + sh32->s_offset + 8), BOOT_ARGS_SIZE);
|
||||||
|
hdr.cmdline[strcspn((char*) hdr.cmdline, "\n")] = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case ELFCLASS64: {
|
||||||
|
|
||||||
|
elf64_ehdr *elf64;
|
||||||
|
elf64_phdr *ph64;
|
||||||
|
elf64_shdr *sh64;
|
||||||
|
|
||||||
|
printf("IMAGE [ELF64]\n");
|
||||||
|
|
||||||
|
elf64 = (elf64_ehdr *) base;
|
||||||
|
|
||||||
|
elf_header_check(elf64, 1);
|
||||||
|
|
||||||
|
ph64 = (elf64_phdr *) (base + elf64->e_phoff);
|
||||||
|
sh64 = (elf64_shdr *) (base + elf64->e_shoff);
|
||||||
|
|
||||||
|
for (int i = 0; i < elf64->e_phnum; ++i) {
|
||||||
|
elf_set(i, base, ph64[i].p_filesz, ph64[i].p_offset, ph64[i].p_paddr);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (elf64->e_shnum) {
|
||||||
|
// cmdline
|
||||||
|
memset(hdr.cmdline, 0, BOOT_ARGS_SIZE);
|
||||||
|
strncpy((char *) hdr.cmdline, (char *) (base + sh64->s_offset + 8), BOOT_ARGS_SIZE);
|
||||||
|
hdr.cmdline[strcspn((char*) hdr.cmdline, "\n")] = '\0';
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
error(1, "ELF format error!");
|
||||||
|
}
|
||||||
|
|
||||||
|
check_headers();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void parse_aosp(unsigned char *base, size_t size) {
|
||||||
|
|
||||||
|
printf("IMG [AOSP]\n");
|
||||||
|
|
||||||
|
size_t pos = 0;
|
||||||
|
|
||||||
|
// Read the header
|
||||||
|
memcpy(&hdr, base, sizeof(hdr));
|
||||||
|
pos += hdr.page_size;
|
||||||
|
|
||||||
|
// Kernel position
|
||||||
|
kernel = base + pos;
|
||||||
|
pos += hdr.kernel_size;
|
||||||
|
mem_align(&pos, hdr.page_size);
|
||||||
|
|
||||||
|
// Ramdisk position
|
||||||
|
ramdisk = base + pos;
|
||||||
|
pos += hdr.ramdisk_size;
|
||||||
|
mem_align(&pos, hdr.page_size);
|
||||||
|
|
||||||
|
if (hdr.second_size) {
|
||||||
|
// Second position
|
||||||
|
second = base + pos;
|
||||||
|
pos += hdr.second_size;
|
||||||
|
mem_align(&pos, hdr.page_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hdr.dt_size) {
|
||||||
|
// dtb position
|
||||||
|
dtb = base + pos;
|
||||||
|
pos += hdr.dt_size;
|
||||||
|
mem_align(&pos, hdr.page_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pos < size) {
|
||||||
|
extra = base + pos;
|
||||||
|
}
|
||||||
|
|
||||||
|
check_headers();
|
||||||
|
}
|
||||||
|
|
||||||
|
void parse_img(unsigned char *orig, size_t size) {
|
||||||
|
unsigned char *base, *end;
|
||||||
|
for(base = orig, end = orig + size; base < end; base += 256, size -= 256) {
|
||||||
|
switch (check_type(base)) {
|
||||||
|
case CHROMEOS:
|
||||||
|
boot_type = CHROMEOS;
|
||||||
|
continue;
|
||||||
|
case AOSP:
|
||||||
|
// Don't override CHROMEOS
|
||||||
|
if (boot_type != CHROMEOS)
|
||||||
|
boot_type = AOSP;
|
||||||
|
parse_aosp(base, size);
|
||||||
|
return;
|
||||||
|
case ELF:
|
||||||
|
boot_type = ELF;
|
||||||
|
parse_elf(base);
|
||||||
|
return;
|
||||||
|
default:
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
error(1, "No boot image magic found!");
|
||||||
|
}
|
146
jni/magiskboot/repack.c
Normal file
146
jni/magiskboot/repack.c
Normal file
@@ -0,0 +1,146 @@
|
|||||||
|
#include "magiskboot.h"
|
||||||
|
|
||||||
|
static size_t restore(const char *filename, int fd) {
|
||||||
|
int ifd = open(filename, O_RDONLY);
|
||||||
|
if (ifd < 0)
|
||||||
|
error(1, "Cannot open %s\n", filename);
|
||||||
|
|
||||||
|
size_t size = lseek(ifd, 0, SEEK_END);
|
||||||
|
lseek(ifd, 0, SEEK_SET);
|
||||||
|
if (sendfile(fd, ifd, NULL, size) != size) {
|
||||||
|
error(1, "Cannot write %s\n", filename);
|
||||||
|
}
|
||||||
|
close(ifd);
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void restore_buf(int fd, const void *buf, size_t size) {
|
||||||
|
if (write(fd, buf, size) != size) {
|
||||||
|
error(1, "Cannot dump from input file\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void repack(const char* orig_image, const char* out_image) {
|
||||||
|
size_t size;
|
||||||
|
unsigned char *orig;
|
||||||
|
char name[PATH_MAX];
|
||||||
|
|
||||||
|
// There are possible two MTK headers
|
||||||
|
mtk_hdr mtk_kernel_hdr, mtk_ramdisk_hdr;
|
||||||
|
size_t mtk_kernel_off, mtk_ramdisk_off;
|
||||||
|
|
||||||
|
// Load original image
|
||||||
|
mmap_ro(orig_image, &orig, &size);
|
||||||
|
|
||||||
|
// Parse original image
|
||||||
|
printf("Parsing boot image: [%s]\n\n", orig_image);
|
||||||
|
parse_img(orig, size);
|
||||||
|
|
||||||
|
printf("Repack to boot image: [%s]\n\n", out_image);
|
||||||
|
|
||||||
|
// Create new image
|
||||||
|
int fd = open_new(out_image);
|
||||||
|
|
||||||
|
// Set all sizes to 0
|
||||||
|
hdr.kernel_size = 0;
|
||||||
|
hdr.ramdisk_size = 0;
|
||||||
|
hdr.second_size = 0;
|
||||||
|
hdr.dt_size = 0;
|
||||||
|
|
||||||
|
// Skip a page for header
|
||||||
|
write_zero(fd, hdr.page_size);
|
||||||
|
|
||||||
|
// Restore kernel
|
||||||
|
if (mtk_kernel) {
|
||||||
|
mtk_kernel_off = lseek(fd, 0, SEEK_CUR);
|
||||||
|
write_zero(fd, 512);
|
||||||
|
memcpy(&mtk_kernel_hdr, kernel, sizeof(mtk_kernel_hdr));
|
||||||
|
}
|
||||||
|
hdr.kernel_size = restore(KERNEL_FILE, fd);
|
||||||
|
file_align(fd, hdr.page_size, 1);
|
||||||
|
|
||||||
|
// Restore ramdisk
|
||||||
|
if (mtk_ramdisk) {
|
||||||
|
mtk_ramdisk_off = lseek(fd, 0, SEEK_CUR);
|
||||||
|
write_zero(fd, 512);
|
||||||
|
memcpy(&mtk_ramdisk_hdr, ramdisk, sizeof(mtk_ramdisk_hdr));
|
||||||
|
}
|
||||||
|
if (access(RAMDISK_FILE, R_OK) == 0) {
|
||||||
|
// If we found raw cpio, compress to original format
|
||||||
|
|
||||||
|
// Before we start, clean up previous compressed files
|
||||||
|
for (int i = 0; i < SUP_NUM; ++i) {
|
||||||
|
sprintf(name, "%s.%s", RAMDISK_FILE, SUP_EXT_LIST[i]);
|
||||||
|
unlink(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t cpio_size;
|
||||||
|
unsigned char *cpio;
|
||||||
|
mmap_ro(RAMDISK_FILE, &cpio, &cpio_size);
|
||||||
|
|
||||||
|
if (comp(ramdisk_type, RAMDISK_FILE, cpio, cpio_size))
|
||||||
|
error(1, "Unsupported ramdisk format!");
|
||||||
|
|
||||||
|
munmap(cpio, cpio_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
int found = 0;
|
||||||
|
for (int i = 0; i < SUP_NUM; ++i) {
|
||||||
|
sprintf(name, "%s.%s", RAMDISK_FILE, SUP_EXT_LIST[i]);
|
||||||
|
if (access(name, R_OK) == 0) {
|
||||||
|
ramdisk_type = SUP_TYPE_LIST[i];
|
||||||
|
found = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!found)
|
||||||
|
error(1, "No ramdisk exists!");
|
||||||
|
hdr.ramdisk_size = restore(name, fd);
|
||||||
|
file_align(fd, hdr.page_size, 1);
|
||||||
|
|
||||||
|
// Restore second
|
||||||
|
if (access(SECOND_FILE, R_OK) == 0) {
|
||||||
|
hdr.second_size = restore(SECOND_FILE, fd);
|
||||||
|
file_align(fd, hdr.page_size, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Restore dtb
|
||||||
|
if (access(DTB_FILE, R_OK) == 0) {
|
||||||
|
hdr.dt_size = restore(DTB_FILE, fd);
|
||||||
|
file_align(fd, hdr.page_size, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check extra info, currently only for LG Bump and Samsung SEANDROIDENFORCE
|
||||||
|
if (extra) {
|
||||||
|
if (memcmp(extra, "SEANDROIDENFORCE", 16) == 0 ||
|
||||||
|
memcmp(extra, "\x41\xa9\xe4\x67\x74\x4d\x1d\x1b\xa4\x29\xf2\xec\xea\x65\x52\x79", 16) == 0 ) {
|
||||||
|
restore_buf(fd, extra, 16);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write headers back
|
||||||
|
if (mtk_kernel) {
|
||||||
|
lseek(fd, mtk_kernel_off, SEEK_SET);
|
||||||
|
mtk_kernel_hdr.size = hdr.kernel_size;
|
||||||
|
hdr.kernel_size += 512;
|
||||||
|
restore_buf(fd, &mtk_kernel_hdr, sizeof(mtk_kernel_hdr));
|
||||||
|
}
|
||||||
|
if (mtk_ramdisk) {
|
||||||
|
lseek(fd, mtk_ramdisk_off, SEEK_SET);
|
||||||
|
mtk_ramdisk_hdr.size = hdr.ramdisk_size;
|
||||||
|
hdr.ramdisk_size += 512;
|
||||||
|
restore_buf(fd, &mtk_ramdisk_hdr, sizeof(mtk_ramdisk_hdr));
|
||||||
|
}
|
||||||
|
// Main header
|
||||||
|
lseek(fd, 0, SEEK_SET);
|
||||||
|
restore_buf(fd, &hdr, sizeof(hdr));
|
||||||
|
|
||||||
|
// Print new image info
|
||||||
|
print_info();
|
||||||
|
|
||||||
|
munmap(orig, size);
|
||||||
|
if (lseek(fd, 0, SEEK_END) > size) {
|
||||||
|
error(2, "Boot partition too small!");
|
||||||
|
}
|
||||||
|
close(fd);
|
||||||
|
}
|
295
jni/magiskboot/sha1.c
Normal file
295
jni/magiskboot/sha1.c
Normal file
@@ -0,0 +1,295 @@
|
|||||||
|
/*
|
||||||
|
SHA-1 in C
|
||||||
|
By Steve Reid <steve@edmweb.com>
|
||||||
|
100% Public Domain
|
||||||
|
|
||||||
|
Test Vectors (from FIPS PUB 180-1)
|
||||||
|
"abc"
|
||||||
|
A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D
|
||||||
|
"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"
|
||||||
|
84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1
|
||||||
|
A million repetitions of "a"
|
||||||
|
34AA973C D4C4DAA4 F61EEB2B DBAD2731 6534016F
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* #define LITTLE_ENDIAN * This should be #define'd already, if true. */
|
||||||
|
/* #define SHA1HANDSOFF * Copies data before messing with it. */
|
||||||
|
|
||||||
|
#define SHA1HANDSOFF
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
/* for uint32_t */
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include "sha1.h"
|
||||||
|
|
||||||
|
|
||||||
|
#define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits))))
|
||||||
|
|
||||||
|
/* blk0() and blk() perform the initial expand. */
|
||||||
|
/* I got the idea of expanding during the round function from SSLeay */
|
||||||
|
#if BYTE_ORDER == LITTLE_ENDIAN
|
||||||
|
#define blk0(i) (block->l[i] = (rol(block->l[i],24)&0xFF00FF00) \
|
||||||
|
|(rol(block->l[i],8)&0x00FF00FF))
|
||||||
|
#elif BYTE_ORDER == BIG_ENDIAN
|
||||||
|
#define blk0(i) block->l[i]
|
||||||
|
#else
|
||||||
|
#error "Endianness not defined!"
|
||||||
|
#endif
|
||||||
|
#define blk(i) (block->l[i&15] = rol(block->l[(i+13)&15]^block->l[(i+8)&15] \
|
||||||
|
^block->l[(i+2)&15]^block->l[i&15],1))
|
||||||
|
|
||||||
|
/* (R0+R1), R2, R3, R4 are the different operations used in SHA1 */
|
||||||
|
#define R0(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk0(i)+0x5A827999+rol(v,5);w=rol(w,30);
|
||||||
|
#define R1(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk(i)+0x5A827999+rol(v,5);w=rol(w,30);
|
||||||
|
#define R2(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0x6ED9EBA1+rol(v,5);w=rol(w,30);
|
||||||
|
#define R3(v,w,x,y,z,i) z+=(((w|x)&y)|(w&x))+blk(i)+0x8F1BBCDC+rol(v,5);w=rol(w,30);
|
||||||
|
#define R4(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0xCA62C1D6+rol(v,5);w=rol(w,30);
|
||||||
|
|
||||||
|
|
||||||
|
/* Hash a single 512-bit block. This is the core of the algorithm. */
|
||||||
|
|
||||||
|
void SHA1Transform(
|
||||||
|
uint32_t state[5],
|
||||||
|
const unsigned char buffer[64]
|
||||||
|
)
|
||||||
|
{
|
||||||
|
uint32_t a, b, c, d, e;
|
||||||
|
|
||||||
|
typedef union
|
||||||
|
{
|
||||||
|
unsigned char c[64];
|
||||||
|
uint32_t l[16];
|
||||||
|
} CHAR64LONG16;
|
||||||
|
|
||||||
|
#ifdef SHA1HANDSOFF
|
||||||
|
CHAR64LONG16 block[1]; /* use array to appear as a pointer */
|
||||||
|
|
||||||
|
memcpy(block, buffer, 64);
|
||||||
|
#else
|
||||||
|
/* The following had better never be used because it causes the
|
||||||
|
* pointer-to-const buffer to be cast into a pointer to non-const.
|
||||||
|
* And the result is written through. I threw a "const" in, hoping
|
||||||
|
* this will cause a diagnostic.
|
||||||
|
*/
|
||||||
|
CHAR64LONG16 *block = (const CHAR64LONG16 *) buffer;
|
||||||
|
#endif
|
||||||
|
/* Copy context->state[] to working vars */
|
||||||
|
a = state[0];
|
||||||
|
b = state[1];
|
||||||
|
c = state[2];
|
||||||
|
d = state[3];
|
||||||
|
e = state[4];
|
||||||
|
/* 4 rounds of 20 operations each. Loop unrolled. */
|
||||||
|
R0(a, b, c, d, e, 0);
|
||||||
|
R0(e, a, b, c, d, 1);
|
||||||
|
R0(d, e, a, b, c, 2);
|
||||||
|
R0(c, d, e, a, b, 3);
|
||||||
|
R0(b, c, d, e, a, 4);
|
||||||
|
R0(a, b, c, d, e, 5);
|
||||||
|
R0(e, a, b, c, d, 6);
|
||||||
|
R0(d, e, a, b, c, 7);
|
||||||
|
R0(c, d, e, a, b, 8);
|
||||||
|
R0(b, c, d, e, a, 9);
|
||||||
|
R0(a, b, c, d, e, 10);
|
||||||
|
R0(e, a, b, c, d, 11);
|
||||||
|
R0(d, e, a, b, c, 12);
|
||||||
|
R0(c, d, e, a, b, 13);
|
||||||
|
R0(b, c, d, e, a, 14);
|
||||||
|
R0(a, b, c, d, e, 15);
|
||||||
|
R1(e, a, b, c, d, 16);
|
||||||
|
R1(d, e, a, b, c, 17);
|
||||||
|
R1(c, d, e, a, b, 18);
|
||||||
|
R1(b, c, d, e, a, 19);
|
||||||
|
R2(a, b, c, d, e, 20);
|
||||||
|
R2(e, a, b, c, d, 21);
|
||||||
|
R2(d, e, a, b, c, 22);
|
||||||
|
R2(c, d, e, a, b, 23);
|
||||||
|
R2(b, c, d, e, a, 24);
|
||||||
|
R2(a, b, c, d, e, 25);
|
||||||
|
R2(e, a, b, c, d, 26);
|
||||||
|
R2(d, e, a, b, c, 27);
|
||||||
|
R2(c, d, e, a, b, 28);
|
||||||
|
R2(b, c, d, e, a, 29);
|
||||||
|
R2(a, b, c, d, e, 30);
|
||||||
|
R2(e, a, b, c, d, 31);
|
||||||
|
R2(d, e, a, b, c, 32);
|
||||||
|
R2(c, d, e, a, b, 33);
|
||||||
|
R2(b, c, d, e, a, 34);
|
||||||
|
R2(a, b, c, d, e, 35);
|
||||||
|
R2(e, a, b, c, d, 36);
|
||||||
|
R2(d, e, a, b, c, 37);
|
||||||
|
R2(c, d, e, a, b, 38);
|
||||||
|
R2(b, c, d, e, a, 39);
|
||||||
|
R3(a, b, c, d, e, 40);
|
||||||
|
R3(e, a, b, c, d, 41);
|
||||||
|
R3(d, e, a, b, c, 42);
|
||||||
|
R3(c, d, e, a, b, 43);
|
||||||
|
R3(b, c, d, e, a, 44);
|
||||||
|
R3(a, b, c, d, e, 45);
|
||||||
|
R3(e, a, b, c, d, 46);
|
||||||
|
R3(d, e, a, b, c, 47);
|
||||||
|
R3(c, d, e, a, b, 48);
|
||||||
|
R3(b, c, d, e, a, 49);
|
||||||
|
R3(a, b, c, d, e, 50);
|
||||||
|
R3(e, a, b, c, d, 51);
|
||||||
|
R3(d, e, a, b, c, 52);
|
||||||
|
R3(c, d, e, a, b, 53);
|
||||||
|
R3(b, c, d, e, a, 54);
|
||||||
|
R3(a, b, c, d, e, 55);
|
||||||
|
R3(e, a, b, c, d, 56);
|
||||||
|
R3(d, e, a, b, c, 57);
|
||||||
|
R3(c, d, e, a, b, 58);
|
||||||
|
R3(b, c, d, e, a, 59);
|
||||||
|
R4(a, b, c, d, e, 60);
|
||||||
|
R4(e, a, b, c, d, 61);
|
||||||
|
R4(d, e, a, b, c, 62);
|
||||||
|
R4(c, d, e, a, b, 63);
|
||||||
|
R4(b, c, d, e, a, 64);
|
||||||
|
R4(a, b, c, d, e, 65);
|
||||||
|
R4(e, a, b, c, d, 66);
|
||||||
|
R4(d, e, a, b, c, 67);
|
||||||
|
R4(c, d, e, a, b, 68);
|
||||||
|
R4(b, c, d, e, a, 69);
|
||||||
|
R4(a, b, c, d, e, 70);
|
||||||
|
R4(e, a, b, c, d, 71);
|
||||||
|
R4(d, e, a, b, c, 72);
|
||||||
|
R4(c, d, e, a, b, 73);
|
||||||
|
R4(b, c, d, e, a, 74);
|
||||||
|
R4(a, b, c, d, e, 75);
|
||||||
|
R4(e, a, b, c, d, 76);
|
||||||
|
R4(d, e, a, b, c, 77);
|
||||||
|
R4(c, d, e, a, b, 78);
|
||||||
|
R4(b, c, d, e, a, 79);
|
||||||
|
/* Add the working vars back into context.state[] */
|
||||||
|
state[0] += a;
|
||||||
|
state[1] += b;
|
||||||
|
state[2] += c;
|
||||||
|
state[3] += d;
|
||||||
|
state[4] += e;
|
||||||
|
/* Wipe variables */
|
||||||
|
a = b = c = d = e = 0;
|
||||||
|
#ifdef SHA1HANDSOFF
|
||||||
|
memset(block, '\0', sizeof(block));
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* SHA1Init - Initialize new context */
|
||||||
|
|
||||||
|
void SHA1Init(
|
||||||
|
SHA1_CTX * context
|
||||||
|
)
|
||||||
|
{
|
||||||
|
/* SHA1 initialization constants */
|
||||||
|
context->state[0] = 0x67452301;
|
||||||
|
context->state[1] = 0xEFCDAB89;
|
||||||
|
context->state[2] = 0x98BADCFE;
|
||||||
|
context->state[3] = 0x10325476;
|
||||||
|
context->state[4] = 0xC3D2E1F0;
|
||||||
|
context->count[0] = context->count[1] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Run your data through this. */
|
||||||
|
|
||||||
|
void SHA1Update(
|
||||||
|
SHA1_CTX * context,
|
||||||
|
const unsigned char *data,
|
||||||
|
uint32_t len
|
||||||
|
)
|
||||||
|
{
|
||||||
|
uint32_t i;
|
||||||
|
|
||||||
|
uint32_t j;
|
||||||
|
|
||||||
|
j = context->count[0];
|
||||||
|
if ((context->count[0] += len << 3) < j)
|
||||||
|
context->count[1]++;
|
||||||
|
context->count[1] += (len >> 29);
|
||||||
|
j = (j >> 3) & 63;
|
||||||
|
if ((j + len) > 63)
|
||||||
|
{
|
||||||
|
memcpy(&context->buffer[j], data, (i = 64 - j));
|
||||||
|
SHA1Transform(context->state, context->buffer);
|
||||||
|
for (; i + 63 < len; i += 64)
|
||||||
|
{
|
||||||
|
SHA1Transform(context->state, &data[i]);
|
||||||
|
}
|
||||||
|
j = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
i = 0;
|
||||||
|
memcpy(&context->buffer[j], &data[i], len - i);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Add padding and return the message digest. */
|
||||||
|
|
||||||
|
void SHA1Final(
|
||||||
|
unsigned char digest[20],
|
||||||
|
SHA1_CTX * context
|
||||||
|
)
|
||||||
|
{
|
||||||
|
unsigned i;
|
||||||
|
|
||||||
|
unsigned char finalcount[8];
|
||||||
|
|
||||||
|
unsigned char c;
|
||||||
|
|
||||||
|
#if 0 /* untested "improvement" by DHR */
|
||||||
|
/* Convert context->count to a sequence of bytes
|
||||||
|
* in finalcount. Second element first, but
|
||||||
|
* big-endian order within element.
|
||||||
|
* But we do it all backwards.
|
||||||
|
*/
|
||||||
|
unsigned char *fcp = &finalcount[8];
|
||||||
|
|
||||||
|
for (i = 0; i < 2; i++)
|
||||||
|
{
|
||||||
|
uint32_t t = context->count[i];
|
||||||
|
|
||||||
|
int j;
|
||||||
|
|
||||||
|
for (j = 0; j < 4; t >>= 8, j++)
|
||||||
|
*--fcp = (unsigned char) t}
|
||||||
|
#else
|
||||||
|
for (i = 0; i < 8; i++)
|
||||||
|
{
|
||||||
|
finalcount[i] = (unsigned char) ((context->count[(i >= 4 ? 0 : 1)] >> ((3 - (i & 3)) * 8)) & 255); /* Endian independent */
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
c = 0200;
|
||||||
|
SHA1Update(context, &c, 1);
|
||||||
|
while ((context->count[0] & 504) != 448)
|
||||||
|
{
|
||||||
|
c = 0000;
|
||||||
|
SHA1Update(context, &c, 1);
|
||||||
|
}
|
||||||
|
SHA1Update(context, finalcount, 8); /* Should cause a SHA1Transform() */
|
||||||
|
for (i = 0; i < 20; i++)
|
||||||
|
{
|
||||||
|
digest[i] = (unsigned char)
|
||||||
|
((context->state[i >> 2] >> ((3 - (i & 3)) * 8)) & 255);
|
||||||
|
}
|
||||||
|
/* Wipe variables */
|
||||||
|
memset(context, '\0', sizeof(*context));
|
||||||
|
memset(&finalcount, '\0', sizeof(finalcount));
|
||||||
|
}
|
||||||
|
|
||||||
|
void SHA1(
|
||||||
|
char *hash_out,
|
||||||
|
const char *str,
|
||||||
|
int len)
|
||||||
|
{
|
||||||
|
SHA1_CTX ctx;
|
||||||
|
unsigned int ii;
|
||||||
|
|
||||||
|
SHA1Init(&ctx);
|
||||||
|
for (ii=0; ii<len; ii+=1)
|
||||||
|
SHA1Update(&ctx, (const unsigned char*)str + ii, 1);
|
||||||
|
SHA1Final((unsigned char *)hash_out, &ctx);
|
||||||
|
hash_out[20] = '\0';
|
||||||
|
}
|
44
jni/magiskboot/sha1.h
Normal file
44
jni/magiskboot/sha1.h
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
#ifndef SHA1_H
|
||||||
|
#define SHA1_H
|
||||||
|
|
||||||
|
/*
|
||||||
|
SHA-1 in C
|
||||||
|
By Steve Reid <steve@edmweb.com>
|
||||||
|
100% Public Domain
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "stdint.h"
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
uint32_t state[5];
|
||||||
|
uint32_t count[2];
|
||||||
|
unsigned char buffer[64];
|
||||||
|
} SHA1_CTX;
|
||||||
|
|
||||||
|
void SHA1Transform(
|
||||||
|
uint32_t state[5],
|
||||||
|
const unsigned char buffer[64]
|
||||||
|
);
|
||||||
|
|
||||||
|
void SHA1Init(
|
||||||
|
SHA1_CTX * context
|
||||||
|
);
|
||||||
|
|
||||||
|
void SHA1Update(
|
||||||
|
SHA1_CTX * context,
|
||||||
|
const unsigned char *data,
|
||||||
|
uint32_t len
|
||||||
|
);
|
||||||
|
|
||||||
|
void SHA1Final(
|
||||||
|
unsigned char digest[20],
|
||||||
|
SHA1_CTX * context
|
||||||
|
);
|
||||||
|
|
||||||
|
void SHA1(
|
||||||
|
char *hash_out,
|
||||||
|
const char *str,
|
||||||
|
int len);
|
||||||
|
|
||||||
|
#endif /* SHA1_H */
|
64
jni/magiskboot/unpack.c
Normal file
64
jni/magiskboot/unpack.c
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
#include "magiskboot.h"
|
||||||
|
|
||||||
|
static void dump(unsigned char *buf, size_t size, const char *filename) {
|
||||||
|
int fd = open_new(filename);
|
||||||
|
if (write(fd, buf, size) != size)
|
||||||
|
error(1, "Cannot dump %s", filename);
|
||||||
|
close(fd);
|
||||||
|
}
|
||||||
|
|
||||||
|
void unpack(const char* image) {
|
||||||
|
size_t size;
|
||||||
|
unsigned char *orig;
|
||||||
|
mmap_ro(image, &orig, &size);
|
||||||
|
|
||||||
|
// Parse image
|
||||||
|
printf("Parsing boot image: [%s]\n\n", image);
|
||||||
|
parse_img(orig, size);
|
||||||
|
|
||||||
|
if (boot_type == CHROMEOS) {
|
||||||
|
// The caller should know it's chromeos, as it needs additional signing
|
||||||
|
dump(orig, 0, "chromeos");
|
||||||
|
}
|
||||||
|
|
||||||
|
char name[PATH_MAX];
|
||||||
|
|
||||||
|
// Dump kernel
|
||||||
|
if (mtk_kernel) {
|
||||||
|
kernel += 512;
|
||||||
|
hdr.kernel_size -= 512;
|
||||||
|
}
|
||||||
|
dump(kernel, hdr.kernel_size, KERNEL_FILE);
|
||||||
|
|
||||||
|
// Dump ramdisk
|
||||||
|
if (mtk_ramdisk) {
|
||||||
|
ramdisk += 512;
|
||||||
|
hdr.ramdisk_size -= 512;
|
||||||
|
}
|
||||||
|
if (decomp(ramdisk_type, RAMDISK_FILE, ramdisk, hdr.ramdisk_size)) {
|
||||||
|
// Dump the compressed ramdisk
|
||||||
|
dump(ramdisk, hdr.ramdisk_size, RAMDISK_FILE ".unsupport");
|
||||||
|
error(1, "Unsupported ramdisk format! Dumped to %s", RAMDISK_FILE ".unsupport");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hdr.second_size) {
|
||||||
|
// Dump second
|
||||||
|
dump(second, hdr.second_size, SECOND_FILE);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hdr.dt_size) {
|
||||||
|
if (boot_type == ELF && (dtb_type != QCDT && dtb_type != ELF)) {
|
||||||
|
printf("Non QC dtb found in ELF kernel, recreate kernel\n");
|
||||||
|
gzip(1, KERNEL_FILE, kernel, hdr.kernel_size);
|
||||||
|
int kfp = open(KERNEL_FILE, O_WRONLY | O_APPEND);
|
||||||
|
write(kfp, dtb, hdr.dt_size);
|
||||||
|
close(kfp);
|
||||||
|
} else {
|
||||||
|
// Dump dtb
|
||||||
|
dump(dtb, hdr.dt_size, DTB_FILE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
munmap(orig, size);
|
||||||
|
}
|
||||||
|
|
179
jni/magiskboot/utils.c
Normal file
179
jni/magiskboot/utils.c
Normal file
@@ -0,0 +1,179 @@
|
|||||||
|
#include "magiskboot.h"
|
||||||
|
#include "elf.h"
|
||||||
|
|
||||||
|
char *SUP_EXT_LIST[SUP_NUM] = { "gz", "xz", "lzma", "bz2", "lz4" };
|
||||||
|
file_t SUP_TYPE_LIST[SUP_NUM] = { GZIP, XZ, LZMA, BZIP2, LZ4 };
|
||||||
|
|
||||||
|
void mmap_ro(const char *filename, unsigned char **buf, size_t *size) {
|
||||||
|
int fd = open(filename, O_RDONLY);
|
||||||
|
if (fd < 0)
|
||||||
|
error(1, "Cannot open %s", filename);
|
||||||
|
*size = lseek(fd, 0, SEEK_END);
|
||||||
|
lseek(fd, 0, SEEK_SET);
|
||||||
|
*buf = mmap(NULL, *size, PROT_READ, MAP_SHARED, fd, 0);
|
||||||
|
close(fd);
|
||||||
|
}
|
||||||
|
|
||||||
|
void mmap_rw(const char *filename, unsigned char **buf, size_t *size) {
|
||||||
|
int fd = open(filename, O_RDWR);
|
||||||
|
if (fd < 0)
|
||||||
|
error(1, "Cannot open %s", filename);
|
||||||
|
*size = lseek(fd, 0, SEEK_END);
|
||||||
|
lseek(fd, 0, SEEK_SET);
|
||||||
|
*buf = mmap(NULL, *size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
|
||||||
|
close(fd);
|
||||||
|
}
|
||||||
|
|
||||||
|
file_t check_type(const unsigned char *buf) {
|
||||||
|
if (memcmp(buf, CHROMEOS_MAGIC, CHROMEOS_MAGIC_SIZE) == 0) {
|
||||||
|
return CHROMEOS;
|
||||||
|
} else if (memcmp(buf, BOOT_MAGIC, BOOT_MAGIC_SIZE) == 0) {
|
||||||
|
return AOSP;
|
||||||
|
} else if (memcmp(buf, ELF_MAGIC, ELF_MAGIC_SIZE) == 0) {
|
||||||
|
return ELF;
|
||||||
|
} else if (memcmp(buf, "\x1f\x8b\x08\x00", 4) == 0) {
|
||||||
|
return GZIP;
|
||||||
|
} else if (memcmp(buf, "\x89\x4c\x5a\x4f\x00\x0d\x0a\x1a\x0a", 9) == 0) {
|
||||||
|
return LZOP;
|
||||||
|
} else if (memcmp(buf, "\xfd""7zXZ\x00", 6) == 0) {
|
||||||
|
return XZ;
|
||||||
|
} else if (memcmp(buf, "\x5d\x00\x00", 3) == 0
|
||||||
|
&& (buf[12] == (unsigned char) '\xff' || buf[12] == (unsigned char) '\x00')) {
|
||||||
|
return LZMA;
|
||||||
|
} else if (memcmp(buf, "BZh", 3) == 0) {
|
||||||
|
return BZIP2;
|
||||||
|
} else if ( ( memcmp(buf, "\x04\x22\x4d\x18", 4) == 0
|
||||||
|
|| memcmp(buf, "\x03\x21\x4c\x18", 4) == 0)
|
||||||
|
|| memcmp(buf, "\x02\x21\x4c\x18", 4) == 0) {
|
||||||
|
return LZ4;
|
||||||
|
} else if (memcmp(buf, "\x88\x16\x88\x58", 4) == 0) {
|
||||||
|
return MTK;
|
||||||
|
} else if (memcmp(buf, "QCDT", 4) == 0) {
|
||||||
|
return QCDT;
|
||||||
|
} else {
|
||||||
|
return UNKNOWN;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void write_zero(int fd, size_t size) {
|
||||||
|
size_t pos = lseek(fd, 0, SEEK_CUR);
|
||||||
|
ftruncate(fd, pos + size);
|
||||||
|
lseek(fd, pos + size, SEEK_SET);
|
||||||
|
}
|
||||||
|
|
||||||
|
void mem_align(size_t *pos, size_t align) {
|
||||||
|
size_t mask = align - 1;
|
||||||
|
if (*pos & mask) {
|
||||||
|
*pos += align - (*pos & mask);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void file_align(int fd, size_t align, int out) {
|
||||||
|
size_t pos = lseek(fd, 0, SEEK_CUR);
|
||||||
|
size_t mask = align - 1;
|
||||||
|
size_t off;
|
||||||
|
if (pos & mask) {
|
||||||
|
off = align - (pos & mask);
|
||||||
|
if (out) {
|
||||||
|
write_zero(fd, off);
|
||||||
|
} else {
|
||||||
|
lseek(fd, pos + off, SEEK_SET);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int open_new(const char *filename) {
|
||||||
|
int fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0644);
|
||||||
|
if (fd < 0)
|
||||||
|
error(1, "Unable to create %s", filename);
|
||||||
|
return fd;
|
||||||
|
}
|
||||||
|
|
||||||
|
void print_info() {
|
||||||
|
printf("KERNEL [%d] @ 0x%08x\n", hdr.kernel_size, hdr.kernel_addr);
|
||||||
|
printf("RAMDISK [%d] @ 0x%08x\n", hdr.ramdisk_size, hdr.ramdisk_addr);
|
||||||
|
printf("SECOND [%d] @ 0x%08x\n", hdr.second_size, hdr.second_addr);
|
||||||
|
printf("DTB [%d] @ 0x%08x\n", hdr.dt_size, hdr.tags_addr);
|
||||||
|
printf("PAGESIZE [%d]\n", hdr.page_size);
|
||||||
|
if (hdr.os_version != 0) {
|
||||||
|
int a,b,c,y,m = 0;
|
||||||
|
int os_version, os_patch_level;
|
||||||
|
os_version = hdr.os_version >> 11;
|
||||||
|
os_patch_level = hdr.os_version & 0x7ff;
|
||||||
|
|
||||||
|
a = (os_version >> 14) & 0x7f;
|
||||||
|
b = (os_version >> 7) & 0x7f;
|
||||||
|
c = os_version & 0x7f;
|
||||||
|
printf("OS_VERSION [%d.%d.%d]\n", a, b, c);
|
||||||
|
|
||||||
|
y = (os_patch_level >> 4) + 2000;
|
||||||
|
m = os_patch_level & 0xf;
|
||||||
|
printf("PATCH_LEVEL [%d-%02d]\n", y, m);
|
||||||
|
}
|
||||||
|
printf("NAME [%s]\n", hdr.name);
|
||||||
|
printf("CMDLINE [%s]\n", hdr.cmdline);
|
||||||
|
|
||||||
|
switch (ramdisk_type) {
|
||||||
|
case GZIP:
|
||||||
|
printf("COMPRESSION [%s]\n", "gzip");
|
||||||
|
break;
|
||||||
|
case XZ:
|
||||||
|
printf("COMPRESSION [%s]\n", "xz");
|
||||||
|
break;
|
||||||
|
case LZMA:
|
||||||
|
printf("COMPRESSION [%s]\n", "lzma");
|
||||||
|
break;
|
||||||
|
case BZIP2:
|
||||||
|
printf("COMPRESSION [%s]\n", "bzip2");
|
||||||
|
break;
|
||||||
|
case LZ4:
|
||||||
|
printf("COMPRESSION [%s]\n", "lz4");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
fprintf(stderr, "Unknown ramdisk format!\n");
|
||||||
|
}
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
void cleanup() {
|
||||||
|
printf("Cleaning up...\n");
|
||||||
|
char name[PATH_MAX];
|
||||||
|
unlink(KERNEL_FILE);
|
||||||
|
unlink(RAMDISK_FILE);
|
||||||
|
unlink(RAMDISK_FILE ".unsupport");
|
||||||
|
unlink(SECOND_FILE);
|
||||||
|
unlink(DTB_FILE);
|
||||||
|
unlink(NEW_BOOT);
|
||||||
|
for (int i = 0; i < SUP_NUM; ++i) {
|
||||||
|
sprintf(name, "%s.%s", RAMDISK_FILE, SUP_EXT_LIST[i]);
|
||||||
|
unlink(name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void vec_init(vector *v) {
|
||||||
|
vec_size(v) = 0;
|
||||||
|
vec_cap(v) = 1;
|
||||||
|
vec_entry(v) = malloc(sizeof(void*));
|
||||||
|
}
|
||||||
|
|
||||||
|
void vec_push_back(vector *v, void *p) {
|
||||||
|
if (v == NULL) return;
|
||||||
|
if (vec_size(v) == vec_cap(v)) {
|
||||||
|
vec_cap(v) *= 2;
|
||||||
|
vec_entry(v) = realloc(vec_entry(v), sizeof(void*) * vec_cap(v));
|
||||||
|
}
|
||||||
|
vec_entry(v)[vec_size(v)] = p;
|
||||||
|
++vec_size(v);
|
||||||
|
}
|
||||||
|
|
||||||
|
void vec_sort(vector *v, int (*compar)(const void *, const void *)) {
|
||||||
|
qsort(vec_entry(v), vec_size(v), sizeof(void*), compar);
|
||||||
|
}
|
||||||
|
|
||||||
|
void vec_destroy(vector *v) {
|
||||||
|
// Will not free each entry!
|
||||||
|
// Manually free each entry, then call this function
|
||||||
|
vec_size(v) = 0;
|
||||||
|
vec_cap(v) = 0;
|
||||||
|
free(v->data);
|
||||||
|
}
|
165
jni/magiskhide.c
165
jni/magiskhide.c
@@ -1,165 +0,0 @@
|
|||||||
typedef unsigned short int sa_family_t;
|
|
||||||
//Linux includes
|
|
||||||
#define _LINUX_TIME_H
|
|
||||||
#define _GNU_SOURCE
|
|
||||||
#include <sys/types.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <sys/stat.h>
|
|
||||||
#include <fcntl.h>
|
|
||||||
#include <linux/connector.h>
|
|
||||||
#include <linux/cn_proc.h>
|
|
||||||
#include <linux/netlink.h>
|
|
||||||
#include <linux/fs.h>
|
|
||||||
#include <sys/socket.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <sys/time.h>
|
|
||||||
#include <sys/resource.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <sys/syscall.h>
|
|
||||||
#include <asm/unistd.h>
|
|
||||||
#include <sys/mount.h>
|
|
||||||
|
|
||||||
char **file_to_str_arr(FILE *fp, int *size) {
|
|
||||||
int allocated = 16;
|
|
||||||
char *line = NULL, **array;
|
|
||||||
size_t len = 0;
|
|
||||||
ssize_t read;
|
|
||||||
|
|
||||||
array = (char **) malloc(sizeof(char*) * allocated);
|
|
||||||
|
|
||||||
*size = 0;
|
|
||||||
while ((read = getline(&line, &len, fp)) != -1) {
|
|
||||||
if (*size >= allocated) {
|
|
||||||
// Double our allocation and re-allocate
|
|
||||||
allocated *= 2;
|
|
||||||
array = (char **) realloc(array, sizeof(char*) * allocated);
|
|
||||||
}
|
|
||||||
// Remove end newline
|
|
||||||
if (line[read - 1] == '\n') {
|
|
||||||
line[read - 1] = '\0';
|
|
||||||
}
|
|
||||||
array[*size] = line;
|
|
||||||
line = NULL;
|
|
||||||
++(*size);
|
|
||||||
}
|
|
||||||
return array;
|
|
||||||
}
|
|
||||||
|
|
||||||
//WARNING: Calling this will change our current namespace
|
|
||||||
//We don't care because we don't want to run from here anyway
|
|
||||||
int hideMagisk(int pid) {
|
|
||||||
char *path = NULL;
|
|
||||||
asprintf(&path, "/proc/%d/ns/mnt", pid);
|
|
||||||
int fd = open(path, O_RDONLY);
|
|
||||||
if(fd == -1) return 2;
|
|
||||||
int res = syscall(SYS_setns, fd, 0);
|
|
||||||
if(res == -1) return 3;
|
|
||||||
|
|
||||||
free(path);
|
|
||||||
path = NULL;
|
|
||||||
asprintf(&path, "/proc/%d/mounts", pid);
|
|
||||||
FILE *mount_fp = fopen(path, "r");
|
|
||||||
if (mount_fp == NULL) {
|
|
||||||
fprintf(stderr, "Error opening mount list!\n");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
free(path);
|
|
||||||
|
|
||||||
int mount_size;
|
|
||||||
char **mount_list = file_to_str_arr(mount_fp, &mount_size), mountpoint[256], *sbstr;
|
|
||||||
fclose(mount_fp);
|
|
||||||
|
|
||||||
int i, unmount = 0;
|
|
||||||
for(i = mount_size - 1; i >= 0; --i) {
|
|
||||||
if((strstr(mount_list[i], "/dev/block/loop") != NULL)) {
|
|
||||||
sscanf(mount_list[i], "%256s %256s", mountpoint, mountpoint);
|
|
||||||
if (strstr(mountpoint, "/.core/dummy") != NULL)
|
|
||||||
unmount = 0;
|
|
||||||
else
|
|
||||||
unmount = 1;
|
|
||||||
} else if ((sbstr = strstr(mount_list[i], "/.core/dummy")) != NULL) {
|
|
||||||
sscanf(sbstr, "/.core/dummy%256s", mountpoint);
|
|
||||||
unmount = 1;
|
|
||||||
}
|
|
||||||
if(unmount) {
|
|
||||||
unmount = 0;
|
|
||||||
res = umount2(mountpoint, MNT_DETACH);
|
|
||||||
if (res != -1) printf("Unmounted: %s\n", mountpoint);
|
|
||||||
else printf("Failed: %s\n", mountpoint);
|
|
||||||
}
|
|
||||||
free(mount_list[i]);
|
|
||||||
}
|
|
||||||
// Free memory
|
|
||||||
free(mount_list);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int main(int argc, char **argv, char **envp) {
|
|
||||||
if (argc != 2) {
|
|
||||||
fprintf(stderr, "%s <process/package name list>\n", argv[0]);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
int i, hide_size;
|
|
||||||
char **hide_list;
|
|
||||||
|
|
||||||
FILE *hide_fp = fopen(argv[1], "r");
|
|
||||||
if (hide_fp == NULL) {
|
|
||||||
fprintf(stderr, "Error opening hide list\n");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
hide_list = file_to_str_arr(hide_fp, &hide_size);
|
|
||||||
fclose(hide_fp);
|
|
||||||
|
|
||||||
printf("Get process / package name from config:\n");
|
|
||||||
for(i = 0; i < hide_size; i++)
|
|
||||||
printf("%s\n", hide_list[i]);
|
|
||||||
printf("\n");
|
|
||||||
|
|
||||||
char buffer[512];
|
|
||||||
FILE *p = popen("while true;do logcat -b events -v raw -s am_proc_start;sleep 1;done", "r");
|
|
||||||
while(!feof(p)) {
|
|
||||||
//Format of am_proc_start is (as of Android 5.1 and 6.0)
|
|
||||||
//UserID, pid, unix uid, processName, hostingType, hostingName
|
|
||||||
fgets(buffer, sizeof(buffer), p);
|
|
||||||
|
|
||||||
{
|
|
||||||
char *pos = buffer;
|
|
||||||
while(1) {
|
|
||||||
pos = strchr(pos, ',');
|
|
||||||
if(pos == NULL)
|
|
||||||
break;
|
|
||||||
pos[0] = ' ';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int user, pid, uid;
|
|
||||||
char processName[256], hostingType[16], hostingName[256];
|
|
||||||
int ret = sscanf(buffer, "[%d %d %d %256s %16s %256s]",
|
|
||||||
&user, &pid, &uid,
|
|
||||||
processName, hostingType, hostingName);
|
|
||||||
|
|
||||||
|
|
||||||
if(ret != 6) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
for (i = 0; i < hide_size; ++i) {
|
|
||||||
if(strstr(processName, hide_list[i]) != NULL) {
|
|
||||||
printf("Disabling for process = %s, PID = %d, UID = %d\n", processName, pid, uid);
|
|
||||||
hideMagisk(pid);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pclose(p);
|
|
||||||
|
|
||||||
// Free memory
|
|
||||||
for(i = 0; i < hide_size; ++i)
|
|
||||||
free(hide_list[i]);
|
|
||||||
free(hide_list);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
6
jni/magiskhide/Android.mk
Normal file
6
jni/magiskhide/Android.mk
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
LOCAL_PATH := $(call my-dir)
|
||||||
|
|
||||||
|
include $(CLEAR_VARS)
|
||||||
|
LOCAL_MODULE := magiskhide
|
||||||
|
LOCAL_SRC_FILES := main.c hide.c list_monitor.c proc_monitor.c util.c
|
||||||
|
include $(BUILD_EXECUTABLE)
|
78
jni/magiskhide/hide.c
Normal file
78
jni/magiskhide/hide.c
Normal file
@@ -0,0 +1,78 @@
|
|||||||
|
#include "magiskhide.h"
|
||||||
|
|
||||||
|
int hideMagisk() {
|
||||||
|
close(pipefd[1]);
|
||||||
|
|
||||||
|
int pid, fd;
|
||||||
|
char cache_block[256];
|
||||||
|
cache_block[0] = '\0';
|
||||||
|
|
||||||
|
while(1) {
|
||||||
|
read(pipefd[0], &pid, sizeof(pid));
|
||||||
|
// Termination called
|
||||||
|
if(pid == -1) break;
|
||||||
|
|
||||||
|
manage_selinux();
|
||||||
|
|
||||||
|
snprintf(buffer, sizeof(buffer), "/proc/%d/ns/mnt", pid);
|
||||||
|
if((fd = open(buffer, O_RDONLY)) == -1) continue; // Maybe process died..
|
||||||
|
if(setns(fd, 0) == -1) {
|
||||||
|
fprintf(logfile, "MagiskHide: Unable to change namespace for pid=%d\n", pid);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
close(fd);
|
||||||
|
|
||||||
|
snprintf(buffer, sizeof(buffer), "/proc/%d/mounts", pid);
|
||||||
|
FILE *mount_fp = fopen(buffer, "r");
|
||||||
|
if (mount_fp == NULL) {
|
||||||
|
fprintf(logfile, "MagiskHide: Error opening mount list!\n");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
int mount_size;
|
||||||
|
char **mount_list = file_to_str_arr(mount_fp, &mount_size);
|
||||||
|
|
||||||
|
// Find the cache block name if not found yet
|
||||||
|
if (strlen(cache_block) == 0) {
|
||||||
|
for(i = 0; i < mount_size; ++i) {
|
||||||
|
if (strstr(mount_list[i], " /cache ")) {
|
||||||
|
sscanf(mount_list[i], "%256s", cache_block);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// First unmount the dummy skeletons, cache mounts, and /sbin links
|
||||||
|
for(i = mount_size - 1; i >= 0; --i) {
|
||||||
|
if (strstr(mount_list[i], "tmpfs /system") || strstr(mount_list[i], "tmpfs /vendor")
|
||||||
|
|| strstr(mount_list[i], "tmpfs /sbin")
|
||||||
|
|| (strstr(mount_list[i], cache_block) && strstr(mount_list[i], "/system/")) ) {
|
||||||
|
sscanf(mount_list[i], "%*s %512s", buffer);
|
||||||
|
lazy_unmount(buffer);
|
||||||
|
}
|
||||||
|
free(mount_list[i]);
|
||||||
|
}
|
||||||
|
free(mount_list);
|
||||||
|
|
||||||
|
// Re-read mount infos
|
||||||
|
fseek(mount_fp, 0, SEEK_SET);
|
||||||
|
mount_list = file_to_str_arr(mount_fp, &mount_size);
|
||||||
|
fclose(mount_fp);
|
||||||
|
|
||||||
|
// Unmount loop mounts
|
||||||
|
for(i = mount_size - 1; i >= 0; --i) {
|
||||||
|
if (strstr(mount_list[i], "/dev/block/loop") && !strstr(mount_list[i], DUMMYPATH)) {
|
||||||
|
sscanf(mount_list[i], "%*s %512s", buffer);
|
||||||
|
lazy_unmount(buffer);
|
||||||
|
}
|
||||||
|
free(mount_list[i]);
|
||||||
|
}
|
||||||
|
free(mount_list);
|
||||||
|
|
||||||
|
// Send resume signal
|
||||||
|
kill(pid, SIGCONT);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Should never go here
|
||||||
|
return 1;
|
||||||
|
}
|
56
jni/magiskhide/list_monitor.c
Normal file
56
jni/magiskhide/list_monitor.c
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
#include "magiskhide.h"
|
||||||
|
|
||||||
|
void *monitor_list(void *path) {
|
||||||
|
char* listpath = (char*) path;
|
||||||
|
signal(SIGQUIT, quit_pthread);
|
||||||
|
|
||||||
|
int inotifyFd = -1;
|
||||||
|
char str[512];
|
||||||
|
|
||||||
|
while(1) {
|
||||||
|
if (inotifyFd == -1 || read(inotifyFd, str, sizeof(str)) == -1) {
|
||||||
|
close(inotifyFd);
|
||||||
|
inotifyFd = inotify_init();
|
||||||
|
if (inotifyFd == -1) {
|
||||||
|
fprintf(logfile, "MagiskHide: Unable to watch %s\n", listpath);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
if (inotify_add_watch(inotifyFd, listpath, IN_MODIFY) == -1) {
|
||||||
|
fprintf(logfile, "MagiskHide: Unable to watch %s\n", listpath);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
update_list(listpath);
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void update_list(const char *listpath) {
|
||||||
|
FILE *hide_fp = fopen(listpath, "r");
|
||||||
|
if (hide_fp == NULL) {
|
||||||
|
fprintf(logfile, "MagiskHide: Error opening hide list\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
pthread_mutex_lock(&mutex);
|
||||||
|
if (hide_list) {
|
||||||
|
// Free memory
|
||||||
|
for(i = 0; i < list_size; ++i)
|
||||||
|
free(hide_list[i]);
|
||||||
|
free(hide_list);
|
||||||
|
}
|
||||||
|
hide_list = file_to_str_arr(hide_fp, &list_size);
|
||||||
|
pthread_mutex_unlock(&mutex);
|
||||||
|
fclose(hide_fp);
|
||||||
|
if (list_size) fprintf(logfile, "MagiskHide: Update process/package list:\n");
|
||||||
|
for(i = 0; i < list_size; i++)
|
||||||
|
fprintf(logfile, "MagiskHide: [%s]\n", hide_list[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
void quit_pthread(int sig) {
|
||||||
|
// Free memory
|
||||||
|
for(i = 0; i < list_size; ++i)
|
||||||
|
free(hide_list[i]);
|
||||||
|
free(hide_list);
|
||||||
|
pthread_exit(NULL);
|
||||||
|
}
|
52
jni/magiskhide/magiskhide.h
Normal file
52
jni/magiskhide/magiskhide.h
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
#ifndef MAGISK_HIDE_H
|
||||||
|
#define MAGISK_HIDE_H
|
||||||
|
|
||||||
|
#define _GNU_SOURCE
|
||||||
|
#include <string.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <sched.h>
|
||||||
|
#include <pthread.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <signal.h>
|
||||||
|
|
||||||
|
#include <sys/mount.h>
|
||||||
|
#include <sys/inotify.h>
|
||||||
|
#include <sys/wait.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <sys/resource.h>
|
||||||
|
|
||||||
|
#define LOGFILE "/cache/magisk.log"
|
||||||
|
#define HIDELIST "/magisk/.core/magiskhide/hidelist"
|
||||||
|
#define DUMMYPATH "/dev/magisk/dummy"
|
||||||
|
#define ENFORCE_FILE "/sys/fs/selinux/enforce"
|
||||||
|
#define SEPOLICY_INJECT "/data/magisk/magiskpolicy"
|
||||||
|
|
||||||
|
// Main thread
|
||||||
|
void monitor_proc();
|
||||||
|
|
||||||
|
// Forked process for namespace setting
|
||||||
|
int hideMagisk();
|
||||||
|
|
||||||
|
// List monitor thread
|
||||||
|
void update_list(const char *listpath);
|
||||||
|
void quit_pthread(int sig);
|
||||||
|
void *monitor_list(void *path);
|
||||||
|
|
||||||
|
// Util functions
|
||||||
|
char **file_to_str_arr(FILE *fp, int *size);
|
||||||
|
void read_namespace(const int pid, char* target, const size_t size);
|
||||||
|
void lazy_unmount(const char* mountpoint);
|
||||||
|
void run_as_daemon();
|
||||||
|
void manage_selinux();
|
||||||
|
|
||||||
|
// Global variable sharing through process/threads
|
||||||
|
extern FILE *logfile;
|
||||||
|
extern int i, list_size, pipefd[2];
|
||||||
|
extern char **hide_list, buffer[512];
|
||||||
|
extern pthread_t list_monitor;
|
||||||
|
extern pthread_mutex_t mutex;
|
||||||
|
|
||||||
|
#endif
|
65
jni/magiskhide/main.c
Normal file
65
jni/magiskhide/main.c
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
#include "magiskhide.h"
|
||||||
|
|
||||||
|
FILE *logfile;
|
||||||
|
int i, list_size, pipefd[2];
|
||||||
|
char **hide_list = NULL, buffer[512];
|
||||||
|
pthread_t list_monitor;
|
||||||
|
pthread_mutex_t mutex;
|
||||||
|
|
||||||
|
static void terminate(int sig) {
|
||||||
|
// Close the config list monitor
|
||||||
|
pthread_kill(list_monitor, SIGQUIT);
|
||||||
|
pthread_mutex_destroy(&mutex);
|
||||||
|
|
||||||
|
// Terminate our children
|
||||||
|
i = -1;
|
||||||
|
write(pipefd[1], &i, sizeof(i));
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char *argv[]) {
|
||||||
|
|
||||||
|
if (argc > 1) {
|
||||||
|
if (strcmp(argv[1], "--daemon") == 0)
|
||||||
|
run_as_daemon();
|
||||||
|
else {
|
||||||
|
fprintf(stderr, "%s (with no options)\n\tRun magiskhide and output to stdout\n", argv[0]);
|
||||||
|
fprintf(stderr, "%s --daemon\n\tRun magiskhide as daemon, output to magisk.log\n", argv[0]);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
logfile = stdout;
|
||||||
|
|
||||||
|
|
||||||
|
// Handle all killing signals
|
||||||
|
signal(SIGINT, terminate);
|
||||||
|
signal(SIGTERM, terminate);
|
||||||
|
|
||||||
|
// Fork a child to handle namespace switches and unmounts
|
||||||
|
pipe(pipefd);
|
||||||
|
switch(fork()) {
|
||||||
|
case -1:
|
||||||
|
exit(-1);
|
||||||
|
case 0:
|
||||||
|
return hideMagisk();
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
close(pipefd[0]);
|
||||||
|
|
||||||
|
// Start a thread to constantly check the hide list
|
||||||
|
pthread_mutex_init(&mutex, NULL);
|
||||||
|
pthread_create(&list_monitor, NULL, monitor_list, HIDELIST);
|
||||||
|
|
||||||
|
// Set main process to the top priority
|
||||||
|
setpriority(PRIO_PROCESS, 0, -20);
|
||||||
|
|
||||||
|
monitor_proc();
|
||||||
|
|
||||||
|
terminate(0);
|
||||||
|
|
||||||
|
fprintf(logfile, "MagiskHide: Cannot monitor am_proc_start, abort...\n");
|
||||||
|
fclose(logfile);
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
82
jni/magiskhide/proc_monitor.c
Normal file
82
jni/magiskhide/proc_monitor.c
Normal file
@@ -0,0 +1,82 @@
|
|||||||
|
#include "magiskhide.h"
|
||||||
|
|
||||||
|
void monitor_proc() {
|
||||||
|
int pid, badns, zygote_num = 0;
|
||||||
|
char init_ns[32], zygote_ns[2][32];
|
||||||
|
|
||||||
|
// Get the mount namespace of init
|
||||||
|
read_namespace(1, init_ns, 32);
|
||||||
|
|
||||||
|
printf("%s\n", init_ns);
|
||||||
|
|
||||||
|
// Get the mount namespace of zygote
|
||||||
|
FILE *p = popen("ps | grep zygote | grep -v grep", "r");
|
||||||
|
while(fgets(buffer, sizeof(buffer), p)) {
|
||||||
|
if (zygote_num == 2) break;
|
||||||
|
sscanf(buffer, "%d", &pid);
|
||||||
|
do {
|
||||||
|
usleep(500);
|
||||||
|
read_namespace(pid, zygote_ns[zygote_num], 32);
|
||||||
|
} while (strcmp(zygote_ns[zygote_num], init_ns) == 0);
|
||||||
|
++zygote_num;
|
||||||
|
}
|
||||||
|
pclose(p);
|
||||||
|
|
||||||
|
for (i = 0; i < zygote_num; ++i)
|
||||||
|
fprintf(logfile, "Zygote(%d) ns=%s ", i, zygote_ns[i]);
|
||||||
|
fprintf(logfile, "\n");
|
||||||
|
|
||||||
|
// Monitor am_proc_start
|
||||||
|
p = popen("while true; do logcat -b events -c; logcat -b events -v raw -s am_proc_start; sleep 1; done", "r");
|
||||||
|
|
||||||
|
while(!feof(p)) {
|
||||||
|
//Format of am_proc_start is (as of Android 5.1 and 6.0)
|
||||||
|
//UserID, pid, unix uid, processName, hostingType, hostingName
|
||||||
|
fgets(buffer, sizeof(buffer), p);
|
||||||
|
|
||||||
|
char *pos = buffer;
|
||||||
|
while(1) {
|
||||||
|
pos = strchr(pos, ',');
|
||||||
|
if(pos == NULL)
|
||||||
|
break;
|
||||||
|
pos[0] = ' ';
|
||||||
|
}
|
||||||
|
|
||||||
|
char processName[256];
|
||||||
|
int ret = sscanf(buffer, "[%*d %d %*d %256s", &pid, processName);
|
||||||
|
|
||||||
|
if(ret != 2)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
pthread_mutex_lock(&mutex);
|
||||||
|
for (i = 0; i < list_size; ++i) {
|
||||||
|
if(strcmp(processName, hide_list[i]) == 0) {
|
||||||
|
while(1) {
|
||||||
|
badns = 0;
|
||||||
|
read_namespace(pid, buffer, 32);
|
||||||
|
for (i = 0; i < zygote_num; ++i) {
|
||||||
|
if (strcmp(buffer, zygote_ns[i]) == 0) {
|
||||||
|
usleep(500);
|
||||||
|
badns = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!badns) break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Send pause signal ASAP
|
||||||
|
if (kill(pid, SIGSTOP) == -1) continue;
|
||||||
|
|
||||||
|
fprintf(logfile, "MagiskHide: %s(PID=%d ns=%s)\n", processName, pid, buffer);
|
||||||
|
|
||||||
|
// Unmount start
|
||||||
|
write(pipefd[1], &pid, sizeof(pid));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pthread_mutex_unlock(&mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Close the logcat monitor
|
||||||
|
pclose(p);
|
||||||
|
}
|
91
jni/magiskhide/util.c
Normal file
91
jni/magiskhide/util.c
Normal file
@@ -0,0 +1,91 @@
|
|||||||
|
#include "magiskhide.h"
|
||||||
|
|
||||||
|
char **file_to_str_arr(FILE *fp, int *size) {
|
||||||
|
int allocated = 16;
|
||||||
|
char *line = NULL, **array;
|
||||||
|
size_t len = 0;
|
||||||
|
ssize_t read;
|
||||||
|
|
||||||
|
array = (char **) malloc(sizeof(char*) * allocated);
|
||||||
|
|
||||||
|
*size = 0;
|
||||||
|
while ((read = getline(&line, &len, fp)) != -1) {
|
||||||
|
if (*size >= allocated) {
|
||||||
|
// Double our allocation and re-allocate
|
||||||
|
allocated *= 2;
|
||||||
|
array = (char **) realloc(array, sizeof(char*) * allocated);
|
||||||
|
}
|
||||||
|
// Remove end newline
|
||||||
|
if (line[read - 1] == '\n') {
|
||||||
|
line[read - 1] = '\0';
|
||||||
|
}
|
||||||
|
array[*size] = line;
|
||||||
|
line = NULL;
|
||||||
|
++(*size);
|
||||||
|
}
|
||||||
|
return array;
|
||||||
|
}
|
||||||
|
|
||||||
|
void read_namespace(const int pid, char* target, const size_t size) {
|
||||||
|
char path[32];
|
||||||
|
snprintf(path, sizeof(path), "/proc/%d/ns/mnt", pid);
|
||||||
|
ssize_t len = readlink(path, target, size);
|
||||||
|
target[len] = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
void lazy_unmount(const char* mountpoint) {
|
||||||
|
if (umount2(mountpoint, MNT_DETACH) != -1)
|
||||||
|
fprintf(logfile, "MagiskHide: Unmounted (%s)\n", mountpoint);
|
||||||
|
else
|
||||||
|
fprintf(logfile, "MagiskHide: Unmount Failed (%s)\n", mountpoint);
|
||||||
|
}
|
||||||
|
|
||||||
|
void run_as_daemon() {
|
||||||
|
switch(fork()) {
|
||||||
|
case -1:
|
||||||
|
exit(-1);
|
||||||
|
case 0:
|
||||||
|
if (setsid() < 0)
|
||||||
|
exit(-1);
|
||||||
|
close(STDIN_FILENO);
|
||||||
|
close(STDOUT_FILENO);
|
||||||
|
close(STDERR_FILENO);
|
||||||
|
logfile = fopen(LOGFILE, "a+");
|
||||||
|
setbuf(logfile, NULL);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void manage_selinux() {
|
||||||
|
char *argv[] = { SEPOLICY_INJECT, "--live", "permissive *", NULL };
|
||||||
|
char str[20];
|
||||||
|
int fd, ret;
|
||||||
|
fd = open(ENFORCE_FILE, O_RDONLY);
|
||||||
|
if (fd < 0)
|
||||||
|
return;
|
||||||
|
ret = read(fd, str, 20);
|
||||||
|
close(fd);
|
||||||
|
if (ret < 1)
|
||||||
|
return;
|
||||||
|
// Permissive
|
||||||
|
if (str[0] == '0') {
|
||||||
|
fprintf(logfile, "MagiskHide: Permissive detected, switching to pseudo enforced\n");
|
||||||
|
fd = open(ENFORCE_FILE, O_RDWR);
|
||||||
|
if (fd < 0)
|
||||||
|
return;
|
||||||
|
ret = write(fd, "1", 1);
|
||||||
|
close(fd);
|
||||||
|
if (ret < 1)
|
||||||
|
return;
|
||||||
|
switch(fork()) {
|
||||||
|
case -1:
|
||||||
|
return;
|
||||||
|
case 0:
|
||||||
|
execvp(argv[0], argv);
|
||||||
|
default:
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
1
jni/magiskpolicy
Submodule
1
jni/magiskpolicy
Submodule
Submodule jni/magiskpolicy added at 2e6bea23ac
1
jni/ndk-compression
Submodule
1
jni/ndk-compression
Submodule
Submodule jni/ndk-compression added at b0579533d1
144
jni/repack.c
144
jni/repack.c
@@ -1,144 +0,0 @@
|
|||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <sys/types.h>
|
|
||||||
#include <sys/stat.h>
|
|
||||||
#include <sys/sendfile.h>
|
|
||||||
#include <sys/mman.h>
|
|
||||||
#include <fcntl.h>
|
|
||||||
#include <assert.h>
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
#include "bootimgtools.h"
|
|
||||||
|
|
||||||
off_t file_size(char *filename) {
|
|
||||||
struct stat st;
|
|
||||||
if(stat(filename, &st))
|
|
||||||
exit(1);
|
|
||||||
return st.st_size;
|
|
||||||
}
|
|
||||||
|
|
||||||
int append_file(int ofd, char *filename, off_t pos) {
|
|
||||||
lseek(ofd, pos, SEEK_SET);
|
|
||||||
int fd = open(filename, O_RDONLY);
|
|
||||||
int size = lseek(fd, 0, SEEK_END);
|
|
||||||
lseek(fd, 0, SEEK_SET);
|
|
||||||
sendfile(ofd, fd, NULL, size);
|
|
||||||
close(fd);
|
|
||||||
return size;
|
|
||||||
}
|
|
||||||
|
|
||||||
int append_ramdisk(int ofd, off_t pos) {
|
|
||||||
if(access("ramdisk-mtk", R_OK) == 0) {
|
|
||||||
char buf[512];
|
|
||||||
off_t size = file_size("ramdisk.gz");
|
|
||||||
memcpy(buf, "\x88\x16\x88\x58", 4);
|
|
||||||
uint32_t v = size;
|
|
||||||
memcpy(buf+4, &v, sizeof(v)); //Should convert to LE
|
|
||||||
|
|
||||||
//TODO: RECOVERY OR ROOTFS?
|
|
||||||
char str[32];
|
|
||||||
memset(str, 0, sizeof(str));
|
|
||||||
if(access("ramdisk-mtk-boot", R_OK)==0) {
|
|
||||||
strcpy(str, "ROOTFS");
|
|
||||||
} else if(access("ramdisk-mtk-recovery", R_OK)==0) {
|
|
||||||
strcpy(str, "RECOVERY");
|
|
||||||
} else {
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
memcpy(buf+8, str, sizeof(str));
|
|
||||||
|
|
||||||
memset(buf+8+sizeof(str), 0xff, 512-8-sizeof(str));
|
|
||||||
|
|
||||||
pwrite(ofd, buf, sizeof(buf), pos);
|
|
||||||
|
|
||||||
return append_file(ofd, "ramdisk.gz", pos + 512) + 512;
|
|
||||||
} else if(access("ramdisk.gz", R_OK) == 0) {
|
|
||||||
return append_file(ofd, "ramdisk.gz", pos);
|
|
||||||
} else {
|
|
||||||
return append_file(ofd, "ramdisk", pos);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void post_process(struct boot_img_hdr *hdr, int ofd, int pos) {
|
|
||||||
if(access("rkcrc", R_OK) == 0) {
|
|
||||||
fprintf(stderr, "Rockchip CRCs not supported yet\n");
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
//Round up the file size
|
|
||||||
ftruncate(ofd, pos);
|
|
||||||
}
|
|
||||||
|
|
||||||
int repack(char *image) {
|
|
||||||
|
|
||||||
//TODO: Merge with extract.c?
|
|
||||||
//{
|
|
||||||
int ifd = open(image, O_RDONLY);
|
|
||||||
off_t isize = lseek(ifd, 0, SEEK_END);
|
|
||||||
lseek(ifd, 0, SEEK_SET);
|
|
||||||
uint8_t *iorig = mmap(NULL, isize, PROT_READ, MAP_SHARED, ifd, 0);
|
|
||||||
uint8_t *ibase = iorig;
|
|
||||||
assert(ibase);
|
|
||||||
|
|
||||||
while(ibase<(iorig+isize)) {
|
|
||||||
if(memcmp(ibase, BOOT_MAGIC, BOOT_MAGIC_SIZE) == 0)
|
|
||||||
break;
|
|
||||||
ibase += 256;
|
|
||||||
}
|
|
||||||
assert(ibase < (iorig+isize));
|
|
||||||
//}
|
|
||||||
//
|
|
||||||
struct boot_img_hdr *ihdr = (struct boot_img_hdr*) ibase;
|
|
||||||
assert(
|
|
||||||
ihdr->page_size == 2048 ||
|
|
||||||
ihdr->page_size == 4096 ||
|
|
||||||
ihdr->page_size == 16384
|
|
||||||
);
|
|
||||||
|
|
||||||
unlink("new-boot.img");
|
|
||||||
int ofd = open("new-boot.img", O_RDWR|O_CREAT, 0644);
|
|
||||||
ftruncate(ofd, ihdr->page_size);
|
|
||||||
//Write back original header, we'll change it later
|
|
||||||
write(ofd, ihdr, sizeof(*ihdr));
|
|
||||||
|
|
||||||
struct boot_img_hdr *hdr = mmap(NULL, sizeof(*ihdr), PROT_READ|PROT_WRITE, MAP_SHARED, ofd, 0);
|
|
||||||
//First set everything to zero, so we know where we are at.
|
|
||||||
hdr->kernel_size = 0;
|
|
||||||
hdr->ramdisk_size = 0;
|
|
||||||
hdr->second_size = 0;
|
|
||||||
hdr->unused[0] = 0;
|
|
||||||
memset(hdr->id, 0, sizeof(hdr->id)); //Setting id to 0 might be wrong?
|
|
||||||
|
|
||||||
int pos = hdr->page_size;
|
|
||||||
int size = 0;
|
|
||||||
|
|
||||||
size = append_file(ofd, "kernel", pos);
|
|
||||||
pos += size + hdr->page_size - 1;
|
|
||||||
pos &= ~(hdr->page_size-1);
|
|
||||||
hdr->kernel_size = size;
|
|
||||||
|
|
||||||
size = append_ramdisk(ofd, pos);
|
|
||||||
pos += size + hdr->page_size - 1;
|
|
||||||
pos &= ~(hdr->page_size-1);
|
|
||||||
hdr->ramdisk_size = size;
|
|
||||||
|
|
||||||
if(access("second", R_OK) == 0) {
|
|
||||||
size = append_file(ofd, "second", pos);
|
|
||||||
pos += size + hdr->page_size - 1;
|
|
||||||
pos &= ~(hdr->page_size-1);
|
|
||||||
hdr->second_size = size;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(access("dt", R_OK) == 0) {
|
|
||||||
size = append_file(ofd, "dt", pos);
|
|
||||||
pos += size + hdr->page_size - 1;
|
|
||||||
pos &= ~(hdr->page_size-1);
|
|
||||||
hdr->unused[0] = size;
|
|
||||||
}
|
|
||||||
|
|
||||||
post_process(hdr, ofd, pos);
|
|
||||||
munmap(hdr, sizeof(*ihdr));
|
|
||||||
close(ofd);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
7
jni/resetprop/Android.mk
Normal file
7
jni/resetprop/Android.mk
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
LOCAL_PATH := $(call my-dir)
|
||||||
|
|
||||||
|
include $(CLEAR_VARS)
|
||||||
|
LOCAL_MODULE := resetprop
|
||||||
|
LOCAL_SRC_FILES := resetprop.cpp system_properties.cpp libc_logging.cpp
|
||||||
|
LOCAL_LDLIBS += -latomic
|
||||||
|
include $(BUILD_EXECUTABLE)
|
339
jni/resetprop/LICENSE
Normal file
339
jni/resetprop/LICENSE
Normal file
@@ -0,0 +1,339 @@
|
|||||||
|
GNU GENERAL PUBLIC LICENSE
|
||||||
|
Version 2, June 1991
|
||||||
|
|
||||||
|
Copyright (C) 1989, 1991 Free Software Foundation, Inc., <http://fsf.org/>
|
||||||
|
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
Everyone is permitted to copy and distribute verbatim copies
|
||||||
|
of this license document, but changing it is not allowed.
|
||||||
|
|
||||||
|
Preamble
|
||||||
|
|
||||||
|
The licenses for most software are designed to take away your
|
||||||
|
freedom to share and change it. By contrast, the GNU General Public
|
||||||
|
License is intended to guarantee your freedom to share and change free
|
||||||
|
software--to make sure the software is free for all its users. This
|
||||||
|
General Public License applies to most of the Free Software
|
||||||
|
Foundation's software and to any other program whose authors commit to
|
||||||
|
using it. (Some other Free Software Foundation software is covered by
|
||||||
|
the GNU Lesser General Public License instead.) You can apply it to
|
||||||
|
your programs, too.
|
||||||
|
|
||||||
|
When we speak of free software, we are referring to freedom, not
|
||||||
|
price. Our General Public Licenses are designed to make sure that you
|
||||||
|
have the freedom to distribute copies of free software (and charge for
|
||||||
|
this service if you wish), that you receive source code or can get it
|
||||||
|
if you want it, that you can change the software or use pieces of it
|
||||||
|
in new free programs; and that you know you can do these things.
|
||||||
|
|
||||||
|
To protect your rights, we need to make restrictions that forbid
|
||||||
|
anyone to deny you these rights or to ask you to surrender the rights.
|
||||||
|
These restrictions translate to certain responsibilities for you if you
|
||||||
|
distribute copies of the software, or if you modify it.
|
||||||
|
|
||||||
|
For example, if you distribute copies of such a program, whether
|
||||||
|
gratis or for a fee, you must give the recipients all the rights that
|
||||||
|
you have. You must make sure that they, too, receive or can get the
|
||||||
|
source code. And you must show them these terms so they know their
|
||||||
|
rights.
|
||||||
|
|
||||||
|
We protect your rights with two steps: (1) copyright the software, and
|
||||||
|
(2) offer you this license which gives you legal permission to copy,
|
||||||
|
distribute and/or modify the software.
|
||||||
|
|
||||||
|
Also, for each author's protection and ours, we want to make certain
|
||||||
|
that everyone understands that there is no warranty for this free
|
||||||
|
software. If the software is modified by someone else and passed on, we
|
||||||
|
want its recipients to know that what they have is not the original, so
|
||||||
|
that any problems introduced by others will not reflect on the original
|
||||||
|
authors' reputations.
|
||||||
|
|
||||||
|
Finally, any free program is threatened constantly by software
|
||||||
|
patents. We wish to avoid the danger that redistributors of a free
|
||||||
|
program will individually obtain patent licenses, in effect making the
|
||||||
|
program proprietary. To prevent this, we have made it clear that any
|
||||||
|
patent must be licensed for everyone's free use or not licensed at all.
|
||||||
|
|
||||||
|
The precise terms and conditions for copying, distribution and
|
||||||
|
modification follow.
|
||||||
|
|
||||||
|
GNU GENERAL PUBLIC LICENSE
|
||||||
|
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||||
|
|
||||||
|
0. This License applies to any program or other work which contains
|
||||||
|
a notice placed by the copyright holder saying it may be distributed
|
||||||
|
under the terms of this General Public License. The "Program", below,
|
||||||
|
refers to any such program or work, and a "work based on the Program"
|
||||||
|
means either the Program or any derivative work under copyright law:
|
||||||
|
that is to say, a work containing the Program or a portion of it,
|
||||||
|
either verbatim or with modifications and/or translated into another
|
||||||
|
language. (Hereinafter, translation is included without limitation in
|
||||||
|
the term "modification".) Each licensee is addressed as "you".
|
||||||
|
|
||||||
|
Activities other than copying, distribution and modification are not
|
||||||
|
covered by this License; they are outside its scope. The act of
|
||||||
|
running the Program is not restricted, and the output from the Program
|
||||||
|
is covered only if its contents constitute a work based on the
|
||||||
|
Program (independent of having been made by running the Program).
|
||||||
|
Whether that is true depends on what the Program does.
|
||||||
|
|
||||||
|
1. You may copy and distribute verbatim copies of the Program's
|
||||||
|
source code as you receive it, in any medium, provided that you
|
||||||
|
conspicuously and appropriately publish on each copy an appropriate
|
||||||
|
copyright notice and disclaimer of warranty; keep intact all the
|
||||||
|
notices that refer to this License and to the absence of any warranty;
|
||||||
|
and give any other recipients of the Program a copy of this License
|
||||||
|
along with the Program.
|
||||||
|
|
||||||
|
You may charge a fee for the physical act of transferring a copy, and
|
||||||
|
you may at your option offer warranty protection in exchange for a fee.
|
||||||
|
|
||||||
|
2. You may modify your copy or copies of the Program or any portion
|
||||||
|
of it, thus forming a work based on the Program, and copy and
|
||||||
|
distribute such modifications or work under the terms of Section 1
|
||||||
|
above, provided that you also meet all of these conditions:
|
||||||
|
|
||||||
|
a) You must cause the modified files to carry prominent notices
|
||||||
|
stating that you changed the files and the date of any change.
|
||||||
|
|
||||||
|
b) You must cause any work that you distribute or publish, that in
|
||||||
|
whole or in part contains or is derived from the Program or any
|
||||||
|
part thereof, to be licensed as a whole at no charge to all third
|
||||||
|
parties under the terms of this License.
|
||||||
|
|
||||||
|
c) If the modified program normally reads commands interactively
|
||||||
|
when run, you must cause it, when started running for such
|
||||||
|
interactive use in the most ordinary way, to print or display an
|
||||||
|
announcement including an appropriate copyright notice and a
|
||||||
|
notice that there is no warranty (or else, saying that you provide
|
||||||
|
a warranty) and that users may redistribute the program under
|
||||||
|
these conditions, and telling the user how to view a copy of this
|
||||||
|
License. (Exception: if the Program itself is interactive but
|
||||||
|
does not normally print such an announcement, your work based on
|
||||||
|
the Program is not required to print an announcement.)
|
||||||
|
|
||||||
|
These requirements apply to the modified work as a whole. If
|
||||||
|
identifiable sections of that work are not derived from the Program,
|
||||||
|
and can be reasonably considered independent and separate works in
|
||||||
|
themselves, then this License, and its terms, do not apply to those
|
||||||
|
sections when you distribute them as separate works. But when you
|
||||||
|
distribute the same sections as part of a whole which is a work based
|
||||||
|
on the Program, the distribution of the whole must be on the terms of
|
||||||
|
this License, whose permissions for other licensees extend to the
|
||||||
|
entire whole, and thus to each and every part regardless of who wrote it.
|
||||||
|
|
||||||
|
Thus, it is not the intent of this section to claim rights or contest
|
||||||
|
your rights to work written entirely by you; rather, the intent is to
|
||||||
|
exercise the right to control the distribution of derivative or
|
||||||
|
collective works based on the Program.
|
||||||
|
|
||||||
|
In addition, mere aggregation of another work not based on the Program
|
||||||
|
with the Program (or with a work based on the Program) on a volume of
|
||||||
|
a storage or distribution medium does not bring the other work under
|
||||||
|
the scope of this License.
|
||||||
|
|
||||||
|
3. You may copy and distribute the Program (or a work based on it,
|
||||||
|
under Section 2) in object code or executable form under the terms of
|
||||||
|
Sections 1 and 2 above provided that you also do one of the following:
|
||||||
|
|
||||||
|
a) Accompany it with the complete corresponding machine-readable
|
||||||
|
source code, which must be distributed under the terms of Sections
|
||||||
|
1 and 2 above on a medium customarily used for software interchange; or,
|
||||||
|
|
||||||
|
b) Accompany it with a written offer, valid for at least three
|
||||||
|
years, to give any third party, for a charge no more than your
|
||||||
|
cost of physically performing source distribution, a complete
|
||||||
|
machine-readable copy of the corresponding source code, to be
|
||||||
|
distributed under the terms of Sections 1 and 2 above on a medium
|
||||||
|
customarily used for software interchange; or,
|
||||||
|
|
||||||
|
c) Accompany it with the information you received as to the offer
|
||||||
|
to distribute corresponding source code. (This alternative is
|
||||||
|
allowed only for noncommercial distribution and only if you
|
||||||
|
received the program in object code or executable form with such
|
||||||
|
an offer, in accord with Subsection b above.)
|
||||||
|
|
||||||
|
The source code for a work means the preferred form of the work for
|
||||||
|
making modifications to it. For an executable work, complete source
|
||||||
|
code means all the source code for all modules it contains, plus any
|
||||||
|
associated interface definition files, plus the scripts used to
|
||||||
|
control compilation and installation of the executable. However, as a
|
||||||
|
special exception, the source code distributed need not include
|
||||||
|
anything that is normally distributed (in either source or binary
|
||||||
|
form) with the major components (compiler, kernel, and so on) of the
|
||||||
|
operating system on which the executable runs, unless that component
|
||||||
|
itself accompanies the executable.
|
||||||
|
|
||||||
|
If distribution of executable or object code is made by offering
|
||||||
|
access to copy from a designated place, then offering equivalent
|
||||||
|
access to copy the source code from the same place counts as
|
||||||
|
distribution of the source code, even though third parties are not
|
||||||
|
compelled to copy the source along with the object code.
|
||||||
|
|
||||||
|
4. You may not copy, modify, sublicense, or distribute the Program
|
||||||
|
except as expressly provided under this License. Any attempt
|
||||||
|
otherwise to copy, modify, sublicense or distribute the Program is
|
||||||
|
void, and will automatically terminate your rights under this License.
|
||||||
|
However, parties who have received copies, or rights, from you under
|
||||||
|
this License will not have their licenses terminated so long as such
|
||||||
|
parties remain in full compliance.
|
||||||
|
|
||||||
|
5. You are not required to accept this License, since you have not
|
||||||
|
signed it. However, nothing else grants you permission to modify or
|
||||||
|
distribute the Program or its derivative works. These actions are
|
||||||
|
prohibited by law if you do not accept this License. Therefore, by
|
||||||
|
modifying or distributing the Program (or any work based on the
|
||||||
|
Program), you indicate your acceptance of this License to do so, and
|
||||||
|
all its terms and conditions for copying, distributing or modifying
|
||||||
|
the Program or works based on it.
|
||||||
|
|
||||||
|
6. Each time you redistribute the Program (or any work based on the
|
||||||
|
Program), the recipient automatically receives a license from the
|
||||||
|
original licensor to copy, distribute or modify the Program subject to
|
||||||
|
these terms and conditions. You may not impose any further
|
||||||
|
restrictions on the recipients' exercise of the rights granted herein.
|
||||||
|
You are not responsible for enforcing compliance by third parties to
|
||||||
|
this License.
|
||||||
|
|
||||||
|
7. If, as a consequence of a court judgment or allegation of patent
|
||||||
|
infringement or for any other reason (not limited to patent issues),
|
||||||
|
conditions are imposed on you (whether by court order, agreement or
|
||||||
|
otherwise) that contradict the conditions of this License, they do not
|
||||||
|
excuse you from the conditions of this License. If you cannot
|
||||||
|
distribute so as to satisfy simultaneously your obligations under this
|
||||||
|
License and any other pertinent obligations, then as a consequence you
|
||||||
|
may not distribute the Program at all. For example, if a patent
|
||||||
|
license would not permit royalty-free redistribution of the Program by
|
||||||
|
all those who receive copies directly or indirectly through you, then
|
||||||
|
the only way you could satisfy both it and this License would be to
|
||||||
|
refrain entirely from distribution of the Program.
|
||||||
|
|
||||||
|
If any portion of this section is held invalid or unenforceable under
|
||||||
|
any particular circumstance, the balance of the section is intended to
|
||||||
|
apply and the section as a whole is intended to apply in other
|
||||||
|
circumstances.
|
||||||
|
|
||||||
|
It is not the purpose of this section to induce you to infringe any
|
||||||
|
patents or other property right claims or to contest validity of any
|
||||||
|
such claims; this section has the sole purpose of protecting the
|
||||||
|
integrity of the free software distribution system, which is
|
||||||
|
implemented by public license practices. Many people have made
|
||||||
|
generous contributions to the wide range of software distributed
|
||||||
|
through that system in reliance on consistent application of that
|
||||||
|
system; it is up to the author/donor to decide if he or she is willing
|
||||||
|
to distribute software through any other system and a licensee cannot
|
||||||
|
impose that choice.
|
||||||
|
|
||||||
|
This section is intended to make thoroughly clear what is believed to
|
||||||
|
be a consequence of the rest of this License.
|
||||||
|
|
||||||
|
8. If the distribution and/or use of the Program is restricted in
|
||||||
|
certain countries either by patents or by copyrighted interfaces, the
|
||||||
|
original copyright holder who places the Program under this License
|
||||||
|
may add an explicit geographical distribution limitation excluding
|
||||||
|
those countries, so that distribution is permitted only in or among
|
||||||
|
countries not thus excluded. In such case, this License incorporates
|
||||||
|
the limitation as if written in the body of this License.
|
||||||
|
|
||||||
|
9. The Free Software Foundation may publish revised and/or new versions
|
||||||
|
of the General Public License from time to time. Such new versions will
|
||||||
|
be similar in spirit to the present version, but may differ in detail to
|
||||||
|
address new problems or concerns.
|
||||||
|
|
||||||
|
Each version is given a distinguishing version number. If the Program
|
||||||
|
specifies a version number of this License which applies to it and "any
|
||||||
|
later version", you have the option of following the terms and conditions
|
||||||
|
either of that version or of any later version published by the Free
|
||||||
|
Software Foundation. If the Program does not specify a version number of
|
||||||
|
this License, you may choose any version ever published by the Free Software
|
||||||
|
Foundation.
|
||||||
|
|
||||||
|
10. If you wish to incorporate parts of the Program into other free
|
||||||
|
programs whose distribution conditions are different, write to the author
|
||||||
|
to ask for permission. For software which is copyrighted by the Free
|
||||||
|
Software Foundation, write to the Free Software Foundation; we sometimes
|
||||||
|
make exceptions for this. Our decision will be guided by the two goals
|
||||||
|
of preserving the free status of all derivatives of our free software and
|
||||||
|
of promoting the sharing and reuse of software generally.
|
||||||
|
|
||||||
|
NO WARRANTY
|
||||||
|
|
||||||
|
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
||||||
|
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
||||||
|
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
|
||||||
|
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
|
||||||
|
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||||
|
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
|
||||||
|
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
|
||||||
|
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
|
||||||
|
REPAIR OR CORRECTION.
|
||||||
|
|
||||||
|
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||||
|
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
||||||
|
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
|
||||||
|
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
|
||||||
|
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
|
||||||
|
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
|
||||||
|
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
|
||||||
|
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
|
||||||
|
POSSIBILITY OF SUCH DAMAGES.
|
||||||
|
|
||||||
|
END OF TERMS AND CONDITIONS
|
||||||
|
|
||||||
|
How to Apply These Terms to Your New Programs
|
||||||
|
|
||||||
|
If you develop a new program, and you want it to be of the greatest
|
||||||
|
possible use to the public, the best way to achieve this is to make it
|
||||||
|
free software which everyone can redistribute and change under these terms.
|
||||||
|
|
||||||
|
To do so, attach the following notices to the program. It is safest
|
||||||
|
to attach them to the start of each source file to most effectively
|
||||||
|
convey the exclusion of warranty; and each file should have at least
|
||||||
|
the "copyright" line and a pointer to where the full notice is found.
|
||||||
|
|
||||||
|
{description}
|
||||||
|
Copyright (C) {year} {fullname}
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 2 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License along
|
||||||
|
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
|
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
|
||||||
|
Also add information on how to contact you by electronic and paper mail.
|
||||||
|
|
||||||
|
If the program is interactive, make it output a short notice like this
|
||||||
|
when it starts in an interactive mode:
|
||||||
|
|
||||||
|
Gnomovision version 69, Copyright (C) year name of author
|
||||||
|
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||||
|
This is free software, and you are welcome to redistribute it
|
||||||
|
under certain conditions; type `show c' for details.
|
||||||
|
|
||||||
|
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||||
|
parts of the General Public License. Of course, the commands you use may
|
||||||
|
be called something other than `show w' and `show c'; they could even be
|
||||||
|
mouse-clicks or menu items--whatever suits your program.
|
||||||
|
|
||||||
|
You should also get your employer (if you work as a programmer) or your
|
||||||
|
school, if any, to sign a "copyright disclaimer" for the program, if
|
||||||
|
necessary. Here is a sample; alter the names:
|
||||||
|
|
||||||
|
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
||||||
|
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
||||||
|
|
||||||
|
{signature of Ty Coon}, 1 April 1989
|
||||||
|
Ty Coon, President of Vice
|
||||||
|
|
||||||
|
This General Public License does not permit incorporating your program into
|
||||||
|
proprietary programs. If your program is a subroutine library, you may
|
||||||
|
consider it more useful to permit linking proprietary applications with the
|
||||||
|
library. If this is what you want to do, use the GNU Lesser General
|
||||||
|
Public License instead of this License.
|
180
jni/resetprop/_system_properties.h
Normal file
180
jni/resetprop/_system_properties.h
Normal file
@@ -0,0 +1,180 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2008 The Android Open Source Project
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* * Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* * Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in
|
||||||
|
* the documentation and/or other materials provided with the
|
||||||
|
* distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||||
|
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||||
|
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||||
|
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
||||||
|
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
|
||||||
|
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||||
|
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
|
||||||
|
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||||
|
* SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _INCLUDE_SYS__SYSTEM_PROPERTIES_H
|
||||||
|
#define _INCLUDE_SYS__SYSTEM_PROPERTIES_H
|
||||||
|
|
||||||
|
#ifndef _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_
|
||||||
|
#error you should #include <sys/system_properties.h> instead
|
||||||
|
#else
|
||||||
|
#include <sys/system_properties.h>
|
||||||
|
|
||||||
|
typedef struct prop_msg prop_msg;
|
||||||
|
|
||||||
|
#define PROP_AREA_MAGIC 0x504f5250
|
||||||
|
#define PROP_AREA_VERSION 0xfc6ed0ab
|
||||||
|
#define PROP_AREA_VERSION_COMPAT 0x45434f76
|
||||||
|
|
||||||
|
#define PROP_SERVICE_NAME "property_service"
|
||||||
|
#define PROP_FILENAME_MAX 1024
|
||||||
|
#define PROP_FILENAME "/dev/__properties__"
|
||||||
|
|
||||||
|
#define PA_SIZE (128 * 1024)
|
||||||
|
|
||||||
|
#define SERIAL_VALUE_LEN(serial) ((serial) >> 24)
|
||||||
|
#define SERIAL_DIRTY(serial) ((serial) & 1)
|
||||||
|
|
||||||
|
__BEGIN_DECLS
|
||||||
|
|
||||||
|
struct prop_msg
|
||||||
|
{
|
||||||
|
unsigned cmd;
|
||||||
|
char name[PROP_NAME_MAX];
|
||||||
|
char value[PROP_VALUE_MAX];
|
||||||
|
};
|
||||||
|
|
||||||
|
#define PROP_MSG_SETPROP 1
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Rules:
|
||||||
|
**
|
||||||
|
** - there is only one writer, but many readers
|
||||||
|
** - prop_area.count will never decrease in value
|
||||||
|
** - once allocated, a prop_info's name will not change
|
||||||
|
** - once allocated, a prop_info's offset will not change
|
||||||
|
** - reading a value requires the following steps
|
||||||
|
** 1. serial = pi->serial
|
||||||
|
** 2. if SERIAL_DIRTY(serial), wait*, then goto 1
|
||||||
|
** 3. memcpy(local, pi->value, SERIAL_VALUE_LEN(serial) + 1)
|
||||||
|
** 4. if pi->serial != serial, goto 2
|
||||||
|
**
|
||||||
|
** - writing a value requires the following steps
|
||||||
|
** 1. pi->serial = pi->serial | 1
|
||||||
|
** 2. memcpy(pi->value, local_value, value_len)
|
||||||
|
** 3. pi->serial = (value_len << 24) | ((pi->serial + 1) & 0xffffff)
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define PROP_PATH_RAMDISK_DEFAULT "/default.prop"
|
||||||
|
#define PROP_PATH_SYSTEM_BUILD "/system/build.prop"
|
||||||
|
#define PROP_PATH_VENDOR_BUILD "/vendor/build.prop"
|
||||||
|
#define PROP_PATH_LOCAL_OVERRIDE "/data/local.prop"
|
||||||
|
#define PROP_PATH_FACTORY "/factory/factory.prop"
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Map the property area from the specified filename. This
|
||||||
|
** method is for testing only.
|
||||||
|
*/
|
||||||
|
int __system_property_set_filename(const char *filename);
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Initialize the area to be used to store properties. Can
|
||||||
|
** only be done by a single process that has write access to
|
||||||
|
** the property area.
|
||||||
|
*/
|
||||||
|
int __system_property_area_init();
|
||||||
|
|
||||||
|
/* Read the global serial number of the system properties
|
||||||
|
**
|
||||||
|
** Called to predict if a series of cached __system_property_find
|
||||||
|
** objects will have seen __system_property_serial values change.
|
||||||
|
** But also aids the converse, as changes in the global serial can
|
||||||
|
** also be used to predict if a failed __system_property_find
|
||||||
|
** could in-turn now find a new object; thus preventing the
|
||||||
|
** cycles of effort to poll __system_property_find.
|
||||||
|
**
|
||||||
|
** Typically called at beginning of a cache cycle to signal if _any_ possible
|
||||||
|
** changes have occurred since last. If there is, one may check each individual
|
||||||
|
** __system_property_serial to confirm dirty, or __system_property_find
|
||||||
|
** to check if the property now exists. If a call to __system_property_add
|
||||||
|
** or __system_property_update has completed between two calls to
|
||||||
|
** __system_property_area_serial then the second call will return a larger
|
||||||
|
** value than the first call. Beware of race conditions as changes to the
|
||||||
|
** properties are not atomic, the main value of this call is to determine
|
||||||
|
** whether the expensive __system_property_find is worth retrying to see if
|
||||||
|
** a property now exists.
|
||||||
|
**
|
||||||
|
** Returns the serial number on success, -1 on error.
|
||||||
|
*/
|
||||||
|
unsigned int __system_property_area_serial();
|
||||||
|
|
||||||
|
/* Add a new system property. Can only be done by a single
|
||||||
|
** process that has write access to the property area, and
|
||||||
|
** that process must handle sequencing to ensure the property
|
||||||
|
** does not already exist and that only one property is added
|
||||||
|
** or updated at a time.
|
||||||
|
**
|
||||||
|
** Returns 0 on success, -1 if the property area is full.
|
||||||
|
*/
|
||||||
|
int __system_property_add(const char *name, unsigned int namelen,
|
||||||
|
const char *value, unsigned int valuelen);
|
||||||
|
|
||||||
|
int __system_property_del(const char *name);
|
||||||
|
|
||||||
|
/* Update the value of a system property returned by
|
||||||
|
** __system_property_find. Can only be done by a single process
|
||||||
|
** that has write access to the property area, and that process
|
||||||
|
** must handle sequencing to ensure that only one property is
|
||||||
|
** updated at a time.
|
||||||
|
**
|
||||||
|
** Returns 0 on success, -1 if the parameters are incorrect.
|
||||||
|
*/
|
||||||
|
int __system_property_update(prop_info *pi, const char *value, unsigned int len);
|
||||||
|
|
||||||
|
/* Read the serial number of a system property returned by
|
||||||
|
** __system_property_find.
|
||||||
|
**
|
||||||
|
** Returns the serial number on success, -1 on error.
|
||||||
|
*/
|
||||||
|
unsigned int __system_property_serial(const prop_info *pi);
|
||||||
|
|
||||||
|
/* Wait for any system property to be updated. Caller must pass
|
||||||
|
** in 0 the first time, and the previous return value on each
|
||||||
|
** successive call. */
|
||||||
|
unsigned int __system_property_wait_any(unsigned int serial);
|
||||||
|
|
||||||
|
/* Compatibility functions to support using an old init with a new libc,
|
||||||
|
** mostly for the OTA updater binary. These can be deleted once OTAs from
|
||||||
|
** a pre-K release no longer needed to be supported. */
|
||||||
|
// const prop_info *__system_property_find_compat(const char *name);
|
||||||
|
// int __system_property_read_compat(const prop_info *pi, char *name, char *value);
|
||||||
|
// int __system_property_foreach_compat(
|
||||||
|
// void (*propfn)(const prop_info *pi, void *cookie),
|
||||||
|
// void *cookie);
|
||||||
|
|
||||||
|
/* Initialize the system properties area in read only mode.
|
||||||
|
* Should be done by all processes that need to read system
|
||||||
|
* properties.
|
||||||
|
*
|
||||||
|
* Returns 0 on success, -1 otherwise.
|
||||||
|
*/
|
||||||
|
int __system_properties_init();
|
||||||
|
|
||||||
|
__END_DECLS
|
||||||
|
|
||||||
|
#endif
|
||||||
|
#endif
|
77
jni/resetprop/bionic_futex.h
Normal file
77
jni/resetprop/bionic_futex.h
Normal file
@@ -0,0 +1,77 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2008 The Android Open Source Project
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* * Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* * Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in
|
||||||
|
* the documentation and/or other materials provided with the
|
||||||
|
* distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||||
|
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||||
|
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||||
|
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
||||||
|
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
|
||||||
|
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||||
|
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
|
||||||
|
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||||
|
* SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
#ifndef _BIONIC_FUTEX_H
|
||||||
|
#define _BIONIC_FUTEX_H
|
||||||
|
|
||||||
|
#include <errno.h>
|
||||||
|
#include <linux/futex.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <sys/cdefs.h>
|
||||||
|
#include <sys/syscall.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
__BEGIN_DECLS
|
||||||
|
|
||||||
|
struct timespec;
|
||||||
|
|
||||||
|
static inline __always_inline int __futex(volatile void* ftx, int op, int value,
|
||||||
|
const struct timespec* timeout,
|
||||||
|
int bitset) {
|
||||||
|
// Our generated syscall assembler sets errno, but our callers (pthread functions) don't want to.
|
||||||
|
int saved_errno = errno;
|
||||||
|
int result = syscall(__NR_futex, ftx, op, value, timeout, NULL, bitset);
|
||||||
|
if (__predict_false(result == -1)) {
|
||||||
|
result = -errno;
|
||||||
|
errno = saved_errno;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int __futex_wake(volatile void* ftx, int count) {
|
||||||
|
return __futex(ftx, FUTEX_WAKE, count, NULL, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int __futex_wake_ex(volatile void* ftx, bool shared, int count) {
|
||||||
|
return __futex(ftx, shared ? FUTEX_WAKE : FUTEX_WAKE_PRIVATE, count, NULL, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int __futex_wait(volatile void* ftx, int value, const struct timespec* timeout) {
|
||||||
|
return __futex(ftx, FUTEX_WAIT, value, timeout, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int __futex_wait_ex(volatile void* ftx, bool shared, int value,
|
||||||
|
bool use_realtime_clock, const struct timespec* abs_timeout) {
|
||||||
|
return __futex(ftx, (shared ? FUTEX_WAIT_BITSET : FUTEX_WAIT_BITSET_PRIVATE) |
|
||||||
|
(use_realtime_clock ? FUTEX_CLOCK_REALTIME : 0), value, abs_timeout,
|
||||||
|
FUTEX_BITSET_MATCH_ANY);
|
||||||
|
}
|
||||||
|
|
||||||
|
__END_DECLS
|
||||||
|
|
||||||
|
#endif /* _BIONIC_FUTEX_H */
|
79
jni/resetprop/bionic_lock.h
Normal file
79
jni/resetprop/bionic_lock.h
Normal file
@@ -0,0 +1,79 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2015 The Android Open Source Project
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* * Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* * Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in
|
||||||
|
* the documentation and/or other materials provided with the
|
||||||
|
* distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||||
|
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||||
|
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||||
|
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
||||||
|
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
|
||||||
|
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||||
|
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
|
||||||
|
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||||
|
* SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
#ifndef _BIONIC_LOCK_H
|
||||||
|
#define _BIONIC_LOCK_H
|
||||||
|
|
||||||
|
#include <stdatomic.h>
|
||||||
|
#include "bionic_futex.h"
|
||||||
|
#include "bionic_macros.h"
|
||||||
|
|
||||||
|
// Lock is used in places like pthread_rwlock_t, which can be initialized without calling
|
||||||
|
// an initialization function. So make sure Lock can be initialized by setting its memory to 0.
|
||||||
|
class Lock {
|
||||||
|
private:
|
||||||
|
enum LockState {
|
||||||
|
Unlocked = 0,
|
||||||
|
LockedWithoutWaiter,
|
||||||
|
LockedWithWaiter,
|
||||||
|
};
|
||||||
|
_Atomic(LockState) state;
|
||||||
|
bool process_shared;
|
||||||
|
|
||||||
|
public:
|
||||||
|
void init(bool process_shared) {
|
||||||
|
atomic_init(&state, Unlocked);
|
||||||
|
this->process_shared = process_shared;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool trylock() {
|
||||||
|
LockState old_state = Unlocked;
|
||||||
|
return __predict_true(atomic_compare_exchange_strong_explicit(&state, &old_state,
|
||||||
|
LockedWithoutWaiter, memory_order_acquire, memory_order_relaxed));
|
||||||
|
}
|
||||||
|
|
||||||
|
void lock() {
|
||||||
|
LockState old_state = Unlocked;
|
||||||
|
if (__predict_true(atomic_compare_exchange_strong_explicit(&state, &old_state,
|
||||||
|
LockedWithoutWaiter, memory_order_acquire, memory_order_relaxed))) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
while (atomic_exchange_explicit(&state, LockedWithWaiter, memory_order_acquire) != Unlocked) {
|
||||||
|
// TODO: As the critical section is brief, it is a better choice to spin a few times befor sleeping.
|
||||||
|
__futex_wait_ex(&state, process_shared, LockedWithWaiter, false, nullptr);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
void unlock() {
|
||||||
|
if (atomic_exchange_explicit(&state, Unlocked, memory_order_release) == LockedWithWaiter) {
|
||||||
|
__futex_wake_ex(&state, process_shared, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // _BIONIC_LOCK_H
|
49
jni/resetprop/bionic_macros.h
Normal file
49
jni/resetprop/bionic_macros.h
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2010 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _BIONIC_MACROS_H_
|
||||||
|
#define _BIONIC_MACROS_H_
|
||||||
|
|
||||||
|
// Frameworks OpenGL code currently leaks this header and allows
|
||||||
|
// collisions with other declarations, e.g., from libnativehelper.
|
||||||
|
// TODO: Remove once cleaned up. b/18334516
|
||||||
|
#if !defined(DISALLOW_COPY_AND_ASSIGN)
|
||||||
|
// DISALLOW_COPY_AND_ASSIGN disallows the copy and operator= functions.
|
||||||
|
// It goes in the private: declarations in a class.
|
||||||
|
#define DISALLOW_COPY_AND_ASSIGN(TypeName) \
|
||||||
|
TypeName(const TypeName&) = delete; \
|
||||||
|
void operator=(const TypeName&) = delete
|
||||||
|
#endif // !defined(DISALLOW_COPY_AND_ASSIGN)
|
||||||
|
|
||||||
|
// A macro to disallow all the implicit constructors, namely the
|
||||||
|
// default constructor, copy constructor and operator= functions.
|
||||||
|
//
|
||||||
|
// This should be used in the private: declarations for a class
|
||||||
|
// that wants to prevent anyone from instantiating it. This is
|
||||||
|
// especially useful for classes containing only static methods.
|
||||||
|
#define DISALLOW_IMPLICIT_CONSTRUCTORS(TypeName) \
|
||||||
|
TypeName() = delete; \
|
||||||
|
DISALLOW_COPY_AND_ASSIGN(TypeName)
|
||||||
|
|
||||||
|
#define BIONIC_ALIGN(value, alignment) \
|
||||||
|
(((value) + (alignment) - 1) & ~((alignment) - 1))
|
||||||
|
|
||||||
|
#define BIONIC_ROUND_UP_POWER_OF_2(value) \
|
||||||
|
((sizeof(value) == 8) \
|
||||||
|
? (1UL << (64 - __builtin_clzl(static_cast<unsigned long>(value)))) \
|
||||||
|
: (1UL << (32 - __builtin_clz(static_cast<unsigned int>(value)))))
|
||||||
|
|
||||||
|
#endif // _BIONIC_MACROS_H_
|
659
jni/resetprop/libc_logging.cpp
Normal file
659
jni/resetprop/libc_logging.cpp
Normal file
@@ -0,0 +1,659 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2010 The Android Open Source Project
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* * Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* * Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in
|
||||||
|
* the documentation and/or other materials provided with the
|
||||||
|
* distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||||
|
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||||
|
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||||
|
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
||||||
|
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
|
||||||
|
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||||
|
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
|
||||||
|
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||||
|
* SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "libc_logging.h" // Relative path so we can #include this .cpp file for testing.
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <pthread.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <sys/mman.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/uio.h>
|
||||||
|
#include <sys/un.h>
|
||||||
|
#include <time.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_
|
||||||
|
#include "_system_properties.h"
|
||||||
|
|
||||||
|
static pthread_mutex_t g_abort_msg_lock = PTHREAD_MUTEX_INITIALIZER;
|
||||||
|
|
||||||
|
__LIBC_HIDDEN__ abort_msg_t** __abort_message_ptr; // Accessible to __libc_init_common.
|
||||||
|
|
||||||
|
// Must be kept in sync with frameworks/base/core/java/android/util/EventLog.java.
|
||||||
|
enum AndroidEventLogType {
|
||||||
|
EVENT_TYPE_INT = 0,
|
||||||
|
EVENT_TYPE_LONG = 1,
|
||||||
|
EVENT_TYPE_STRING = 2,
|
||||||
|
EVENT_TYPE_LIST = 3,
|
||||||
|
EVENT_TYPE_FLOAT = 4,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct BufferOutputStream {
|
||||||
|
public:
|
||||||
|
BufferOutputStream(char* buffer, size_t size) : total(0) {
|
||||||
|
buffer_ = buffer;
|
||||||
|
end_ = buffer + size - 1;
|
||||||
|
pos_ = buffer_;
|
||||||
|
pos_[0] = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
~BufferOutputStream() {
|
||||||
|
}
|
||||||
|
|
||||||
|
void Send(const char* data, int len) {
|
||||||
|
if (len < 0) {
|
||||||
|
len = strlen(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
total += len;
|
||||||
|
|
||||||
|
while (len > 0) {
|
||||||
|
int avail = end_ - pos_;
|
||||||
|
if (avail == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (avail > len) {
|
||||||
|
avail = len;
|
||||||
|
}
|
||||||
|
memcpy(pos_, data, avail);
|
||||||
|
pos_ += avail;
|
||||||
|
pos_[0] = '\0';
|
||||||
|
len -= avail;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t total;
|
||||||
|
|
||||||
|
private:
|
||||||
|
char* buffer_;
|
||||||
|
char* pos_;
|
||||||
|
char* end_;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct FdOutputStream {
|
||||||
|
public:
|
||||||
|
FdOutputStream(int fd) : total(0), fd_(fd) {
|
||||||
|
}
|
||||||
|
|
||||||
|
void Send(const char* data, int len) {
|
||||||
|
if (len < 0) {
|
||||||
|
len = strlen(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
total += len;
|
||||||
|
|
||||||
|
while (len > 0) {
|
||||||
|
int rc = TEMP_FAILURE_RETRY(write(fd_, data, len));
|
||||||
|
if (rc == -1) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
data += rc;
|
||||||
|
len -= rc;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t total;
|
||||||
|
|
||||||
|
private:
|
||||||
|
int fd_;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*** formatted output implementation
|
||||||
|
***/
|
||||||
|
|
||||||
|
/* Parse a decimal string from 'format + *ppos',
|
||||||
|
* return the value, and writes the new position past
|
||||||
|
* the decimal string in '*ppos' on exit.
|
||||||
|
*
|
||||||
|
* NOTE: Does *not* handle a sign prefix.
|
||||||
|
*/
|
||||||
|
static unsigned parse_decimal(const char *format, int *ppos) {
|
||||||
|
const char* p = format + *ppos;
|
||||||
|
unsigned result = 0;
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
int ch = *p;
|
||||||
|
unsigned d = static_cast<unsigned>(ch - '0');
|
||||||
|
|
||||||
|
if (d >= 10U) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
result = result*10 + d;
|
||||||
|
p++;
|
||||||
|
}
|
||||||
|
*ppos = p - format;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Writes number 'value' in base 'base' into buffer 'buf' of size 'buf_size' bytes.
|
||||||
|
// Assumes that buf_size > 0.
|
||||||
|
static void format_unsigned(char* buf, size_t buf_size, uint64_t value, int base, bool caps) {
|
||||||
|
char* p = buf;
|
||||||
|
char* end = buf + buf_size - 1;
|
||||||
|
|
||||||
|
// Generate digit string in reverse order.
|
||||||
|
while (value) {
|
||||||
|
unsigned d = value % base;
|
||||||
|
value /= base;
|
||||||
|
if (p != end) {
|
||||||
|
char ch;
|
||||||
|
if (d < 10) {
|
||||||
|
ch = '0' + d;
|
||||||
|
} else {
|
||||||
|
ch = (caps ? 'A' : 'a') + (d - 10);
|
||||||
|
}
|
||||||
|
*p++ = ch;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Special case for 0.
|
||||||
|
if (p == buf) {
|
||||||
|
if (p != end) {
|
||||||
|
*p++ = '0';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*p = '\0';
|
||||||
|
|
||||||
|
// Reverse digit string in-place.
|
||||||
|
size_t length = p - buf;
|
||||||
|
for (size_t i = 0, j = length - 1; i < j; ++i, --j) {
|
||||||
|
char ch = buf[i];
|
||||||
|
buf[i] = buf[j];
|
||||||
|
buf[j] = ch;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void format_integer(char* buf, size_t buf_size, uint64_t value, char conversion) {
|
||||||
|
// Decode the conversion specifier.
|
||||||
|
int is_signed = (conversion == 'd' || conversion == 'i' || conversion == 'o');
|
||||||
|
int base = 10;
|
||||||
|
if (conversion == 'x' || conversion == 'X') {
|
||||||
|
base = 16;
|
||||||
|
} else if (conversion == 'o') {
|
||||||
|
base = 8;
|
||||||
|
}
|
||||||
|
bool caps = (conversion == 'X');
|
||||||
|
|
||||||
|
if (is_signed && static_cast<int64_t>(value) < 0) {
|
||||||
|
buf[0] = '-';
|
||||||
|
buf += 1;
|
||||||
|
buf_size -= 1;
|
||||||
|
value = static_cast<uint64_t>(-static_cast<int64_t>(value));
|
||||||
|
}
|
||||||
|
format_unsigned(buf, buf_size, value, base, caps);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Out>
|
||||||
|
static void SendRepeat(Out& o, char ch, int count) {
|
||||||
|
char pad[8];
|
||||||
|
memset(pad, ch, sizeof(pad));
|
||||||
|
|
||||||
|
const int pad_size = static_cast<int>(sizeof(pad));
|
||||||
|
while (count > 0) {
|
||||||
|
int avail = count;
|
||||||
|
if (avail > pad_size) {
|
||||||
|
avail = pad_size;
|
||||||
|
}
|
||||||
|
o.Send(pad, avail);
|
||||||
|
count -= avail;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Perform formatted output to an output target 'o' */
|
||||||
|
template <typename Out>
|
||||||
|
static void out_vformat(Out& o, const char* format, va_list args) {
|
||||||
|
int nn = 0;
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
int mm;
|
||||||
|
int padZero = 0;
|
||||||
|
int padLeft = 0;
|
||||||
|
char sign = '\0';
|
||||||
|
int width = -1;
|
||||||
|
int prec = -1;
|
||||||
|
size_t bytelen = sizeof(int);
|
||||||
|
int slen;
|
||||||
|
char buffer[32]; /* temporary buffer used to format numbers */
|
||||||
|
|
||||||
|
char c;
|
||||||
|
|
||||||
|
/* first, find all characters that are not 0 or '%' */
|
||||||
|
/* then send them to the output directly */
|
||||||
|
mm = nn;
|
||||||
|
do {
|
||||||
|
c = format[mm];
|
||||||
|
if (c == '\0' || c == '%')
|
||||||
|
break;
|
||||||
|
mm++;
|
||||||
|
} while (1);
|
||||||
|
|
||||||
|
if (mm > nn) {
|
||||||
|
o.Send(format+nn, mm-nn);
|
||||||
|
nn = mm;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* is this it ? then exit */
|
||||||
|
if (c == '\0')
|
||||||
|
break;
|
||||||
|
|
||||||
|
/* nope, we are at a '%' modifier */
|
||||||
|
nn++; // skip it
|
||||||
|
|
||||||
|
/* parse flags */
|
||||||
|
for (;;) {
|
||||||
|
c = format[nn++];
|
||||||
|
if (c == '\0') { /* single trailing '%' ? */
|
||||||
|
c = '%';
|
||||||
|
o.Send(&c, 1);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else if (c == '0') {
|
||||||
|
padZero = 1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else if (c == '-') {
|
||||||
|
padLeft = 1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else if (c == ' ' || c == '+') {
|
||||||
|
sign = c;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* parse field width */
|
||||||
|
if ((c >= '0' && c <= '9')) {
|
||||||
|
nn --;
|
||||||
|
width = static_cast<int>(parse_decimal(format, &nn));
|
||||||
|
c = format[nn++];
|
||||||
|
}
|
||||||
|
|
||||||
|
/* parse precision */
|
||||||
|
if (c == '.') {
|
||||||
|
prec = static_cast<int>(parse_decimal(format, &nn));
|
||||||
|
c = format[nn++];
|
||||||
|
}
|
||||||
|
|
||||||
|
/* length modifier */
|
||||||
|
switch (c) {
|
||||||
|
case 'h':
|
||||||
|
bytelen = sizeof(short);
|
||||||
|
if (format[nn] == 'h') {
|
||||||
|
bytelen = sizeof(char);
|
||||||
|
nn += 1;
|
||||||
|
}
|
||||||
|
c = format[nn++];
|
||||||
|
break;
|
||||||
|
case 'l':
|
||||||
|
bytelen = sizeof(long);
|
||||||
|
if (format[nn] == 'l') {
|
||||||
|
bytelen = sizeof(long long);
|
||||||
|
nn += 1;
|
||||||
|
}
|
||||||
|
c = format[nn++];
|
||||||
|
break;
|
||||||
|
case 'z':
|
||||||
|
bytelen = sizeof(size_t);
|
||||||
|
c = format[nn++];
|
||||||
|
break;
|
||||||
|
case 't':
|
||||||
|
bytelen = sizeof(ptrdiff_t);
|
||||||
|
c = format[nn++];
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* conversion specifier */
|
||||||
|
const char* str = buffer;
|
||||||
|
if (c == 's') {
|
||||||
|
/* string */
|
||||||
|
str = va_arg(args, const char*);
|
||||||
|
if (str == NULL) {
|
||||||
|
str = "(null)";
|
||||||
|
}
|
||||||
|
} else if (c == 'c') {
|
||||||
|
/* character */
|
||||||
|
/* NOTE: char is promoted to int when passed through the stack */
|
||||||
|
buffer[0] = static_cast<char>(va_arg(args, int));
|
||||||
|
buffer[1] = '\0';
|
||||||
|
} else if (c == 'p') {
|
||||||
|
uint64_t value = reinterpret_cast<uintptr_t>(va_arg(args, void*));
|
||||||
|
buffer[0] = '0';
|
||||||
|
buffer[1] = 'x';
|
||||||
|
format_integer(buffer + 2, sizeof(buffer) - 2, value, 'x');
|
||||||
|
} else if (c == 'd' || c == 'i' || c == 'o' || c == 'u' || c == 'x' || c == 'X') {
|
||||||
|
/* integers - first read value from stack */
|
||||||
|
uint64_t value;
|
||||||
|
int is_signed = (c == 'd' || c == 'i' || c == 'o');
|
||||||
|
|
||||||
|
/* NOTE: int8_t and int16_t are promoted to int when passed
|
||||||
|
* through the stack
|
||||||
|
*/
|
||||||
|
switch (bytelen) {
|
||||||
|
case 1: value = static_cast<uint8_t>(va_arg(args, int)); break;
|
||||||
|
case 2: value = static_cast<uint16_t>(va_arg(args, int)); break;
|
||||||
|
case 4: value = va_arg(args, uint32_t); break;
|
||||||
|
case 8: value = va_arg(args, uint64_t); break;
|
||||||
|
default: return; /* should not happen */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* sign extension, if needed */
|
||||||
|
if (is_signed) {
|
||||||
|
int shift = 64 - 8*bytelen;
|
||||||
|
value = static_cast<uint64_t>((static_cast<int64_t>(value << shift)) >> shift);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* format the number properly into our buffer */
|
||||||
|
format_integer(buffer, sizeof(buffer), value, c);
|
||||||
|
} else if (c == '%') {
|
||||||
|
buffer[0] = '%';
|
||||||
|
buffer[1] = '\0';
|
||||||
|
} else {
|
||||||
|
__assert(__FILE__, __LINE__, "conversion specifier unsupported");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* if we are here, 'str' points to the content that must be
|
||||||
|
* outputted. handle padding and alignment now */
|
||||||
|
|
||||||
|
slen = strlen(str);
|
||||||
|
|
||||||
|
if (sign != '\0' || prec != -1) {
|
||||||
|
__assert(__FILE__, __LINE__, "sign/precision unsupported");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (slen < width && !padLeft) {
|
||||||
|
char padChar = padZero ? '0' : ' ';
|
||||||
|
SendRepeat(o, padChar, width - slen);
|
||||||
|
}
|
||||||
|
|
||||||
|
o.Send(str, slen);
|
||||||
|
|
||||||
|
if (slen < width && padLeft) {
|
||||||
|
char padChar = padZero ? '0' : ' ';
|
||||||
|
SendRepeat(o, padChar, width - slen);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int __libc_format_buffer(char* buffer, size_t buffer_size, const char* format, ...) {
|
||||||
|
BufferOutputStream os(buffer, buffer_size);
|
||||||
|
va_list args;
|
||||||
|
va_start(args, format);
|
||||||
|
out_vformat(os, format, args);
|
||||||
|
va_end(args);
|
||||||
|
return os.total;
|
||||||
|
}
|
||||||
|
|
||||||
|
int __libc_format_fd(int fd, const char* format, ...) {
|
||||||
|
FdOutputStream os(fd);
|
||||||
|
va_list args;
|
||||||
|
va_start(args, format);
|
||||||
|
out_vformat(os, format, args);
|
||||||
|
va_end(args);
|
||||||
|
return os.total;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int __libc_write_stderr(const char* tag, const char* msg) {
|
||||||
|
int fd = TEMP_FAILURE_RETRY(open("/dev/stderr", O_CLOEXEC | O_WRONLY | O_APPEND));
|
||||||
|
if (fd == -1) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
iovec vec[4];
|
||||||
|
vec[0].iov_base = const_cast<char*>(tag);
|
||||||
|
vec[0].iov_len = strlen(tag);
|
||||||
|
vec[1].iov_base = const_cast<char*>(": ");
|
||||||
|
vec[1].iov_len = 2;
|
||||||
|
vec[2].iov_base = const_cast<char*>(msg);
|
||||||
|
vec[2].iov_len = strlen(msg);
|
||||||
|
vec[3].iov_base = const_cast<char*>("\n");
|
||||||
|
vec[3].iov_len = 1;
|
||||||
|
|
||||||
|
int result = TEMP_FAILURE_RETRY(writev(fd, vec, 4));
|
||||||
|
close(fd);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int __libc_open_log_socket() {
|
||||||
|
// ToDo: Ideally we want this to fail if the gid of the current
|
||||||
|
// process is AID_LOGD, but will have to wait until we have
|
||||||
|
// registered this in private/android_filesystem_config.h. We have
|
||||||
|
// found that all logd crashes thus far have had no problem stuffing
|
||||||
|
// the UNIX domain socket and moving on so not critical *today*.
|
||||||
|
|
||||||
|
int log_fd = TEMP_FAILURE_RETRY(socket(PF_UNIX, SOCK_DGRAM | SOCK_CLOEXEC, 0));
|
||||||
|
if (log_fd < 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fcntl(log_fd, F_SETFL, O_NONBLOCK) == -1) {
|
||||||
|
close(log_fd);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
union {
|
||||||
|
struct sockaddr addr;
|
||||||
|
struct sockaddr_un addrUn;
|
||||||
|
} u;
|
||||||
|
memset(&u, 0, sizeof(u));
|
||||||
|
u.addrUn.sun_family = AF_UNIX;
|
||||||
|
strlcpy(u.addrUn.sun_path, "/dev/socket/logdw", sizeof(u.addrUn.sun_path));
|
||||||
|
|
||||||
|
if (TEMP_FAILURE_RETRY(connect(log_fd, &u.addr, sizeof(u.addrUn))) != 0) {
|
||||||
|
close(log_fd);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return log_fd;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct cache {
|
||||||
|
const prop_info* pinfo;
|
||||||
|
uint32_t serial;
|
||||||
|
char c;
|
||||||
|
};
|
||||||
|
|
||||||
|
static void refresh_cache(struct cache *cache, const char *key)
|
||||||
|
{
|
||||||
|
if (!cache->pinfo) {
|
||||||
|
cache->pinfo = __system_property_find(key);
|
||||||
|
if (!cache->pinfo) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
uint32_t serial = __system_property_serial(cache->pinfo);
|
||||||
|
if (serial == cache->serial) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
cache->serial = serial;
|
||||||
|
|
||||||
|
char buf[PROP_VALUE_MAX];
|
||||||
|
__system_property_read(cache->pinfo, 0, buf);
|
||||||
|
cache->c = buf[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Timestamp state generally remains constant, since a change is
|
||||||
|
// rare, we can accept a trylock failure gracefully.
|
||||||
|
static pthread_mutex_t lock_clockid = PTHREAD_MUTEX_INITIALIZER;
|
||||||
|
|
||||||
|
static clockid_t __android_log_clockid()
|
||||||
|
{
|
||||||
|
static struct cache r_time_cache = { NULL, static_cast<uint32_t>(-1), 0 };
|
||||||
|
static struct cache p_time_cache = { NULL, static_cast<uint32_t>(-1), 0 };
|
||||||
|
char c;
|
||||||
|
|
||||||
|
if (pthread_mutex_trylock(&lock_clockid)) {
|
||||||
|
// We are willing to accept some race in this context
|
||||||
|
if (!(c = p_time_cache.c)) {
|
||||||
|
c = r_time_cache.c;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
static uint32_t serial;
|
||||||
|
uint32_t current_serial = __system_property_area_serial();
|
||||||
|
if (current_serial != serial) {
|
||||||
|
refresh_cache(&r_time_cache, "ro.logd.timestamp");
|
||||||
|
refresh_cache(&p_time_cache, "persist.logd.timestamp");
|
||||||
|
serial = current_serial;
|
||||||
|
}
|
||||||
|
if (!(c = p_time_cache.c)) {
|
||||||
|
c = r_time_cache.c;
|
||||||
|
}
|
||||||
|
|
||||||
|
pthread_mutex_unlock(&lock_clockid);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (tolower(c) == 'm') ? CLOCK_MONOTONIC : CLOCK_REALTIME;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct log_time { // Wire format
|
||||||
|
uint32_t tv_sec;
|
||||||
|
uint32_t tv_nsec;
|
||||||
|
};
|
||||||
|
|
||||||
|
int __libc_write_log(int priority, const char* tag, const char* msg) {
|
||||||
|
int main_log_fd = __libc_open_log_socket();
|
||||||
|
if (main_log_fd == -1) {
|
||||||
|
// Try stderr instead.
|
||||||
|
return __libc_write_stderr(tag, msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
iovec vec[6];
|
||||||
|
char log_id = (priority == ANDROID_LOG_FATAL) ? LOG_ID_CRASH : LOG_ID_MAIN;
|
||||||
|
vec[0].iov_base = &log_id;
|
||||||
|
vec[0].iov_len = sizeof(log_id);
|
||||||
|
uint16_t tid = gettid();
|
||||||
|
vec[1].iov_base = &tid;
|
||||||
|
vec[1].iov_len = sizeof(tid);
|
||||||
|
timespec ts;
|
||||||
|
clock_gettime(__android_log_clockid(), &ts);
|
||||||
|
log_time realtime_ts;
|
||||||
|
realtime_ts.tv_sec = ts.tv_sec;
|
||||||
|
realtime_ts.tv_nsec = ts.tv_nsec;
|
||||||
|
vec[2].iov_base = &realtime_ts;
|
||||||
|
vec[2].iov_len = sizeof(realtime_ts);
|
||||||
|
|
||||||
|
vec[3].iov_base = &priority;
|
||||||
|
vec[3].iov_len = 1;
|
||||||
|
vec[4].iov_base = const_cast<char*>(tag);
|
||||||
|
vec[4].iov_len = strlen(tag) + 1;
|
||||||
|
vec[5].iov_base = const_cast<char*>(msg);
|
||||||
|
vec[5].iov_len = strlen(msg) + 1;
|
||||||
|
|
||||||
|
int result = TEMP_FAILURE_RETRY(writev(main_log_fd, vec, sizeof(vec) / sizeof(vec[0])));
|
||||||
|
close(main_log_fd);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
int __libc_format_log_va_list(int priority, const char* tag, const char* format, va_list args) {
|
||||||
|
char buffer[1024];
|
||||||
|
BufferOutputStream os(buffer, sizeof(buffer));
|
||||||
|
out_vformat(os, format, args);
|
||||||
|
return __libc_write_log(priority, tag, buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
int __libc_format_log(int priority, const char* tag, const char* format, ...) {
|
||||||
|
va_list args;
|
||||||
|
va_start(args, format);
|
||||||
|
int result = __libc_format_log_va_list(priority, tag, format, args);
|
||||||
|
va_end(args);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int __libc_android_log_event(int32_t tag, char type, const void* payload, size_t len) {
|
||||||
|
iovec vec[6];
|
||||||
|
char log_id = LOG_ID_EVENTS;
|
||||||
|
vec[0].iov_base = &log_id;
|
||||||
|
vec[0].iov_len = sizeof(log_id);
|
||||||
|
uint16_t tid = gettid();
|
||||||
|
vec[1].iov_base = &tid;
|
||||||
|
vec[1].iov_len = sizeof(tid);
|
||||||
|
timespec ts;
|
||||||
|
clock_gettime(__android_log_clockid(), &ts);
|
||||||
|
log_time realtime_ts;
|
||||||
|
realtime_ts.tv_sec = ts.tv_sec;
|
||||||
|
realtime_ts.tv_nsec = ts.tv_nsec;
|
||||||
|
vec[2].iov_base = &realtime_ts;
|
||||||
|
vec[2].iov_len = sizeof(realtime_ts);
|
||||||
|
|
||||||
|
vec[3].iov_base = &tag;
|
||||||
|
vec[3].iov_len = sizeof(tag);
|
||||||
|
vec[4].iov_base = &type;
|
||||||
|
vec[4].iov_len = sizeof(type);
|
||||||
|
vec[5].iov_base = const_cast<void*>(payload);
|
||||||
|
vec[5].iov_len = len;
|
||||||
|
|
||||||
|
int event_log_fd = __libc_open_log_socket();
|
||||||
|
|
||||||
|
if (event_log_fd == -1) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
int result = TEMP_FAILURE_RETRY(writev(event_log_fd, vec, sizeof(vec) / sizeof(vec[0])));
|
||||||
|
close(event_log_fd);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void __libc_android_log_event_int(int32_t tag, int value) {
|
||||||
|
__libc_android_log_event(tag, EVENT_TYPE_INT, &value, sizeof(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
void __libc_android_log_event_uid(int32_t tag) {
|
||||||
|
__libc_android_log_event_int(tag, getuid());
|
||||||
|
}
|
||||||
|
|
||||||
|
void __fortify_chk_fail(const char* msg, uint32_t tag) {
|
||||||
|
if (tag != 0) {
|
||||||
|
__libc_android_log_event_uid(tag);
|
||||||
|
}
|
||||||
|
__libc_fatal("FORTIFY: %s", msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
void __libc_fatal_no_abort(const char* format, ...) {
|
||||||
|
va_list args;
|
||||||
|
va_start(args, format);
|
||||||
|
__libc_fatal(format, args);
|
||||||
|
va_end(args);
|
||||||
|
}
|
||||||
|
|
||||||
|
void __libc_fatal(const char* format, ...) {
|
||||||
|
va_list args;
|
||||||
|
va_start(args, format);
|
||||||
|
__libc_fatal(format, args);
|
||||||
|
va_end(args);
|
||||||
|
abort();
|
||||||
|
}
|
115
jni/resetprop/libc_logging.h
Normal file
115
jni/resetprop/libc_logging.h
Normal file
@@ -0,0 +1,115 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2010 The Android Open Source Project
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* * Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* * Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in
|
||||||
|
* the documentation and/or other materials provided with the
|
||||||
|
* distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||||
|
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||||
|
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||||
|
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
||||||
|
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
|
||||||
|
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||||
|
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
|
||||||
|
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||||
|
* SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _LIBC_LOGGING_H
|
||||||
|
#define _LIBC_LOGGING_H
|
||||||
|
|
||||||
|
#include <sys/cdefs.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
__BEGIN_DECLS
|
||||||
|
|
||||||
|
enum {
|
||||||
|
ANDROID_LOG_UNKNOWN = 0,
|
||||||
|
ANDROID_LOG_DEFAULT, /* only for SetMinPriority() */
|
||||||
|
|
||||||
|
ANDROID_LOG_VERBOSE,
|
||||||
|
ANDROID_LOG_DEBUG,
|
||||||
|
ANDROID_LOG_INFO,
|
||||||
|
ANDROID_LOG_WARN,
|
||||||
|
ANDROID_LOG_ERROR,
|
||||||
|
ANDROID_LOG_FATAL,
|
||||||
|
|
||||||
|
ANDROID_LOG_SILENT, /* only for SetMinPriority(); must be last */
|
||||||
|
};
|
||||||
|
|
||||||
|
enum {
|
||||||
|
LOG_ID_MIN = 0,
|
||||||
|
|
||||||
|
LOG_ID_MAIN = 0,
|
||||||
|
LOG_ID_RADIO = 1,
|
||||||
|
LOG_ID_EVENTS = 2,
|
||||||
|
LOG_ID_SYSTEM = 3,
|
||||||
|
LOG_ID_CRASH = 4,
|
||||||
|
|
||||||
|
LOG_ID_MAX
|
||||||
|
};
|
||||||
|
|
||||||
|
struct abort_msg_t {
|
||||||
|
size_t size;
|
||||||
|
char msg[0];
|
||||||
|
};
|
||||||
|
|
||||||
|
//
|
||||||
|
// Formats a message to the log (priority 'fatal'), then aborts.
|
||||||
|
//
|
||||||
|
|
||||||
|
__LIBC_HIDDEN__ __noreturn void __libc_fatal(const char* format, ...) __printflike(1, 2);
|
||||||
|
|
||||||
|
//
|
||||||
|
// Formats a message to the log (priority 'fatal'), but doesn't abort.
|
||||||
|
// Used by the malloc implementation to ensure that debuggerd dumps memory
|
||||||
|
// around the bad address.
|
||||||
|
//
|
||||||
|
|
||||||
|
__LIBC_HIDDEN__ void __libc_fatal_no_abort(const char* format, ...)
|
||||||
|
__printflike(1, 2);
|
||||||
|
|
||||||
|
//
|
||||||
|
// Formatting routines for the C library's internal debugging.
|
||||||
|
// Unlike the usual alternatives, these don't allocate, and they don't drag in all of stdio.
|
||||||
|
//
|
||||||
|
|
||||||
|
__LIBC_HIDDEN__ int __libc_format_buffer(char* buffer, size_t buffer_size, const char* format, ...)
|
||||||
|
__printflike(3, 4);
|
||||||
|
|
||||||
|
__LIBC_HIDDEN__ int __libc_format_fd(int fd, const char* format, ...)
|
||||||
|
__printflike(2, 3);
|
||||||
|
|
||||||
|
__LIBC_HIDDEN__ int __libc_format_log(int priority, const char* tag, const char* format, ...)
|
||||||
|
__printflike(3, 4);
|
||||||
|
|
||||||
|
__LIBC_HIDDEN__ int __libc_format_log_va_list(int priority, const char* tag, const char* format,
|
||||||
|
va_list ap);
|
||||||
|
|
||||||
|
__LIBC_HIDDEN__ int __libc_write_log(int priority, const char* tag, const char* msg);
|
||||||
|
|
||||||
|
//
|
||||||
|
// Event logging.
|
||||||
|
//
|
||||||
|
|
||||||
|
__LIBC_HIDDEN__ void __libc_android_log_event_int(int32_t tag, int value);
|
||||||
|
__LIBC_HIDDEN__ void __libc_android_log_event_uid(int32_t tag);
|
||||||
|
|
||||||
|
__LIBC_HIDDEN__ __noreturn void __fortify_chk_fail(const char* msg, uint32_t event_tag);
|
||||||
|
|
||||||
|
__END_DECLS
|
||||||
|
|
||||||
|
#endif
|
280
jni/resetprop/resetprop.cpp
Normal file
280
jni/resetprop/resetprop.cpp
Normal file
@@ -0,0 +1,280 @@
|
|||||||
|
/*
|
||||||
|
*
|
||||||
|
* resetprop.cpp
|
||||||
|
*
|
||||||
|
* Copyright 2016 nkk71 <nkk71x@gmail.com>
|
||||||
|
* Copyright 2016 topjohnwu <topjohnwu#gmail.com>
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||||
|
* MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
|
||||||
|
#define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_
|
||||||
|
#include "_system_properties.h"
|
||||||
|
#include <sys/system_properties.h>
|
||||||
|
|
||||||
|
/* Info:
|
||||||
|
*
|
||||||
|
* all changes are in
|
||||||
|
*
|
||||||
|
* bionic/libc/bionic/system_properties.cpp
|
||||||
|
*
|
||||||
|
* Functions that need to be patched/added in system_properties.cpp
|
||||||
|
*
|
||||||
|
* int __system_properties_init()
|
||||||
|
* on android 7, first tear down the everything then let it initialize again:
|
||||||
|
* if (initialized) {
|
||||||
|
* //list_foreach(contexts, [](context_node* l) { l->reset_access(); });
|
||||||
|
* //return 0;
|
||||||
|
* free_and_unmap_contexts();
|
||||||
|
* initialized = false;
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* static prop_area* map_prop_area(const char* filename, bool is_legacy)
|
||||||
|
* we dont want this read only so change: 'O_RDONLY' to 'O_RDWR'
|
||||||
|
*
|
||||||
|
* static prop_area* map_fd_ro(const int fd)
|
||||||
|
* we dont want this read only so change: 'PROT_READ' to 'PROT_READ | PROT_WRITE'
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* Copy the code of prop_info *prop_area::find_property, and modify to delete props
|
||||||
|
* const prop_info *prop_area::find_property_and_del(prop_bt *const trie, const char *name)
|
||||||
|
* {
|
||||||
|
* ...
|
||||||
|
* ... Do not alloc a new prop_bt here, remove all code involve alloc_if_needed
|
||||||
|
* ...
|
||||||
|
*
|
||||||
|
* if (prop_offset != 0) {
|
||||||
|
* atomic_store_explicit(¤t->prop, 0, memory_order_release); // Add this line to nullify the prop entry
|
||||||
|
* return to_prop_info(¤t->prop);
|
||||||
|
* } else {
|
||||||
|
*
|
||||||
|
* ....
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* by patching just those functions directly, all other functions should be ok
|
||||||
|
* as is.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
int verbose = 0, del = 0, file = 0, trigger = 1;
|
||||||
|
|
||||||
|
static bool is_legal_property_name(const char* name, size_t namelen)
|
||||||
|
{
|
||||||
|
size_t i;
|
||||||
|
if (namelen >= PROP_NAME_MAX) return false;
|
||||||
|
if (namelen < 1) return false;
|
||||||
|
if (name[0] == '.') return false;
|
||||||
|
if (name[namelen - 1] == '.') return false;
|
||||||
|
|
||||||
|
/* Only allow alphanumeric, plus '.', '-', or '_' */
|
||||||
|
/* Don't allow ".." to appear in a property name */
|
||||||
|
for (i = 0; i < namelen; i++) {
|
||||||
|
if (name[i] == '.') {
|
||||||
|
// i=0 is guaranteed to never have a dot. See above.
|
||||||
|
if (name[i-1] == '.') return false;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (name[i] == '_' || name[i] == '-') continue;
|
||||||
|
if (name[i] >= 'a' && name[i] <= 'z') continue;
|
||||||
|
if (name[i] >= 'A' && name[i] <= 'Z') continue;
|
||||||
|
if (name[i] >= '0' && name[i] <= '9') continue;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
int x_property_set(const char *name, const char *value)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
char value_read[PROP_VALUE_MAX];
|
||||||
|
|
||||||
|
size_t namelen = strlen(name);
|
||||||
|
size_t valuelen = strlen(value);
|
||||||
|
|
||||||
|
if (trigger) {
|
||||||
|
printf("Set with property_service: '%s'='%s'\n", name, value);
|
||||||
|
} else {
|
||||||
|
printf("Modify data structure: '%s'='%s'\n", name, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
__system_property_get(name, value_read);
|
||||||
|
|
||||||
|
if(strlen(value_read)) {
|
||||||
|
printf("Existing property: '%s'='%s'\n", name, value_read);
|
||||||
|
if (trigger) {
|
||||||
|
if (!strncmp(name, "ro.", 3)) __system_property_del(name); // Only delete ro props
|
||||||
|
ret = __system_property_set(name, value);
|
||||||
|
} else {
|
||||||
|
ret = __system_property_update((prop_info*) __system_property_find(name), value, valuelen);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (trigger) {
|
||||||
|
ret = __system_property_set(name, value);
|
||||||
|
} else {
|
||||||
|
ret = __system_property_add(name, namelen, value, valuelen);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ret != 0) {
|
||||||
|
fprintf(stderr, "Failed to set '%s'='%s'\n", name, value);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
__system_property_get(name, value_read);
|
||||||
|
printf("Recheck property: '%s'='%s'\n", name, value_read);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int read_prop_file(const char* filename) {
|
||||||
|
printf("Attempting to read props from \'%s\'\n", filename);
|
||||||
|
FILE *fp = fopen(filename, "r");
|
||||||
|
if (fp == NULL) {
|
||||||
|
fprintf(stderr, "Cannot open \'%s\'\n", filename);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
char *line = NULL, *pch;
|
||||||
|
size_t len;
|
||||||
|
ssize_t read;
|
||||||
|
int comment = 0, i;
|
||||||
|
while ((read = getline(&line, &len, fp)) != -1) {
|
||||||
|
// Remove the trailing newline
|
||||||
|
if (line[read - 1] == '\n') {
|
||||||
|
line[read - 1] = '\0';
|
||||||
|
--read;
|
||||||
|
}
|
||||||
|
comment = 0;
|
||||||
|
for (i = 0; i < read; ++i) {
|
||||||
|
// Ignore starting spaces
|
||||||
|
if (line[i] == ' ') continue;
|
||||||
|
else {
|
||||||
|
// A line starting with # is ignored
|
||||||
|
if (line[i] == '#') comment = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (comment) continue;
|
||||||
|
pch = strchr(line, '=');
|
||||||
|
// Ignore ivalid formats
|
||||||
|
if ( ((pch == NULL) || (i >= (pch - line))) || (pch >= line + read - 1) ) continue;
|
||||||
|
// Separate the string
|
||||||
|
*pch = '\0';
|
||||||
|
x_property_set(line + i, pch + 1);
|
||||||
|
}
|
||||||
|
free(line);
|
||||||
|
fclose(fp);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int usage(char* name) {
|
||||||
|
fprintf(stderr, "usage: %s [-v] [-n] [--file propfile] [--delete name] [ name value ] \n", name);
|
||||||
|
fprintf(stderr, " -v :\n");
|
||||||
|
fprintf(stderr, " verbose output (Default: Disabled)\n");
|
||||||
|
fprintf(stderr, " -n :\n");
|
||||||
|
fprintf(stderr, " no event triggers when changing props (Default: Will trigger events)\n");
|
||||||
|
fprintf(stderr, " --file propfile :\n");
|
||||||
|
fprintf(stderr, " Read props from prop files (e.g. build.prop)\n");
|
||||||
|
fprintf(stderr, " --delete name :\n");
|
||||||
|
fprintf(stderr, " Remove a prop entry\n\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
|
||||||
|
int exp_arg = 2, stdout_bak, null;
|
||||||
|
char *name, *value, *filename;
|
||||||
|
|
||||||
|
if (argc < 3) {
|
||||||
|
return usage(argv[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 1; i < argc; ++i) {
|
||||||
|
if (!strcmp("-v", argv[i])) {
|
||||||
|
verbose = 1;
|
||||||
|
} else if (!strcmp("-n", argv[i])) {
|
||||||
|
trigger = 0;
|
||||||
|
} else if (!strcmp("--file", argv[i])) {
|
||||||
|
file = 1;
|
||||||
|
exp_arg = 1;
|
||||||
|
} else if (!strcmp("--delete", argv[i])) {
|
||||||
|
del = 1;
|
||||||
|
exp_arg = 1;
|
||||||
|
} else {
|
||||||
|
if (i + exp_arg > argc) {
|
||||||
|
return usage(argv[0]);
|
||||||
|
}
|
||||||
|
if (file) {
|
||||||
|
filename = argv[i];
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
if(!is_legal_property_name(argv[i], strlen(argv[i]))) {
|
||||||
|
fprintf(stderr, "Illegal property name \'%s\'\n", argv[i]);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
name = argv[i];
|
||||||
|
if (exp_arg > 1) {
|
||||||
|
if (strlen(argv[i + 1]) >= PROP_VALUE_MAX) {
|
||||||
|
fprintf(stderr, "Value too long \'%s\'\n", argv[i + 1]);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
value = argv[i + 1];
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!verbose) {
|
||||||
|
fflush(stdout);
|
||||||
|
stdout_bak = dup(1);
|
||||||
|
null = open("/dev/null", O_WRONLY);
|
||||||
|
dup2(null, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("resetprop by nkk71 & topjohnwu\n");
|
||||||
|
|
||||||
|
printf("Initializing...\n");
|
||||||
|
if (__system_properties_init()) {
|
||||||
|
fprintf(stderr, "Error during init\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (file) {
|
||||||
|
if (read_prop_file(filename)) return 1;
|
||||||
|
} else if (del) {
|
||||||
|
printf("Attempting to delete '%s'\n", name);
|
||||||
|
if (__system_property_del(name)) return 1;
|
||||||
|
} else {
|
||||||
|
if(x_property_set(name, value)) return 1;
|
||||||
|
}
|
||||||
|
printf("Done!\n\n");
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
}
|
1385
jni/resetprop/system_properties.cpp
Normal file
1385
jni/resetprop/system_properties.cpp
Normal file
File diff suppressed because it is too large
Load Diff
1
jni/selinux
Submodule
1
jni/selinux
Submodule
Submodule jni/selinux added at d7c6efa178
Submodule jni/sepolicy-inject deleted from 3a0df56605
1
jni/su
Submodule
1
jni/su
Submodule
Submodule jni/su added at 356b2c0f5f
479
scripts/flash_script.sh
Normal file
479
scripts/flash_script.sh
Normal file
@@ -0,0 +1,479 @@
|
|||||||
|
#!/sbin/sh
|
||||||
|
##########################################################################################
|
||||||
|
#
|
||||||
|
# Magisk Boot Image Patcher
|
||||||
|
# by topjohnwu
|
||||||
|
#
|
||||||
|
# This zip will patch your boot image with Magisk support
|
||||||
|
#
|
||||||
|
##########################################################################################
|
||||||
|
|
||||||
|
MAGISK=true
|
||||||
|
|
||||||
|
# Detect whether in boot mode
|
||||||
|
ps | grep zygote | grep -v grep >/dev/null && BOOTMODE=true || BOOTMODE=false
|
||||||
|
|
||||||
|
# This path should work in any cases
|
||||||
|
TMPDIR=/dev/tmp
|
||||||
|
|
||||||
|
INSTALLER=$TMPDIR/magisk
|
||||||
|
COMMONDIR=$INSTALLER/common
|
||||||
|
BOOTTMP=$TMPDIR/boottmp
|
||||||
|
COREDIR=/magisk/.core
|
||||||
|
CHROMEDIR=$INSTALLER/chromeos
|
||||||
|
|
||||||
|
# Default permissions
|
||||||
|
umask 022
|
||||||
|
|
||||||
|
##########################################################################################
|
||||||
|
# Flashable update-binary preparation
|
||||||
|
##########################################################################################
|
||||||
|
|
||||||
|
OUTFD=$2
|
||||||
|
ZIP=$3
|
||||||
|
|
||||||
|
readlink /proc/$$/fd/$OUTFD 2>/dev/null | grep /tmp >/dev/null
|
||||||
|
if [ "$?" -eq "0" ]; then
|
||||||
|
OUTFD=0
|
||||||
|
|
||||||
|
for FD in `ls /proc/$$/fd`; do
|
||||||
|
readlink /proc/$$/fd/$FD 2>/dev/null | grep pipe >/dev/null
|
||||||
|
if [ "$?" -eq "0" ]; then
|
||||||
|
ps | grep " 3 $FD " | grep -v grep >/dev/null
|
||||||
|
if [ "$?" -eq "0" ]; then
|
||||||
|
OUTFD=$FD
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
|
||||||
|
mkdir -p $INSTALLER
|
||||||
|
cd $INSTALLER
|
||||||
|
unzip -o "$ZIP"
|
||||||
|
|
||||||
|
##########################################################################################
|
||||||
|
# Functions
|
||||||
|
##########################################################################################
|
||||||
|
|
||||||
|
ui_print() {
|
||||||
|
if $BOOTMODE; then
|
||||||
|
echo "$1"
|
||||||
|
else
|
||||||
|
echo -n -e "ui_print $1\n" >> /proc/self/fd/$OUTFD
|
||||||
|
echo -n -e "ui_print\n" >> /proc/self/fd/$OUTFD
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
getvar() {
|
||||||
|
local VARNAME=$1
|
||||||
|
local VALUE=$(eval echo \$"$VARNAME");
|
||||||
|
for FILE in /dev/.magisk /data/.magisk /cache/.magisk /system/.magisk; do
|
||||||
|
if [ -z "$VALUE" ]; then
|
||||||
|
LINE=$(cat $FILE 2>/dev/null | grep "$VARNAME=")
|
||||||
|
if [ ! -z "$LINE" ]; then
|
||||||
|
VALUE=${LINE#*=}
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
eval $VARNAME=\$VALUE
|
||||||
|
}
|
||||||
|
|
||||||
|
find_boot_image() {
|
||||||
|
if [ -z "$BOOTIMAGE" ]; then
|
||||||
|
for PARTITION in kern-a KERN-A android_boot ANDROID_BOOT kernel KERNEL boot BOOT lnx LNX; do
|
||||||
|
BOOTIMAGE=`readlink /dev/block/by-name/$PARTITION || readlink /dev/block/platform/*/by-name/$PARTITION || readlink /dev/block/platform/*/*/by-name/$PARTITION`
|
||||||
|
if [ ! -z "$BOOTIMAGE" ]; then break; fi
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
if [ -z "$BOOTIMAGE" ]; then
|
||||||
|
FSTAB="/etc/recovery.fstab"
|
||||||
|
[ ! -f "$FSTAB" ] && FSTAB="/etc/recovery.fstab.bak"
|
||||||
|
[ -f "$FSTAB" ] && BOOTIMAGE=`grep -E '\b/boot\b' "$FSTAB" | grep -oE '/dev/[a-zA-Z0-9_./-]*'`
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
is_mounted() {
|
||||||
|
if [ ! -z "$2" ]; then
|
||||||
|
cat /proc/mounts | grep $1 | grep $2, >/dev/null
|
||||||
|
else
|
||||||
|
cat /proc/mounts | grep $1 >/dev/null
|
||||||
|
fi
|
||||||
|
return $?
|
||||||
|
}
|
||||||
|
|
||||||
|
mount_image() {
|
||||||
|
if [ ! -d "$2" ]; then
|
||||||
|
mount -o rw,remount rootfs /
|
||||||
|
mkdir -p $2 2>/dev/null
|
||||||
|
($BOOTMODE) && mount -o ro,remount rootfs /
|
||||||
|
[ ! -d "$2" ] && return 1
|
||||||
|
fi
|
||||||
|
if (! is_mounted $2); then
|
||||||
|
LOOPDEVICE=
|
||||||
|
for LOOP in 0 1 2 3 4 5 6 7; do
|
||||||
|
if (! is_mounted $2); then
|
||||||
|
LOOPDEVICE=/dev/block/loop$LOOP
|
||||||
|
if [ ! -f "$LOOPDEVICE" ]; then
|
||||||
|
mknod $LOOPDEVICE b 7 $LOOP 2>/dev/null
|
||||||
|
fi
|
||||||
|
losetup $LOOPDEVICE $1
|
||||||
|
if [ "$?" -eq "0" ]; then
|
||||||
|
mount -t ext4 -o loop $LOOPDEVICE $2
|
||||||
|
if (! is_mounted $2); then
|
||||||
|
/system/bin/toolbox mount -t ext4 -o loop $LOOPDEVICE $2
|
||||||
|
fi
|
||||||
|
if (! is_mounted $2); then
|
||||||
|
/system/bin/toybox mount -t ext4 -o loop $LOOPDEVICE $2
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
if (is_mounted $2); then
|
||||||
|
ui_print "- Mounting $1 to $2"
|
||||||
|
break;
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
grep_prop() {
|
||||||
|
REGEX="s/^$1=//p"
|
||||||
|
shift
|
||||||
|
FILES=$@
|
||||||
|
if [ -z "$FILES" ]; then
|
||||||
|
FILES='/system/build.prop'
|
||||||
|
fi
|
||||||
|
cat $FILES 2>/dev/null | sed -n "$REGEX" | head -n 1
|
||||||
|
}
|
||||||
|
|
||||||
|
remove_system_su() {
|
||||||
|
if [ -f /system/bin/su -o -f /system/xbin/su ] && [ ! -f /su/bin/su ]; then
|
||||||
|
ui_print "! System installed root detected, mount rw :("
|
||||||
|
mount -o rw,remount /system
|
||||||
|
# SuperSU
|
||||||
|
if [ -e /system/bin/.ext/.su ]; then
|
||||||
|
mv -f /system/bin/app_process32_original /system/bin/app_process32 2>/dev/null
|
||||||
|
mv -f /system/bin/app_process64_original /system/bin/app_process64 2>/dev/null
|
||||||
|
mv -f /system/bin/install-recovery_original.sh /system/bin/install-recovery.sh 2>/dev/null
|
||||||
|
cd /system/bin
|
||||||
|
if [ -e app_process64 ]; then
|
||||||
|
ln -sf app_process64 app_process
|
||||||
|
else
|
||||||
|
ln -sf app_process32 app_process
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
rm -rf /system/.pin /system/bin/.ext /system/etc/.installed_su_daemon /system/etc/.has_su_daemon \
|
||||||
|
/system/xbin/daemonsu /system/xbin/su /system/xbin/sugote /system/xbin/sugote-mksh /system/xbin/supolicy \
|
||||||
|
/system/bin/app_process_init /system/bin/su /cache/su /system/lib/libsupol.so /system/lib64/libsupol.so \
|
||||||
|
/system/su.d /system/etc/install-recovery.sh /system/etc/init.d/99SuperSUDaemon /cache/install-recovery.sh \
|
||||||
|
/system/.supersu /cache/.supersu /data/.supersu \
|
||||||
|
/system/app/Superuser.apk /system/app/SuperSU /cache/Superuser.apk 2>/dev/null
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
##########################################################################################
|
||||||
|
# Detection
|
||||||
|
##########################################################################################
|
||||||
|
|
||||||
|
ui_print "*****************************"
|
||||||
|
ui_print "MAGISK_VERSION_STUB"
|
||||||
|
ui_print "*****************************"
|
||||||
|
|
||||||
|
if [ ! -d "$COMMONDIR" ]; then
|
||||||
|
ui_print "! Failed: Unable to extract zip file!"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
ui_print "- Mounting /system(ro), /cache, /data"
|
||||||
|
mount -o ro /system 2>/dev/null
|
||||||
|
mount /cache 2>/dev/null
|
||||||
|
mount /data 2>/dev/null
|
||||||
|
|
||||||
|
if [ ! -f '/system/build.prop' ]; then
|
||||||
|
ui_print "! Failed: /system could not be mounted!"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# read override variables
|
||||||
|
getvar KEEPVERITY
|
||||||
|
getvar KEEPFORCEENCRYPT
|
||||||
|
getvar BOOTIMAGE
|
||||||
|
|
||||||
|
[ -z $KEEPVERITY ] && KEEPVERITY=false
|
||||||
|
[ -z $KEEPFORCEENCRYPT ] && KEEPFORCEENCRYPT=false
|
||||||
|
|
||||||
|
# Check if system root is installed and remove
|
||||||
|
remove_system_su
|
||||||
|
|
||||||
|
API=`grep_prop ro.build.version.sdk`
|
||||||
|
ABI=`grep_prop ro.product.cpu.abi | cut -c-3`
|
||||||
|
ABI2=`grep_prop ro.product.cpu.abi2 | cut -c-3`
|
||||||
|
ABILONG=`grep_prop ro.product.cpu.abi`
|
||||||
|
|
||||||
|
ARCH=arm
|
||||||
|
IS64BIT=false
|
||||||
|
if [ "$ABI" = "x86" ]; then ARCH=x86; fi;
|
||||||
|
if [ "$ABI2" = "x86" ]; then ARCH=x86; fi;
|
||||||
|
if [ "$ABILONG" = "arm64-v8a" ]; then ARCH=arm64; IS64BIT=true; fi;
|
||||||
|
if [ "$ABILONG" = "x86_64" ]; then ARCH=x64; IS64BIT=true; fi;
|
||||||
|
|
||||||
|
|
||||||
|
if [ "$API" -lt "21" ]; then
|
||||||
|
ui_print "! Magisk is only for Lollipop 5.0+ (SDK 21+)"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
ui_print "- Device platform: $ARCH"
|
||||||
|
|
||||||
|
BINDIR=$INSTALLER/$ARCH
|
||||||
|
chmod -R 755 $CHROMEDIR $BINDIR
|
||||||
|
|
||||||
|
SYSTEMLIB=/system/lib
|
||||||
|
$IS64BIT && SYSTEMLIB=/system/lib64
|
||||||
|
|
||||||
|
find_boot_image
|
||||||
|
if [ -z $BOOTIMAGE ]; then
|
||||||
|
ui_print "! Unable to detect boot image"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
##########################################################################################
|
||||||
|
# Environment
|
||||||
|
##########################################################################################
|
||||||
|
|
||||||
|
ui_print "- Constructing environment"
|
||||||
|
|
||||||
|
is_mounted /data && MAGISKBIN=/data/magisk || MAGISKBIN=/cache/data_bin
|
||||||
|
|
||||||
|
# Copy required files
|
||||||
|
rm -rf $MAGISKBIN 2>/dev/null
|
||||||
|
mkdir -p $MAGISKBIN
|
||||||
|
cp -af $BINDIR/. $COMMONDIR/ramdisk_patch.sh $COMMONDIR/magic_mask.sh \
|
||||||
|
$COMMONDIR/init.magisk.rc $COMMONDIR/magisk.apk $MAGISKBIN
|
||||||
|
# Legacy support
|
||||||
|
ln -sf /data/magisk/magiskpolicy $MAGISKBIN/sepolicy-inject
|
||||||
|
|
||||||
|
chmod -R 755 $MAGISKBIN
|
||||||
|
chcon -h u:object_r:system_file:s0 $MAGISKBIN $MAGISKBIN/*
|
||||||
|
|
||||||
|
# Temporary busybox for installation
|
||||||
|
rm -rf $TMPDIR/busybox 2>/dev/null
|
||||||
|
mkdir -p $TMPDIR/busybox
|
||||||
|
$BINDIR/busybox --install -s $TMPDIR/busybox
|
||||||
|
rm -f $TMPDIR/busybox/su $TMPDIR/busybox/sh $TMPDIR/busybox/reboot
|
||||||
|
PATH=$TMPDIR/busybox:$PATH
|
||||||
|
|
||||||
|
##########################################################################################
|
||||||
|
# Unpack boot
|
||||||
|
##########################################################################################
|
||||||
|
|
||||||
|
ui_print "- Found Boot Image: $BOOTIMAGE"
|
||||||
|
|
||||||
|
rm -rf $BOOTTMP 2>/dev/null
|
||||||
|
mkdir -p $BOOTTMP
|
||||||
|
cd $BOOTTMP
|
||||||
|
|
||||||
|
ui_print "- Unpacking boot image"
|
||||||
|
LD_LIBRARY_PATH=$SYSTEMLIB $BINDIR/magiskboot --unpack $BOOTIMAGE
|
||||||
|
if [ $? -ne 0 ]; then
|
||||||
|
ui_print "! Unable to unpack boot image"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
##########################################################################################
|
||||||
|
# Ramdisk restores
|
||||||
|
##########################################################################################
|
||||||
|
|
||||||
|
# Update our previous backup to new format if exists
|
||||||
|
if [ -f /data/stock_boot.img ]; then
|
||||||
|
SHA1=`LD_LIBRARY_PATH=$SYSTEMLIB $BINDIR/magiskboot --sha1 /data/stock_boot.img | tail -n 1`
|
||||||
|
STOCKDUMP=/data/stock_boot_${SHA1}.img
|
||||||
|
mv /data/stock_boot.img $STOCKDUMP
|
||||||
|
LD_LIBRARY_PATH=$SYSTEMLIB $BINDIR/magiskboot --compress $STOCKDUMP
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Test patch status and do restore, after this section, ramdisk.cpio.orig is guaranteed to exist
|
||||||
|
SUPERSU=false
|
||||||
|
ui_print "- Checking patch status"
|
||||||
|
LD_LIBRARY_PATH=$SYSTEMLIB $BINDIR/magiskboot --cpio-test ramdisk.cpio
|
||||||
|
case $? in
|
||||||
|
0 ) # Stock boot
|
||||||
|
ui_print "- Backing up stock boot image"
|
||||||
|
rm -f /data/stock_boot*
|
||||||
|
SHA1=`LD_LIBRARY_PATH=$SYSTEMLIB $BINDIR/magiskboot --sha1 $BOOTIMAGE | tail -n 1`
|
||||||
|
is_mounted /data && STOCKDUMP=/data/stock_boot_${SHA1}.img || STOCKDUMP=/cache/stock_boot_${SHA1}.img
|
||||||
|
dd if=$BOOTIMAGE of=$STOCKDUMP
|
||||||
|
LD_LIBRARY_PATH=$SYSTEMLIB $BINDIR/magiskboot --compress $STOCKDUMP
|
||||||
|
cp -af ramdisk.cpio ramdisk.cpio.orig
|
||||||
|
;;
|
||||||
|
1 ) # Magisk patched
|
||||||
|
# Find SHA1 of stock boot image
|
||||||
|
if [ -z $SHA1 ]; then
|
||||||
|
LD_LIBRARY_PATH=$SYSTEMLIB $BINDIR/magiskboot --cpio-extract ramdisk.cpio init.magisk.rc init.magisk.rc
|
||||||
|
SHA1=`grep_prop "# STOCKSHA1" init.magisk.rc`
|
||||||
|
[ ! -z $SHA1 ] && STOCKDUMP=/data/stock_boot_${SHA1}.img
|
||||||
|
rm -f init.magisk.rc
|
||||||
|
fi
|
||||||
|
ui_print "- Restoring ramdisk backup"
|
||||||
|
LD_LIBRARY_PATH=$SYSTEMLIB $BINDIR/magiskboot --cpio-restore ramdisk.cpio
|
||||||
|
if [ $? -ne 0 ]; then
|
||||||
|
# Restore failed, try to find original
|
||||||
|
ui_print "! Cannot restore from ramdisk backup"
|
||||||
|
ui_print "- Finding stock boot image backup"
|
||||||
|
if [ -f ${STOCKDUMP}.gz ]; then
|
||||||
|
LD_LIBRARY_PATH=$SYSTEMLIB $BINDIR/magiskboot --decompress ${STOCKDUMP}.gz stock_boot.img
|
||||||
|
LD_LIBRARY_PATH=$SYSTEMLIB $BINDIR/magiskboot --unpack stock_boot.img
|
||||||
|
rm -f stock_boot.img
|
||||||
|
else
|
||||||
|
ui_print "! Cannot find stock boot image backup"
|
||||||
|
ui_print "! Will still try to complete installation"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
cp -af ramdisk.cpio ramdisk.cpio.orig
|
||||||
|
;;
|
||||||
|
2 ) # SuperSU patched
|
||||||
|
SUPERSU=true
|
||||||
|
ui_print "- SuperSU patched boot detected!"
|
||||||
|
ui_print "- Adding auto patch script for SuperSU"
|
||||||
|
cp -af $COMMONDIR/ramdisk_patch.sh /data/custom_ramdisk_patch.sh
|
||||||
|
is_mounted /data && SUIMG=/data/su.img || SUIMG=/cache/su.img
|
||||||
|
mount_image $SUIMG /su
|
||||||
|
SUPERSULOOP=$LOOPDEVICE
|
||||||
|
if (is_mounted /su); then
|
||||||
|
ui_print "- Restoring ramdisk backup with sukernel"
|
||||||
|
LD_LIBRARY_PATH=$SYSTEMLIB /su/bin/sukernel --cpio-restore ramdisk.cpio ramdisk.cpio.orig
|
||||||
|
if [ $? -ne 0 ]; then
|
||||||
|
ui_print "! Cannot restore from ramdisk"
|
||||||
|
ui_print "- Finding stock boot image backup with sukernel"
|
||||||
|
LD_LIBRARY_PATH=$SYSTEMLIB /su/bin/sukernel --restore ramdisk.cpio stock_boot.img
|
||||||
|
if [ $? -eq 0 ]; then
|
||||||
|
LD_LIBRARY_PATH=$SYSTEMLIB $BINDIR/magiskboot --unpack stock_boot.img
|
||||||
|
cp -af ramdisk.cpio ramdisk.cpio.orig
|
||||||
|
rm stock_boot.img
|
||||||
|
else
|
||||||
|
ui_print "! Cannot find stock boot image backup"
|
||||||
|
ui_print "! Will still try to complete installation"
|
||||||
|
# Since no backup at all, let's try our best...
|
||||||
|
LD_LIBRARY_PATH=$SYSTEMLIB $BINDIR/magiskboot --cpio-restore ramdisk.cpio
|
||||||
|
cp -af ramdisk.cpio ramdisk.cpio.orig
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
ui_print "! SuperSU image mount failed..."
|
||||||
|
ui_print "! Will still try to complete installation"
|
||||||
|
# Since we cannot rely on sukernel, do it outselves...
|
||||||
|
LD_LIBRARY_PATH=$SYSTEMLIB $BINDIR/magiskboot --cpio-restore ramdisk.cpio
|
||||||
|
cp -af ramdisk.cpio ramdisk.cpio.orig
|
||||||
|
fi
|
||||||
|
# Remove SuperSU backups, since we are recreating it
|
||||||
|
LD_LIBRARY_PATH=$SYSTEMLIB $BINDIR/magiskboot --cpio-rm ramdisk.cpio -r .subackup
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
##########################################################################################
|
||||||
|
# Ramdisk patch
|
||||||
|
##########################################################################################
|
||||||
|
|
||||||
|
# All ramdisk patch commands are stored in a separate script
|
||||||
|
ui_print "- Patching ramdisk"
|
||||||
|
source $COMMONDIR/ramdisk_patch.sh $BOOTTMP/ramdisk.cpio
|
||||||
|
|
||||||
|
cd $BOOTTMP
|
||||||
|
# Create ramdisk backups
|
||||||
|
if $SUPERSU; then
|
||||||
|
[ -f /su/bin/sukernel ] && LD_LIBRARY_PATH=$SYSTEMLIB /su/bin/sukernel --cpio-backup ramdisk.cpio.orig ramdisk.cpio ramdisk.cpio
|
||||||
|
else
|
||||||
|
LD_LIBRARY_PATH=$SYSTEMLIB $BINDIR/magiskboot --cpio-backup ramdisk.cpio ramdisk.cpio.orig
|
||||||
|
fi
|
||||||
|
|
||||||
|
rm -f ramdisk.cpio.orig
|
||||||
|
|
||||||
|
##########################################################################################
|
||||||
|
# Magisk Image
|
||||||
|
##########################################################################################
|
||||||
|
|
||||||
|
# Fix SuperSU.....
|
||||||
|
$BOOTMODE && $BINDIR/magiskpolicy --live "allow fsck * * *"
|
||||||
|
|
||||||
|
if (is_mounted /data); then
|
||||||
|
IMG=/data/magisk.img
|
||||||
|
else
|
||||||
|
IMG=/cache/magisk.img
|
||||||
|
ui_print "- Data unavailable, use cache workaround"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -f $IMG ]; then
|
||||||
|
ui_print "- $IMG detected!"
|
||||||
|
else
|
||||||
|
ui_print "- Creating $IMG"
|
||||||
|
make_ext4fs -l 64M -a /magisk -S $COMMONDIR/file_contexts_image $IMG
|
||||||
|
fi
|
||||||
|
|
||||||
|
mount_image $IMG /magisk
|
||||||
|
if (! is_mounted /magisk); then
|
||||||
|
ui_print "! Magisk image mount failed..."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
MAGISKLOOP=$LOOPDEVICE
|
||||||
|
|
||||||
|
# Core folders and scripts
|
||||||
|
mkdir -p $COREDIR/magiskhide $COREDIR/post-fs-data.d $COREDIR/service.d 2>/dev/null
|
||||||
|
cp -af $COMMONDIR/magiskhide/. $COREDIR/magiskhide
|
||||||
|
chmod -R 755 $COREDIR/magiskhide $COREDIR/post-fs-data.d $COREDIR/service.d
|
||||||
|
chown -R 0.0 $COREDIR/magiskhide $COREDIR/post-fs-data.d $COREDIR/service.d
|
||||||
|
|
||||||
|
##########################################################################################
|
||||||
|
# Repack and flash
|
||||||
|
##########################################################################################
|
||||||
|
|
||||||
|
LD_LIBRARY_PATH=$SYSTEMLIB $BINDIR/magiskboot --repack $BOOTIMAGE
|
||||||
|
|
||||||
|
case $? in
|
||||||
|
1 )
|
||||||
|
ui_print "! Unable to repack boot image!"
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
2 )
|
||||||
|
ui_print "! Boot partition space insufficient"
|
||||||
|
ui_print "! Remove ramdisk backups and try again"
|
||||||
|
LD_LIBRARY_PATH=$SYSTEMLIB $BINDIR/magiskboot --cpio-rm ramdisk.cpio -r .backup
|
||||||
|
LD_LIBRARY_PATH=$SYSTEMLIB $BINDIR/magiskboot --repack $BOOTIMAGE
|
||||||
|
if [ $? -eq 2 ]; then
|
||||||
|
ui_print "! Boot partition size still too small..."
|
||||||
|
ui_print "! Unable to install Magisk"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
# Sign chromeos boot
|
||||||
|
if [ -f chromeos ]; then
|
||||||
|
cp -af $CHROMEDIR/. $MAGISKBIN/chromeos
|
||||||
|
echo > config
|
||||||
|
echo > bootloader
|
||||||
|
LD_LIBRARY_PATH=$SYSTEMLIB $CHROMEDIR/futility vbutil_kernel --pack new-boot.img.signed --keyblock $CHROMEDIR/kernel.keyblock --signprivate $CHROMEDIR/kernel_data_key.vbprivk --version 1 --vmlinuz new-boot.img --config config --arch arm --bootloader bootloader --flags 0x1
|
||||||
|
rm -f new-boot.img
|
||||||
|
mv new-boot.img.signed new-boot.img
|
||||||
|
fi
|
||||||
|
|
||||||
|
ui_print "- Flashing new boot image"
|
||||||
|
[ ! -L $BOOTIMAGE ] && dd if=/dev/zero of=$BOOTIMAGE bs=4096 2>/dev/null
|
||||||
|
dd if=new-boot.img of=$BOOTIMAGE bs=4096
|
||||||
|
|
||||||
|
cd /
|
||||||
|
|
||||||
|
if ! $BOOTMODE; then
|
||||||
|
ui_print "- Unmounting partitions"
|
||||||
|
umount /magisk
|
||||||
|
losetup -d $MAGISKLOOP
|
||||||
|
rmdir /magisk
|
||||||
|
if $SUPERSU; then
|
||||||
|
umount /su
|
||||||
|
losetup -d $SUPERSULOOP
|
||||||
|
rmdir /su
|
||||||
|
fi
|
||||||
|
umount /system
|
||||||
|
fi
|
||||||
|
|
||||||
|
ui_print "- Done"
|
||||||
|
exit 0
|
@@ -3,15 +3,15 @@
|
|||||||
on post-fs
|
on post-fs
|
||||||
start magisk_pfs
|
start magisk_pfs
|
||||||
wait /dev/.magisk.unblock 20
|
wait /dev/.magisk.unblock 20
|
||||||
rm /dev/.magisk.unblock
|
|
||||||
|
|
||||||
on post-fs-data
|
on post-fs-data
|
||||||
start magisk_pfsd
|
|
||||||
wait /dev/.magisk.unblock 40
|
|
||||||
rm /dev/.magisk.unblock
|
rm /dev/.magisk.unblock
|
||||||
|
load_persist_props
|
||||||
|
start magisk_pfsd
|
||||||
|
wait /dev/.magisk.unblock 60
|
||||||
|
|
||||||
on property:magisk.hide=1
|
on property:magisk.restart_pfsd=1
|
||||||
restart magisk_hide
|
trigger post-fs-data
|
||||||
|
|
||||||
# Services
|
# Services
|
||||||
|
|
||||||
@@ -33,9 +33,3 @@ service magisk_service /sbin/magic_mask.sh service
|
|||||||
user root
|
user root
|
||||||
seclabel u:r:su:s0
|
seclabel u:r:su:s0
|
||||||
oneshot
|
oneshot
|
||||||
|
|
||||||
# launch magisk hide script
|
|
||||||
service magisk_hide /sbin/magic_mask.sh hide
|
|
||||||
user root
|
|
||||||
seclabel u:r:su:s0
|
|
||||||
oneshot
|
|
541
scripts/magic_mask.sh
Normal file
541
scripts/magic_mask.sh
Normal file
@@ -0,0 +1,541 @@
|
|||||||
|
#!/system/bin/sh
|
||||||
|
|
||||||
|
LOGFILE=/cache/magisk.log
|
||||||
|
DISABLEFILE=/cache/.disable_magisk
|
||||||
|
UNINSTALLER=/cache/magisk_uninstaller.sh
|
||||||
|
IMG=/data/magisk.img
|
||||||
|
WHITELIST="/system/bin"
|
||||||
|
|
||||||
|
MOUNTPOINT=/magisk
|
||||||
|
|
||||||
|
COREDIR=$MOUNTPOINT/.core
|
||||||
|
|
||||||
|
TMPDIR=/dev/magisk
|
||||||
|
DUMMDIR=$TMPDIR/dummy
|
||||||
|
MIRRDIR=$TMPDIR/mirror
|
||||||
|
MOUNTINFO=$TMPDIR/mnt
|
||||||
|
|
||||||
|
# Use the included busybox for maximum compatibility and reliable results
|
||||||
|
# e.g. we rely on the option "-c" for cp (reserve contexts), and -exec for find
|
||||||
|
TOOLPATH=/dev/busybox
|
||||||
|
BINPATH=/data/magisk
|
||||||
|
OLDPATH=$PATH
|
||||||
|
export PATH=$TOOLPATH:$OLDPATH
|
||||||
|
|
||||||
|
APPDIR=/data/data/com.topjohnwu.magisk/files
|
||||||
|
|
||||||
|
# Default permissions
|
||||||
|
umask 022
|
||||||
|
|
||||||
|
log_print() {
|
||||||
|
echo "$1"
|
||||||
|
echo "$1" >> $LOGFILE
|
||||||
|
log -p i -t Magisk "$1"
|
||||||
|
}
|
||||||
|
|
||||||
|
mktouch() {
|
||||||
|
mkdir -p "${1%/*}" 2>/dev/null
|
||||||
|
if [ -z "$2" ]; then
|
||||||
|
touch "$1" 2>/dev/null
|
||||||
|
else
|
||||||
|
echo "$2" > "$1" 2>/dev/null
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
in_list() {
|
||||||
|
for i in $2; do
|
||||||
|
[ "$1" = "$i" ] && return 0
|
||||||
|
done
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
unblock() {
|
||||||
|
touch /dev/.magisk.unblock
|
||||||
|
chcon u:object_r:device:s0 /dev/.magisk.unblock
|
||||||
|
exit
|
||||||
|
}
|
||||||
|
|
||||||
|
bind_mount() {
|
||||||
|
if [ -e "$1" -a -e "$2" ]; then
|
||||||
|
mount -o bind "$1" "$2" || log_print "Mount Fail: $1 -> $2"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
loopsetup() {
|
||||||
|
LOOPDEVICE=
|
||||||
|
for DEV in `ls /dev/block/loop*`; do
|
||||||
|
if losetup $DEV $1; then
|
||||||
|
LOOPDEVICE=$DEV
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
image_size_check() {
|
||||||
|
e2fsck -yf $1
|
||||||
|
curBlocks=`e2fsck -n $1 2>/dev/null | grep $1 | cut -d, -f3 | cut -d\ -f2`;
|
||||||
|
curUsedM=`echo "$curBlocks" | cut -d/ -f1`
|
||||||
|
curSizeM=`echo "$curBlocks" | cut -d/ -f1`
|
||||||
|
curFreeM=$(((curSizeM - curUsedM) * 4 / 1024))
|
||||||
|
curUsedM=$((curUsedM * 4 / 1024 + 1))
|
||||||
|
curSizeM=$((curSizeM * 4 / 1024))
|
||||||
|
}
|
||||||
|
|
||||||
|
run_scripts() {
|
||||||
|
BASE=$MOUNTPOINT
|
||||||
|
for MOD in $BASE/* ; do
|
||||||
|
if [ ! -f $MOD/disable ]; then
|
||||||
|
if [ -f $MOD/$1.sh ]; then
|
||||||
|
chmod 755 $MOD/$1.sh
|
||||||
|
chcon u:object_r:system_file:s0 $MOD/$1.sh
|
||||||
|
log_print "$1: $MOD/$1.sh"
|
||||||
|
sh $MOD/$1.sh
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
for SCRIPT in $COREDIR/${1}.d/* ; do
|
||||||
|
if [ -f "$SCRIPT" ]; then
|
||||||
|
chmod 755 $SCRIPT
|
||||||
|
chcon u:object_r:system_file:s0 $SCRIPT
|
||||||
|
log_print "${1}.d: $SCRIPT"
|
||||||
|
sh $SCRIPT
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
travel() {
|
||||||
|
cd "$TRAVEL_ROOT/$1"
|
||||||
|
if [ -f .replace ]; then
|
||||||
|
log_print "Replace: /$1"
|
||||||
|
rm -rf "$MOUNTINFO/$1"
|
||||||
|
mktouch "$MOUNTINFO/$1" "$TRAVEL_ROOT"
|
||||||
|
else
|
||||||
|
for ITEM in * ; do
|
||||||
|
# This means it's an empty folder (shouldn't happen, but better to be safe)
|
||||||
|
[ "$ITEM" = "*" ] && return
|
||||||
|
# Ignore /system/vendor since we will handle it differently
|
||||||
|
[ "$1" = "system" -a "$ITEM" = "vendor" ] && continue
|
||||||
|
|
||||||
|
# Target not found or target/file is a symlink
|
||||||
|
if [ ! -e "/$1/$ITEM" -o -L "/$1/$ITEM" -o -L "$ITEM" ]; then
|
||||||
|
# If we are in a higher level, delete the lower levels
|
||||||
|
rm -rf "$MOUNTINFO/dummy/$1" 2>/dev/null
|
||||||
|
# Mount the dummy parent
|
||||||
|
log_print "Replace with dummy: /$1"
|
||||||
|
mktouch "$MOUNTINFO/dummy/$1"
|
||||||
|
|
||||||
|
if [ -L "$ITEM" ]; then
|
||||||
|
# Copy symlinks
|
||||||
|
log_print "Symlink: /$1/$ITEM"
|
||||||
|
mkdir -p "$DUMMDIR/$1" 2>/dev/null
|
||||||
|
cp -afc "$ITEM" $"DUMMDIR/$1/$ITEM"
|
||||||
|
elif [ -d "$ITEM" ]; then
|
||||||
|
# Create new dummy directory and mount it
|
||||||
|
log_print "New directory: /$1/$ITEM"
|
||||||
|
mkdir -p "$DUMMDIR/$1/$ITEM"
|
||||||
|
mktouch "$MOUNTINFO/$1/$ITEM" "$TRAVEL_ROOT"
|
||||||
|
else
|
||||||
|
# Create new dummy file and mount it
|
||||||
|
log_print "New file: /$1/$ITEM"
|
||||||
|
mktouch "$DUMMDIR/$1/$ITEM"
|
||||||
|
mktouch "$MOUNTINFO/$1/$ITEM" "$TRAVEL_ROOT"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
if [ -d "$ITEM" ]; then
|
||||||
|
# It's an directory, travel deeper
|
||||||
|
(travel "$1/$ITEM")
|
||||||
|
elif [ ! -L "$ITEM" ]; then
|
||||||
|
# Mount this file
|
||||||
|
log_print "Replace: /$1/$ITEM"
|
||||||
|
mktouch "$MOUNTINFO/$1/$ITEM" "$TRAVEL_ROOT"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
clone_dummy() {
|
||||||
|
LINK=false
|
||||||
|
in_list "$1" "$WHITELIST" && LINK=true
|
||||||
|
|
||||||
|
for ITEM in $MIRRDIR$1/* ; do
|
||||||
|
REAL="${ITEM#$MIRRDIR}"
|
||||||
|
if [ -d "$MOUNTINFO$REAL" ]; then
|
||||||
|
# Need to clone deeper
|
||||||
|
mkdir -p "$DUMMDIR$REAL"
|
||||||
|
(clone_dummy "$REAL")
|
||||||
|
elif [ ! -f "$DUMMDIR$REAL" ]; then
|
||||||
|
# It's not the file to be added/replaced, clone it
|
||||||
|
if [ -L "$ITEM" ]; then
|
||||||
|
# Copy original symlink
|
||||||
|
cp -afc "$ITEM" "$DUMMDIR$REAL"
|
||||||
|
else
|
||||||
|
if $LINK && [ ! -e "$MOUNTINFO$REAL" ]; then
|
||||||
|
ln -sf "$MIRRDIR$REAL" "$DUMMDIR$REAL"
|
||||||
|
else
|
||||||
|
if [ -d "$ITEM" ]; then
|
||||||
|
mkdir -p "$DUMMDIR$REAL"
|
||||||
|
else
|
||||||
|
mktouch "$DUMMDIR$REAL"
|
||||||
|
fi
|
||||||
|
if [ ! -e "$MOUNTINFO$REAL" ]; then
|
||||||
|
log_print "Clone skeleton: $REAL"
|
||||||
|
mktouch "$MOUNTINFO/mirror$REAL"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
merge_image() {
|
||||||
|
if [ -f $1 ]; then
|
||||||
|
log_print "$1 found"
|
||||||
|
if [ -f $IMG ]; then
|
||||||
|
log_print "$IMG found, attempt to merge"
|
||||||
|
|
||||||
|
# Handle large images
|
||||||
|
image_size_check $1
|
||||||
|
mergeUsedM=$curUsedM
|
||||||
|
image_size_check $IMG
|
||||||
|
if [ "$mergeUsedM" -gt "$curFreeM" ]; then
|
||||||
|
NEWDATASIZE=$(((mergeUsedM + curUsedM) / 32 * 32 + 32))
|
||||||
|
log_print "Expanding $IMG to ${NEWDATASIZE}M..."
|
||||||
|
resize2fs $IMG ${NEWDATASIZE}M
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Start merging
|
||||||
|
mkdir /cache/data_img
|
||||||
|
mkdir /cache/merge_img
|
||||||
|
|
||||||
|
# setup loop devices
|
||||||
|
loopsetup $IMG
|
||||||
|
LOOPDATA=$LOOPDEVICE
|
||||||
|
log_print "$LOOPDATA $IMG"
|
||||||
|
|
||||||
|
loopsetup $1
|
||||||
|
LOOPMERGE=$LOOPDEVICE
|
||||||
|
log_print "$LOOPMERGE $1"
|
||||||
|
|
||||||
|
if [ ! -z $LOOPDATA -a ! -z $LOOPMERGE ]; then
|
||||||
|
# if loop devices have been setup, mount images
|
||||||
|
OK=false
|
||||||
|
mount -t ext4 -o rw,noatime $LOOPDATA /cache/data_img && \
|
||||||
|
mount -t ext4 -o rw,noatime $LOOPMERGE /cache/merge_img && \
|
||||||
|
OK=true
|
||||||
|
|
||||||
|
if $OK; then
|
||||||
|
# Merge (will reserve selinux contexts)
|
||||||
|
cd /cache/merge_img
|
||||||
|
for MOD in *; do
|
||||||
|
if [ "$MOD" != "lost+found" ]; then
|
||||||
|
log_print "Merging: $MOD"
|
||||||
|
rm -rf /cache/data_img/$MOD
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
cp -afc . /cache/data_img
|
||||||
|
log_print "Merge complete"
|
||||||
|
cd /
|
||||||
|
fi
|
||||||
|
|
||||||
|
umount /cache/data_img
|
||||||
|
umount /cache/merge_img
|
||||||
|
fi
|
||||||
|
|
||||||
|
losetup -d $LOOPDATA
|
||||||
|
losetup -d $LOOPMERGE
|
||||||
|
|
||||||
|
rmdir /cache/data_img
|
||||||
|
rmdir /cache/merge_img
|
||||||
|
else
|
||||||
|
log_print "Moving $1 to $IMG "
|
||||||
|
mv $1 $IMG
|
||||||
|
fi
|
||||||
|
rm -f $1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
case $1 in
|
||||||
|
post-fs )
|
||||||
|
mv $LOGFILE /cache/last_magisk.log
|
||||||
|
touch $LOGFILE
|
||||||
|
chmod 644 $LOGFILE
|
||||||
|
|
||||||
|
# No more cache mods!
|
||||||
|
# Only for multirom!
|
||||||
|
|
||||||
|
log_print "** Magisk post-fs mode running..."
|
||||||
|
|
||||||
|
# Cleanup legacy stuffs...
|
||||||
|
rm -rf /cache/magisk /cache/magisk_merge /cache/magiskhide.log
|
||||||
|
|
||||||
|
[ -f $DISABLEFILE -o -f $UNINSTALLER ] && unblock
|
||||||
|
|
||||||
|
if [ -d /cache/magisk_mount ]; then
|
||||||
|
log_print "* Mounting cache files"
|
||||||
|
find /cache/magisk_mount -type f 2>/dev/null | while read ITEM ; do
|
||||||
|
chmod 644 "$ITEM"
|
||||||
|
chcon u:object_r:system_file:s0 "$ITEM"
|
||||||
|
TARGET="${ITEM#/cache/magisk_mount}"
|
||||||
|
bind_mount "$ITEM" "$TARGET"
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
|
||||||
|
unblock
|
||||||
|
;;
|
||||||
|
|
||||||
|
post-fs-data )
|
||||||
|
# /data not mounted yet
|
||||||
|
! mount | grep " /data " >/dev/null && unblock
|
||||||
|
mount | grep " /data " | grep "tmpfs" >/dev/null && unblock
|
||||||
|
|
||||||
|
# Don't run twice
|
||||||
|
if [ "`getprop magisk.restart_pfsd`" != "1" ]; then
|
||||||
|
|
||||||
|
log_print "** Magisk post-fs-data mode running..."
|
||||||
|
|
||||||
|
# Cache support
|
||||||
|
mv /cache/stock_boot* /data 2>/dev/null
|
||||||
|
if [ -d /cache/data_bin ]; then
|
||||||
|
rm -rf $BINPATH
|
||||||
|
mv /cache/data_bin $BINPATH
|
||||||
|
fi
|
||||||
|
|
||||||
|
chmod -R 755 $BINPATH
|
||||||
|
chown -R 0.0 $BINPATH
|
||||||
|
|
||||||
|
# Live patch sepolicy
|
||||||
|
$BINPATH/magiskpolicy --live
|
||||||
|
|
||||||
|
if [ -f $UNINSTALLER ]; then
|
||||||
|
touch /dev/.magisk.unblock
|
||||||
|
chcon u:object_r:device:s0 /dev/.magisk.unblock
|
||||||
|
BOOTMODE=true sh $UNINSTALLER
|
||||||
|
exit
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Set up environment
|
||||||
|
mkdir -p $TOOLPATH
|
||||||
|
$BINPATH/busybox --install -s $TOOLPATH
|
||||||
|
ln -sf $BINPATH/busybox $TOOLPATH/busybox
|
||||||
|
# Prevent issues
|
||||||
|
rm -f $TOOLPATH/su $TOOLPATH/sh $TOOLPATH/reboot
|
||||||
|
chmod -R 755 $TOOLPATH
|
||||||
|
chown -R 0.0 $TOOLPATH
|
||||||
|
find $BINPATH $TOOLPATH -exec chcon -h u:object_r:system_file:s0 {} \;
|
||||||
|
|
||||||
|
log_print "* Linking binaries to /sbin"
|
||||||
|
mount -o rw,remount rootfs /
|
||||||
|
chmod 755 /sbin
|
||||||
|
ln -sf $BINPATH/magiskpolicy /sbin/magiskpolicy
|
||||||
|
ln -sf $BINPATH/magiskpolicy /sbin/sepolicy-inject
|
||||||
|
ln -sf $BINPATH/resetprop /sbin/resetprop
|
||||||
|
if [ ! -f /sbin/launch_daemonsu.sh ]; then
|
||||||
|
log_print "* Starting MagiskSU"
|
||||||
|
export PATH=$OLDPATH
|
||||||
|
ln -sf $BINPATH/su /sbin/su
|
||||||
|
ln -sf $BINPATH/magiskpolicy /sbin/supolicy
|
||||||
|
/sbin/su --daemon
|
||||||
|
export PATH=$TOOLPATH:$OLDPATH
|
||||||
|
fi
|
||||||
|
mount -o ro,remount rootfs /
|
||||||
|
|
||||||
|
[ -f $DISABLEFILE ] && unblock
|
||||||
|
|
||||||
|
# Multirom functions should go here, not available right now
|
||||||
|
MULTIROM=false
|
||||||
|
|
||||||
|
# Image merging
|
||||||
|
chmod 644 $IMG /cache/magisk.img /data/magisk_merge.img 2>/dev/null
|
||||||
|
merge_image /cache/magisk.img
|
||||||
|
merge_image /data/magisk_merge.img
|
||||||
|
|
||||||
|
# Mount magisk.img
|
||||||
|
[ ! -d $MOUNTPOINT ] && mkdir -p $MOUNTPOINT
|
||||||
|
if ! mount | grep $MOUNTPOINT; then
|
||||||
|
loopsetup $IMG
|
||||||
|
[ ! -z $LOOPDEVICE ] && mount -t ext4 -o rw,noatime $LOOPDEVICE $MOUNTPOINT
|
||||||
|
if [ $? -ne 0 ]; then
|
||||||
|
log_print "magisk.img mount failed, nothing to do :("
|
||||||
|
unblock
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Remove empty directories, legacy paths, symlinks, old temporary images
|
||||||
|
find $MOUNTPOINT -type d -depth ! -path "*core*" -exec rmdir {} \; 2>/dev/null
|
||||||
|
rm -rf $MOUNTPOINT/zzsupersu $MOUNTPOINT/phh $COREDIR/bin $COREDIR/dummy $COREDIR/mirror \
|
||||||
|
$COREDIR/busybox $COREDIR/su /data/magisk/*.img /data/busybox 2>/dev/null
|
||||||
|
|
||||||
|
# Remove modules that are labeled to be removed
|
||||||
|
for MOD in $MOUNTPOINT/* ; do
|
||||||
|
rm -f $MOD/system/placeholder 2>/dev/null
|
||||||
|
if [ -f $MOD/remove ]; then
|
||||||
|
log_print "Remove module: $MOD"
|
||||||
|
rm -rf $MOD
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
# Unmount, shrink, remount
|
||||||
|
if umount $MOUNTPOINT; then
|
||||||
|
losetup -d $LOOPDEVICE 2>/dev/null
|
||||||
|
image_size_check $IMG
|
||||||
|
NEWDATASIZE=$((curUsedM / 32 * 32 + 32))
|
||||||
|
if [ "$curSizeM" -gt "$NEWDATASIZE" ]; then
|
||||||
|
log_print "Shrinking $IMG to ${NEWDATASIZE}M..."
|
||||||
|
resize2fs $IMG ${NEWDATASIZE}M
|
||||||
|
fi
|
||||||
|
loopsetup $IMG
|
||||||
|
[ ! -z $LOOPDEVICE ] && mount -t ext4 -o rw,noatime $LOOPDEVICE $MOUNTPOINT
|
||||||
|
if [ $? -ne 0 ]; then
|
||||||
|
log_print "magisk.img mount failed, nothing to do :("
|
||||||
|
unblock
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
log_print "* Preparing modules"
|
||||||
|
|
||||||
|
# Remove crap folder
|
||||||
|
rm -rf $MOUNTPOINT/lost+found
|
||||||
|
|
||||||
|
# Link vendor if not exist
|
||||||
|
if [ ! -e /vendor ]; then
|
||||||
|
mount -o rw,remount rootfs /
|
||||||
|
ln -sf /system/vendor /vendor
|
||||||
|
mount -o ro,remount rootfs /
|
||||||
|
fi
|
||||||
|
|
||||||
|
for MOD in $MOUNTPOINT/* ; do
|
||||||
|
if [ ! -f $MOD/disable ]; then
|
||||||
|
# Travel through all mods
|
||||||
|
if [ -f $MOD/auto_mount -a -d $MOD/system ]; then
|
||||||
|
log_print "Analyzing module: $MOD"
|
||||||
|
TRAVEL_ROOT=$MOD
|
||||||
|
(travel system)
|
||||||
|
rm -f $MOD/vendor 2>/dev/null
|
||||||
|
if [ -d $MOD/system/vendor ]; then
|
||||||
|
ln -sf $MOD/system/vendor $MOD/vendor
|
||||||
|
(travel vendor)
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
# Read in defined system props
|
||||||
|
if [ -f $MOD/system.prop ]; then
|
||||||
|
log_print "* Reading props from $MOD/system.prop"
|
||||||
|
$BINPATH/resetprop --file $MOD/system.prop
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
# Proper permissions for generated items
|
||||||
|
find $TMPDIR -exec chcon -h u:object_r:system_file:s0 {} \;
|
||||||
|
|
||||||
|
# linker(64), t*box required for bin
|
||||||
|
if [ -f $MOUNTINFO/dummy/system/bin ]; then
|
||||||
|
cp -afc /system/bin/linker* /system/bin/t*box $DUMMDIR/system/bin/
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Start doing tasks
|
||||||
|
|
||||||
|
# Stage 1
|
||||||
|
log_print "* Stage 1: Mount system and vendor mirrors"
|
||||||
|
SYSTEMBLOCK=`mount | grep " /system " | awk '{print $1}'`
|
||||||
|
mkdir -p $MIRRDIR/system
|
||||||
|
mount -o ro $SYSTEMBLOCK $MIRRDIR/system
|
||||||
|
if [ `mount | grep -c " /vendor "` -ne 0 ]; then
|
||||||
|
VENDORBLOCK=`mount | grep " /vendor " | awk '{print $1}'`
|
||||||
|
mkdir -p $MIRRDIR/vendor
|
||||||
|
mount -o ro $VENDORBLOCK $MIRRDIR/vendor
|
||||||
|
else
|
||||||
|
ln -sf $MIRRDIR/system/vendor $MIRRDIR/vendor
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Since mirrors always exist, we load libraries and binaries from mirrors
|
||||||
|
export LD_LIBRARY_PATH=$MIRRDIR/system/lib:$MIRRDIR/vendor/lib
|
||||||
|
[ -d $MIRRDIR/system/lib64 ] && export LD_LIBRARY_PATH=$MIRRDIR/system/lib64:$MIRRDIR/vendor/lib64
|
||||||
|
|
||||||
|
# Stage 2
|
||||||
|
log_print "* Stage 2: Mount dummy skeletons"
|
||||||
|
# Move /system/vendor to /vendor for consistency
|
||||||
|
mv -f $MOUNTINFO/dummy/system/vendor $MOUNTINFO/dummy/vendor 2>/dev/null
|
||||||
|
mv -f $DUMMDIR/system/vendor $DUMMDIR/vendor 2>/dev/null
|
||||||
|
find $MOUNTINFO/dummy -type f 2>/dev/null | while read ITEM ; do
|
||||||
|
TARGET="${ITEM#$MOUNTINFO/dummy}"
|
||||||
|
ORIG="$DUMMDIR$TARGET"
|
||||||
|
(clone_dummy "$TARGET")
|
||||||
|
bind_mount "$ORIG" "$TARGET"
|
||||||
|
done
|
||||||
|
|
||||||
|
# Check if the dummy /system/bin is empty, it shouldn't
|
||||||
|
[ -e $DUMMDIR/system/bin -a ! -e $DUMMDIR/system/bin/sh ] && clone_dummy /system/bin
|
||||||
|
|
||||||
|
# Stage 3
|
||||||
|
log_print "* Stage 3: Mount module items"
|
||||||
|
find $MOUNTINFO/system $MOUNTINFO/vendor -type f 2>/dev/null | while read ITEM ; do
|
||||||
|
TARGET="${ITEM#$MOUNTINFO}"
|
||||||
|
ORIG="`cat "$ITEM"`$TARGET"
|
||||||
|
bind_mount "$ORIG" "$TARGET"
|
||||||
|
done
|
||||||
|
|
||||||
|
# Stage 4
|
||||||
|
log_print "* Stage 4: Execute scripts"
|
||||||
|
run_scripts post-fs-data
|
||||||
|
|
||||||
|
# Stage 5
|
||||||
|
log_print "* Stage 5: Mount mirrored items back to dummy"
|
||||||
|
find $MOUNTINFO/mirror -type f 2>/dev/null | while read ITEM ; do
|
||||||
|
TARGET="${ITEM#$MOUNTINFO/mirror}"
|
||||||
|
ORIG="$MIRRDIR$TARGET"
|
||||||
|
bind_mount "$ORIG" "$TARGET"
|
||||||
|
done
|
||||||
|
|
||||||
|
# Bind hosts for Adblock apps
|
||||||
|
if [ -f $COREDIR/hosts ]; then
|
||||||
|
log_print "* Enabling systemless hosts file support"
|
||||||
|
bind_mount $COREDIR/hosts /system/etc/hosts
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -f $BINPATH/magisk.apk ]; then
|
||||||
|
if ! ls /data/app | grep com.topjohnwu.magisk; then
|
||||||
|
mkdir /data/app/com.topjohnwu.magisk-1
|
||||||
|
cp $BINPATH/magisk.apk /data/app/com.topjohnwu.magisk-1/base.apk
|
||||||
|
chown 1000.1000 /data/app/com.topjohnwu.magisk-1
|
||||||
|
chown 1000.1000 /data/app/com.topjohnwu.magisk-1/base.apk
|
||||||
|
chmod 755 /data/app/com.topjohnwu.magisk-1
|
||||||
|
chmod 644 /data/app/com.topjohnwu.magisk-1/base.apk
|
||||||
|
chcon u:object_r:apk_data_file:s0 /data/app/com.topjohnwu.magisk-1
|
||||||
|
chcon u:object_r:apk_data_file:s0 /data/app/com.topjohnwu.magisk-1/base.apk
|
||||||
|
fi
|
||||||
|
rm -f $BINPATH/magisk.apk 2>/dev/null
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Expose busybox
|
||||||
|
[ "`getprop persist.magisk.busybox`" = "1" ] && sh /sbin/magic_mask.sh mount_busybox
|
||||||
|
|
||||||
|
# Restart post-fs-data if necessary (multirom)
|
||||||
|
$MULTIROM && setprop magisk.restart_pfsd 1
|
||||||
|
|
||||||
|
fi
|
||||||
|
unblock
|
||||||
|
;;
|
||||||
|
|
||||||
|
mount_busybox )
|
||||||
|
log_print "* Enabling BusyBox"
|
||||||
|
cp -afc /system/xbin/. $TOOLPATH
|
||||||
|
umount /system/xbin 2>/dev/null
|
||||||
|
bind_mount $TOOLPATH /system/xbin
|
||||||
|
;;
|
||||||
|
|
||||||
|
service )
|
||||||
|
# Version info
|
||||||
|
MAGISK_VERSION_STUB
|
||||||
|
log_print "** Magisk late_start service mode running..."
|
||||||
|
if [ -f $DISABLEFILE ]; then
|
||||||
|
setprop ro.magisk.disable 1
|
||||||
|
exit
|
||||||
|
fi
|
||||||
|
run_scripts service
|
||||||
|
|
||||||
|
# Start MagiskHide
|
||||||
|
[ "`getprop persist.magisk.hide`" = "1" ] && sh $COREDIR/magiskhide/enable
|
||||||
|
;;
|
||||||
|
|
||||||
|
esac
|
133
scripts/magisk_uninstaller.sh
Normal file
133
scripts/magisk_uninstaller.sh
Normal file
@@ -0,0 +1,133 @@
|
|||||||
|
[ -z $BOOTMODE ] && BOOTMODE=false
|
||||||
|
|
||||||
|
# This path should work in any cases
|
||||||
|
TMPDIR=/dev/tmp
|
||||||
|
|
||||||
|
BOOTTMP=$TMPDIR/boottmp
|
||||||
|
MAGISKBIN=/data/magisk
|
||||||
|
CHROMEDIR=$MAGISKBIN/chromeos
|
||||||
|
|
||||||
|
SYSTEMLIB=/system/lib
|
||||||
|
[ -d /system/lib64 ] && SYSTEMLIB=/system/lib64
|
||||||
|
|
||||||
|
# Default permissions
|
||||||
|
umask 022
|
||||||
|
|
||||||
|
ui_print_wrapper() {
|
||||||
|
type ui_print >/dev/null && ui_print "$1" || echo "$1"
|
||||||
|
}
|
||||||
|
|
||||||
|
grep_prop() {
|
||||||
|
REGEX="s/^$1=//p"
|
||||||
|
shift
|
||||||
|
FILES=$@
|
||||||
|
if [ -z "$FILES" ]; then
|
||||||
|
FILES='/system/build.prop'
|
||||||
|
fi
|
||||||
|
cat $FILES 2>/dev/null | sed -n "$REGEX" | head -n 1
|
||||||
|
}
|
||||||
|
|
||||||
|
find_boot_image() {
|
||||||
|
if [ -z "$BOOTIMAGE" ]; then
|
||||||
|
for PARTITION in kern-a KERN-A android_boot ANDROID_BOOT kernel KERNEL boot BOOT lnx LNX; do
|
||||||
|
BOOTIMAGE=`readlink /dev/block/by-name/$PARTITION || readlink /dev/block/platform/*/by-name/$PARTITION || readlink /dev/block/platform/*/*/by-name/$PARTITION`
|
||||||
|
if [ ! -z "$BOOTIMAGE" ]; then break; fi
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
if [ -z "$BOOTIMAGE" ]; then
|
||||||
|
FSTAB="/etc/recovery.fstab"
|
||||||
|
[ ! -f "$FSTAB" ] && FSTAB="/etc/recovery.fstab.bak"
|
||||||
|
[ -f "$FSTAB" ] && BOOTIMAGE=`grep -E '\b/boot\b' "$FSTAB" | grep -oE '/dev/[a-zA-Z0-9_./-]*'`
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Environments
|
||||||
|
# Set permissions
|
||||||
|
chmod -R 755 $CHROMEDIR/futility $MAGISKBIN 2>/dev/null
|
||||||
|
# Temporary busybox for installation
|
||||||
|
mkdir -p $TMPDIR/busybox
|
||||||
|
$MAGISKBIN/busybox --install -s $TMPDIR/busybox
|
||||||
|
rm -f $TMPDIR/busybox/su $TMPDIR/busybox/sh $TMPDIR/busybox/reboot
|
||||||
|
PATH=$TMPDIR/busybox:$PATH
|
||||||
|
|
||||||
|
# Find the boot image
|
||||||
|
find_boot_image
|
||||||
|
if [ -z "$BOOTIMAGE" ]; then
|
||||||
|
ui_print_wrapper "! Unable to detect boot image"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
ui_print_wrapper "- Found Boot Image: $BOOTIMAGE"
|
||||||
|
|
||||||
|
rm -rf $BOOTTMP 2>/dev/null
|
||||||
|
mkdir -p $BOOTTMP
|
||||||
|
cd $BOOTTMP
|
||||||
|
|
||||||
|
ui_print_wrapper "- Unpacking boot image"
|
||||||
|
LD_LIBRARY_PATH=$SYSTEMLIB $MAGISKBIN/magiskboot --unpack $BOOTIMAGE
|
||||||
|
if [ $? -ne 0 ]; then
|
||||||
|
ui_print_wrapper "! Unable to unpack boot image"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Update our previous backup to new format if exists
|
||||||
|
if [ -f /data/stock_boot.img ]; then
|
||||||
|
SHA1=`LD_LIBRARY_PATH=$SYSTEMLIB $MAGISKBIN/magiskboot --sha1 /data/stock_boot.img | tail -n 1`
|
||||||
|
STOCKDUMP=/data/stock_boot_${SHA1}.img
|
||||||
|
mv /data/stock_boot.img $STOCKDUMP
|
||||||
|
LD_LIBRARY_PATH=$SYSTEMLIB $MAGISKBIN/magiskboot --compress $STOCKDUMP
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Detect boot image state
|
||||||
|
LD_LIBRARY_PATH=$SYSTEMLIB $MAGISKBIN/magiskboot --cpio-test ramdisk.cpio
|
||||||
|
case $? in
|
||||||
|
0 )
|
||||||
|
ui_print_wrapper "! Magisk is not installed!"
|
||||||
|
ui_print_wrapper "! Nothing to uninstall"
|
||||||
|
exit
|
||||||
|
;;
|
||||||
|
1 )
|
||||||
|
# Find SHA1 of stock boot image
|
||||||
|
if [ -z $SHA1 ]; then
|
||||||
|
LD_LIBRARY_PATH=$SYSTEMLIB $MAGISKBIN/magiskboot --cpio-extract ramdisk.cpio init.magisk.rc init.magisk.rc
|
||||||
|
SHA1=`grep_prop "# STOCKSHA1" init.magisk.rc`
|
||||||
|
[ ! -z $SHA1 ] && STOCKDUMP=/data/stock_boot_${SHA1}.img
|
||||||
|
rm -f init.magisk.rc
|
||||||
|
fi
|
||||||
|
if [ -f ${STOCKDUMP}.gz ]; then
|
||||||
|
ui_print_wrapper "- Boot image backup found!"
|
||||||
|
LD_LIBRARY_PATH=$SYSTEMLIB $MAGISKBIN/magiskboot --decompress ${STOCKDUMP}.gz stock_boot.img
|
||||||
|
else
|
||||||
|
ui_print_wrapper "! Boot image backup unavailable"
|
||||||
|
ui_print_wrapper "- Restoring ramdisk with backup"
|
||||||
|
LD_LIBRARY_PATH=$SYSTEMLIB $MAGISKBIN/magiskboot --cpio-restore ramdisk.cpio
|
||||||
|
LD_LIBRARY_PATH=$SYSTEMLIB $MAGISKBIN/magiskboot --repack $BOOTIMAGE stock_boot.img
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
2 )
|
||||||
|
ui_print_wrapper "- SuperSU patched image detected"
|
||||||
|
LD_LIBRARY_PATH=$SYSTEMLIB $MAGISKBIN/magiskboot --cpio-restore ramdisk.cpio
|
||||||
|
LD_LIBRARY_PATH=$SYSTEMLIB $MAGISKBIN/magiskboot --repack $BOOTIMAGE stock_boot.img
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
# Sign chromeos boot
|
||||||
|
if [ -f chromeos ]; then
|
||||||
|
echo > config
|
||||||
|
echo > bootloader
|
||||||
|
LD_LIBRARY_PATH=$SYSTEMLIB $CHROMEDIR/futility vbutil_kernel --pack stock_boot.img.signed --keyblock $CHROMEDIR/kernel.keyblock --signprivate $CHROMEDIR/kernel_data_key.vbprivk --version 1 --vmlinuz stock_boot.img --config config --arch arm --bootloader bootloader --flags 0x1
|
||||||
|
rm -f stock_boot.img
|
||||||
|
mv stock_boot.img.signed stock_boot.img
|
||||||
|
fi
|
||||||
|
|
||||||
|
ui_print_wrapper "- Flashing stock/reverted image"
|
||||||
|
[ ! -L "$BOOTIMAGE" ] && dd if=/dev/zero of=$BOOTIMAGE bs=4096 2>/dev/null
|
||||||
|
dd if=stock_boot.img of=$BOOTIMAGE bs=4096
|
||||||
|
|
||||||
|
ui_print_wrapper "- Removing Magisk files"
|
||||||
|
rm -rf /cache/magisk.log /cache/last_magisk.log /cache/magiskhide.log /cache/.disable_magisk \
|
||||||
|
/cache/magisk /cache/magisk_merge /cache/magisk_mount /cache/unblock /cache/magisk_uninstaller.sh \
|
||||||
|
/data/Magisk.apk /data/magisk.apk /data/magisk.img /data/magisk_merge.img \
|
||||||
|
/data/busybox /data/magisk /data/custom_ramdisk_patch.sh 2>/dev/null
|
||||||
|
|
||||||
|
$BOOTMODE && reboot
|
57
scripts/ramdisk_patch.sh
Normal file
57
scripts/ramdisk_patch.sh
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
# This file will be sourced by Magisk patch zip, so all variables in the main script should be present
|
||||||
|
# However, this file may also be called by SuperSU, so we still have to find our own variables in this case
|
||||||
|
|
||||||
|
RAMDISK=$1
|
||||||
|
|
||||||
|
if [ -z $MAGISK ]; then
|
||||||
|
TMPDIR=/dev/tmp
|
||||||
|
MAGISKBIN=/data/magisk
|
||||||
|
[ ! -e $MAGISKBIN ] && MAGISKBIN=/cache/data_bin
|
||||||
|
[ ! -e $MAGISKBIN ] && exit 1
|
||||||
|
SYSTEMLIB=/system/lib
|
||||||
|
[ -d /system/lib64 ] && SYSTEMLIB=/system/lib64
|
||||||
|
KEEPVERITY=true
|
||||||
|
KEEPFORCEENCRYPT=true
|
||||||
|
fi
|
||||||
|
|
||||||
|
cd $TMPDIR
|
||||||
|
|
||||||
|
# --cpio-add <incpio> <mode> <entry> <infile>
|
||||||
|
cpio_add() {
|
||||||
|
LD_LIBRARY_PATH=$SYSTEMLIB $MAGISKBIN/magiskboot --cpio-add $RAMDISK $1 $2 $3
|
||||||
|
}
|
||||||
|
|
||||||
|
# --cpio-extract <incpio> <entry> <outfile>
|
||||||
|
cpio_extract() {
|
||||||
|
LD_LIBRARY_PATH=$SYSTEMLIB $MAGISKBIN/magiskboot --cpio-extract $RAMDISK $1 $2
|
||||||
|
}
|
||||||
|
|
||||||
|
# --cpio-mkdir <incpio> <mode> <entry>
|
||||||
|
cpio_mkdir() {
|
||||||
|
LD_LIBRARY_PATH=$SYSTEMLIB $MAGISKBIN/magiskboot --cpio-mkdir $RAMDISK $1 $2
|
||||||
|
}
|
||||||
|
|
||||||
|
# The common patches
|
||||||
|
$KEEPVERITY || LD_LIBRARY_PATH=$SYSTEMLIB $MAGISKBIN/magiskboot --cpio-patch-dmverity $RAMDISK
|
||||||
|
$KEEPFORCEENCRYPT || LD_LIBRARY_PATH=$SYSTEMLIB $MAGISKBIN/magiskboot --cpio-patch-forceencrypt $RAMDISK
|
||||||
|
|
||||||
|
# Add magisk entrypoint
|
||||||
|
cpio_extract init.rc init.rc
|
||||||
|
grep "import /init.magisk.rc" init.rc >/dev/null || sed -i '1,/.*import.*/s/.*import.*/import \/init.magisk.rc\n&/' init.rc
|
||||||
|
sed -i "/selinux.reload_policy/d" init.rc
|
||||||
|
cpio_add 750 init.rc init.rc
|
||||||
|
|
||||||
|
# sepolicy patches
|
||||||
|
cpio_extract sepolicy sepolicy
|
||||||
|
LD_LIBRARY_PATH=$SYSTEMLIB $MAGISKBIN/magiskpolicy --load sepolicy --save sepolicy --minimal
|
||||||
|
cpio_add 644 sepolicy sepolicy
|
||||||
|
|
||||||
|
# Add new items
|
||||||
|
|
||||||
|
cpio_mkdir 755 magisk
|
||||||
|
|
||||||
|
cp -af $MAGISKBIN/init.magisk.rc init.magisk.rc
|
||||||
|
[ ! -z $SHA1 ] && echo "# STOCKSHA1=$SHA1" >> init.magisk.rc
|
||||||
|
cpio_add 750 init.magisk.rc init.magisk.rc
|
||||||
|
|
||||||
|
cpio_add 750 sbin/magic_mask.sh $MAGISKBIN/magic_mask.sh
|
1
selinux
1
selinux
Submodule selinux deleted from df7346cd5b
@@ -10,6 +10,9 @@
|
|||||||
|
|
||||||
INSTALLER=/tmp/uninstall
|
INSTALLER=/tmp/uninstall
|
||||||
|
|
||||||
|
# Default permissions
|
||||||
|
umask 022
|
||||||
|
|
||||||
##########################################################################################
|
##########################################################################################
|
||||||
# Flashable update-binary preparation
|
# Flashable update-binary preparation
|
||||||
##########################################################################################
|
##########################################################################################
|
||||||
@@ -46,34 +49,6 @@ ui_print() {
|
|||||||
echo -n -e "ui_print\n" >> /proc/self/fd/$OUTFD
|
echo -n -e "ui_print\n" >> /proc/self/fd/$OUTFD
|
||||||
}
|
}
|
||||||
|
|
||||||
getvar() {
|
|
||||||
local VARNAME=$1
|
|
||||||
local VALUE=$(eval echo \$"$VARNAME");
|
|
||||||
for FILE in /data/.magisk /cache/.magisk /system/.magisk; do
|
|
||||||
if [ -z "$VALUE" ]; then
|
|
||||||
LINE=$(cat $FILE 2>/dev/null | grep "$VARNAME=")
|
|
||||||
if [ ! -z "$LINE" ]; then
|
|
||||||
VALUE=${LINE#*=}
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
eval $VARNAME=\$VALUE
|
|
||||||
}
|
|
||||||
|
|
||||||
find_boot_image() {
|
|
||||||
if [ -z "$BOOTIMAGE" ]; then
|
|
||||||
for PARTITION in kern-a KERN-A android_boot ANDROID_BOOT kernel KERNEL boot BOOT lnx LNX; do
|
|
||||||
BOOTIMAGE=$(readlink /dev/block/by-name/$PARTITION || readlink /dev/block/platform/*/by-name/$PARTITION || readlink /dev/block/platform/*/*/by-name/$PARTITION)
|
|
||||||
if [ ! -z "$BOOTIMAGE" ]; then break; fi
|
|
||||||
done
|
|
||||||
fi
|
|
||||||
if [ -z "$BOOTIMAGE" ]; then
|
|
||||||
FSTAB="/etc/recovery.fstab"
|
|
||||||
[ ! -f "$FSTAB" ] && FSTAB="/etc/recovery.fstab.bak"
|
|
||||||
BOOTIMAGE=$(grep -E '\b/boot\b' "$FSTAB" | grep -oE '/dev/[a-zA-Z0-9_./-]*')
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
is_mounted() {
|
is_mounted() {
|
||||||
if [ ! -z "$2" ]; then
|
if [ ! -z "$2" ]; then
|
||||||
cat /proc/mounts | grep $1 | grep $2, >/dev/null
|
cat /proc/mounts | grep $1 | grep $2, >/dev/null
|
||||||
@@ -93,78 +68,6 @@ grep_prop() {
|
|||||||
cat $FILES 2>/dev/null | sed -n $REGEX | head -n 1
|
cat $FILES 2>/dev/null | sed -n $REGEX | head -n 1
|
||||||
}
|
}
|
||||||
|
|
||||||
unpack_boot() {
|
|
||||||
rm -rf $UNPACKDIR $RAMDISK 2>/dev/null
|
|
||||||
mkdir -p $UNPACKDIR
|
|
||||||
mkdir -p $RAMDISK
|
|
||||||
cd $UNPACKDIR
|
|
||||||
$BINDIR/bootimgtools --extract $1
|
|
||||||
|
|
||||||
find $TMPDIR/boottmp -type d -exec chmod 755 {} \;
|
|
||||||
find $TMPDIR/boottmp -type f -exec chmod 644 {} \;
|
|
||||||
chmod 755 $(find $TMPDIR/boottmp -type d)
|
|
||||||
chmod 644 $(find $TMPDIR/boottmp -type f)
|
|
||||||
|
|
||||||
cd $RAMDISK
|
|
||||||
gunzip -c < $UNPACKDIR/ramdisk.gz | cpio -i
|
|
||||||
}
|
|
||||||
|
|
||||||
repack_boot() {
|
|
||||||
cd $RAMDISK
|
|
||||||
find . | cpio -o -H newc 2>/dev/null | gzip -9 > $UNPACKDIR/ramdisk.gz
|
|
||||||
cd $UNPACKDIR
|
|
||||||
$BINDIR/bootimgtools --repack $ORIGBOOT
|
|
||||||
if [ -f chromeos ]; then
|
|
||||||
echo " " > config
|
|
||||||
echo " " > bootloader
|
|
||||||
$CHROMEDIR/futility vbutil_kernel --pack new-boot.img.signed --keyblock $CHROMEDIR/kernel.keyblock --signprivate $CHROMEDIR/kernel_data_key.vbprivk --version 1 --vmlinuz new-boot.img --config config --arch arm --bootloader bootloader --flags 0x1
|
|
||||||
rm -f new-boot.img
|
|
||||||
mv new-boot.img.signed new-boot.img
|
|
||||||
fi
|
|
||||||
if ($SAMSUNG); then
|
|
||||||
SAMSUNG_CHECK=$(cat new-boot.img | grep SEANDROIDENFORCE)
|
|
||||||
if [ $? -ne 0 ]; then
|
|
||||||
echo -n "SEANDROIDENFORCE" >> new-boot.img
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
mv new-boot.img $NEWBOOT
|
|
||||||
}
|
|
||||||
|
|
||||||
revert_boot() {
|
|
||||||
rm -rf $TMPDIR/boottmp 2>/dev/null
|
|
||||||
mkdir -p $TMPDIR/boottmp
|
|
||||||
|
|
||||||
CHROMEDIR=$INSTALLER/chromeos
|
|
||||||
ORIGBOOT=$TMPDIR/boottmp/boot.img
|
|
||||||
NEWBOOT=$TMPDIR/boottmp/new-boot.img
|
|
||||||
UNPACKDIR=$TMPDIR/boottmp/bootunpack
|
|
||||||
RAMDISK=$TMPDIR/boottmp/ramdisk
|
|
||||||
|
|
||||||
chmod 777 $CHROMEDIR/futility $BINDIR/*
|
|
||||||
|
|
||||||
ui_print "- Dumping boot image"
|
|
||||||
dd if=$BOOTIMAGE of=$ORIGBOOT
|
|
||||||
|
|
||||||
ui_print "- Unpacking boot image"
|
|
||||||
unpack_boot $ORIGBOOT
|
|
||||||
|
|
||||||
if [ -d ".backup" ]; then
|
|
||||||
ui_print "- Restoring ramdisk with backup"
|
|
||||||
cp -af .backup/* .
|
|
||||||
rm -rf magisk init.magisk.rc sbin/magic_mask.sh 2>/dev/null
|
|
||||||
rm -rf .backup
|
|
||||||
else
|
|
||||||
ui_print "! No ramdisk backup found"
|
|
||||||
ui_print "! Unable to revert completely"
|
|
||||||
ui_print "! Will still remove Magisk additions"
|
|
||||||
# Removing boot image modifications
|
|
||||||
rm -rf magisk init.magisk.rc sbin/magic_mask.sh 2>/dev/null
|
|
||||||
fi
|
|
||||||
|
|
||||||
ui_print "- Repacking boot image"
|
|
||||||
repack_boot
|
|
||||||
}
|
|
||||||
|
|
||||||
##########################################################################################
|
##########################################################################################
|
||||||
# Main
|
# Main
|
||||||
##########################################################################################
|
##########################################################################################
|
||||||
@@ -188,78 +91,43 @@ if [ ! -f '/system/build.prop' ]; then
|
|||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
API=$(grep_prop ro.build.version.sdk)
|
API=`grep_prop ro.build.version.sdk`
|
||||||
ABI=$(grep_prop ro.product.cpu.abi | cut -c-3)
|
ABI=`grep_prop ro.product.cpu.abi | cut -c-3`
|
||||||
ABI2=$(grep_prop ro.product.cpu.abi2 | cut -c-3)
|
ABI2=`grep_prop ro.product.cpu.abi2 | cut -c-3`
|
||||||
ABILONG=$(grep_prop ro.product.cpu.abi)
|
ABILONG=`grep_prop ro.product.cpu.abi`
|
||||||
|
|
||||||
ARCH=arm
|
ARCH=arm
|
||||||
IS64BIT=
|
IS64BIT=false
|
||||||
if [ "$ABI" = "x86" ]; then ARCH=x86; fi;
|
if [ "$ABI" = "x86" ]; then ARCH=x86; fi;
|
||||||
if [ "$ABI2" = "x86" ]; then ARCH=x86; fi;
|
if [ "$ABI2" = "x86" ]; then ARCH=x86; fi;
|
||||||
if [ "$ABILONG" = "arm64-v8a" ]; then ARCH=arm64; IS64BIT=1; fi;
|
if [ "$ABILONG" = "arm64-v8a" ]; then ARCH=arm64; IS64BIT=true; fi;
|
||||||
if [ "$ABILONG" = "x86_64" ]; then ARCH=x64; IS64BIT=1; fi;
|
if [ "$ABILONG" = "x86_64" ]; then ARCH=x64; IS64BIT=true; fi;
|
||||||
|
|
||||||
ui_print "- Device platform: $ARCH"
|
ui_print "- Device platform: $ARCH"
|
||||||
|
CHROMEDIR=$INSTALLER/chromeos
|
||||||
|
BINDIR=$INSTALLER/$ARCH
|
||||||
|
|
||||||
BINDIR=$INSTALLER/arm
|
# Copy the binaries to /data/magisk
|
||||||
if [ "$ARCH" = "x86" -o "$ARCH" = "x64" ]; then
|
mkdir -p /data/magisk 2>/dev/null
|
||||||
BINDIR=$INSTALLER/x86
|
cp -af $BINDIR/* $CHROMEDIR /data/magisk
|
||||||
fi
|
|
||||||
|
|
||||||
find_boot_image
|
|
||||||
if [ -z "$BOOTIMAGE" ]; then
|
|
||||||
ui_print "! Unable to detect boot image"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
SAMSUNG=false
|
|
||||||
SAMSUNG_CHECK=$(cat /system/build.prop | grep "ro.build.fingerprint=" | grep -i "samsung")
|
|
||||||
if [ $? -eq 0 ]; then
|
|
||||||
SAMSUNG=true
|
|
||||||
fi
|
|
||||||
|
|
||||||
##########################################################################################
|
##########################################################################################
|
||||||
# Detection all done, start installing
|
# Detection all done, start installing
|
||||||
##########################################################################################
|
##########################################################################################
|
||||||
|
|
||||||
umount /magisk 2>/dev/null
|
|
||||||
|
|
||||||
if (is_mounted /data); then
|
if (is_mounted /data); then
|
||||||
cp -af /data/stock_boot_*.gz /data/stock_boot.img.gz 2>/dev/null
|
. $INSTALLER/common/magisk_uninstaller.sh
|
||||||
gzip -d /data/stock_boot.img.gz 2>/dev/null
|
|
||||||
rm -rf /data/stock_boot.img.gz 2>/dev/null
|
|
||||||
if [ -f "/data/stock_boot.img" ]; then
|
|
||||||
ui_print "- Boot image backup found!"
|
|
||||||
NEWBOOT=/data/stock_boot.img
|
|
||||||
else
|
|
||||||
ui_print "! Boot image backup unavalible, try using ramdisk backup"
|
|
||||||
revert_boot
|
|
||||||
fi
|
|
||||||
ui_print "- Removing Magisk files"
|
|
||||||
rm -rf /cache/magisk /cache/magisk_merge /cache/magisk.log /cache/last_magisk.log /cache/unblock /data/Magisk.apk /data/magisk.img /data/magisk_merge.img /data/busybox /data/magisk 2>/dev/null
|
|
||||||
else
|
else
|
||||||
ui_print "! Data unavalible"
|
ui_print "! Data unavailable"
|
||||||
ui_print "! Impossible to restore original boot image"
|
ui_print "! Placing uninstall script to /cache"
|
||||||
ui_print "! Try using ramdisk backup"
|
ui_print "! The device might reboot multiple times"
|
||||||
revert_boot
|
cp -af $INSTALLER/common/magisk_uninstaller.sh /cache/magisk_uninstaller.sh
|
||||||
ui_print "- Removing Magisk files"
|
umount /system
|
||||||
rm -rf /cache/magisk* /cache/last_magisk.log /cache/unblock 2>/dev/null
|
ui_print "- Rebooting....."
|
||||||
ui_print "*****************************************"
|
sleep 5
|
||||||
ui_print " Magisk is not fully removed yet "
|
reboot
|
||||||
ui_print " Please manually remove /data/magisk.img "
|
|
||||||
ui_print "*****************************************"
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ -L "$BOOTIMAGE" ]; then
|
|
||||||
ui_print "- Block symlink detected!"
|
|
||||||
else
|
|
||||||
dd if=/dev/zero of=$BOOTIMAGE bs=4096 2>/dev/null
|
|
||||||
fi
|
|
||||||
ui_print "- Flashing reverted image"
|
|
||||||
dd if=$NEWBOOT of=$BOOTIMAGE bs=4096
|
|
||||||
|
|
||||||
umount /system
|
umount /system
|
||||||
|
|
||||||
ui_print "- Done"
|
ui_print "- Done"
|
||||||
exit 0
|
exit 0
|
||||||
|
Binary file not shown.
Binary file not shown.
@@ -1,479 +0,0 @@
|
|||||||
#!/sbin/sh
|
|
||||||
##########################################################################################
|
|
||||||
#
|
|
||||||
# Magisk Boot Image Patcher
|
|
||||||
# by topjohnwu
|
|
||||||
#
|
|
||||||
# This zip will patch your boot image with Magisk support
|
|
||||||
#
|
|
||||||
##########################################################################################
|
|
||||||
|
|
||||||
if [ -z "$BOOTMODE" ]; then
|
|
||||||
BOOTMODE=false
|
|
||||||
fi
|
|
||||||
|
|
||||||
TMPDIR=/tmp
|
|
||||||
($BOOTMODE) && TMPDIR=/dev/tmp
|
|
||||||
|
|
||||||
INSTALLER=$TMPDIR/magisk
|
|
||||||
|
|
||||||
COREDIR=/magisk/.core
|
|
||||||
|
|
||||||
##########################################################################################
|
|
||||||
# Flashable update-binary preparation
|
|
||||||
##########################################################################################
|
|
||||||
|
|
||||||
OUTFD=$2
|
|
||||||
ZIP=$3
|
|
||||||
|
|
||||||
readlink /proc/$$/fd/$OUTFD 2>/dev/null | grep /tmp >/dev/null
|
|
||||||
if [ "$?" -eq "0" ]; then
|
|
||||||
OUTFD=0
|
|
||||||
|
|
||||||
for FD in `ls /proc/$$/fd`; do
|
|
||||||
readlink /proc/$$/fd/$FD 2>/dev/null | grep pipe >/dev/null
|
|
||||||
if [ "$?" -eq "0" ]; then
|
|
||||||
ps | grep " 3 $FD " | grep -v grep >/dev/null
|
|
||||||
if [ "$?" -eq "0" ]; then
|
|
||||||
OUTFD=$FD
|
|
||||||
break
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
fi
|
|
||||||
|
|
||||||
mkdir -p $INSTALLER
|
|
||||||
cd $INSTALLER
|
|
||||||
unzip -o "$ZIP"
|
|
||||||
|
|
||||||
##########################################################################################
|
|
||||||
# Functions
|
|
||||||
##########################################################################################
|
|
||||||
|
|
||||||
ui_print() {
|
|
||||||
if ($BOOTMODE); then
|
|
||||||
echo "$1"
|
|
||||||
else
|
|
||||||
echo -n -e "ui_print $1\n" >> /proc/self/fd/$OUTFD
|
|
||||||
echo -n -e "ui_print\n" >> /proc/self/fd/$OUTFD
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
getvar() {
|
|
||||||
local VARNAME=$1
|
|
||||||
local VALUE=$(eval echo \$"$VARNAME");
|
|
||||||
for FILE in /data/.magisk /cache/.magisk /system/.magisk; do
|
|
||||||
if [ -z "$VALUE" ]; then
|
|
||||||
LINE=$(cat $FILE 2>/dev/null | grep "$VARNAME=")
|
|
||||||
if [ ! -z "$LINE" ]; then
|
|
||||||
VALUE=${LINE#*=}
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
eval $VARNAME=\$VALUE
|
|
||||||
}
|
|
||||||
|
|
||||||
find_boot_image() {
|
|
||||||
if [ -z "$BOOTIMAGE" ]; then
|
|
||||||
for PARTITION in kern-a KERN-A android_boot ANDROID_BOOT kernel KERNEL boot BOOT lnx LNX; do
|
|
||||||
BOOTIMAGE=$(readlink /dev/block/by-name/$PARTITION || readlink /dev/block/platform/*/by-name/$PARTITION || readlink /dev/block/platform/*/*/by-name/$PARTITION)
|
|
||||||
if [ ! -z "$BOOTIMAGE" ]; then break; fi
|
|
||||||
done
|
|
||||||
fi
|
|
||||||
if [ -z "$BOOTIMAGE" ]; then
|
|
||||||
FSTAB="/etc/recovery.fstab"
|
|
||||||
[ ! -f "$FSTAB" ] && FSTAB="/etc/recovery.fstab.bak"
|
|
||||||
BOOTIMAGE=$(grep -E '\b/boot\b' "$FSTAB" | grep -oE '/dev/[a-zA-Z0-9_./-]*')
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
is_mounted() {
|
|
||||||
if [ ! -z "$2" ]; then
|
|
||||||
cat /proc/mounts | grep $1 | grep $2, >/dev/null
|
|
||||||
else
|
|
||||||
cat /proc/mounts | grep $1 >/dev/null
|
|
||||||
fi
|
|
||||||
return $?
|
|
||||||
}
|
|
||||||
|
|
||||||
mount_image() {
|
|
||||||
if [ ! -d "$2" ]; then
|
|
||||||
mount -o rw,remount rootfs /
|
|
||||||
mkdir -p $2 2>/dev/null
|
|
||||||
($BOOTMODE) && mount -o ro,remount rootfs /
|
|
||||||
[ ! -d "$2" ] && return 1
|
|
||||||
fi
|
|
||||||
if (! is_mounted $2); then
|
|
||||||
LOOPDEVICE=
|
|
||||||
for LOOP in 0 1 2 3 4 5 6 7; do
|
|
||||||
if (! is_mounted $2); then
|
|
||||||
LOOPDEVICE=/dev/block/loop$LOOP
|
|
||||||
if [ ! -f "$LOOPDEVICE" ]; then
|
|
||||||
mknod $LOOPDEVICE b 7 $LOOP
|
|
||||||
fi
|
|
||||||
losetup $LOOPDEVICE $1
|
|
||||||
if [ "$?" -eq "0" ]; then
|
|
||||||
mount -t ext4 -o loop $LOOPDEVICE $2
|
|
||||||
if (! is_mounted $2); then
|
|
||||||
/system/bin/toolbox mount -t ext4 -o loop $LOOPDEVICE $2
|
|
||||||
fi
|
|
||||||
if (! is_mounted $2); then
|
|
||||||
/system/bin/toybox mount -t ext4 -o loop $LOOPDEVICE $2
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
if (is_mounted $2); then
|
|
||||||
ui_print "- Mounting $1 to $2"
|
|
||||||
break;
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
grep_prop() {
|
|
||||||
REGEX="s/^$1=//p"
|
|
||||||
shift
|
|
||||||
FILES=$@
|
|
||||||
if [ -z "$FILES" ]; then
|
|
||||||
FILES='/system/build.prop'
|
|
||||||
fi
|
|
||||||
cat $FILES 2>/dev/null | sed -n $REGEX | head -n 1
|
|
||||||
}
|
|
||||||
|
|
||||||
unpack_boot() {
|
|
||||||
rm -rf $UNPACKDIR $RAMDISK 2>/dev/null
|
|
||||||
mkdir -p $UNPACKDIR
|
|
||||||
mkdir -p $RAMDISK
|
|
||||||
cd $UNPACKDIR
|
|
||||||
$BINDIR/bootimgtools --extract $1
|
|
||||||
|
|
||||||
find $TMPDIR/boottmp -type d -exec chmod 755 {} \;
|
|
||||||
find $TMPDIR/boottmp -type f -exec chmod 644 {} \;
|
|
||||||
chmod 755 $(find $TMPDIR/boottmp -type d)
|
|
||||||
chmod 644 $(find $TMPDIR/boottmp -type f)
|
|
||||||
|
|
||||||
cd $RAMDISK
|
|
||||||
gunzip -c < $UNPACKDIR/ramdisk.gz | cpio -i
|
|
||||||
}
|
|
||||||
|
|
||||||
repack_boot() {
|
|
||||||
cd $RAMDISK
|
|
||||||
find . | cpio -o -H newc 2>/dev/null | gzip -9 > $UNPACKDIR/ramdisk.gz
|
|
||||||
cd $UNPACKDIR
|
|
||||||
$BINDIR/bootimgtools --repack $ORIGBOOT
|
|
||||||
if [ -f chromeos ]; then
|
|
||||||
echo " " > config
|
|
||||||
echo " " > bootloader
|
|
||||||
$CHROMEDIR/futility vbutil_kernel --pack new-boot.img.signed --keyblock $CHROMEDIR/kernel.keyblock --signprivate $CHROMEDIR/kernel_data_key.vbprivk --version 1 --vmlinuz new-boot.img --config config --arch arm --bootloader bootloader --flags 0x1
|
|
||||||
rm -f new-boot.img
|
|
||||||
mv new-boot.img.signed new-boot.img
|
|
||||||
fi
|
|
||||||
if ($SAMSUNG); then
|
|
||||||
SAMSUNG_CHECK=$(cat new-boot.img | grep SEANDROIDENFORCE)
|
|
||||||
if [ $? -ne 0 ]; then
|
|
||||||
echo -n "SEANDROIDENFORCE" >> new-boot.img
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
mv new-boot.img $NEWBOOT
|
|
||||||
$BINDIR/bootimgtools --hexpatch $NEWBOOT \
|
|
||||||
49010054011440B93FA00F71E9000054010840B93FA00F7189000054001840B91FA00F7188010054 \
|
|
||||||
A1020054011440B93FA00F7140020054010840B93FA00F71E0010054001840B91FA00F7181010054
|
|
||||||
}
|
|
||||||
|
|
||||||
##########################################################################################
|
|
||||||
# Detection
|
|
||||||
##########################################################################################
|
|
||||||
|
|
||||||
ui_print "****************************"
|
|
||||||
ui_print "Magisk v8 Boot Image Patcher"
|
|
||||||
ui_print "****************************"
|
|
||||||
|
|
||||||
if [ ! -d "$INSTALLER/common" ]; then
|
|
||||||
ui_print "! Failed: Unable to extract zip file!"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
ui_print "- Mounting /system(ro), /cache, /data"
|
|
||||||
mount -o ro /system 2>/dev/null
|
|
||||||
mount /cache 2>/dev/null
|
|
||||||
mount /data 2>/dev/null
|
|
||||||
|
|
||||||
if [ ! -f '/system/build.prop' ]; then
|
|
||||||
ui_print "! Failed: /system could not be mounted!"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
API=$(grep_prop ro.build.version.sdk)
|
|
||||||
ABI=$(grep_prop ro.product.cpu.abi | cut -c-3)
|
|
||||||
ABI2=$(grep_prop ro.product.cpu.abi2 | cut -c-3)
|
|
||||||
ABILONG=$(grep_prop ro.product.cpu.abi)
|
|
||||||
|
|
||||||
ARCH=arm
|
|
||||||
IS64BIT=false
|
|
||||||
if [ "$ABI" = "x86" ]; then ARCH=x86; fi;
|
|
||||||
if [ "$ABI2" = "x86" ]; then ARCH=x86; fi;
|
|
||||||
if [ "$ABILONG" = "arm64-v8a" ]; then ARCH=arm64; IS64BIT=true; fi;
|
|
||||||
if [ "$ABILONG" = "x86_64" ]; then ARCH=x64; IS64BIT=true; fi;
|
|
||||||
|
|
||||||
|
|
||||||
if [ "$API" -lt "21" ]; then
|
|
||||||
ui_print "! Magisk is only for Lollipop 5.0+ (SDK 21+)"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
ui_print "- Device platform: $ARCH"
|
|
||||||
|
|
||||||
BINDIR=$INSTALLER/arm
|
|
||||||
if [ "$ARCH" = "x86" -o "$ARCH" = "x64" ]; then
|
|
||||||
BINDIR=$INSTALLER/x86
|
|
||||||
fi
|
|
||||||
|
|
||||||
find_boot_image
|
|
||||||
if [ -z "$BOOTIMAGE" ]; then
|
|
||||||
ui_print "! Unable to detect boot image"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ -z "$NOOVERRIDE" ]; then
|
|
||||||
# read override variables
|
|
||||||
getvar KEEPVERITY
|
|
||||||
getvar KEEPFORCEENCRYPT
|
|
||||||
getvar NORESTORE
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ -z "$KEEPVERITY" ]; then
|
|
||||||
# we don't keep dm-verity by default
|
|
||||||
KEEPVERITY=false
|
|
||||||
fi
|
|
||||||
if [ -z "$KEEPFORCEENCRYPT" ]; then
|
|
||||||
# we don't keep forceencrypt by default
|
|
||||||
KEEPFORCEENCRYPT=false
|
|
||||||
fi
|
|
||||||
if [ -z "$NORESTORE" ]; then
|
|
||||||
# we don't keep ramdisk by default
|
|
||||||
NORESTORE=false
|
|
||||||
fi
|
|
||||||
|
|
||||||
SAMSUNG=false
|
|
||||||
SAMSUNG_CHECK=$(cat /system/build.prop | grep "ro.build.fingerprint=" | grep -i "samsung")
|
|
||||||
if [ $? -eq 0 ]; then
|
|
||||||
SAMSUNG=true
|
|
||||||
fi
|
|
||||||
|
|
||||||
##########################################################################################
|
|
||||||
# Environment
|
|
||||||
##########################################################################################
|
|
||||||
|
|
||||||
ui_print "- Constructing environment"
|
|
||||||
|
|
||||||
if (is_mounted /data); then
|
|
||||||
rm -rf /data/busybox /data/magisk 2>/dev/null
|
|
||||||
mkdir -p /data/busybox
|
|
||||||
cp -af $BINDIR /data/magisk
|
|
||||||
cp -af $INSTALLER/common/init.magisk.rc $INSTALLER/common/magic_mask.sh /data/magisk
|
|
||||||
chmod 755 /data/busybox /data/magisk /data/magisk/*
|
|
||||||
chcon 'u:object_r:system_file:s0' /data/busybox /data/magisk /data/magisk/*
|
|
||||||
/data/magisk/busybox --install -s /data/busybox
|
|
||||||
# Prevent issues
|
|
||||||
rm -f /data/busybox/su /data/busybox/sh
|
|
||||||
else
|
|
||||||
rm -rf /cache/data_bin 2>/dev/null
|
|
||||||
mkdir -p /cache/data_bin
|
|
||||||
cp -af $BINDIR /cache/data_bin
|
|
||||||
cp -af $INSTALLER/common/init.magisk.rc $INSTALLER/common/magic_mask.sh /cache/data_bin
|
|
||||||
fi
|
|
||||||
|
|
||||||
##########################################################################################
|
|
||||||
# Image
|
|
||||||
##########################################################################################
|
|
||||||
|
|
||||||
# Fix SuperSU.....
|
|
||||||
($BOOTMODE) && /data/magisk/sepolicy-inject -s fsck --live
|
|
||||||
|
|
||||||
if (is_mounted /data); then
|
|
||||||
IMG=/data/magisk.img
|
|
||||||
else
|
|
||||||
IMG=/cache/magisk.img
|
|
||||||
ui_print "- Data unavalible, use cache workaround"
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ -f "$IMG" ]; then
|
|
||||||
ui_print "- $IMG detected!"
|
|
||||||
else
|
|
||||||
ui_print "- Creating $IMG"
|
|
||||||
make_ext4fs -l 64M -a /magisk -S $INSTALLER/common/file_contexts_image $IMG
|
|
||||||
fi
|
|
||||||
|
|
||||||
mount_image $IMG /magisk
|
|
||||||
if (! is_mounted /magisk); then
|
|
||||||
ui_print "! Image mount failed... abort"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
MAGISKLOOP=$LOOPDEVICE
|
|
||||||
|
|
||||||
mkdir -p /magisk/.core/magiskhide 2>/dev/null
|
|
||||||
cp -af $INSTALLER/common/magiskhide/. /magisk/.core/magiskhide
|
|
||||||
|
|
||||||
# Remove legacy SuperSU module
|
|
||||||
mkdir -p /magisk/zzsupersu
|
|
||||||
touch /magisk/zzsupersu/remove
|
|
||||||
|
|
||||||
##########################################################################################
|
|
||||||
# Boot image patch
|
|
||||||
##########################################################################################
|
|
||||||
|
|
||||||
ui_print "- Found Boot Image: $BOOTIMAGE"
|
|
||||||
|
|
||||||
rm -rf $TMPDIR/boottmp 2>/dev/null
|
|
||||||
mkdir -p $TMPDIR/boottmp
|
|
||||||
|
|
||||||
CHROMEDIR=$INSTALLER/chromeos
|
|
||||||
ORIGBOOT=$TMPDIR/boottmp/boot.img
|
|
||||||
NEWBOOT=$TMPDIR/boottmp/new-boot.img
|
|
||||||
UNPACKDIR=$TMPDIR/boottmp/bootunpack
|
|
||||||
RAMDISK=$TMPDIR/boottmp/ramdisk
|
|
||||||
|
|
||||||
chmod 777 $CHROMEDIR/futility $BINDIR/*
|
|
||||||
|
|
||||||
ui_print "- Dumping boot image"
|
|
||||||
dd if=$BOOTIMAGE of=$ORIGBOOT
|
|
||||||
|
|
||||||
ui_print "- Unpacking boot image"
|
|
||||||
unpack_boot $ORIGBOOT
|
|
||||||
|
|
||||||
# Restore ramdisk
|
|
||||||
SUPERSU=false
|
|
||||||
if (! $NORESTORE); then
|
|
||||||
if [ -d ".backup" ]; then
|
|
||||||
ui_print "- Restoring ramdisk with ramdisk backup"
|
|
||||||
cp -af .backup/. .
|
|
||||||
rm -rf magisk init.magisk.rc sbin/magic_mask.sh 2>/dev/null
|
|
||||||
else
|
|
||||||
[ -f "sbin/launch_daemonsu.sh" ] && SUPERSU=true
|
|
||||||
if ($SUPERSU); then
|
|
||||||
ui_print "- SuperSU patched boot detected!"
|
|
||||||
ui_print "- Adding auto patch script for SuperSU"
|
|
||||||
cp -af $INSTALLER/common/custom_ramdisk_patch.sh /data/custom_ramdisk_patch.sh
|
|
||||||
fi
|
|
||||||
if [ -d "magisk" ]; then
|
|
||||||
# If Magisk is installed and no SuperSU and no ramdisk backups
|
|
||||||
# Restore previous stock boot image
|
|
||||||
if (! $SUPERSU); then
|
|
||||||
cp -af /data/stock_boot_*.gz /data/stock_boot.img.gz 2>/dev/null
|
|
||||||
gzip -d /data/stock_boot.img.gz 2>/dev/null
|
|
||||||
if [ -f "/data/stock_boot.img" ]; then
|
|
||||||
ui_print "- Restoring boot image with backup"
|
|
||||||
cp -af /data/stock_boot.img $ORIGBOOT
|
|
||||||
unpack_boot $ORIGBOOT
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
# Removing possible modifications
|
|
||||||
rm -rf magisk init.magisk.rc sbin/magic_mask.sh 2>/dev/null
|
|
||||||
rm -rf init.xposed.rc sbin/mount_xposed.sh 2>/dev/null
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
if (! $SUPERSU); then
|
|
||||||
ui_print "- Creating backups"
|
|
||||||
mkdir .backup 2>/dev/null
|
|
||||||
cp -af init.environ.rc *fstab* verity_key sepolicy .backup 2>/dev/null
|
|
||||||
if (! $SUPERSU); then
|
|
||||||
# SuperSU already backup stock boot, no need to do again
|
|
||||||
if (is_mounted /data); then
|
|
||||||
cp -af $ORIGBOOT /data/stock_boot.img
|
|
||||||
else
|
|
||||||
cp -af $ORIGBOOT /cache/stock_boot.img
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Patch ramdisk
|
|
||||||
ui_print "- Patching ramdisk"
|
|
||||||
|
|
||||||
# Add magisk entrypoint
|
|
||||||
for INIT in init*.rc; do
|
|
||||||
if [ $(grep -c "import /init.environ.rc" $INIT) -ne "0" ] && [ $(grep -c "import /init.magisk.rc" $INIT) -eq "0" ]; then
|
|
||||||
cp $INIT .backup
|
|
||||||
sed -i "/import \/init\.environ\.rc/iimport /init.magisk.rc" $INIT
|
|
||||||
break
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
|
|
||||||
# Add magisk PATH
|
|
||||||
if [ $(grep -c "export PATH" init.environ.rc) -eq "0" ]; then
|
|
||||||
sed -i "/on init/a\ \ \ \ export PATH /magisk/.core/bin:/sbin:/vendor/bin:/system/sbin:/system/bin:/system/xbin:/magisk/.core/busybox" init.environ.rc
|
|
||||||
else
|
|
||||||
if [ $(grep -c "/magisk/.core/busybox" init.environ.rc) -eq "0" ]; then
|
|
||||||
sed -i "/export PATH/ s/\/system\/xbin/\/system\/xbin:\/magisk\/.core\/busybox/g" init.environ.rc
|
|
||||||
fi
|
|
||||||
if [ $(grep -c "/magisk/.core/bin" init.environ.rc) -eq "0" ] && (! $SUPERSU); then
|
|
||||||
sed -i "/export PATH/ s/\/sbin/\/magisk\/.core\/bin:\/sbin/g" init.environ.rc
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
if (! $SUPERSU); then
|
|
||||||
sed -i "/selinux.reload_policy/d" init.rc
|
|
||||||
find . -type f -name "*fstab*" 2>/dev/null | while read FSTAB ; do
|
|
||||||
if (! $KEEPVERITY); then
|
|
||||||
sed -i "s/,support_scfs//g" $FSTAB
|
|
||||||
sed -i 's;,\{0,1\}verify\(=[^,]*\)\{0,1\};;g' $FSTAB
|
|
||||||
fi
|
|
||||||
if (! $KEEPFORCEENCRYPT); then
|
|
||||||
sed -i "s/forceencrypt/encryptable/g" $FSTAB
|
|
||||||
sed -i "s/forcefdeorfbe/encryptable/g" $FSTAB
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
if (! $KEEPVERITY); then
|
|
||||||
rm verity_key 2>/dev/null
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
# sepolicy patches
|
|
||||||
$BINDIR/sepolicy-inject --magisk -P sepolicy
|
|
||||||
|
|
||||||
# Add new items
|
|
||||||
mkdir -p magisk 2>/dev/null
|
|
||||||
cp -af $INSTALLER/common/init.magisk.rc init.magisk.rc
|
|
||||||
cp -af $INSTALLER/common/magic_mask.sh sbin/magic_mask.sh
|
|
||||||
|
|
||||||
chmod 0755 magisk
|
|
||||||
chmod 0750 init.magisk.rc sbin/magic_mask.sh
|
|
||||||
|
|
||||||
ui_print "- Repacking boot image"
|
|
||||||
repack_boot
|
|
||||||
|
|
||||||
ORIGSIZE=$(ls -l $ORIGBOOT | awk '{print $5}')
|
|
||||||
NEWSIZE=$(ls -l $NEWBOOT | awk '{print $5}')
|
|
||||||
if [ "$NEWSIZE" -gt "$ORIGSIZE" ]; then
|
|
||||||
ui_print "! Boot partition space insufficient"
|
|
||||||
ui_print "! Try to remove ramdisk backups"
|
|
||||||
rm -rf $RAMDISK/.backup $NEWBOOT 2>/dev/null
|
|
||||||
repack_boot
|
|
||||||
NEWSIZE=$(ls -l $NEWBOOT | awk '{print $5}')
|
|
||||||
if [ "$NEWSIZE" -gt "$ORIGSIZE" ]; then
|
|
||||||
ui_print "! Boot partition size still too small..."
|
|
||||||
ui_print "! Unable to install Magisk"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
chmod 644 $NEWBOOT
|
|
||||||
|
|
||||||
if [ -L "$BOOTIMAGE" ]; then
|
|
||||||
ui_print "- Block symlink detected!"
|
|
||||||
else
|
|
||||||
dd if=/dev/zero of=$BOOTIMAGE bs=4096 2>/dev/null
|
|
||||||
fi
|
|
||||||
ui_print "- Flashing new boot image"
|
|
||||||
dd if=$NEWBOOT of=$BOOTIMAGE bs=4096
|
|
||||||
|
|
||||||
if (! $BOOTMODE); then
|
|
||||||
ui_print "- Unmounting partitions"
|
|
||||||
umount /magisk
|
|
||||||
losetup -d $MAGISKLOOP
|
|
||||||
umount /system
|
|
||||||
fi
|
|
||||||
|
|
||||||
ui_print "- Done"
|
|
||||||
exit 0
|
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -1,53 +0,0 @@
|
|||||||
#!/system/bin/sh
|
|
||||||
|
|
||||||
RAMDISK=$1
|
|
||||||
BINDIR=/data/magisk
|
|
||||||
|
|
||||||
cpio_add() {
|
|
||||||
/su/bin/sukernel --cpio-add $RAMDISK $RAMDISK $2 $1 $1
|
|
||||||
}
|
|
||||||
|
|
||||||
cpio_extract() {
|
|
||||||
/su/bin/sukernel --cpio-extract $RAMDISK $1 $1
|
|
||||||
}
|
|
||||||
|
|
||||||
cpio_mkdir() {
|
|
||||||
/su/bin/sukernel --cpio-mkdir $RAMDISK $RAMDISK $2 $1
|
|
||||||
}
|
|
||||||
|
|
||||||
rm -rf /tmp/magisk/ramdisk 2>/dev/null
|
|
||||||
mkdir -p /tmp/magisk/ramdisk
|
|
||||||
cd /tmp/magisk/ramdisk
|
|
||||||
|
|
||||||
cat $RAMDISK | cpio -i
|
|
||||||
|
|
||||||
# Patch ramdisk
|
|
||||||
echo "- Patching ramdisk"
|
|
||||||
|
|
||||||
# Add magisk entrypoint
|
|
||||||
for INIT in init*.rc; do
|
|
||||||
if [ $(grep -c "import /init.environ.rc" $INIT) -ne "0" ] && [ $(grep -c "import /init.magisk.rc" $INIT) -eq "0" ]; then
|
|
||||||
sed -i "/import \/init\.environ\.rc/iimport /init.magisk.rc" $INIT
|
|
||||||
cpio_add $INIT 750
|
|
||||||
break
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
|
|
||||||
# Add magisk PATH
|
|
||||||
if [ $(grep -c "/magisk/.core/busybox" init.environ.rc) -eq "0" ]; then
|
|
||||||
sed -i "/export PATH/ s/\/system\/xbin/\/system\/xbin:\/magisk\/.core\/busybox/g" init.environ.rc
|
|
||||||
cpio_add init.environ.rc 750
|
|
||||||
fi
|
|
||||||
|
|
||||||
# sepolicy patches
|
|
||||||
$BINDIR/sepolicy-inject --magisk -P sepolicy
|
|
||||||
cpio_add sepolicy 644
|
|
||||||
|
|
||||||
# Add new items
|
|
||||||
mkdir -p magisk 2>/dev/null
|
|
||||||
cp -af $BINDIR/init.magisk.rc init.magisk.rc
|
|
||||||
cp -af $BINDIR/magic_mask.sh sbin/magic_mask.sh
|
|
||||||
|
|
||||||
cpio_mkdir magisk 755
|
|
||||||
cpio_add init.magisk.rc 750
|
|
||||||
cpio_add sbin/magic_mask.sh 750
|
|
@@ -1,429 +0,0 @@
|
|||||||
#!/system/bin/sh
|
|
||||||
|
|
||||||
LOGFILE=/cache/magisk.log
|
|
||||||
HIDELOG=/cache/magiskhide.log
|
|
||||||
IMG=/data/magisk.img
|
|
||||||
|
|
||||||
export MOUNTPOINT=/magisk
|
|
||||||
|
|
||||||
COREDIR=$MOUNTPOINT/.core
|
|
||||||
|
|
||||||
DUMMDIR=$COREDIR/dummy
|
|
||||||
MIRRDIR=$COREDIR/mirror
|
|
||||||
|
|
||||||
TMPDIR=/dev/tmp
|
|
||||||
|
|
||||||
# Use the included busybox to do everything for maximum compatibility
|
|
||||||
# We also do so because we rely on the option "-c" for cp (reserve contexts)
|
|
||||||
|
|
||||||
# Reserve the original PATH
|
|
||||||
export OLDPATH=$PATH
|
|
||||||
export PATH="/data/busybox:$PATH"
|
|
||||||
|
|
||||||
log_print() {
|
|
||||||
echo $1
|
|
||||||
echo $1 >> $LOGFILE
|
|
||||||
log -p i -t Magisk "$1"
|
|
||||||
}
|
|
||||||
|
|
||||||
mktouch() {
|
|
||||||
mkdir -p ${1%/*} 2>/dev/null
|
|
||||||
if [ -z "$2" ]; then
|
|
||||||
touch $1 2>/dev/null
|
|
||||||
else
|
|
||||||
echo $2 > $1 2>/dev/null
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
unblock() {
|
|
||||||
touch /dev/.magisk.unblock
|
|
||||||
exit
|
|
||||||
}
|
|
||||||
|
|
||||||
run_scripts() {
|
|
||||||
BASE=$MOUNTPOINT
|
|
||||||
if [ "$1" = "post-fs" ]; then
|
|
||||||
BASE=/cache/magisk
|
|
||||||
fi
|
|
||||||
|
|
||||||
for MOD in $BASE/* ; do
|
|
||||||
if [ ! -f "$MOD/disable" ]; then
|
|
||||||
if [ -f "$MOD/$1.sh" ]; then
|
|
||||||
chmod 755 $MOD/$1.sh
|
|
||||||
chcon 'u:object_r:system_file:s0' $MOD/$1.sh
|
|
||||||
log_print "$1: $MOD/$1.sh"
|
|
||||||
$MOD/$1.sh
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
}
|
|
||||||
|
|
||||||
loopsetup() {
|
|
||||||
LOOPDEVICE=
|
|
||||||
for DEV in $(ls /dev/block/loop*); do
|
|
||||||
if [ `losetup $DEV $1 >/dev/null 2>&1; echo $?` -eq 0 ]; then
|
|
||||||
LOOPDEVICE=$DEV
|
|
||||||
break
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
}
|
|
||||||
|
|
||||||
target_size_check() {
|
|
||||||
e2fsck -p -f $1
|
|
||||||
curBlocks=`e2fsck -n $1 2>/dev/null | cut -d, -f3 | cut -d\ -f2`;
|
|
||||||
curUsedM=$((`echo "$curBlocks" | cut -d/ -f1` * 4 / 1024));
|
|
||||||
curSizeM=$((`echo "$curBlocks" | cut -d/ -f2` * 4 / 1024));
|
|
||||||
curFreeM=$((curSizeM - curUsedM));
|
|
||||||
}
|
|
||||||
|
|
||||||
travel() {
|
|
||||||
cd $1/$2
|
|
||||||
if [ -f ".replace" ]; then
|
|
||||||
rm -rf $TMPDIR/$2
|
|
||||||
mktouch $TMPDIR/$2 $1
|
|
||||||
else
|
|
||||||
for ITEM in * ; do
|
|
||||||
if [ ! -e "/$2/$ITEM" ]; then
|
|
||||||
# New item found
|
|
||||||
if [ $2 = "system" ]; then
|
|
||||||
# We cannot add new items to /system root, delete it
|
|
||||||
rm -rf $ITEM
|
|
||||||
else
|
|
||||||
if [ -d "$TMPDIR/dummy/$2" ]; then
|
|
||||||
# We are in a higher level, delete the lower levels
|
|
||||||
rm -rf $TMPDIR/dummy/$2
|
|
||||||
fi
|
|
||||||
# Mount the dummy parent
|
|
||||||
mktouch $TMPDIR/dummy/$2
|
|
||||||
|
|
||||||
mkdir -p $DUMMDIR/$2 2>/dev/null
|
|
||||||
if [ -d "$ITEM" ]; then
|
|
||||||
# Create new dummy directory
|
|
||||||
mkdir -p $DUMMDIR/$2/$ITEM
|
|
||||||
elif [ -L "$ITEM" ]; then
|
|
||||||
# Symlinks are small, copy them
|
|
||||||
cp -afc $ITEM $DUMMDIR/$2/$ITEM
|
|
||||||
else
|
|
||||||
# Create new dummy file
|
|
||||||
mktouch $DUMMDIR/$2/$ITEM
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Clone the original /system structure (depth 1)
|
|
||||||
if [ -e "/$2" ]; then
|
|
||||||
for DUMMY in /$2/* ; do
|
|
||||||
if [ -d "$DUMMY" ]; then
|
|
||||||
# Create dummy directory
|
|
||||||
mkdir -p $DUMMDIR$DUMMY
|
|
||||||
elif [ -L "$DUMMY" ]; then
|
|
||||||
# Symlinks are small, copy them
|
|
||||||
cp -afc $DUMMY $DUMMDIR$DUMMY
|
|
||||||
else
|
|
||||||
# Create dummy file
|
|
||||||
mktouch $DUMMDIR$DUMMY
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ -d "$ITEM" ]; then
|
|
||||||
# It's an directory, travel deeper
|
|
||||||
(travel $1 $2/$ITEM)
|
|
||||||
elif [ ! -L "$ITEM" ]; then
|
|
||||||
# Mount this file
|
|
||||||
mktouch $TMPDIR/$2/$ITEM $1
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
bind_mount() {
|
|
||||||
if [ -e "$1" -a -e "$2" ]; then
|
|
||||||
mount -o bind $1 $2
|
|
||||||
if [ "$?" -eq "0" ]; then
|
|
||||||
log_print "Mount: $1"
|
|
||||||
else
|
|
||||||
log_print "Mount Fail: $1"
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
merge_image() {
|
|
||||||
if [ -f "$1" ]; then
|
|
||||||
log_print "$1 found"
|
|
||||||
if [ -f "$IMG" ]; then
|
|
||||||
log_print "$IMG found, attempt to merge"
|
|
||||||
|
|
||||||
# Handle large images
|
|
||||||
target_size_check $1
|
|
||||||
MERGEUSED=$curUsedM
|
|
||||||
target_size_check $IMG
|
|
||||||
if [ "$MERGEUSED" -gt "$curFreeM" ]; then
|
|
||||||
NEWDATASIZE=$((((MERGEUSED + curUsedM) / 32 + 2) * 32))
|
|
||||||
log_print "Expanding $IMG to ${NEWDATASIZE}M..."
|
|
||||||
resize2fs $IMG ${NEWDATASIZE}M
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Start merging
|
|
||||||
mkdir /cache/data_img
|
|
||||||
mkdir /cache/merge_img
|
|
||||||
|
|
||||||
# setup loop devices
|
|
||||||
loopsetup $IMG
|
|
||||||
LOOPDATA=$LOOPDEVICE
|
|
||||||
log_print "$LOOPDATA $IMG"
|
|
||||||
|
|
||||||
loopsetup $1
|
|
||||||
LOOPMERGE=$LOOPDEVICE
|
|
||||||
log_print "$LOOPMERGE $1"
|
|
||||||
|
|
||||||
if [ ! -z "$LOOPDATA" ]; then
|
|
||||||
if [ ! -z "$LOOPMERGE" ]; then
|
|
||||||
# if loop devices have been setup, mount images
|
|
||||||
OK=true
|
|
||||||
|
|
||||||
if [ `mount -t ext4 -o rw,noatime $LOOPDATA /cache/data_img >/dev/null 2>&1; echo $?` -ne 0 ]; then
|
|
||||||
OK=false
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ `mount -t ext4 -o rw,noatime $LOOPMERGE /cache/merge_img >/dev/null 2>&1; echo $?` -ne 0 ]; then
|
|
||||||
OK=false
|
|
||||||
fi
|
|
||||||
|
|
||||||
if ($OK); then
|
|
||||||
# Merge (will reserve selinux contexts)
|
|
||||||
cd /cache/merge_img
|
|
||||||
for MOD in *; do
|
|
||||||
log_print "Merging: $MOD"
|
|
||||||
rm -rf /cache/data_img/$MOD
|
|
||||||
cp -afc $MOD /cache/data_img/
|
|
||||||
done
|
|
||||||
log_print "Merge complete"
|
|
||||||
fi
|
|
||||||
|
|
||||||
umount /cache/data_img
|
|
||||||
umount /cache/merge_img
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
losetup -d $LOOPDATA
|
|
||||||
losetup -d $LOOPMERGE
|
|
||||||
|
|
||||||
rmdir /cache/data_img
|
|
||||||
rmdir /cache/merge_img
|
|
||||||
else
|
|
||||||
log_print "Moving $1 to $IMG "
|
|
||||||
mv $1 $IMG
|
|
||||||
fi
|
|
||||||
rm -f $1
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
case $1 in
|
|
||||||
post-fs )
|
|
||||||
mv $LOGFILE /cache/last_magisk.log
|
|
||||||
touch $LOGFILE
|
|
||||||
chmod 644 $LOGFILE
|
|
||||||
log_print "Magisk post-fs mode running..."
|
|
||||||
|
|
||||||
if [ -d "/cache/magisk_merge" ]; then
|
|
||||||
cd /cache/magisk_merge
|
|
||||||
for MOD in *; do
|
|
||||||
log_print "Merging: $MOD"
|
|
||||||
rm -rf /cache/magisk/$MOD
|
|
||||||
mv $MOD /cache/magisk/$MOD
|
|
||||||
done
|
|
||||||
rm -rf /cache/magisk_merge
|
|
||||||
fi
|
|
||||||
|
|
||||||
for MOD in /cache/magisk/* ; do
|
|
||||||
if [ -f "$MOD/remove" ]; then
|
|
||||||
log_print "Remove module: $MOD"
|
|
||||||
rm -rf $MOD
|
|
||||||
elif [ -f "$MOD/auto_mount" -a ! -f "$MOD/disable" ]; then
|
|
||||||
find $MOD/system -type f 2>/dev/null | while read ITEM ; do
|
|
||||||
TARGET=${ITEM#$MOD}
|
|
||||||
bind_mount $ITEM $TARGET
|
|
||||||
done
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
|
|
||||||
run_scripts post-fs
|
|
||||||
unblock
|
|
||||||
;;
|
|
||||||
|
|
||||||
post-fs-data )
|
|
||||||
if [ `mount | grep " /data " >/dev/null 2>&1; echo $?` -ne 0 ]; then
|
|
||||||
# /data not mounted yet, we will be called again later
|
|
||||||
unblock
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ `mount | grep " /data " | grep "tmpfs" >/dev/null 2>&1; echo $?` -eq 0 ]; then
|
|
||||||
# /data not mounted yet, we will be called again later
|
|
||||||
unblock
|
|
||||||
fi
|
|
||||||
|
|
||||||
log_print "Magisk post-fs-data mode running..."
|
|
||||||
|
|
||||||
# Live patch sepolicy
|
|
||||||
/data/magisk/sepolicy-inject --live -s su
|
|
||||||
|
|
||||||
[ ! -d "$MOUNTPOINT" ] && mkdir -p $MOUNTPOINT
|
|
||||||
|
|
||||||
# Cache support
|
|
||||||
if [ -d "/cache/data_bin" ]; then
|
|
||||||
rm -rf /data/busybox /data/magisk
|
|
||||||
mkdir -p /data/busybox
|
|
||||||
mv /cache/data_bin /data/magisk
|
|
||||||
chmod 755 /data/busybox /data/magisk /data/magisk/*
|
|
||||||
chcon 'u:object_r:system_file:s0' /data/busybox /data/magisk /data/magisk/*
|
|
||||||
/data/magisk/busybox --install -s /data/busybox
|
|
||||||
# Prevent issues
|
|
||||||
rm -f /data/busybox/su /data/busybox/sh
|
|
||||||
fi
|
|
||||||
mv /cache/stock_boot.img /data 2>/dev/null
|
|
||||||
|
|
||||||
chmod 644 $IMG /cache/magisk.img /data/magisk_merge.img 2>/dev/null
|
|
||||||
|
|
||||||
# Handle image merging
|
|
||||||
merge_image /cache/magisk.img
|
|
||||||
merge_image /data/magisk_merge.img
|
|
||||||
|
|
||||||
# Mount magisk.img
|
|
||||||
if [ `cat /proc/mounts | grep $MOUNTPOINT >/dev/null 2>&1; echo $?` -ne 0 ]; then
|
|
||||||
loopsetup $IMG
|
|
||||||
if [ ! -z "$LOOPDEVICE" ]; then
|
|
||||||
mount -t ext4 -o rw,noatime $LOOPDEVICE $MOUNTPOINT
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ `cat /proc/mounts | grep $MOUNTPOINT >/dev/null 2>&1; echo $?` -ne 0 ]; then
|
|
||||||
log_print "magisk.img mount failed, nothing to do :("
|
|
||||||
unblock
|
|
||||||
fi
|
|
||||||
|
|
||||||
log_print "Preparing modules"
|
|
||||||
# First do cleanups
|
|
||||||
rm -rf $DUMMDIR
|
|
||||||
rmdir $(find $MOUNTPOINT -type d -depth ! -path "*core*" ) 2>/dev/null
|
|
||||||
rm -rf $COREDIR/bin
|
|
||||||
|
|
||||||
mkdir -p $DUMMDIR
|
|
||||||
mkdir -p $MIRRDIR/system
|
|
||||||
|
|
||||||
# Travel through all mods
|
|
||||||
for MOD in $MOUNTPOINT/* ; do
|
|
||||||
if [ -f "$MOD/remove" ]; then
|
|
||||||
log_print "Remove module: $MOD"
|
|
||||||
rm -rf $MOD
|
|
||||||
elif [ -f "$MOD/auto_mount" -a -d "$MOD/system" -a ! -f "$MOD/disable" ]; then
|
|
||||||
(travel $MOD system)
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
|
|
||||||
# Proper permissions for generated items
|
|
||||||
chmod 755 $(find $COREDIR -type d)
|
|
||||||
chmod 644 $(find $COREDIR -type f)
|
|
||||||
find $COREDIR -type d -exec chmod 755 {} \;
|
|
||||||
find $COREDIR -type f -exec chmod 644 {} \;
|
|
||||||
|
|
||||||
# linker(64), t*box, and app_process* are required if we need to dummy mount bin folder
|
|
||||||
if [ -f "$TMPDIR/dummy/system/bin" ]; then
|
|
||||||
rm -f $DUMMDIR/system/bin/linker* $DUMMDIR/system/bin/t*box $DUMMDIR/system/bin/app_process*
|
|
||||||
cd /system/bin
|
|
||||||
cp -afc linker* t*box app_process* $DUMMDIR/system/bin/
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Unmount, shrink, remount
|
|
||||||
if [ `umount $MOUNTPOINT >/dev/null 2>&1; echo $?` -eq 0 ]; then
|
|
||||||
losetup -d $LOOPDEVICE
|
|
||||||
target_size_check $IMG
|
|
||||||
NEWDATASIZE=$(((curUsedM / 32 + 2) * 32))
|
|
||||||
if [ "$curSizeM" -gt "$NEWDATASIZE" ]; then
|
|
||||||
log_print "Shrinking $IMG to ${NEWDATASIZE}M..."
|
|
||||||
resize2fs $IMG ${NEWDATASIZE}M
|
|
||||||
fi
|
|
||||||
loopsetup $IMG
|
|
||||||
if [ ! -z "$LOOPDEVICE" ]; then
|
|
||||||
mount -t ext4 -o rw,noatime $LOOPDEVICE $MOUNTPOINT
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ `cat /proc/mounts | grep $MOUNTPOINT >/dev/null 2>&1; echo $?` -ne 0 ]; then
|
|
||||||
log_print "magisk.img mount failed, nothing to do :("
|
|
||||||
unblock
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Remove crap folder
|
|
||||||
rm -rf $MOUNTPOINT/lost+found
|
|
||||||
|
|
||||||
# Start doing tasks
|
|
||||||
|
|
||||||
# Stage 1
|
|
||||||
log_print "Bind mount dummy system"
|
|
||||||
find $TMPDIR/dummy -type f 2>/dev/null | while read ITEM ; do
|
|
||||||
TARGET=${ITEM#$TMPDIR/dummy}
|
|
||||||
ORIG=$DUMMDIR$TARGET
|
|
||||||
bind_mount $ORIG $TARGET
|
|
||||||
done
|
|
||||||
|
|
||||||
# Stage 2
|
|
||||||
log_print "Bind mount module items"
|
|
||||||
find $TMPDIR/system -type f 2>/dev/null | while read ITEM ; do
|
|
||||||
TARGET=${ITEM#$TMPDIR}
|
|
||||||
ORIG=`cat $ITEM`$TARGET
|
|
||||||
bind_mount $ORIG $TARGET
|
|
||||||
rm -f $DUMMDIR${TARGET%/*}/.dummy 2>/dev/null
|
|
||||||
done
|
|
||||||
|
|
||||||
# Run scripts
|
|
||||||
run_scripts post-fs-data
|
|
||||||
|
|
||||||
# Bind hosts for Adblock apps
|
|
||||||
[ ! -f "$COREDIR/hosts" ] && cp -afc /system/etc/hosts $COREDIR/hosts
|
|
||||||
log_print "Enabling systemless hosts file support"
|
|
||||||
bind_mount $COREDIR/hosts /system/etc/hosts
|
|
||||||
|
|
||||||
# Stage 3
|
|
||||||
log_print "Bind mount system mirror"
|
|
||||||
bind_mount /system $MIRRDIR/system
|
|
||||||
|
|
||||||
# Stage 4
|
|
||||||
log_print "Bind mount mirror items"
|
|
||||||
# Find all empty directores and dummy files, they should be mounted by original files in /system
|
|
||||||
find $DUMMDIR -type d -exec sh -c '[ -z "$(ls -A $1)" ] && echo $1' -- {} \; -o \( -type f -size 0 -print \) | while read ITEM ; do
|
|
||||||
ORIG=${ITEM/dummy/mirror}
|
|
||||||
TARGET=${ITEM#$DUMMDIR}
|
|
||||||
bind_mount $ORIG $TARGET
|
|
||||||
done
|
|
||||||
|
|
||||||
# All done
|
|
||||||
rm -rf $TMPDIR
|
|
||||||
|
|
||||||
unblock
|
|
||||||
;;
|
|
||||||
|
|
||||||
service )
|
|
||||||
# Version info
|
|
||||||
setprop magisk.version 8
|
|
||||||
log_print "Magisk late_start service mode running..."
|
|
||||||
run_scripts service
|
|
||||||
[ -f "$COREDIR/magiskhide/enable" ] && setprop magisk.hide 1
|
|
||||||
;;
|
|
||||||
|
|
||||||
hide )
|
|
||||||
# Enable magiskhide
|
|
||||||
[ ! -f "$COREDIR/magiskhide/hidelist" ] && mktouch $COREDIR/magiskhide/hidelist
|
|
||||||
# Add preset for Safety Net
|
|
||||||
if [ $(grep -c "com.google.android.gms.unstable" $COREDIR/magiskhide/hidelist) -eq "0" ]; then
|
|
||||||
mv $COREDIR/magiskhide/hidelist $COREDIR/magiskhide/hidelist.tmp
|
|
||||||
echo "com.google.android.gms.unstable" > $COREDIR/magiskhide/hidelist
|
|
||||||
cat $COREDIR/magiskhide/hidelist.tmp >> $COREDIR/magiskhide/hidelist
|
|
||||||
rm -f $COREDIR/magiskhide/hidelist.tmp
|
|
||||||
fi
|
|
||||||
chmod 755 $COREDIR/magiskhide $COREDIR/magiskhide/*
|
|
||||||
log_print "Starting Magisk Hide"
|
|
||||||
exec /data/magisk/magiskhide $COREDIR/magiskhide/hidelist > $HIDELOG
|
|
||||||
;;
|
|
||||||
|
|
||||||
esac
|
|
BIN
zip_static/common/magisk.apk
Normal file
BIN
zip_static/common/magisk.apk
Normal file
Binary file not shown.
@@ -1,12 +1,14 @@
|
|||||||
#!/system/bin/sh
|
#!/system/bin/sh
|
||||||
|
|
||||||
HIDELIST=$MOUNTPOINT/.core/magiskhide/hidelist
|
HIDELIST=/magisk/.core/magiskhide/hidelist
|
||||||
|
PROCESS=$1
|
||||||
|
TOOLPATH=/dev/busybox
|
||||||
|
|
||||||
if [ ! -z "$1" ]; then
|
if [ ! -z "$PROCESS" ]; then
|
||||||
if [ $(grep -c "^$1$" $HIDELIST) -eq "0" ]; then
|
if [ `grep -c "^$PROCESS$" $HIDELIST` -eq "0" ]; then
|
||||||
echo "$1" >> $HIDELIST
|
echo "$PROCESS" >> $HIDELIST
|
||||||
|
set --
|
||||||
|
set `$TOOLPATH/ps -o pid,args | grep "$PROCESS" | grep -v grep` >/dev/null
|
||||||
|
[ ! -z "$1" ] && kill "$1"
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Reload the list
|
|
||||||
setprop magisk.hide 1
|
|
||||||
|
27
zip_static/common/magiskhide/disable
Normal file
27
zip_static/common/magiskhide/disable
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
#!/system/bin/sh
|
||||||
|
|
||||||
|
MODDIR=/magisk/.core/magiskhide
|
||||||
|
LOGFILE=/cache/magisk.log
|
||||||
|
TOOLPATH=/dev/busybox
|
||||||
|
|
||||||
|
log_print() {
|
||||||
|
echo "MagiskHide: $1"
|
||||||
|
echo "MagiskHide: $1" >> $LOGFILE
|
||||||
|
log -p i -t Magisk "MagiskHide: $1"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Only disable when MagiskHide is started
|
||||||
|
ps | grep "magiskhide --daemon" | grep -v grep >/dev/null 2>&1 || exit
|
||||||
|
|
||||||
|
log_print "Stopping MagiskHide daemon"
|
||||||
|
|
||||||
|
set --
|
||||||
|
set `$TOOLPATH/ps -o pid,args | grep "magiskhide" | grep -v grep | head -1` >/dev/null
|
||||||
|
[ ! -z "$1" ] && kill "$1"
|
||||||
|
|
||||||
|
while read PROCESS; do
|
||||||
|
log_print "Killing $PROCESS"
|
||||||
|
set --
|
||||||
|
set `$TOOLPATH/ps -o pid,args | grep "$PROCESS" | grep -v grep` >/dev/null
|
||||||
|
[ ! -z "$1" ] && kill "$1"
|
||||||
|
done < $MODDIR/hidelist
|
75
zip_static/common/magiskhide/enable
Normal file
75
zip_static/common/magiskhide/enable
Normal file
@@ -0,0 +1,75 @@
|
|||||||
|
#!/system/bin/sh
|
||||||
|
|
||||||
|
MODDIR=/magisk/.core/magiskhide
|
||||||
|
BINPATH=/data/magisk
|
||||||
|
LOGFILE=/cache/magisk.log
|
||||||
|
TOOLPATH=/dev/busybox
|
||||||
|
|
||||||
|
log_print() {
|
||||||
|
echo "MagiskHide: $1"
|
||||||
|
echo "MagiskHide: $1" >> $LOGFILE
|
||||||
|
log -p i -t Magisk "MagiskHide: $1"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Only enable when isn't started
|
||||||
|
ps | grep "magiskhide --daemon" | grep -v grep >/dev/null 2>&1 && exit
|
||||||
|
|
||||||
|
if [ ! -d /sbin_orig ]; then
|
||||||
|
log_print "Moving and re-linking /sbin binaries"
|
||||||
|
mount -o rw,remount rootfs /
|
||||||
|
mv -f /sbin /sbin_orig
|
||||||
|
mkdir /sbin
|
||||||
|
mount -o ro,remount rootfs /
|
||||||
|
mkdir -p /dev/sbin_bind
|
||||||
|
chmod 755 /dev/sbin_bind
|
||||||
|
ln -s /sbin_orig/* /dev/sbin_bind
|
||||||
|
chcon -h u:object_r:rootfs:s0 /dev/sbin_bind /dev/sbin_bind/*
|
||||||
|
mount -o bind /dev/sbin_bind /sbin
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Sammy device like these permissions
|
||||||
|
chmod 640 /sys/fs/selinux/enforce
|
||||||
|
chmod 440 /sys/fs/selinux/policy
|
||||||
|
|
||||||
|
log_print "Removing dangerous read-only system props"
|
||||||
|
|
||||||
|
VERIFYBOOT=`getprop ro.boot.verifiedbootstate`
|
||||||
|
FLASHLOCKED=`getprop ro.boot.flash.locked`
|
||||||
|
VERITYMODE=`getprop ro.boot.veritymode`
|
||||||
|
DEBUGGABLE=`getprop ro.debuggable`
|
||||||
|
SECURE=`getprop ro.secure`
|
||||||
|
BUILDTYPE=`getprop ro.build.type`
|
||||||
|
BUILDTAGS=`getprop ro.build.tags`
|
||||||
|
BUILDSELINUX=`getprop ro.build.selinux`
|
||||||
|
|
||||||
|
[ ! -z "$VERIFYBOOT" -a "$VERIFYBOOT" != "green" ] && \
|
||||||
|
log_print "`$BINPATH/resetprop -v -n ro.boot.verifiedbootstate green`"
|
||||||
|
[ ! -z "$FLASHLOCKED" -a "$FLASHLOCKED" != "1" ] && \
|
||||||
|
log_print "`$BINPATH/resetprop -v -n ro.boot.flash.locked 1`"
|
||||||
|
[ ! -z "$VERITYMODE" -a "$VERITYMODE" != "enforcing" ] && \
|
||||||
|
log_print "`$BINPATH/resetprop -v -n ro.boot.veritymode enforcing`"
|
||||||
|
[ ! -z "$DEBUGGABLE" -a "$DEBUGGABLE" != "0" ] && \
|
||||||
|
log_print "`$BINPATH/resetprop -v -n ro.debuggable 0`"
|
||||||
|
[ ! -z "$SECURE" -a "$SECURE" != "1" ] && \
|
||||||
|
log_print "`$BINPATH/resetprop -v -n ro.secure 1`"
|
||||||
|
[ ! -z "$BUILDTYPE" -a "$BUILDTYPE" != "user" ] && \
|
||||||
|
log_print "`$BINPATH/resetprop -v -n ro.build.type user`"
|
||||||
|
[ ! -z "$BUILDTAGS" -a "$BUILDTAGS" != "release-keys" ] && \
|
||||||
|
log_print "`$BINPATH/resetprop -v -n ro.build.tags release-keys`"
|
||||||
|
[ ! -z "$BUILDSELINUX" -a "$BUILDSELINUX" != "1" ] && \
|
||||||
|
log_print "`$BINPATH/resetprop -v -n ro.build.selinux 1`"
|
||||||
|
|
||||||
|
touch $MODDIR/hidelist
|
||||||
|
chmod -R 755 $MODDIR
|
||||||
|
# Add Safety Net preset
|
||||||
|
$MODDIR/add com.google.android.gms.unstable
|
||||||
|
|
||||||
|
while read PROCESS; do
|
||||||
|
log_print "Killing $PROCESS"
|
||||||
|
set --
|
||||||
|
set `$TOOLPATH/ps -o pid,args | grep "$PROCESS" | grep -v grep` >/dev/null
|
||||||
|
[ ! -z "$1" ] && kill "$1"
|
||||||
|
done < $MODDIR/hidelist
|
||||||
|
|
||||||
|
log_print "Starting MagiskHide daemon"
|
||||||
|
$BINPATH/magiskhide --daemon
|
@@ -1,4 +1,5 @@
|
|||||||
#!/system/bin/sh
|
#!/system/bin/sh
|
||||||
|
|
||||||
HIDELIST=$MOUNTPOINT/.core/magiskhide/hidelist
|
HIDELIST=/magisk/.core/magiskhide/hidelist
|
||||||
|
|
||||||
cat $HIDELIST
|
cat $HIDELIST
|
||||||
|
@@ -1,12 +1,14 @@
|
|||||||
#!/system/bin/sh
|
#!/system/bin/sh
|
||||||
|
|
||||||
HIDELIST=$MOUNTPOINT/.core/magiskhide/hidelist
|
HIDELIST=/magisk/.core/magiskhide/hidelist
|
||||||
|
PROCESS=$1
|
||||||
|
TOOLPATH=/dev/busybox
|
||||||
|
|
||||||
if [ ! -z "$1" ]; then
|
if [ ! -z "$PROCESS" ]; then
|
||||||
mv $HIDELIST $HIDELIST.tmp
|
cp -af $HIDELIST $HIDELIST.tmp
|
||||||
cat $HIDELIST.tmp | grep -v "^$1$" > $HIDELIST
|
cat $HIDELIST.tmp | grep -v "^$PROCESS$" > $HIDELIST
|
||||||
rm -f $HIDELIST.tmp
|
rm -f $HIDELIST.tmp
|
||||||
|
set --
|
||||||
|
set `$TOOLPATH/ps -o pid,args | grep "$PROCESS" | grep -v grep` >/dev/null
|
||||||
|
[ ! -z "$1" ] && kill "$1"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Reload the list
|
|
||||||
setprop magisk.hide 1
|
|
||||||
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
ziptools/minsignapk.jar
Normal file
BIN
ziptools/minsignapk.jar
Normal file
Binary file not shown.
BIN
ziptools/signapk.jar
Normal file
BIN
ziptools/signapk.jar
Normal file
Binary file not shown.
191
ziptools/src/MinSignAPK.java
Normal file
191
ziptools/src/MinSignAPK.java
Normal file
@@ -0,0 +1,191 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2008 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
/* This is just a copy/paste/cut job from original SignAPK sources. This
|
||||||
|
* adaptation adds only the whole-file signature to a ZIP(jar,apk) file, and
|
||||||
|
* doesn't do any of the per-file signing, creating manifests, etc. This is
|
||||||
|
* useful when you've changed the structure itself of an existing (signed!)
|
||||||
|
* ZIP file, but the extracted contents are still identical. Using
|
||||||
|
* the normal SignAPK may re-arrange other things inside the ZIP, which may
|
||||||
|
* be unwanted behavior. This version only changes the ZIP's tail and keeps
|
||||||
|
* the rest the same - CF
|
||||||
|
*/
|
||||||
|
|
||||||
|
package eu.chainfire.minsignapk;
|
||||||
|
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.DataInputStream;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileInputStream;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
import java.security.GeneralSecurityException;
|
||||||
|
import java.security.KeyFactory;
|
||||||
|
import java.security.PrivateKey;
|
||||||
|
import java.security.Signature;
|
||||||
|
import java.security.cert.CertificateFactory;
|
||||||
|
import java.security.cert.X509Certificate;
|
||||||
|
import java.security.spec.InvalidKeySpecException;
|
||||||
|
import java.security.spec.KeySpec;
|
||||||
|
import java.security.spec.PKCS8EncodedKeySpec;
|
||||||
|
|
||||||
|
import sun.security.pkcs.ContentInfo;
|
||||||
|
import sun.security.pkcs.PKCS7;
|
||||||
|
import sun.security.pkcs.SignerInfo;
|
||||||
|
import sun.security.x509.AlgorithmId;
|
||||||
|
import sun.security.x509.X500Name;
|
||||||
|
|
||||||
|
public class MinSignAPK {
|
||||||
|
/** Write a .RSA file with a digital signature. */
|
||||||
|
private static void writeSignatureBlock(Signature signature, X509Certificate publicKey, OutputStream out)
|
||||||
|
throws IOException, GeneralSecurityException {
|
||||||
|
SignerInfo signerInfo = new SignerInfo(new X500Name(publicKey.getIssuerX500Principal().getName()),
|
||||||
|
publicKey.getSerialNumber(), AlgorithmId.get("SHA1"), AlgorithmId.get("RSA"), signature.sign());
|
||||||
|
|
||||||
|
PKCS7 pkcs7 = new PKCS7(new AlgorithmId[] { AlgorithmId.get("SHA1") }, new ContentInfo(ContentInfo.DATA_OID,
|
||||||
|
null), new X509Certificate[] { publicKey }, new SignerInfo[] { signerInfo });
|
||||||
|
|
||||||
|
pkcs7.encodeSignedData(out);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void signWholeOutputFile(byte[] zipData, OutputStream outputStream, X509Certificate publicKey,
|
||||||
|
PrivateKey privateKey) throws IOException, GeneralSecurityException {
|
||||||
|
|
||||||
|
// For a zip with no archive comment, the
|
||||||
|
// end-of-central-directory record will be 22 bytes long, so
|
||||||
|
// we expect to find the EOCD marker 22 bytes from the end.
|
||||||
|
if (zipData[zipData.length - 22] != 0x50 || zipData[zipData.length - 21] != 0x4b
|
||||||
|
|| zipData[zipData.length - 20] != 0x05 || zipData[zipData.length - 19] != 0x06) {
|
||||||
|
throw new IllegalArgumentException("zip data already has an archive comment");
|
||||||
|
}
|
||||||
|
|
||||||
|
Signature signature = Signature.getInstance("SHA1withRSA");
|
||||||
|
signature.initSign(privateKey);
|
||||||
|
signature.update(zipData, 0, zipData.length - 2);
|
||||||
|
|
||||||
|
ByteArrayOutputStream temp = new ByteArrayOutputStream();
|
||||||
|
|
||||||
|
// put a readable message and a null char at the start of the
|
||||||
|
// archive comment, so that tools that display the comment
|
||||||
|
// (hopefully) show something sensible.
|
||||||
|
// TODO: anything more useful we can put in this message?
|
||||||
|
byte[] message = "signed by SignApk".getBytes("UTF-8");
|
||||||
|
temp.write(message);
|
||||||
|
temp.write(0);
|
||||||
|
writeSignatureBlock(signature, publicKey, temp);
|
||||||
|
int total_size = temp.size() + 6;
|
||||||
|
if (total_size > 0xffff) {
|
||||||
|
throw new IllegalArgumentException("signature is too big for ZIP file comment");
|
||||||
|
}
|
||||||
|
// signature starts this many bytes from the end of the file
|
||||||
|
int signature_start = total_size - message.length - 1;
|
||||||
|
temp.write(signature_start & 0xff);
|
||||||
|
temp.write((signature_start >> 8) & 0xff);
|
||||||
|
// Why the 0xff bytes? In a zip file with no archive comment,
|
||||||
|
// bytes [-6:-2] of the file are the little-endian offset from
|
||||||
|
// the start of the file to the central directory. So for the
|
||||||
|
// two high bytes to be 0xff 0xff, the archive would have to
|
||||||
|
// be nearly 4GB in side. So it's unlikely that a real
|
||||||
|
// commentless archive would have 0xffs here, and lets us tell
|
||||||
|
// an old signed archive from a new one.
|
||||||
|
temp.write(0xff);
|
||||||
|
temp.write(0xff);
|
||||||
|
temp.write(total_size & 0xff);
|
||||||
|
temp.write((total_size >> 8) & 0xff);
|
||||||
|
temp.flush();
|
||||||
|
|
||||||
|
// Signature verification checks that the EOCD header is the
|
||||||
|
// last such sequence in the file (to avoid minzip finding a
|
||||||
|
// fake EOCD appended after the signature in its scan). The
|
||||||
|
// odds of producing this sequence by chance are very low, but
|
||||||
|
// let's catch it here if it does.
|
||||||
|
byte[] b = temp.toByteArray();
|
||||||
|
for (int i = 0; i < b.length - 3; ++i) {
|
||||||
|
if (b[i] == 0x50 && b[i + 1] == 0x4b && b[i + 2] == 0x05 && b[i + 3] == 0x06) {
|
||||||
|
throw new IllegalArgumentException("found spurious EOCD header at " + i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
outputStream.write(zipData, 0, zipData.length - 2);
|
||||||
|
outputStream.write(total_size & 0xff);
|
||||||
|
outputStream.write((total_size >> 8) & 0xff);
|
||||||
|
temp.writeTo(outputStream);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static PrivateKey readPrivateKey(File file)
|
||||||
|
throws IOException, GeneralSecurityException {
|
||||||
|
DataInputStream input = new DataInputStream(new FileInputStream(file));
|
||||||
|
try {
|
||||||
|
byte[] bytes = new byte[(int) file.length()];
|
||||||
|
input.read(bytes);
|
||||||
|
|
||||||
|
// dont support encrypted keys atm
|
||||||
|
//KeySpec spec = decryptPrivateKey(bytes, file);
|
||||||
|
//if (spec == null) {
|
||||||
|
KeySpec spec = new PKCS8EncodedKeySpec(bytes);
|
||||||
|
//}
|
||||||
|
|
||||||
|
try {
|
||||||
|
return KeyFactory.getInstance("RSA").generatePrivate(spec);
|
||||||
|
} catch (InvalidKeySpecException ex) {
|
||||||
|
return KeyFactory.getInstance("DSA").generatePrivate(spec);
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
input.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static X509Certificate readPublicKey(File file)
|
||||||
|
throws IOException, GeneralSecurityException {
|
||||||
|
FileInputStream input = new FileInputStream(file);
|
||||||
|
try {
|
||||||
|
CertificateFactory cf = CertificateFactory.getInstance("X.509");
|
||||||
|
return (X509Certificate) cf.generateCertificate(input);
|
||||||
|
} finally {
|
||||||
|
input.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
if (args.length < 4) {
|
||||||
|
System.out.println("MinSignAPK pemfile pk8file inzip outzip");
|
||||||
|
System.out.println("- only adds whole-file signature to zip");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
String pemFile = args[0];
|
||||||
|
String pk8File = args[1];
|
||||||
|
String inFile = args[2];
|
||||||
|
String outFile = args[3];
|
||||||
|
|
||||||
|
try {
|
||||||
|
X509Certificate publicKey = readPublicKey(new File(pemFile));
|
||||||
|
PrivateKey privateKey = readPrivateKey(new File(pk8File));
|
||||||
|
|
||||||
|
InputStream fis = new FileInputStream(inFile);
|
||||||
|
byte[] buffer = new byte[(int)(new File(inFile)).length()];
|
||||||
|
fis.read(buffer);
|
||||||
|
fis.close();
|
||||||
|
|
||||||
|
OutputStream fos = new FileOutputStream(outFile, false);
|
||||||
|
signWholeOutputFile(buffer, fos, publicKey, privateKey);
|
||||||
|
fos.close();
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
324
ziptools/src/zipadjust.c
Normal file
324
ziptools/src/zipadjust.c
Normal file
@@ -0,0 +1,324 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2013 Jorrit "Chainfire" Jongma
|
||||||
|
* Copyright (C) 2013 The OmniROM Project
|
||||||
|
*/
|
||||||
|
/*
|
||||||
|
* This file is part of OpenDelta.
|
||||||
|
*
|
||||||
|
* OpenDelta is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* OpenDelta is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with OpenDelta. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <zlib.h>
|
||||||
|
|
||||||
|
#ifndef O_BINARY
|
||||||
|
#define O_BINARY 0
|
||||||
|
#define O_TEXT 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#pragma pack(1)
|
||||||
|
struct local_header_struct {
|
||||||
|
uint32_t signature;
|
||||||
|
uint16_t extract_version;
|
||||||
|
uint16_t flags;
|
||||||
|
uint16_t compression_method;
|
||||||
|
uint16_t last_modified_time;
|
||||||
|
uint16_t last_modified_date;
|
||||||
|
uint32_t crc32;
|
||||||
|
uint32_t size_compressed;
|
||||||
|
uint32_t size_uncompressed;
|
||||||
|
uint16_t length_filename;
|
||||||
|
uint16_t length_extra;
|
||||||
|
// filename
|
||||||
|
// extra
|
||||||
|
};
|
||||||
|
typedef struct local_header_struct local_header_t;
|
||||||
|
|
||||||
|
#pragma pack(1)
|
||||||
|
struct data_descriptor_struct {
|
||||||
|
uint32_t signature;
|
||||||
|
uint32_t crc32;
|
||||||
|
uint32_t size_compressed;
|
||||||
|
uint32_t size_uncompressed;
|
||||||
|
};
|
||||||
|
typedef struct data_descriptor_struct data_descriptor_t;
|
||||||
|
|
||||||
|
#pragma pack(1)
|
||||||
|
struct central_header_struct {
|
||||||
|
uint32_t signature;
|
||||||
|
uint16_t version_made;
|
||||||
|
uint16_t version_needed;
|
||||||
|
uint16_t flags;
|
||||||
|
uint16_t compression_method;
|
||||||
|
uint16_t last_modified_time;
|
||||||
|
uint16_t last_modified_date;
|
||||||
|
uint32_t crc32;
|
||||||
|
uint32_t size_compressed;
|
||||||
|
uint32_t size_uncompressed;
|
||||||
|
uint16_t length_filename;
|
||||||
|
uint16_t length_extra;
|
||||||
|
uint16_t length_comment;
|
||||||
|
uint16_t disk_start;
|
||||||
|
uint16_t attr_internal;
|
||||||
|
uint32_t attr_external;
|
||||||
|
uint32_t offset;
|
||||||
|
// filename
|
||||||
|
// extra
|
||||||
|
// comment
|
||||||
|
};
|
||||||
|
typedef struct central_header_struct central_header_t;
|
||||||
|
|
||||||
|
#pragma pack(1)
|
||||||
|
struct central_footer_struct {
|
||||||
|
uint32_t signature;
|
||||||
|
uint16_t disk_number;
|
||||||
|
uint16_t disk_number_central_directory;
|
||||||
|
uint16_t central_directory_entries_this_disk;
|
||||||
|
uint16_t central_directory_entries_total;
|
||||||
|
uint32_t central_directory_size;
|
||||||
|
uint32_t central_directory_offset;
|
||||||
|
uint16_t length_comment;
|
||||||
|
// comment
|
||||||
|
};
|
||||||
|
typedef struct central_footer_struct central_footer_t;
|
||||||
|
|
||||||
|
#define MAGIC_LOCAL_HEADER 0x04034b50
|
||||||
|
#define MAGIC_DATA_DESCRIPTOR 0x08074b50
|
||||||
|
#define MAGIC_CENTRAL_HEADER 0x02014b50
|
||||||
|
#define MAGIC_CENTRAL_FOOTER 0x06054b50
|
||||||
|
|
||||||
|
static int xerror(char* message) {
|
||||||
|
fprintf(stderr, "%s\n", message);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int xseekread(int fd, off_t offset, void* buf, size_t bytes) {
|
||||||
|
if (lseek(fd, offset, SEEK_SET) == (off_t)-1) return xerror("Seek failed");
|
||||||
|
if (read(fd, buf, bytes) != bytes) return xerror("Read failed");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int xseekwrite(int fd, off_t offset, void* buf, size_t bytes) {
|
||||||
|
if (lseek(fd, offset, SEEK_SET) == (off_t)-1) return xerror("Seek failed");
|
||||||
|
if (write(fd, buf, bytes) != bytes) return xerror("Write failed");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int xfilecopy(int fdIn, int fdOut, off_t offsetIn, off_t offsetOut, size_t bytes) {
|
||||||
|
if ((offsetIn != (off_t)-1) && (lseek(fdIn, offsetIn, SEEK_SET) == (off_t)-1)) return xerror("Seek failed");
|
||||||
|
if ((offsetOut != (off_t)-1) && (lseek(fdOut, offsetOut, SEEK_SET) == (off_t)-1)) return xerror("Seek failed");
|
||||||
|
|
||||||
|
int CHUNK = 256 * 1024;
|
||||||
|
void* buf = malloc(CHUNK);
|
||||||
|
if (buf == NULL) return xerror("malloc failed");
|
||||||
|
size_t left = bytes;
|
||||||
|
while (left > 0) {
|
||||||
|
size_t wanted = (left < CHUNK) ? left : CHUNK;
|
||||||
|
size_t r = read(fdIn, buf, wanted);
|
||||||
|
if (r <= 0) return xerror("Read failed");
|
||||||
|
if (write(fdOut, buf, r) != r) return xerror("Write failed");
|
||||||
|
left -= r;
|
||||||
|
}
|
||||||
|
free(buf);
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int xdecompress(int fdIn, int fdOut, off_t offsetIn, off_t offsetOut, size_t bytes) {
|
||||||
|
if ((offsetIn != (off_t)-1) && (lseek(fdIn, offsetIn, SEEK_SET) == (off_t)-1)) return xerror("Seek failed");
|
||||||
|
if ((offsetOut != (off_t)-1) && (lseek(fdOut, offsetOut, SEEK_SET) == (off_t)-1)) return xerror("Seek failed");
|
||||||
|
|
||||||
|
int CHUNK = 256 * 1024;
|
||||||
|
|
||||||
|
int ret;
|
||||||
|
unsigned have;
|
||||||
|
z_stream strm;
|
||||||
|
unsigned char in[CHUNK];
|
||||||
|
unsigned char out[CHUNK];
|
||||||
|
|
||||||
|
strm.zalloc = Z_NULL;
|
||||||
|
strm.zfree = Z_NULL;
|
||||||
|
strm.opaque = Z_NULL;
|
||||||
|
strm.avail_in = 0;
|
||||||
|
strm.next_in = Z_NULL;
|
||||||
|
ret = inflateInit2(&strm, -15);
|
||||||
|
if (ret != Z_OK) return xerror("ret != Z_OK");
|
||||||
|
|
||||||
|
do {
|
||||||
|
strm.avail_in = read(fdIn, in, CHUNK);
|
||||||
|
if (strm.avail_in < 0) {
|
||||||
|
(void)inflateEnd(&strm);
|
||||||
|
return xerror("Read failed");
|
||||||
|
}
|
||||||
|
if (strm.avail_in == 0) break;
|
||||||
|
strm.next_in = in;
|
||||||
|
|
||||||
|
do {
|
||||||
|
strm.avail_out = CHUNK;
|
||||||
|
strm.next_out = out;
|
||||||
|
|
||||||
|
ret = inflate(&strm, Z_NO_FLUSH);
|
||||||
|
if (ret == Z_STREAM_ERROR) return xerror("Stream error");
|
||||||
|
switch (ret) {
|
||||||
|
case Z_NEED_DICT:
|
||||||
|
ret = Z_DATA_ERROR;
|
||||||
|
case Z_DATA_ERROR:
|
||||||
|
case Z_MEM_ERROR:
|
||||||
|
(void)inflateEnd(&strm);
|
||||||
|
return xerror("DICT/DATA/MEM error");
|
||||||
|
}
|
||||||
|
|
||||||
|
have = CHUNK - strm.avail_out;
|
||||||
|
if (write(fdOut, out, have) != have) {
|
||||||
|
(void)inflateEnd(&strm);
|
||||||
|
return xerror("Write failed");
|
||||||
|
}
|
||||||
|
} while (strm.avail_out == 0);
|
||||||
|
} while (ret != Z_STREAM_END);
|
||||||
|
(void)inflateEnd(&strm);
|
||||||
|
|
||||||
|
return ret == Z_STREAM_END ? 1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int zipadjust(char* filenameIn, char* filenameOut, int decompress) {
|
||||||
|
int ok = 0;
|
||||||
|
|
||||||
|
int fin = open(filenameIn, O_RDONLY | O_BINARY);
|
||||||
|
if (fin > 0) {
|
||||||
|
unsigned int size = lseek(fin, 0, SEEK_END);
|
||||||
|
lseek(fin, 0, SEEK_SET);
|
||||||
|
printf("%d bytes\n", size);
|
||||||
|
|
||||||
|
char filename[1024];
|
||||||
|
|
||||||
|
central_footer_t central_footer;
|
||||||
|
uint32_t central_directory_in_position = 0;
|
||||||
|
uint32_t central_directory_in_size = 0;
|
||||||
|
uint32_t central_directory_out_size = 0;
|
||||||
|
|
||||||
|
int i;
|
||||||
|
for (i = size - 4; i >= 0; i--) {
|
||||||
|
uint32_t magic = 0;
|
||||||
|
if (!xseekread(fin, i, &magic, sizeof(uint32_t))) return 0;
|
||||||
|
if (magic == MAGIC_CENTRAL_FOOTER) {
|
||||||
|
printf("central footer @ %08X\n", i);
|
||||||
|
if (!xseekread(fin, i, ¢ral_footer, sizeof(central_footer_t))) return 0;
|
||||||
|
|
||||||
|
central_header_t central_header;
|
||||||
|
if (!xseekread(fin, central_footer.central_directory_offset, ¢ral_header, sizeof(central_header_t))) return 0;
|
||||||
|
if ( central_header.signature == MAGIC_CENTRAL_HEADER ) {
|
||||||
|
central_directory_in_position = central_footer.central_directory_offset;
|
||||||
|
central_directory_in_size = size - central_footer.central_directory_offset;
|
||||||
|
printf("central header @ %08X (%d)\n", central_footer.central_directory_offset, central_footer.central_directory_size);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (central_directory_in_position == 0) return 0;
|
||||||
|
|
||||||
|
unsigned char* central_directory_in = (unsigned char*)malloc(central_directory_in_size);
|
||||||
|
unsigned char* central_directory_out = (unsigned char*)malloc(central_directory_in_size);
|
||||||
|
if (!xseekread(fin, central_directory_in_position, central_directory_in, central_directory_in_size)) return 0;
|
||||||
|
memset(central_directory_out, 0, central_directory_in_size);
|
||||||
|
|
||||||
|
unlink(filenameOut);
|
||||||
|
int fout = open(filenameOut, O_CREAT | O_WRONLY | O_BINARY, 0644);
|
||||||
|
if (fout > 0) {
|
||||||
|
|
||||||
|
uintptr_t central_directory_in_index = 0;
|
||||||
|
uintptr_t central_directory_out_index = 0;
|
||||||
|
|
||||||
|
central_header_t* central_header = NULL;
|
||||||
|
local_header_t local_header;
|
||||||
|
|
||||||
|
uint32_t out_index = 0;
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
central_header = (central_header_t*)¢ral_directory_in[central_directory_in_index];
|
||||||
|
if (central_header->signature != MAGIC_CENTRAL_HEADER) break;
|
||||||
|
|
||||||
|
filename[central_header->length_filename] = (char)0;
|
||||||
|
memcpy(filename, ¢ral_directory_in[central_directory_in_index + sizeof(central_header_t)], central_header->length_filename);
|
||||||
|
printf("%s (%d --> %d) [%08X] (%d)\n", filename, central_header->size_uncompressed, central_header->size_compressed, central_header->crc32, central_header->length_extra + central_header->length_comment);
|
||||||
|
|
||||||
|
local_header_t local_header;
|
||||||
|
if (!xseekread(fin, central_header->offset, &local_header, sizeof(local_header_t))) return 0;
|
||||||
|
|
||||||
|
// save and update to next index before we clobber the data
|
||||||
|
uint16_t compression_method_old = central_header->compression_method;
|
||||||
|
uint32_t size_compressed_old = central_header->size_compressed;
|
||||||
|
uint32_t offset_old = central_header->offset;
|
||||||
|
uint32_t length_extra_old = central_header->length_extra;
|
||||||
|
central_directory_in_index += sizeof(central_header_t) + central_header->length_filename + central_header->length_extra + central_header->length_comment;
|
||||||
|
|
||||||
|
// copying, rewriting, and correcting local and central headers so all the information matches, and no data descriptors are necessary
|
||||||
|
central_header->offset = out_index;
|
||||||
|
central_header->flags = central_header->flags & !8;
|
||||||
|
if (decompress && (compression_method_old == 8)) {
|
||||||
|
central_header->compression_method = 0;
|
||||||
|
central_header->size_compressed = central_header->size_uncompressed;
|
||||||
|
}
|
||||||
|
central_header->length_extra = 0;
|
||||||
|
central_header->length_comment = 0;
|
||||||
|
local_header.compression_method = central_header->compression_method;
|
||||||
|
local_header.flags = central_header->flags;
|
||||||
|
local_header.crc32 = central_header->crc32;
|
||||||
|
local_header.size_uncompressed = central_header->size_uncompressed;
|
||||||
|
local_header.size_compressed = central_header->size_compressed;
|
||||||
|
local_header.length_extra = 0;
|
||||||
|
|
||||||
|
if (!xseekwrite(fout, out_index, &local_header, sizeof(local_header_t))) return 0;
|
||||||
|
out_index += sizeof(local_header_t);
|
||||||
|
if (!xseekwrite(fout, out_index, &filename[0], central_header->length_filename)) return 0;
|
||||||
|
out_index += central_header->length_filename;
|
||||||
|
|
||||||
|
if (decompress && (compression_method_old == 8)) {
|
||||||
|
if (!xdecompress(fin, fout, offset_old + sizeof(local_header_t) + central_header->length_filename + length_extra_old, out_index, size_compressed_old)) return 0;
|
||||||
|
} else {
|
||||||
|
if (!xfilecopy(fin, fout, offset_old + sizeof(local_header_t) + central_header->length_filename + length_extra_old, out_index, size_compressed_old)) return 0;
|
||||||
|
}
|
||||||
|
out_index += local_header.size_compressed;
|
||||||
|
|
||||||
|
memcpy(¢ral_directory_out[central_directory_out_index], central_header, sizeof(central_header_t) + central_header->length_filename);
|
||||||
|
central_directory_out_index += sizeof(central_header_t) + central_header->length_filename;
|
||||||
|
}
|
||||||
|
|
||||||
|
central_directory_out_size = central_directory_out_index;
|
||||||
|
central_footer.central_directory_size = central_directory_out_size;
|
||||||
|
central_footer.central_directory_offset = out_index;
|
||||||
|
central_footer.length_comment = 0;
|
||||||
|
if (!xseekwrite(fout, out_index, central_directory_out, central_directory_out_size)) return 0;
|
||||||
|
out_index += central_directory_out_size;
|
||||||
|
if (!xseekwrite(fout, out_index, ¢ral_footer, sizeof(central_footer_t))) return 0;
|
||||||
|
|
||||||
|
printf("central header @ %08X (%d)\n", central_footer.central_directory_offset, central_footer.central_directory_size);
|
||||||
|
printf("central footer @ %08X\n", out_index);
|
||||||
|
|
||||||
|
close(fout);
|
||||||
|
ok = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
free(central_directory_in);
|
||||||
|
free(central_directory_out);
|
||||||
|
close(fin);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ok;
|
||||||
|
}
|
27
ziptools/src/zipadjust.h
Normal file
27
ziptools/src/zipadjust.h
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2013 Jorrit "Chainfire" Jongma
|
||||||
|
* Copyright (C) 2013 The OmniROM Project
|
||||||
|
*/
|
||||||
|
/*
|
||||||
|
* This file is part of OpenDelta.
|
||||||
|
*
|
||||||
|
* OpenDelta is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* OpenDelta is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with OpenDelta. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __ZIPADJUST_H
|
||||||
|
#define __ZIPADJUST_H
|
||||||
|
|
||||||
|
int zipadjust(char* filenameIn, char* filenameOut, int decompress);
|
||||||
|
|
||||||
|
#endif
|
45
ziptools/src/zipadjust_run.c
Normal file
45
ziptools/src/zipadjust_run.c
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2013 Jorrit "Chainfire" Jongma
|
||||||
|
* Copyright (C) 2013 The OmniROM Project
|
||||||
|
*/
|
||||||
|
/*
|
||||||
|
* This file is part of OpenDelta.
|
||||||
|
*
|
||||||
|
* OpenDelta is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* OpenDelta is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with OpenDelta. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include "zipadjust.h"
|
||||||
|
|
||||||
|
int main(int argc, char *argv[]) {
|
||||||
|
if (argc >= 3) {
|
||||||
|
if ((argc >= 4) && (strcmp(argv[1], "--decompress") == 0)) {
|
||||||
|
zipadjust(argv[2], argv[3], 1);
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
zipadjust(argv[1], argv[2], 0);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("zipadjust - Copyright (c) 2013 Jorrit Jongma (Chainfire)\n");
|
||||||
|
printf("\n");
|
||||||
|
printf("Usage: zipadjust [--decompress] input.zip output.zip\n");
|
||||||
|
printf("\n");
|
||||||
|
printf("Rewrites a zipfile removing all extra fields and comments (this includes the signapk whole-file signature), and synchronizing local headers with the central directory so no data descriptors are needed anymore. Optionally, the output zip is converted to only use STORE.\n");
|
||||||
|
printf("\n");
|
||||||
|
printf("Written to work specifically with Android OTA zip files, and does not cope with all possible zip file features and formats.\n");
|
||||||
|
return 0;
|
||||||
|
}
|
27
ziptools/test.certificate.x509.pem
Normal file
27
ziptools/test.certificate.x509.pem
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIEqDCCA5CgAwIBAgIJAJNurL4H8gHfMA0GCSqGSIb3DQEBBQUAMIGUMQswCQYD
|
||||||
|
VQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNTW91bnRhaW4g
|
||||||
|
VmlldzEQMA4GA1UEChMHQW5kcm9pZDEQMA4GA1UECxMHQW5kcm9pZDEQMA4GA1UE
|
||||||
|
AxMHQW5kcm9pZDEiMCAGCSqGSIb3DQEJARYTYW5kcm9pZEBhbmRyb2lkLmNvbTAe
|
||||||
|
Fw0wODAyMjkwMTMzNDZaFw0zNTA3MTcwMTMzNDZaMIGUMQswCQYDVQQGEwJVUzET
|
||||||
|
MBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNTW91bnRhaW4gVmlldzEQMA4G
|
||||||
|
A1UEChMHQW5kcm9pZDEQMA4GA1UECxMHQW5kcm9pZDEQMA4GA1UEAxMHQW5kcm9p
|
||||||
|
ZDEiMCAGCSqGSIb3DQEJARYTYW5kcm9pZEBhbmRyb2lkLmNvbTCCASAwDQYJKoZI
|
||||||
|
hvcNAQEBBQADggENADCCAQgCggEBANaTGQTexgskse3HYuDZ2CU+Ps1s6x3i/waM
|
||||||
|
qOi8qM1r03hupwqnbOYOuw+ZNVn/2T53qUPn6D1LZLjk/qLT5lbx4meoG7+yMLV4
|
||||||
|
wgRDvkxyGLhG9SEVhvA4oU6Jwr44f46+z4/Kw9oe4zDJ6pPQp8PcSvNQIg1QCAcy
|
||||||
|
4ICXF+5qBTNZ5qaU7Cyz8oSgpGbIepTYOzEJOmc3Li9kEsBubULxWBjf/gOBzAzU
|
||||||
|
RNps3cO4JFgZSAGzJWQTT7/emMkod0jb9WdqVA2BVMi7yge54kdVMxHEa5r3b97s
|
||||||
|
zI5p58ii0I54JiCUP5lyfTwE/nKZHZnfm644oLIXf6MdW2r+6R8CAQOjgfwwgfkw
|
||||||
|
HQYDVR0OBBYEFEhZAFY9JyxGrhGGBaR0GawJyowRMIHJBgNVHSMEgcEwgb6AFEhZ
|
||||||
|
AFY9JyxGrhGGBaR0GawJyowRoYGapIGXMIGUMQswCQYDVQQGEwJVUzETMBEGA1UE
|
||||||
|
CBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNTW91bnRhaW4gVmlldzEQMA4GA1UEChMH
|
||||||
|
QW5kcm9pZDEQMA4GA1UECxMHQW5kcm9pZDEQMA4GA1UEAxMHQW5kcm9pZDEiMCAG
|
||||||
|
CSqGSIb3DQEJARYTYW5kcm9pZEBhbmRyb2lkLmNvbYIJAJNurL4H8gHfMAwGA1Ud
|
||||||
|
EwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAHqvlozrUMRBBVEY0NqrrwFbinZa
|
||||||
|
J6cVosK0TyIUFf/azgMJWr+kLfcHCHJsIGnlw27drgQAvilFLAhLwn62oX6snb4Y
|
||||||
|
LCBOsVMR9FXYJLZW2+TcIkCRLXWG/oiVHQGo/rWuWkJgU134NDEFJCJGjDbiLCpe
|
||||||
|
+ZTWHdcwauTJ9pUbo8EvHRkU3cYfGmLaLfgn9gP+pWA7LFQNvXwBnDa6sppCccEX
|
||||||
|
31I828XzgXpJ4O+mDL1/dBd+ek8ZPUP0IgdyZm5MTYPhvVqGCHzzTy3sIeJFymwr
|
||||||
|
sBbmg2OAUNLEMO6nwmocSdN2ClirfxqCzJOLSDE4QyS9BAH6EhY6UFcOaE0=
|
||||||
|
-----END CERTIFICATE-----
|
BIN
ziptools/test.key.pk8
Normal file
BIN
ziptools/test.key.pk8
Normal file
Binary file not shown.
BIN
ziptools/win_bin/date.exe
Normal file
BIN
ziptools/win_bin/date.exe
Normal file
Binary file not shown.
BIN
ziptools/win_bin/zip.exe
Normal file
BIN
ziptools/win_bin/zip.exe
Normal file
Binary file not shown.
BIN
ziptools/win_bin/zipadjust.exe
Normal file
BIN
ziptools/win_bin/zipadjust.exe
Normal file
Binary file not shown.
Reference in New Issue
Block a user