mirror of
https://github.com/topjohnwu/Magisk.git
synced 2025-08-14 13:07:25 +00:00
Compare commits
132 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
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
|
||||
libs
|
||||
obj/
|
||||
libs/
|
||||
*.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"]
|
||||
path = selinux
|
||||
url = https://github.com/topjohnwu/selinux
|
||||
[submodule "jni/sepolicy-inject"]
|
||||
path = jni/sepolicy-inject
|
||||
url = https://github.com/topjohnwu/sepolicy-inject
|
||||
[submodule "jni/selinux"]
|
||||
path = jni/selinux
|
||||
url = https://github.com/topjohnwu/selinux.git
|
||||
[submodule "jni/su"]
|
||||
path = jni/su
|
||||
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
|
||||
Static binaries included:
|
||||
###Static binaries included:
|
||||
* 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 $(CLEAR_VARS)
|
||||
LOCAL_MODULE := magiskhide
|
||||
LOCAL_MODULE_TAGS := optional
|
||||
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
|
||||
include jni/magiskboot/Android.mk
|
||||
include jni/magiskhide/Android.mk
|
||||
include jni/resetprop/Android.mk
|
||||
include jni/magiskpolicy/Android.mk
|
||||
include jni/su/Android.mk
|
||||
|
@@ -1,3 +1,3 @@
|
||||
APP_ABI := x86 armeabi
|
||||
APP_PIE = true
|
||||
APP_ABI := x86 x86_64 armeabi-v7a arm64-v8a
|
||||
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 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 */
|
||||
|
||||
@@ -66,10 +73,13 @@ struct boot_img_hdr
|
||||
** +-----------------+
|
||||
** | second stage | o pages
|
||||
** +-----------------+
|
||||
** | device tree | p pages
|
||||
** +-----------------+
|
||||
**
|
||||
** n = (kernel_size + page_size - 1) / page_size
|
||||
** m = (ramdisk_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
|
||||
** 1. kernel and ramdisk are required (size != 0)
|
||||
@@ -83,8 +93,10 @@ struct boot_img_hdr
|
||||
** else: jump to kernel_addr
|
||||
*/
|
||||
|
||||
int extract(char *image);
|
||||
int repack(char *image);
|
||||
int hexpatch(char *image, char *from, char *to);
|
||||
typedef struct mtk_hdr {
|
||||
uint8_t magic[4]; /* MTK magic */
|
||||
uint32_t size; /* Size of the content */
|
||||
uint8_t name[32]; /* The type of the header */
|
||||
} mtk_hdr;
|
||||
|
||||
#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
|
||||
start magisk_pfs
|
||||
wait /dev/.magisk.unblock 20
|
||||
rm /dev/.magisk.unblock
|
||||
|
||||
on post-fs-data
|
||||
start magisk_pfsd
|
||||
wait /dev/.magisk.unblock 40
|
||||
rm /dev/.magisk.unblock
|
||||
load_persist_props
|
||||
start magisk_pfsd
|
||||
wait /dev/.magisk.unblock 60
|
||||
|
||||
on property:magisk.hide=1
|
||||
restart magisk_hide
|
||||
on property:magisk.restart_pfsd=1
|
||||
trigger post-fs-data
|
||||
|
||||
# Services
|
||||
|
||||
@@ -33,9 +33,3 @@ service magisk_service /sbin/magic_mask.sh service
|
||||
user root
|
||||
seclabel u:r:su:s0
|
||||
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 | 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 {} \;
|
||||
|
||||
# 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 "* 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
|
||||
|
||||
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
|
||||
|
||||
# Default permissions
|
||||
umask 022
|
||||
|
||||
##########################################################################################
|
||||
# Flashable update-binary preparation
|
||||
##########################################################################################
|
||||
@@ -46,34 +49,6 @@ ui_print() {
|
||||
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() {
|
||||
if [ ! -z "$2" ]; then
|
||||
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
|
||||
}
|
||||
|
||||
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
|
||||
##########################################################################################
|
||||
@@ -188,78 +91,43 @@ if [ ! -f '/system/build.prop' ]; then
|
||||
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)
|
||||
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=
|
||||
IS64BIT=false
|
||||
if [ "$ABI" = "x86" ]; then ARCH=x86; fi;
|
||||
if [ "$ABI2" = "x86" ]; then ARCH=x86; fi;
|
||||
if [ "$ABILONG" = "arm64-v8a" ]; then ARCH=arm64; IS64BIT=1; fi;
|
||||
if [ "$ABILONG" = "x86_64" ]; then ARCH=x64; IS64BIT=1; fi;
|
||||
if [ "$ABILONG" = "arm64-v8a" ]; then ARCH=arm64; IS64BIT=true; fi;
|
||||
if [ "$ABILONG" = "x86_64" ]; then ARCH=x64; IS64BIT=true; fi;
|
||||
|
||||
ui_print "- Device platform: $ARCH"
|
||||
CHROMEDIR=$INSTALLER/chromeos
|
||||
BINDIR=$INSTALLER/$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
|
||||
|
||||
SAMSUNG=false
|
||||
SAMSUNG_CHECK=$(cat /system/build.prop | grep "ro.build.fingerprint=" | grep -i "samsung")
|
||||
if [ $? -eq 0 ]; then
|
||||
SAMSUNG=true
|
||||
fi
|
||||
# Copy the binaries to /data/magisk
|
||||
mkdir -p /data/magisk 2>/dev/null
|
||||
cp -af $BINDIR/* $CHROMEDIR /data/magisk
|
||||
|
||||
##########################################################################################
|
||||
# Detection all done, start installing
|
||||
##########################################################################################
|
||||
|
||||
umount /magisk 2>/dev/null
|
||||
|
||||
if (is_mounted /data); 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
|
||||
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
|
||||
. $INSTALLER/common/magisk_uninstaller.sh
|
||||
else
|
||||
ui_print "! Data unavalible"
|
||||
ui_print "! Impossible to restore original boot image"
|
||||
ui_print "! Try using ramdisk backup"
|
||||
revert_boot
|
||||
ui_print "- Removing Magisk files"
|
||||
rm -rf /cache/magisk* /cache/last_magisk.log /cache/unblock 2>/dev/null
|
||||
ui_print "*****************************************"
|
||||
ui_print " Magisk is not fully removed yet "
|
||||
ui_print " Please manually remove /data/magisk.img "
|
||||
ui_print "*****************************************"
|
||||
ui_print "! Data unavailable"
|
||||
ui_print "! Placing uninstall script to /cache"
|
||||
ui_print "! The device might reboot multiple times"
|
||||
cp -af $INSTALLER/common/magisk_uninstaller.sh /cache/magisk_uninstaller.sh
|
||||
umount /system
|
||||
ui_print "- Rebooting....."
|
||||
sleep 5
|
||||
reboot
|
||||
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
|
||||
|
||||
ui_print "- Done"
|
||||
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
|
||||
|
||||
HIDELIST=$MOUNTPOINT/.core/magiskhide/hidelist
|
||||
HIDELIST=/magisk/.core/magiskhide/hidelist
|
||||
PROCESS=$1
|
||||
TOOLPATH=/dev/busybox
|
||||
|
||||
if [ ! -z "$1" ]; then
|
||||
if [ $(grep -c "^$1$" $HIDELIST) -eq "0" ]; then
|
||||
echo "$1" >> $HIDELIST
|
||||
if [ ! -z "$PROCESS" ]; then
|
||||
if [ `grep -c "^$PROCESS$" $HIDELIST` -eq "0" ]; then
|
||||
echo "$PROCESS" >> $HIDELIST
|
||||
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
|
||||
|
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" != "0" ] && \
|
||||
log_print "`$BINPATH/resetprop -v -n ro.build.selinux 0`"
|
||||
|
||||
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
|
||||
|
||||
HIDELIST=$MOUNTPOINT/.core/magiskhide/hidelist
|
||||
HIDELIST=/magisk/.core/magiskhide/hidelist
|
||||
|
||||
cat $HIDELIST
|
||||
|
@@ -1,12 +1,14 @@
|
||||
#!/system/bin/sh
|
||||
|
||||
HIDELIST=$MOUNTPOINT/.core/magiskhide/hidelist
|
||||
HIDELIST=/magisk/.core/magiskhide/hidelist
|
||||
PROCESS=$1
|
||||
TOOLPATH=/dev/busybox
|
||||
|
||||
if [ ! -z "$1" ]; then
|
||||
mv $HIDELIST $HIDELIST.tmp
|
||||
cat $HIDELIST.tmp | grep -v "^$1$" > $HIDELIST
|
||||
if [ ! -z "$PROCESS" ]; then
|
||||
cp -af $HIDELIST $HIDELIST.tmp
|
||||
cat $HIDELIST.tmp | grep -v "^$PROCESS$" > $HIDELIST
|
||||
rm -f $HIDELIST.tmp
|
||||
set --
|
||||
set `$TOOLPATH/ps -o pid,args | grep "$PROCESS" | grep -v grep` >/dev/null
|
||||
[ ! -z "$1" ] && kill "$1"
|
||||
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