1+ package app.revanced.patches.all.misc.spoof
2+
3+ import app.revanced.patcher.patch.resourcePatch
4+ import app.revanced.patcher.patch.stringOption
5+ import app.revanced.util.getNode
6+ import com.android.apksig.ApkVerifier
7+ import com.android.apksig.apk.ApkFormatException
8+ import org.w3c.dom.Element
9+ import java.io.File
10+ import java.io.IOException
11+ import java.nio.file.InvalidPathException
12+ import java.security.NoSuchAlgorithmException
13+ import java.security.cert.CertificateException
14+ import java.security.cert.CertificateFactory
15+ import java.util.*
16+
17+ @Suppress(" unused" )
18+ val enableRomSignatureSpoofing = resourcePatch(
19+ name = " Enable ROM signature spoofing" ,
20+ description = " Spoofs the signature via the manifest meta-data \" fake-signature\" . " +
21+ " This patch only works with ROMs that support signature spoofing." ,
22+ use = false ,
23+ ) {
24+ val signatureOrPath by stringOption(
25+ key = " signatureOrApkFilePath" ,
26+ title = " Signature or APK file path" ,
27+ validator = validator@{ signature ->
28+ signature ? : return @validator false
29+
30+ parseSignature(signature) != null
31+ },
32+ description = " The hex-encoded signature or path to an APK file with the desired signature." ,
33+ required = true ,
34+ )
35+ execute {
36+ document(" AndroidManifest.xml" ).use { document ->
37+ val permission = document.createElement(" uses-permission" ).apply {
38+ setAttribute(" android:name" , " android.permission.FAKE_PACKAGE_SIGNATURE" )
39+ }
40+ val manifest = document.getNode(" manifest" ).appendChild(permission)
41+
42+
43+ val fakeSignatureMetadata = document.createElement(" meta-data" ).apply {
44+ setAttribute(" android:name" , " fake-signature" )
45+ setAttribute(" android:value" , parseSignature(signatureOrPath!! ))
46+ }
47+ document.getNode(" application" ).appendChild(fakeSignatureMetadata)
48+ }
49+ }
50+ }
51+
52+ private fun parseSignature (optionValue : String ): String? {
53+ // Parse as a hex-encoded signature.
54+ try {
55+ // TODO: Replace with signature.hexToByteArray when stable in kotlin
56+ val signatureBytes = HexFormat .of().parseHex(optionValue)
57+ CertificateFactory .getInstance(" X.509" ).generateCertificate(signatureBytes.inputStream())
58+
59+ return optionValue
60+ } catch (_: IllegalArgumentException ) {
61+ } catch (_: CertificateException ) {
62+ }
63+
64+ // Parse as a path to an APK file.
65+ try {
66+ val apkFile = File (optionValue)
67+ if (! apkFile.isFile) return null
68+
69+ val result = ApkVerifier .Builder (apkFile).build().verify()
70+
71+ val hexFormat = HexFormat .of()
72+
73+ val signature = (if (result.isVerifiedUsingV3Scheme) {
74+ result.v3SchemeSigners[0 ].certificate
75+ } else if (result.isVerifiedUsingV2Scheme) {
76+ result.v2SchemeSigners[0 ].certificate
77+ } else if (result.isVerifiedUsingV1Scheme) {
78+ result.v1SchemeSigners[0 ].certificate
79+ } else {
80+ return null
81+ }).encoded
82+
83+ return hexFormat.formatHex(signature)
84+ } catch (_: IOException ) {
85+ } catch (_: InvalidPathException ) {
86+ } catch (_: ApkFormatException ) {
87+ } catch (_: NoSuchAlgorithmException ) {
88+ } catch (_: IllegalArgumentException ) {
89+ }
90+
91+ return null
92+ }
0 commit comments