forked from topjohnwu/Magisk
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Building through the build script will compile all binaries, and generate a properly signed zip Should work on linux and macOS environments
- Loading branch information
Showing
26 changed files
with
760 additions
and
6 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,21 @@ | ||
obj | ||
libs | ||
obj/ | ||
libs/ | ||
*.zip | ||
|
||
# Generated binaries | ||
zip_static/arm/* | ||
zip_static/arm64/* | ||
zip_static/x86/* | ||
zip_static/x64/* | ||
uninstaller/arm/* | ||
uninstaller/arm64/* | ||
uninstaller/x86/* | ||
uninstaller/x64/* | ||
zipsigntools/zipadjust | ||
|
||
# Generated scripts | ||
zip_static/common/magic_mask.sh | ||
zip_static/META-INF/com/google/android/update-binary | ||
|
||
# Leave all busybox! | ||
!busybox |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,127 @@ | ||
#!/bin/bash | ||
|
||
usage() { | ||
echo "$0 --all <version number>" | ||
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 number>" | ||
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 | ||
ls zip_static/arm/* | grep -v "busybox" | xargs rm -rfv | ||
ls zip_static/arm64/* | grep -v "busybox" | xargs rm -rfv | ||
ls zip_static/x86/* | grep -v "busybox" | xargs rm -rfv | ||
ls zip_static/x64/* | grep -v "busybox" | xargs rm -rfv | ||
rm -rfv zip_static/META-INF/com/google/android/update-binary | ||
rm -rfv zip_static/common/magic_mask.sh | ||
rm -rfv uninstaller/arm | ||
rm -rfv uninstaller/arm64 | ||
rm -rfv uninstaller/x86 | ||
rm -rfv uninstaller/x64 | ||
} | ||
|
||
mkcp() { | ||
[ ! -d "$2" ] && mkdir -p "$2" | ||
cp -afv $1 $2 | ||
} | ||
|
||
build_bin() { | ||
echo "************************" | ||
echo "* Building binaries" | ||
echo "************************" | ||
ndk-build -j4 | ||
echo "************************" | ||
echo "* Copying binaries" | ||
echo "************************" | ||
mkcp "libs/armeabi/*" zip_static/arm | ||
mkcp libs/armeabi/bootimgtools uninstaller/arm | ||
mkcp "libs/arm64-v8a/*" zip_static/arm64 | ||
mkcp libs/arm64-v8a/bootimgtools uninstaller/arm64 | ||
mkcp "libs/x86/*" zip_static/x86 | ||
mkcp libs/x86/bootimgtools uninstaller/x86 | ||
mkcp "libs/x86_64/*" zip_static/x64 | ||
mkcp libs/x86_64/bootimgtools uninstaller/x64 | ||
} | ||
|
||
zip_package() { | ||
echo "************************" | ||
echo "* Adding version info" | ||
echo "* \"Magisk v$1\"" | ||
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 "* Zipping the package" | ||
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" | ||
} | ||
|
||
sign_zip() { | ||
if [ ! -f "zipsigntools/zipadjust" ]; then | ||
echo "************************" | ||
echo "* Compiling ZipAdjust" | ||
echo "************************" | ||
gcc -o zipsigntools/zipadjust zipsigntools/src/*.c -lz | ||
chmod 755 zipsigntools/zipadjust | ||
fi | ||
echo "************************" | ||
echo "* First sign $1" | ||
echo "************************" | ||
java -jar "zipsigntools/signapk.jar" "zipsigntools/test.certificate.x509.pem" "zipsigntools/test.key.pk8" "$1" "${1%.*}-firstsign.zip" | ||
echo "************************" | ||
echo "* Adjusting $1" | ||
echo "************************" | ||
zipsigntools/zipadjust "${1%.*}-firstsign.zip" "${1%.*}-adjusted.zip" | ||
echo "************************" | ||
echo "* Final sign $1" | ||
echo "************************" | ||
java -jar "zipsigntools/signapk.jar" "zipsigntools/test.certificate.x509.pem" "zipsigntools/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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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.
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.
Binary file not shown.
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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(); | ||
} | ||
} | ||
} |
Oops, something went wrong.