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