├── .github ├── ISSUE_TEMPLATE │ ├── bug_report.yml │ └── config.yml ├── stale.yml └── workflows │ └── android.yml ├── .gitignore ├── LICENSE ├── README.md ├── app ├── .gitignore ├── build.gradle.kts ├── proguard-rules.pro └── src │ └── main │ ├── AndroidManifest.xml │ ├── assets │ └── xposed_init │ ├── java │ └── toolkit │ │ └── coderstory │ │ ├── CorePatchForQ.java │ │ ├── CorePatchForR.java │ │ ├── CorePatchForS.java │ │ ├── CorePatchForT.java │ │ ├── CorePatchForU.java │ │ ├── CorePatchForV.java │ │ ├── MainHook.java │ │ ├── ReturnConstant.java │ │ ├── SettingsActivity.java │ │ └── XposedHelper.java │ └── res │ ├── layout │ └── activity_settings.xml │ ├── values-fr │ └── strings.xml │ ├── values-in │ └── strings.xml │ ├── values-it │ └── strings.xml │ ├── values-ja │ └── strings.xml │ ├── values-ko │ └── strings.xml │ ├── values-night │ └── styles.xml │ ├── values-pt-rBR │ └── strings.xml │ ├── values-ru │ └── strings.xml │ ├── values-zh-rCN │ └── strings.xml │ ├── values-zh-rTW │ └── strings.xml │ ├── values │ ├── array.xml │ ├── strings.xml │ └── styles.xml │ └── xml │ └── prefs.xml ├── build.gradle.kts ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat └── settings.gradle.kts /.github/ISSUE_TEMPLATE/bug_report.yml: -------------------------------------------------------------------------------- 1 | name: Bug report/反馈 Bug 2 | description: Report errors or unexpected behavior. Your issue will be close if not following this template. / 反馈错误或异常行为,不使用此模板提交会被close。 3 | title: "[Bug] " 4 | labels: [bug] 5 | body: 6 | - type: textarea 7 | attributes: 8 | label: What happened/什么情况 9 | placeholder: | 10 | Such as bootloops, module not work, etc/如无法开机、模块无效等 11 | validations: 12 | required: true 13 | - type: input 14 | attributes: 15 | label: LSPosed version/LSPosed 版本 16 | description: Don't use 'latest'. Specify actual version with 4 digits, otherwise your issue will be closed./不要填用“最新版”。给出四位版本号,不然 issue 会被关闭。 17 | validations: 18 | required: true 19 | - type: input 20 | attributes: 21 | label: Android version/Android 版本 22 | validations: 23 | required: true 24 | - type: input 25 | attributes: 26 | label: Version of Core Patch/核心破解版本 27 | validations: 28 | required: true 29 | - type: textarea 30 | attributes: 31 | label: Logs/日志 32 | description: Please provide the log zip saved from LSPosed manager. Without log, the issue will be closed. /请提供从 LSPosed 管理器保存的日志压缩包,无日志提交会被关闭。 33 | validations: 34 | required: true 35 | - type: textarea 36 | attributes: 37 | label: Module settings screenshot/模块设置截图 38 | validations: 39 | required: true 40 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/config.yml: -------------------------------------------------------------------------------- 1 | blank_issues_enabled: false 2 | contact_links: 3 | - name: Official Telegram Channel/官方 Telegram 频道 4 | url: https://t.me/corepatch 5 | about: Subscribe for notifications and releases/可以订阅通知和发行版 6 | -------------------------------------------------------------------------------- /.github/stale.yml: -------------------------------------------------------------------------------- 1 | # Number of days of inactivity before an issue becomes stale 2 | daysUntilStale: 60 3 | # Number of days of inactivity before a stale issue is closed 4 | daysUntilClose: 7 5 | # Issues with these labels will never be considered stale 6 | exemptLabels: 7 | - announcement 8 | - confirmed 9 | - develop 10 | - enhancement 11 | - TODO 12 | # Label to use when marking an issue as stale 13 | staleLabel: stale 14 | # Comment to post when marking an issue as stale. Set to `false` to disable 15 | markComment: > 16 | This issue has been automatically marked as stale because it has not had 17 | recent activity. It will be closed if no further activity occurs. Thank you 18 | for your contributions. 19 | # Comment to post when closing a stale issue. Set to `false` to disable 20 | closeComment: false -------------------------------------------------------------------------------- /.github/workflows/android.yml: -------------------------------------------------------------------------------- 1 | name: Android CI 2 | 3 | on: 4 | push: 5 | branches: [ main ] 6 | pull_request: 7 | workflow_dispatch: 8 | 9 | jobs: 10 | build: 11 | 12 | runs-on: ubuntu-latest 13 | 14 | steps: 15 | - name: Checkout 16 | uses: actions/checkout@v3 17 | 18 | - name: Set up JDK 21 19 | uses: actions/setup-java@v3 20 | with: 21 | java-version: 21 22 | distribution: 'temurin' 23 | cache: 'gradle' 24 | 25 | - name: Write key 26 | if: github.event_name != 'pull_request' && github.ref == 'refs/heads/main' 27 | run: | 28 | if [ ! -z "${{ secrets.SIGNING_KEY }}" ]; then 29 | echo releaseStorePassword='${{ secrets.KEY_STORE_PASSWORD }}' >> gradle.properties 30 | echo releaseKeyAlias='${{ secrets.ALIAS }}' >> gradle.properties 31 | echo releaseKeyPassword='${{ secrets.KEY_PASSWORD }}' >> gradle.properties 32 | echo releaseStoreFile='key.jks' >> gradle.properties 33 | echo ${{ secrets.SIGNING_KEY }} | base64 --decode > key.jks 34 | fi 35 | 36 | - name: Build with Gradle 37 | run: ./gradlew assembleRelease assembleDebug 38 | 39 | - name: Upload artifact 40 | uses: actions/upload-artifact@v4 41 | with: 42 | name: Signed app bundle 43 | path: app/build/outputs/apk 44 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/workspace.xml 5 | /.idea/libraries 6 | .DS_Store 7 | /build 8 | /captures 9 | .externalNativeBuild 10 | /.idea/ 11 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 2, June 1991 3 | 4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc. 5 | 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA 6 | 7 | Everyone is permitted to copy and distribute verbatim copies 8 | of this license document, but changing it is not allowed. 9 | 10 | Preamble 11 | 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 Library General Public License instead.) You can apply it to your programs, too. 12 | 13 | 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. 14 | 15 | 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. 16 | 17 | 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. 18 | 19 | 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. 20 | 21 | 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. 22 | 23 | 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. 24 | 25 | The precise terms and conditions for copying, distribution and modification follow. 26 | 27 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 28 | 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". 29 | 30 | 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. 31 | 32 | 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. 33 | 34 | 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. 35 | 36 | 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: 37 | 38 | 39 | a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. 40 | 41 | 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. 42 | 43 | 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.) 44 | 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. 45 | 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. 46 | 47 | 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. 48 | 49 | 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: 50 | 51 | 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, 52 | 53 | 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, 54 | 55 | 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.) 56 | 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. 57 | 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. 58 | 59 | 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. 60 | 61 | 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. 62 | 63 | 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. 64 | 65 | 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. 66 | 67 | 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. 68 | 69 | 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. 70 | 71 | This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 72 | 73 | 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. 74 | 75 | 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. 76 | 77 | 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. 78 | 79 | 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. 80 | 81 | 82 | NO WARRANTY 83 | 84 | 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. 85 | 86 | 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. 87 | 88 | 89 | END OF TERMS AND CONDITIONS 90 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # CorePatch 2 | 3 | ``` 4 | A Module For Xposed Framework 5 | Disable signature verification For Android 6 | ``` 7 | ![Android CI](https://github.com/coderstory/CorePatch/workflows/Android%20CI/badge.svg) ![GitHub release (latest by date)](https://img.shields.io/github/v/release/coderstory/CorePatch) ![CRAN/METACRAN](https://img.shields.io/cran/l/devtools) 8 | 9 | ### Description 10 | ``` 11 | branch master -> support android 4.4-7.x 12 | Android8.x -> maybe you need find the commit what change version name to 2.1,then compile by you self 13 | branch Q -> support android 9.0-10.0 14 | branch main -> support android 10-15 15 | ``` 16 | 17 | ## Features 18 | ``` 19 | allows to downgrade application, suppresses [INSTALL_FAILED_VERSION_DOWNGRADE] 20 | 21 | allows to directly install apps after modifing APK file [ignore invalid digest error etc..] 22 | 23 | allows overlay install apps with inconsistent signatures 24 | ``` 25 | 26 | ### History 27 | You can download history version from https://soft.shouji.com.cn/down/32512.html 28 | 29 | ### Thanks 30 | ``` 31 | weishu: Reference some code 32 | LSPosed Hook Framework for ART 33 | lovesykun: Technical support 34 | ``` 35 | ### License 36 | CorePatch is released under the GPL V2 license. See LICENSE for details. 37 | 38 | ### CI 39 | You can download dev build from github actions 40 | https://github.com/coderstory/CorePatch/actions 41 | 42 | ### Community 43 | [TG Chat](https://t.me/core_patch_chat) 44 | 45 | 46 | ### Donate 47 | [paypal](http://paypal.me/code620) 48 | 49 | 50 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | build 2 | release 3 | -------------------------------------------------------------------------------- /app/build.gradle.kts: -------------------------------------------------------------------------------- 1 | import java.nio.file.Paths 2 | 3 | plugins { 4 | id("com.android.application") 5 | } 6 | 7 | val releaseStoreFile: String? by rootProject 8 | val releaseStorePassword: String? by rootProject 9 | val releaseKeyAlias: String? by rootProject 10 | val releaseKeyPassword: String? by rootProject 11 | 12 | android { 13 | compileSdk = 36 14 | buildToolsVersion = "36.0.0" 15 | defaultConfig { 16 | applicationId = "com.coderstory.toolkit" 17 | minSdk = 28 18 | targetSdk = 36 19 | versionCode = 2029 20 | versionName = "4.6" 21 | } 22 | 23 | signingConfigs { 24 | create("config") { 25 | releaseStoreFile?.also { 26 | storeFile = rootProject.file(it) 27 | storePassword = releaseStorePassword 28 | keyAlias = releaseKeyAlias 29 | keyPassword = releaseKeyPassword 30 | } 31 | } 32 | } 33 | packaging { 34 | jniLibs { 35 | excludes += "META-INF/**" 36 | } 37 | resources { 38 | excludes += "META-INF/**" 39 | } 40 | } 41 | 42 | 43 | buildTypes { 44 | all { 45 | signingConfig = 46 | if (releaseStoreFile.isNullOrEmpty()) signingConfigs.getByName("debug") else signingConfigs.getByName( 47 | "config" 48 | ) 49 | } 50 | release { 51 | isMinifyEnabled = true 52 | isShrinkResources = true 53 | proguardFiles("proguard-rules.pro") 54 | } 55 | } 56 | compileOptions { 57 | sourceCompatibility(JavaVersion.VERSION_11) 58 | targetCompatibility(JavaVersion.VERSION_11) 59 | } 60 | lint { 61 | abortOnError = false 62 | } 63 | namespace = "com.coderstory.toolkit" 64 | buildFeatures { 65 | buildConfig = true 66 | } 67 | } 68 | 69 | dependencies { 70 | compileOnly("de.robv.android.xposed:api:82") 71 | } 72 | val optimizeReleaseRes = task("optimizeReleaseRes").doLast { 73 | val aapt2 = Paths.get( 74 | project.android.sdkDirectory.path, 75 | "build-tools", project.android.buildToolsVersion, "aapt2" 76 | ) 77 | val zip = Paths.get( 78 | project.layout.buildDirectory.get().asFile.path, "intermediates", 79 | "optimized_processed_res", "release", "optimizeReleaseResources", "resources-release-optimize.ap_" 80 | ) 81 | val optimized = File("${zip}.opt") 82 | val cmd = exec { 83 | commandLine(aapt2, "optimize", "--collapse-resource-names", "-o", optimized, zip) 84 | isIgnoreExitValue = true 85 | } 86 | if (cmd.exitValue == 0) { 87 | delete(zip) 88 | optimized.renameTo(zip.toFile()) 89 | } 90 | } 91 | tasks.configureEach { 92 | when (name) { 93 | "optimizeReleaseResources" -> { 94 | finalizedBy(optimizeReleaseRes) 95 | } 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | -keep class toolkit.coderstory.MainHook 2 | 3 | -repackageclasses 4 | -allowaccessmodification 5 | -overloadaggressively 6 | -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 11 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 23 | 26 | 29 | 32 | 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /app/src/main/assets/xposed_init: -------------------------------------------------------------------------------- 1 | toolkit.coderstory.MainHook -------------------------------------------------------------------------------- /app/src/main/java/toolkit/coderstory/CorePatchForQ.java: -------------------------------------------------------------------------------- 1 | package toolkit.coderstory; 2 | 3 | 4 | import android.content.pm.ApplicationInfo; 5 | import android.content.pm.Signature; 6 | 7 | import com.coderstory.toolkit.BuildConfig; 8 | 9 | import java.lang.reflect.Constructor; 10 | import java.lang.reflect.Field; 11 | import java.lang.reflect.InvocationTargetException; 12 | import java.util.Arrays; 13 | 14 | import de.robv.android.xposed.IXposedHookLoadPackage; 15 | import de.robv.android.xposed.XC_MethodHook; 16 | import de.robv.android.xposed.XSharedPreferences; 17 | import de.robv.android.xposed.XposedHelpers; 18 | import de.robv.android.xposed.callbacks.XC_LoadPackage; 19 | 20 | public class CorePatchForQ extends XposedHelper implements IXposedHookLoadPackage { 21 | final XSharedPreferences prefs = new XSharedPreferences(BuildConfig.APPLICATION_ID, "conf"); 22 | 23 | @Override 24 | public void handleLoadPackage(XC_LoadPackage.LoadPackageParam loadPackageParam) throws IllegalAccessException, InvocationTargetException, InstantiationException { 25 | // 允许降级 26 | Class packageClazz = XposedHelpers.findClass("android.content.pm.PackageParser.Package", loadPackageParam.classLoader); 27 | hookAllMethods("com.android.server.pm.PackageManagerService", loadPackageParam.classLoader, "checkDowngrade", new XC_MethodHook() { 28 | public void beforeHookedMethod(MethodHookParam methodHookParam) throws Throwable { 29 | if (prefs.getBoolean("downgrade", true)) { 30 | Object packageInfoLite = methodHookParam.args[0]; 31 | 32 | if (prefs.getBoolean("downgrade", true)) { 33 | Field field = packageClazz.getField("mVersionCode"); 34 | field.setAccessible(true); 35 | field.set(packageInfoLite, 0); 36 | field = packageClazz.getField("mVersionCodeMajor"); 37 | field.setAccessible(true); 38 | field.set(packageInfoLite, 0); 39 | } 40 | } 41 | } 42 | }); 43 | 44 | hookAllMethods("android.util.jar.StrictJarVerifier", loadPackageParam.classLoader, "verifyMessageDigest", 45 | new ReturnConstant(prefs, "authcreak", true)); 46 | hookAllMethods("android.util.jar.StrictJarVerifier", loadPackageParam.classLoader, "verify", 47 | new ReturnConstant(prefs, "authcreak", true)); 48 | hookAllMethods("java.security.MessageDigest", loadPackageParam.classLoader, "isEqual", 49 | new ReturnConstant(prefs, "authcreak", true)); 50 | hookAllMethods("com.android.server.pm.PackageManagerServiceUtils", loadPackageParam.classLoader, "verifySignatures", 51 | new ReturnConstant(prefs, "authcreak", false)); 52 | 53 | Class signingDetails = XposedHelpers.findClass("android.content.pm.PackageParser.SigningDetails", loadPackageParam.classLoader); 54 | Constructor findConstructorExact = XposedHelpers.findConstructorExact(signingDetails, Signature[].class, Integer.TYPE); 55 | findConstructorExact.setAccessible(true); 56 | Class packageParserException = XposedHelpers.findClass("android.content.pm.PackageParser.PackageParserException", loadPackageParam.classLoader); 57 | Field error = XposedHelpers.findField(packageParserException, "error"); 58 | error.setAccessible(true); 59 | Object[] signingDetailsArgs = new Object[2]; 60 | signingDetailsArgs[0] = new Signature[]{new Signature(SIGNATURE)}; 61 | signingDetailsArgs[1] = 1; 62 | final Object newInstance = findConstructorExact.newInstance(signingDetailsArgs); 63 | hookAllMethods("android.util.apk.ApkSignatureVerifier", loadPackageParam.classLoader, "verifyV1Signature", new XC_MethodHook() { 64 | public void afterHookedMethod(MethodHookParam methodHookParam) throws Throwable { 65 | if (prefs.getBoolean("authcreak", false)) { 66 | Throwable throwable = methodHookParam.getThrowable(); 67 | if (throwable != null) { 68 | Throwable cause = throwable.getCause(); 69 | if (throwable.getClass() == packageParserException) { 70 | if (error.getInt(throwable) == -103) { 71 | methodHookParam.setResult(newInstance); 72 | } 73 | } 74 | if (cause != null && cause.getClass() == packageParserException) { 75 | if (error.getInt(cause) == -103) { 76 | methodHookParam.setResult(newInstance); 77 | } 78 | } 79 | } 80 | } 81 | } 82 | }); 83 | 84 | //New package has a different signature 85 | //处理覆盖安装但签名不一致 86 | hookAllMethods(signingDetails, "checkCapability", new XC_MethodHook() { 87 | @Override 88 | protected void beforeHookedMethod(MethodHookParam param) throws Throwable { 89 | if (prefs.getBoolean("digestCreak", true)) { 90 | if ((Integer) param.args[1] != 4 && (Integer) param.args[1] != 16 && prefs.getBoolean("authcreak", false)) { 91 | param.setResult(Boolean.TRUE); 92 | } 93 | } 94 | } 95 | }); 96 | hookAllMethods(signingDetails, "checkCapabilityRecover", 97 | new XC_MethodHook() { 98 | @Override 99 | protected void beforeHookedMethod(MethodHookParam param) throws Throwable { 100 | if (prefs.getBoolean("digestCreak", true)) { 101 | if ((Integer) param.args[1] != 4 && (Integer) param.args[1] != 16 && prefs.getBoolean("authcreak", false)) { 102 | param.setResult(Boolean.TRUE); 103 | } 104 | } 105 | } 106 | }); 107 | 108 | // if app is system app, allow to use hidden api, even if app not using a system signature 109 | findAndHookMethod("android.content.pm.ApplicationInfo", loadPackageParam.classLoader, "isPackageWhitelistedForHiddenApis", new XC_MethodHook() { 110 | @Override 111 | protected void beforeHookedMethod(MethodHookParam param) throws Throwable { 112 | if (prefs.getBoolean("digestCreak", true)) { 113 | ApplicationInfo info = (ApplicationInfo) param.thisObject; 114 | if ((info.flags & ApplicationInfo.FLAG_SYSTEM) != 0 115 | || (info.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0) { 116 | param.setResult(true); 117 | } 118 | } 119 | } 120 | }); 121 | 122 | var keySetManagerClass = findClass("com.android.server.pm.KeySetManagerService", loadPackageParam.classLoader); 123 | if (keySetManagerClass != null) { 124 | var shouldBypass = new ThreadLocal(); 125 | hookAllMethods(keySetManagerClass, "shouldCheckUpgradeKeySetLocked", new XC_MethodHook() { 126 | @Override 127 | protected void afterHookedMethod(MethodHookParam param) throws Throwable { 128 | if (prefs.getBoolean("digestCreak", true) && 129 | Arrays.stream(Thread.currentThread().getStackTrace()).anyMatch((o) -> 130 | (/* API 29 */ "preparePackageLI".equals(o.getMethodName()) || /* API 28 */ "installPackageLI".equals(o.getMethodName())))) { 131 | shouldBypass.set(true); 132 | param.setResult(true); 133 | } else { 134 | shouldBypass.set(false); 135 | } 136 | } 137 | }); 138 | hookAllMethods(keySetManagerClass, "checkUpgradeKeySetLocked", new XC_MethodHook() { 139 | @Override 140 | protected void afterHookedMethod(MethodHookParam param) throws Throwable { 141 | if (prefs.getBoolean("digestCreak", true) && shouldBypass.get()) { 142 | param.setResult(true); 143 | } 144 | } 145 | }); 146 | } 147 | hookAllMethods( 148 | XposedHelpers.findClass("com.android.server.pm.PackageManagerService", loadPackageParam.classLoader), 149 | "isVerificationEnabled", 150 | new ReturnConstant(prefs, "disableVerificationAgent", false) 151 | ); 152 | } 153 | } 154 | -------------------------------------------------------------------------------- /app/src/main/java/toolkit/coderstory/CorePatchForR.java: -------------------------------------------------------------------------------- 1 | package toolkit.coderstory; 2 | 3 | 4 | import android.annotation.TargetApi; 5 | import android.app.AndroidAppHelper; 6 | import android.content.pm.ApplicationInfo; 7 | import android.content.pm.PackageInfo; 8 | import android.content.pm.PackageManager; 9 | import android.content.pm.Signature; 10 | import android.os.Build; 11 | import android.util.Log; 12 | 13 | import com.coderstory.toolkit.BuildConfig; 14 | 15 | import java.io.PrintWriter; 16 | import java.lang.reflect.Constructor; 17 | import java.lang.reflect.Field; 18 | import java.lang.reflect.InvocationTargetException; 19 | import java.lang.reflect.Member; 20 | import java.lang.reflect.Method; 21 | import java.security.cert.Certificate; 22 | import java.security.cert.X509Certificate; 23 | import java.util.Arrays; 24 | import java.util.List; 25 | import java.util.Map; 26 | import java.util.Objects; 27 | import java.util.zip.ZipEntry; 28 | 29 | import de.robv.android.xposed.IXposedHookLoadPackage; 30 | import de.robv.android.xposed.XC_MethodHook; 31 | import de.robv.android.xposed.XSharedPreferences; 32 | import de.robv.android.xposed.XposedBridge; 33 | import de.robv.android.xposed.XposedHelpers; 34 | import de.robv.android.xposed.callbacks.XC_LoadPackage; 35 | 36 | @TargetApi(Build.VERSION_CODES.R) 37 | public class CorePatchForR extends XposedHelper implements IXposedHookLoadPackage { 38 | private final static Method deoptimizeMethod; 39 | 40 | static { 41 | Method m = null; 42 | try { 43 | m = XposedBridge.class.getDeclaredMethod("deoptimizeMethod", Member.class); 44 | } catch (Throwable t) { 45 | XposedBridge.log("E/" + MainHook.TAG + " " + Log.getStackTraceString(t)); 46 | } 47 | deoptimizeMethod = m; 48 | } 49 | 50 | static void deoptimizeMethod(Class c, String n) throws InvocationTargetException, IllegalAccessException { 51 | for (Method m : c.getDeclaredMethods()) { 52 | if (deoptimizeMethod != null && m.getName().equals(n)) { 53 | deoptimizeMethod.invoke(null, m); 54 | if (BuildConfig.DEBUG) 55 | XposedBridge.log("D/" + MainHook.TAG + " Deoptimized " + m.getName()); 56 | } 57 | } 58 | } 59 | 60 | final XSharedPreferences prefs = new XSharedPreferences(BuildConfig.APPLICATION_ID, "conf"); 61 | 62 | @Override 63 | public void handleLoadPackage(XC_LoadPackage.LoadPackageParam loadPackageParam) throws IllegalAccessException, InvocationTargetException, InstantiationException { 64 | if (BuildConfig.DEBUG) { 65 | XposedBridge.log("D/" + MainHook.TAG + " downgrade=" + prefs.getBoolean("downgrade", true)); 66 | XposedBridge.log("D/" + MainHook.TAG + " authcreak=" + prefs.getBoolean("authcreak", false)); 67 | XposedBridge.log("D/" + MainHook.TAG + " digestCreak=" + prefs.getBoolean("digestCreak", true)); 68 | XposedBridge.log("D/" + MainHook.TAG + " UsePreSig=" + prefs.getBoolean("UsePreSig", false)); 69 | XposedBridge.log("D/" + MainHook.TAG + " bypassBlock=" + prefs.getBoolean("bypassBlock", true)); 70 | XposedBridge.log("D/" + MainHook.TAG + " sharedUser=" + prefs.getBoolean("sharedUser", false)); 71 | XposedBridge.log("D/" + MainHook.TAG + " disableVerificationAgent=" + prefs.getBoolean("disableVerificationAgent", true)); 72 | } 73 | 74 | var pmService = XposedHelpers.findClassIfExists("com.android.server.pm.PackageManagerService", 75 | loadPackageParam.classLoader); 76 | if (pmService != null) { 77 | var checkDowngrade = XposedHelpers.findMethodExactIfExists(pmService, "checkDowngrade", 78 | "com.android.server.pm.parsing.pkg.AndroidPackage", 79 | "android.content.pm.PackageInfoLite"); 80 | if (checkDowngrade != null) { 81 | // 允许降级 82 | XposedBridge.hookMethod(checkDowngrade, new ReturnConstant(prefs, "downgrade", null)); 83 | } 84 | // exists on flyme 9(Android 11) only 85 | var flymeCheckDowngrade = XposedHelpers.findMethodExactIfExists(pmService, "checkDowngrade", 86 | "android.content.pm.PackageInfoLite", 87 | "android.content.pm.PackageInfoLite"); 88 | if (flymeCheckDowngrade != null) 89 | XposedBridge.hookMethod(flymeCheckDowngrade, new ReturnConstant(prefs, "downgrade", true)); 90 | } 91 | 92 | // apk内文件修改后 digest校验会失败 93 | hookAllMethods("android.util.jar.StrictJarVerifier", loadPackageParam.classLoader, "verifyMessageDigest", 94 | new ReturnConstant(prefs, "authcreak", true)); 95 | hookAllMethods("android.util.jar.StrictJarVerifier", loadPackageParam.classLoader, "verify", 96 | new ReturnConstant(prefs, "authcreak", true)); 97 | hookAllMethods("java.security.MessageDigest", loadPackageParam.classLoader, "isEqual", 98 | new ReturnConstant(prefs, "authcreak", true)); 99 | 100 | // Targeting R+ (version " + Build.VERSION_CODES.R + " and above) requires" 101 | // + " the resources.arsc of installed APKs to be stored uncompressed" 102 | // + " and aligned on a 4-byte boundary 103 | // target >=30 的情况下 resources.arsc 必须是未压缩的且4K对齐 104 | hookAllMethods("android.content.res.AssetManager", loadPackageParam.classLoader, "containsAllocatedTable", 105 | new ReturnConstant(prefs, "authcreak", false)); 106 | 107 | // No signature found in package of version " + minSignatureSchemeVersion 108 | // + " or newer for package " + apkPath 109 | findAndHookMethod("android.util.apk.ApkSignatureVerifier", loadPackageParam.classLoader, "getMinimumSignatureSchemeVersionForTargetSdk", int.class, 110 | new ReturnConstant(prefs, "authcreak", 0)); 111 | var apkVerifierClass = XposedHelpers.findClassIfExists("com.android.apksig.ApkVerifier", 112 | loadPackageParam.classLoader); 113 | if (apkVerifierClass != null) { 114 | findAndHookMethod(apkVerifierClass, "getMinimumSignatureSchemeVersionForTargetSdk", int.class, 115 | new ReturnConstant(prefs, "authcreak", 0)); 116 | } 117 | 118 | // 当verifyV1Signature抛出转换异常时,替换一个签名作为返回值 119 | // 如果用户已安装apk,并且其定义了私有权限,则安装时会因签名与模块内硬编码的不一致而被拒绝。尝试从待安装apk中获取签名。如果其中apk的签名和已安装的一致(只动了内容)就没有问题。此策略可能有潜在的安全隐患。 120 | Class pkc = XposedHelpers.findClass("sun.security.pkcs.PKCS7", loadPackageParam.classLoader); 121 | Constructor constructor = XposedHelpers.findConstructorExact(pkc, byte[].class); 122 | constructor.setAccessible(true); 123 | Class ASV = XposedHelpers.findClass("android.util.apk.ApkSignatureVerifier", loadPackageParam.classLoader); 124 | Class sJarClass = XposedHelpers.findClass("android.util.jar.StrictJarFile", loadPackageParam.classLoader); 125 | Constructor constructorExact = XposedHelpers.findConstructorExact(sJarClass, String.class, boolean.class, boolean.class); 126 | constructorExact.setAccessible(true); 127 | Class signingDetails = getSigningDetails(loadPackageParam.classLoader); 128 | Constructor findConstructorExact = XposedHelpers.findConstructorExact(signingDetails, Signature[].class, Integer.TYPE); 129 | findConstructorExact.setAccessible(true); 130 | Class packageParserException = XposedHelpers.findClass("android.content.pm.PackageParser.PackageParserException", loadPackageParam.classLoader); 131 | Field error = XposedHelpers.findField(packageParserException, "error"); 132 | error.setAccessible(true); 133 | Object[] signingDetailsArgs = new Object[2]; 134 | signingDetailsArgs[1] = 1; 135 | Class parseResult = XposedHelpers.findClassIfExists("android.content.pm.parsing.result.ParseResult", loadPackageParam.classLoader); 136 | hookAllMethods("android.util.jar.StrictJarVerifier", loadPackageParam.classLoader, "verifyBytes", new XC_MethodHook() { 137 | public void afterHookedMethod(MethodHookParam param) throws Throwable { 138 | if (prefs.getBoolean("digestCreak", true)) { 139 | if (!prefs.getBoolean("UsePreSig", false)) { 140 | final Object block = constructor.newInstance(param.args[0]); 141 | Object[] infos = (Object[]) XposedHelpers.callMethod(block, "getSignerInfos"); 142 | Object info = infos[0]; 143 | @SuppressWarnings("unchecked") 144 | List verifiedSignerCertChain = (List) XposedHelpers.callMethod(info, "getCertificateChain", block); 145 | param.setResult(verifiedSignerCertChain.toArray( 146 | new X509Certificate[0])); 147 | } 148 | } 149 | } 150 | }); 151 | hookAllMethods("android.util.apk.ApkSignatureVerifier", loadPackageParam.classLoader, "verifyV1Signature", new XC_MethodHook() { 152 | public void afterHookedMethod(MethodHookParam methodHookParam) throws Throwable { 153 | if (prefs.getBoolean("authcreak", false)) { 154 | Throwable throwable = methodHookParam.getThrowable(); 155 | Integer parseErr = null; 156 | if (parseResult != null && ((Method) methodHookParam.method).getReturnType() == parseResult) { 157 | Object result = methodHookParam.getResult(); 158 | if ((boolean) XposedHelpers.callMethod(result, "isError")) { 159 | parseErr = (int) XposedHelpers.callMethod(result, "getErrorCode"); 160 | } 161 | } 162 | if (throwable != null || parseErr != null) { 163 | Signature[] lastSigs = null; 164 | try { 165 | if (prefs.getBoolean("UsePreSig", false)) { 166 | PackageManager PM = AndroidAppHelper.currentApplication().getPackageManager(); 167 | if (PM == null) { 168 | XposedBridge.log("E/" + MainHook.TAG + " " + BuildConfig.APPLICATION_ID + " Cannot get the Package Manager... Are you using MiUI?"); 169 | } else { 170 | PackageInfo pI; 171 | if (parseErr != null) { 172 | pI = PM.getPackageArchiveInfo((String) methodHookParam.args[1], 0); 173 | } else { 174 | pI = PM.getPackageArchiveInfo((String) methodHookParam.args[0], 0); 175 | } 176 | PackageInfo InstpI = PM.getPackageInfo(pI.packageName, PackageManager.GET_SIGNING_CERTIFICATES); 177 | lastSigs = InstpI.signingInfo.getSigningCertificateHistory(); 178 | } 179 | } 180 | } catch (Throwable ignored) { 181 | 182 | } 183 | try { 184 | if (lastSigs == null && prefs.getBoolean("digestCreak", true)) { 185 | final Object origJarFile = constructorExact.newInstance(methodHookParam.args[parseErr == null ? 0 : 1], true, false); 186 | final ZipEntry manifestEntry = (ZipEntry) XposedHelpers.callMethod(origJarFile, "findEntry", "AndroidManifest.xml"); 187 | final Certificate[][] lastCerts; 188 | if (parseErr != null) { 189 | lastCerts = (Certificate[][]) XposedHelpers.callMethod(XposedHelpers.callStaticMethod(ASV, "loadCertificates", methodHookParam.args[0], origJarFile, manifestEntry), "getResult"); 190 | } else { 191 | lastCerts = (Certificate[][]) XposedHelpers.callStaticMethod(ASV, "loadCertificates", origJarFile, manifestEntry); 192 | } 193 | lastSigs = (Signature[]) XposedHelpers.callStaticMethod(ASV, "convertToSignatures", (Object) lastCerts); 194 | } 195 | } catch (Throwable ignored) { 196 | } 197 | signingDetailsArgs[0] = Objects.requireNonNullElseGet(lastSigs, () -> new Signature[]{new Signature(SIGNATURE)}); 198 | Object newInstance = findConstructorExact.newInstance(signingDetailsArgs); 199 | 200 | //修复 java.lang.ClassCastException: Cannot cast android.content.pm.PackageParser$SigningDetails to android.util.apk.ApkSignatureVerifier$SigningDetailsWithDigests 201 | Class signingDetailsWithDigests = XposedHelpers.findClassIfExists("android.util.apk.ApkSignatureVerifier.SigningDetailsWithDigests", loadPackageParam.classLoader); 202 | if (signingDetailsWithDigests != null) { 203 | Constructor signingDetailsWithDigestsConstructorExact = XposedHelpers.findConstructorExact(signingDetailsWithDigests, signingDetails, Map.class); 204 | signingDetailsWithDigestsConstructorExact.setAccessible(true); 205 | newInstance = signingDetailsWithDigestsConstructorExact.newInstance(newInstance, null); 206 | } 207 | if (throwable != null) { 208 | Throwable cause = throwable.getCause(); 209 | if (throwable.getClass() == packageParserException) { 210 | if (error.getInt(throwable) == -103) { 211 | methodHookParam.setResult(newInstance); 212 | } 213 | } 214 | if (cause != null && cause.getClass() == packageParserException) { 215 | if (error.getInt(cause) == -103) { 216 | methodHookParam.setResult(newInstance); 217 | } 218 | } 219 | } 220 | if (parseErr != null && parseErr == -103) { 221 | Object input = methodHookParam.args[0]; 222 | XposedHelpers.callMethod(input, "reset"); 223 | methodHookParam.setResult(XposedHelpers.callMethod(input, "success", newInstance)); 224 | } 225 | } 226 | } 227 | } 228 | }); 229 | 230 | 231 | //New package has a different signature 232 | //处理覆盖安装但签名不一致 233 | hookAllMethods(signingDetails, "checkCapability", new XC_MethodHook() { 234 | @Override 235 | protected void beforeHookedMethod(MethodHookParam param) { 236 | // Don't handle PERMISSION & AUTH 237 | // Or applications will have all privileged permissions 238 | // https://cs.android.com/android/platform/superproject/+/master:frameworks/base/core/java/android/content/pm/PackageParser.java;l=5947?q=CertCapabilities 239 | // https://cs.android.com/android/platform/superproject/main/+/main:frameworks/base/services/core/java/com/android/server/accounts/AccountManagerService.java;l=5867 240 | if ((Integer) param.args[1] != 4 && (Integer) param.args[1] != 16 && prefs.getBoolean("digestCreak", true)) { 241 | param.setResult(true); 242 | } 243 | } 244 | }); 245 | // if app is system app, allow to use hidden api, even if app not using a system signature 246 | findAndHookMethod("android.content.pm.ApplicationInfo", loadPackageParam.classLoader, "isPackageWhitelistedForHiddenApis", new XC_MethodHook() { 247 | @Override 248 | protected void beforeHookedMethod(MethodHookParam param) throws Throwable { 249 | if (prefs.getBoolean("digestCreak", true)) { 250 | ApplicationInfo info = (ApplicationInfo) param.thisObject; 251 | if ((info.flags & ApplicationInfo.FLAG_SYSTEM) != 0 252 | || (info.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0) { 253 | param.setResult(true); 254 | } 255 | } 256 | } 257 | }); 258 | 259 | var keySetManagerClass = findClass("com.android.server.pm.KeySetManagerService", loadPackageParam.classLoader); 260 | if (keySetManagerClass != null) { 261 | var shouldBypass = new ThreadLocal(); 262 | hookAllMethods(keySetManagerClass, "shouldCheckUpgradeKeySetLocked", new XC_MethodHook() { 263 | @Override 264 | protected void afterHookedMethod(MethodHookParam param) { 265 | if (prefs.getBoolean("digestCreak", true) && Arrays.stream(Thread.currentThread().getStackTrace()).anyMatch((o) -> "preparePackageLI".equals(o.getMethodName()))) { 266 | shouldBypass.set(true); 267 | param.setResult(true); 268 | } else { 269 | shouldBypass.set(false); 270 | } 271 | } 272 | }); 273 | hookAllMethods(keySetManagerClass, "checkUpgradeKeySetLocked", new XC_MethodHook() { 274 | @Override 275 | protected void afterHookedMethod(MethodHookParam param) { 276 | if (prefs.getBoolean("digestCreak", true) && shouldBypass.get()) { 277 | param.setResult(true); 278 | } 279 | } 280 | }); 281 | } 282 | 283 | // for SharedUser 284 | // "Package " + packageName + " has a signing lineage " + "that diverges from the lineage of the sharedUserId" 285 | // https://cs.android.com/android/platform/superproject/+/android-11.0.0_r21:frameworks/base/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java;l=728;drc=02a58171a9d41ad0048d6a1a48d79dee585c22a5 286 | hookAllMethods(signingDetails, "hasCommonAncestor", new XC_MethodHook() { 287 | @Override 288 | protected void beforeHookedMethod(MethodHookParam param) throws Throwable { 289 | if (prefs.getBoolean("digestCreak", true) 290 | && prefs.getBoolean("sharedUser", false) 291 | // because of LSPosed's bug, we can't hook verifySignatures while deoptimize it 292 | && Arrays.stream(Thread.currentThread().getStackTrace()).anyMatch((o) -> "verifySignatures".equals(o.getMethodName())) 293 | ) 294 | param.setResult(true); 295 | } 296 | }); 297 | 298 | var utilClass = findClass("com.android.server.pm.PackageManagerServiceUtils", loadPackageParam.classLoader); 299 | if (utilClass != null) { 300 | try { 301 | deoptimizeMethod(utilClass, "verifySignatures"); 302 | } catch (Throwable e) { 303 | XposedBridge.log("E/" + MainHook.TAG + " deoptimizing failed" + Log.getStackTraceString(e)); 304 | } 305 | } 306 | 307 | // choose a signature after all old signed packages are removed 308 | var sharedUserSettingClass = XposedHelpers.findClass("com.android.server.pm.SharedUserSetting", loadPackageParam.classLoader); 309 | XposedBridge.hookAllMethods( 310 | sharedUserSettingClass, 311 | "removePackage", 312 | new XC_MethodHook() { 313 | @Override 314 | protected void beforeHookedMethod(MethodHookParam param) throws Throwable { 315 | if (!prefs.getBoolean("digestCreak", true) || !prefs.getBoolean("sharedUser", false)) 316 | return; 317 | var flags = (int) XposedHelpers.getObjectField(param.thisObject, "uidFlags"); 318 | if ((flags & ApplicationInfo.FLAG_SYSTEM) != 0) 319 | return; // do not modify system's signature 320 | var toRemove = param.args[0]; // PackageSetting 321 | if (toRemove == null) return; 322 | var removed = false; // Is toRemove really needed to be removed 323 | var sharedUserSig = Setting_getSigningDetails(param.thisObject); 324 | Object newSig = null; 325 | var packages = /*Watchable?ArraySet*/ SharedUserSetting_packages(param.thisObject); 326 | var size = (int) XposedHelpers.callMethod(packages, "size"); 327 | for (var i = 0; i < size; i++) { 328 | var p = XposedHelpers.callMethod(packages, "valueAt", i); 329 | // skip the removed package 330 | if (toRemove.equals(p)) { 331 | removed = true; 332 | continue; 333 | } 334 | var packageSig = Setting_getSigningDetails(p); 335 | // if old signing exists, return 336 | if ((boolean) callOriginMethod(packageSig, "checkCapability", sharedUserSig, 0) || (boolean) callOriginMethod(sharedUserSig, "checkCapability", packageSig, 0)) { 337 | return; 338 | } 339 | // otherwise, choose the first signature we meet, and merge with others if possible 340 | // https://cs.android.com/android/platform/superproject/main/+/main:frameworks/base/services/core/java/com/android/server/pm/ReconcilePackageUtils.java;l=193;drc=c9a8baf585e8eb0f3272443930301a61331b65c1 341 | // respect to system 342 | if (newSig == null) newSig = packageSig; 343 | else newSig = SigningDetails_mergeLineageWith(newSig, packageSig); 344 | } 345 | if (!removed || newSig == null) return; 346 | XposedBridge.log("updating signature in sharedUser during remove: " + param.thisObject); 347 | Setting_setSigningDetails(param.thisObject, newSig); 348 | } 349 | } 350 | ); 351 | 352 | XposedBridge.hookAllMethods( 353 | sharedUserSettingClass, 354 | "addPackage", 355 | new XC_MethodHook() { 356 | @Override 357 | protected void beforeHookedMethod(MethodHookParam param) throws Throwable { 358 | if (!prefs.getBoolean("digestCreak", true) || !prefs.getBoolean("sharedUser", false)) 359 | return; 360 | var flags = (int) XposedHelpers.getObjectField(param.thisObject, "uidFlags"); 361 | if ((flags & ApplicationInfo.FLAG_SYSTEM) != 0) 362 | return; // do not modify system's signature 363 | var toAdd = param.args[0]; // PackageSetting 364 | if (toAdd == null) return; 365 | var added = false; 366 | var sharedUserSig = Setting_getSigningDetails(param.thisObject); 367 | Object newSig = null; 368 | var packages = /*Watchable?ArraySet*/ SharedUserSetting_packages(param.thisObject); 369 | var size = (int) XposedHelpers.callMethod(packages, "size"); 370 | for (var i = 0; i < size; i++) { 371 | var p = XposedHelpers.callMethod(packages, "valueAt", i); 372 | if (toAdd.equals(p)) { 373 | // must be an existing package 374 | added = true; 375 | p = toAdd; 376 | } 377 | var packageSig = Setting_getSigningDetails(p); 378 | // if old signing exists, return 379 | if ((boolean) callOriginMethod(packageSig, "checkCapability", sharedUserSig, 0) || (boolean) callOriginMethod(sharedUserSig, "checkCapability", packageSig, 0)) { 380 | return; 381 | } 382 | // otherwise, choose the first signature we meet, and merge with others if possible 383 | // https://cs.android.com/android/platform/superproject/main/+/main:frameworks/base/services/core/java/com/android/server/pm/ReconcilePackageUtils.java;l=193;drc=c9a8baf585e8eb0f3272443930301a61331b65c1 384 | // respect to system 385 | if (newSig == null) newSig = packageSig; 386 | else newSig = SigningDetails_mergeLineageWith(newSig, packageSig); 387 | } 388 | if (!added || newSig == null) return; 389 | XposedBridge.log("CorePatch: updating signature in sharedUser during add " + toAdd + ": " + param.thisObject); 390 | Setting_setSigningDetails(param.thisObject, newSig); 391 | } 392 | } 393 | ); 394 | 395 | hookAllMethods(getIsVerificationEnabledClass(loadPackageParam.classLoader), "isVerificationEnabled", new ReturnConstant(prefs, "disableVerificationAgent", false)); 396 | 397 | if (BuildConfig.DEBUG) initializeDebugHook(loadPackageParam); 398 | } 399 | 400 | static Object callOriginMethod(Object obj, String methodName, Object... args) { 401 | try { 402 | var method = XposedHelpers.findMethodBestMatch(obj.getClass(), methodName, args); 403 | return XposedBridge.invokeOriginalMethod(method, obj, args); 404 | } catch (IllegalAccessException e) { 405 | // should not happen 406 | XposedBridge.log(e); 407 | throw new IllegalAccessError(e.getMessage()); 408 | } catch (IllegalArgumentException e) { 409 | throw e; 410 | } catch (InvocationTargetException e) { 411 | throw new RuntimeException(e.getCause()); 412 | } 413 | } 414 | 415 | Class getIsVerificationEnabledClass(ClassLoader classLoader) { 416 | return XposedHelpers.findClass("com.android.server.pm.PackageManagerService", classLoader); 417 | } 418 | 419 | Class getSigningDetails(ClassLoader classLoader) { 420 | return XposedHelpers.findClass("android.content.pm.PackageParser.SigningDetails", classLoader); 421 | } 422 | 423 | Object mPMS = null; 424 | 425 | void initializeDebugHook(XC_LoadPackage.LoadPackageParam lpparam) throws IllegalAccessException, InvocationTargetException { 426 | XposedBridge.hookAllMethods( 427 | XposedHelpers.findClass("com.android.server.pm.PackageManagerShellCommand", lpparam.classLoader), 428 | "onCommand", 429 | new XC_MethodHook() { 430 | @Override 431 | protected void beforeHookedMethod(MethodHookParam param) throws Throwable { 432 | try { 433 | var pms = mPMS; 434 | if (pms == null) return; 435 | var cmd = (String) param.args[0]; 436 | if (!"corepatch".equals(cmd)) return; 437 | var self = param.thisObject; 438 | var pw = (PrintWriter) XposedHelpers.callMethod(self, "getOutPrintWriter"); 439 | var type = (String) XposedHelpers.callMethod(self, "getNextArgRequired"); 440 | var settings = XposedHelpers.getObjectField(pms, "mSettings"); 441 | if ("p".equals(type) || "package".equals(type)) { 442 | var packageName = (String) XposedHelpers.callMethod(self, "getNextArgRequired"); 443 | var packageSetting = XposedHelpers.callMethod(settings, "getPackageLPr", packageName); 444 | if (packageSetting != null) { 445 | dumpPackageSetting(packageSetting, pw, settings); 446 | } else { 447 | pw.println("no package " + packageName + " found"); 448 | } 449 | } else if ("su".equals(type) || "shareduser".equals(type)) { 450 | var name = (String) XposedHelpers.callMethod(self, "getNextArgRequired"); 451 | var su = getSharedUser(name, settings); 452 | if (su != null) { 453 | dumpSharedUserSetting(su, pw); 454 | } else { 455 | pw.println("no shared user " + name + " found"); 456 | } 457 | } else { 458 | pw.println("usage: "); 459 | } 460 | param.setResult(0); 461 | } catch (Throwable t) { 462 | XposedBridge.log(t); 463 | param.setThrowable(t); 464 | } 465 | } 466 | } 467 | ); 468 | 469 | var pmsClass = XposedHelpers.findClassIfExists("com.android.server.pm.PackageManagerService", 470 | lpparam.classLoader); 471 | 472 | XposedBridge.hookAllConstructors(pmsClass, new XC_MethodHook() { 473 | @Override 474 | protected void afterHookedMethod(MethodHookParam param) throws Throwable { 475 | mPMS = param.thisObject; 476 | } 477 | } 478 | ); 479 | 480 | deoptimizeMethod(pmsClass, "onShellCommand"); 481 | } 482 | 483 | void dumpPackageSetting(Object packageSetting, PrintWriter pw, Object /*Settings*/ settings) { 484 | var signingDetails = Setting_getSigningDetails(packageSetting); 485 | pw.println("signing for package " + packageSetting); 486 | dumpSigningDetails(signingDetails, pw); 487 | var pkg = XposedHelpers.getObjectField(packageSetting, "pkg"); // AndroidPackage 488 | if (pkg == null) { 489 | pw.println("android package is null!"); 490 | return; 491 | } 492 | var id = (String) XposedHelpers.callMethod(pkg, "getSharedUserId"); 493 | pw.println("shared user id:" + id); 494 | if (settings != null) { 495 | var su = getSharedUser(id, settings); 496 | if (su != null) { 497 | dumpSharedUserSetting(su, pw); 498 | } 499 | } 500 | } 501 | 502 | Object getSharedUser(String id, Object /*Settings*/ settings) { 503 | // TODO: use Setting.getSharedUserSettingLPr(appId)? 504 | var sharedUserSettings = XposedHelpers.getObjectField(settings, "mSharedUsers"); 505 | if (sharedUserSettings == null) return null; 506 | return XposedHelpers.callMethod(sharedUserSettings, "get", id); 507 | } 508 | 509 | void dumpSharedUserSetting(Object sharedUser, PrintWriter pw) { 510 | var signingDetails = Setting_getSigningDetails(sharedUser); 511 | pw.println("signing for shared user " + sharedUser); 512 | dumpSigningDetails(signingDetails, pw); 513 | } 514 | 515 | protected void dumpSigningDetails(Object signingDetails, PrintWriter pw) { 516 | var i = 0; 517 | for (var sign : (Signature[]) XposedHelpers.getObjectField(signingDetails, "signatures")) { 518 | i++; 519 | pw.println(i + ": " + sign.toCharsString()); 520 | } 521 | } 522 | 523 | /** 524 | * Get signing details for PackageSetting or SharedUserSetting 525 | */ 526 | Object Setting_getSigningDetails(Object pkgOrSharedUser) { 527 | // PackageSettingBase(A11)|PackageSetting(A13)|SharedUserSetting.signatures.mSigningDetails 528 | return XposedHelpers.getObjectField(XposedHelpers.getObjectField(pkgOrSharedUser, "signatures"), "mSigningDetails"); 529 | } 530 | 531 | /** 532 | * Set signing details for PackageSetting or SharedUserSetting 533 | */ 534 | void Setting_setSigningDetails(Object pkgOrSharedUser, Object signingDetails) { 535 | XposedHelpers.setObjectField(XposedHelpers.getObjectField(pkgOrSharedUser, "signatures"), "mSigningDetails", signingDetails); 536 | } 537 | 538 | protected Object SharedUserSetting_packages(Object /*SharedUserSetting*/ sharedUser) { 539 | return XposedHelpers.getObjectField(sharedUser, "packages"); 540 | } 541 | 542 | protected Object SigningDetails_mergeLineageWith(Object self, Object other) { 543 | return XposedHelpers.callMethod(self, "mergeLineageWith", other); 544 | } 545 | } 546 | -------------------------------------------------------------------------------- /app/src/main/java/toolkit/coderstory/CorePatchForS.java: -------------------------------------------------------------------------------- 1 | package toolkit.coderstory; 2 | 3 | import java.lang.reflect.InvocationTargetException; 4 | 5 | import de.robv.android.xposed.XC_MethodHook; 6 | import de.robv.android.xposed.XposedBridge; 7 | import de.robv.android.xposed.XposedHelpers; 8 | import de.robv.android.xposed.callbacks.XC_LoadPackage; 9 | 10 | public class CorePatchForS extends CorePatchForR { 11 | @Override 12 | public void handleLoadPackage(XC_LoadPackage.LoadPackageParam loadPackageParam) throws IllegalAccessException, InvocationTargetException, InstantiationException { 13 | super.handleLoadPackage(loadPackageParam); 14 | var pmService = XposedHelpers.findClassIfExists("com.android.server.pm.PackageManagerService", 15 | loadPackageParam.classLoader); 16 | if (pmService != null) { 17 | var doesSignatureMatchForPermissions = XposedHelpers.findMethodExactIfExists(pmService, "doesSignatureMatchForPermissions", 18 | String.class, "com.android.server.pm.parsing.pkg.ParsedPackage", int.class); 19 | if (doesSignatureMatchForPermissions != null) { 20 | XposedBridge.hookMethod(doesSignatureMatchForPermissions, new XC_MethodHook() { 21 | @Override 22 | protected void afterHookedMethod(MethodHookParam param) { 23 | if (prefs.getBoolean("digestCreak", true) && prefs.getBoolean("UsePreSig", false)) { 24 | //If we decide to crack this then at least make sure they are same apks, avoid another one that tries to impersonate. 25 | if (param.getResult().equals(false)) { 26 | String pPname = (String) XposedHelpers.callMethod(param.args[1], "getPackageName"); 27 | if (pPname.contentEquals((String) param.args[0])) { 28 | param.setResult(true); 29 | } 30 | } 31 | } 32 | } 33 | }); 34 | } 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /app/src/main/java/toolkit/coderstory/CorePatchForT.java: -------------------------------------------------------------------------------- 1 | package toolkit.coderstory; 2 | 3 | import android.content.pm.Signature; 4 | 5 | import java.io.PrintWriter; 6 | import java.lang.reflect.InvocationTargetException; 7 | 8 | import de.robv.android.xposed.XC_MethodHook; 9 | import de.robv.android.xposed.XposedBridge; 10 | import de.robv.android.xposed.XposedHelpers; 11 | import de.robv.android.xposed.callbacks.XC_LoadPackage; 12 | 13 | public class CorePatchForT extends CorePatchForS { 14 | @Override 15 | public void handleLoadPackage(XC_LoadPackage.LoadPackageParam loadPackageParam) throws IllegalAccessException, InvocationTargetException, InstantiationException { 16 | super.handleLoadPackage(loadPackageParam); 17 | var checkDowngrade = XposedHelpers.findMethodExactIfExists("com.android.server.pm.PackageManagerServiceUtils", loadPackageParam.classLoader, 18 | "checkDowngrade", 19 | "com.android.server.pm.parsing.pkg.AndroidPackage", 20 | "android.content.pm.PackageInfoLite"); 21 | if (checkDowngrade != null) { 22 | XposedBridge.hookMethod(checkDowngrade, new ReturnConstant(prefs, "downgrade", null)); 23 | } 24 | 25 | Class signingDetails = getSigningDetails(loadPackageParam.classLoader); 26 | //New package has a different signature 27 | //处理覆盖安装但签名不一致 28 | hookAllMethods(signingDetails, "checkCapability", new XC_MethodHook() { 29 | @Override 30 | protected void beforeHookedMethod(MethodHookParam param) { 31 | // Don't handle PERMISSION & AUTH 32 | // Or applications will have all privileged permissions 33 | // https://cs.android.com/android/platform/superproject/+/master:frameworks/base/core/java/android/content/pm/PackageParser.java;l=5947?q=CertCapabilities 34 | // https://cs.android.com/android/platform/superproject/main/+/main:frameworks/base/services/core/java/com/android/server/accounts/AccountManagerService.java;l=5867 35 | if (prefs.getBoolean("digestCreak", true)) { 36 | if ((Integer) param.args[1] != 4 && (Integer) param.args[1] != 16) { 37 | param.setResult(true); 38 | } 39 | } 40 | } 41 | }); 42 | 43 | Class ParsedPackage = getParsedPackage(loadPackageParam.classLoader); 44 | findAndHookMethod("com.android.server.pm.InstallPackageHelper", loadPackageParam.classLoader, 45 | "doesSignatureMatchForPermissions", String.class, 46 | ParsedPackage, int.class, new XC_MethodHook() { 47 | @Override 48 | protected void afterHookedMethod(MethodHookParam param) { 49 | if (prefs.getBoolean("digestCreak", true) && prefs.getBoolean("UsePreSig", false)) { 50 | //If we decide to crack this then at least make sure they are same apks, avoid another one that tries to impersonate. 51 | if (param.getResult().equals(false)) { 52 | String pPname = (String) XposedHelpers.callMethod(param.args[1], "getPackageName"); 53 | if (pPname.contentEquals((String) param.args[0])) { 54 | param.setResult(true); 55 | } 56 | } 57 | } 58 | } 59 | }); 60 | 61 | var assertMinSignatureSchemeIsValid = XposedHelpers.findMethodExactIfExists("com.android.server.pm.ScanPackageUtils", loadPackageParam.classLoader, 62 | "assertMinSignatureSchemeIsValid", 63 | "com.android.server.pm.parsing.pkg.AndroidPackage", int.class); 64 | if (assertMinSignatureSchemeIsValid != null) { 65 | XposedBridge.hookMethod(assertMinSignatureSchemeIsValid, new XC_MethodHook() { 66 | @Override 67 | protected void afterHookedMethod(MethodHookParam param) { 68 | if (prefs.getBoolean("authcreak", false)) { 69 | param.setResult(null); 70 | } 71 | } 72 | }); 73 | } 74 | 75 | Class strictJarVerifier = findClass("android.util.jar.StrictJarVerifier", loadPackageParam.classLoader); 76 | if (strictJarVerifier != null) { 77 | XposedBridge.hookAllConstructors(strictJarVerifier, new XC_MethodHook() { 78 | @Override 79 | protected void afterHookedMethod(MethodHookParam param) { 80 | if (prefs.getBoolean("authcreak", false)) { 81 | XposedHelpers.setBooleanField(param.thisObject, "signatureSchemeRollbackProtectionsEnforced", false); 82 | } 83 | } 84 | }); 85 | } 86 | 87 | // ensure verifySignatures success 88 | // https://cs.android.com/android/platform/superproject/main/+/main:frameworks/base/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java;l=621;drc=2e50991320cbef77d3e8504a4b284adae8c2f4d2 89 | var utils = XposedHelpers.findClassIfExists("com.android.server.pm.PackageManagerServiceUtils", loadPackageParam.classLoader); 90 | if (utils != null) { 91 | deoptimizeMethod(utils, "canJoinSharedUserId"); 92 | } 93 | } 94 | 95 | Class getParsedPackage(ClassLoader classLoader) { 96 | return XposedHelpers.findClassIfExists("com.android.server.pm.parsing.pkg.ParsedPackage", classLoader); 97 | } 98 | 99 | Class getSigningDetails(ClassLoader classLoader) { 100 | return XposedHelpers.findClassIfExists("android.content.pm.SigningDetails", classLoader); 101 | } 102 | 103 | @Override 104 | protected void dumpSigningDetails(Object signingDetails, PrintWriter pw) { 105 | var i = 0; 106 | for (var sign : (Signature[]) XposedHelpers.callMethod(signingDetails, "getSignatures")) { 107 | i++; 108 | pw.println(i + ": " + sign.toCharsString()); 109 | } 110 | } 111 | 112 | @Override 113 | protected Object SharedUserSetting_packages(Object sharedUser) { 114 | return XposedHelpers.getObjectField(sharedUser, "mPackages"); 115 | } 116 | 117 | @Override 118 | protected Object SigningDetails_mergeLineageWith(Object self, Object other) { 119 | return XposedHelpers.callMethod(self, "mergeLineageWith", other, 2 /*MERGE_RESTRICTED_CAPABILITY*/); 120 | } 121 | 122 | @Override 123 | Class getIsVerificationEnabledClass(ClassLoader classLoader) { 124 | return XposedHelpers.findClass("com.android.server.pm.VerificationParams", classLoader); 125 | } 126 | } 127 | -------------------------------------------------------------------------------- /app/src/main/java/toolkit/coderstory/CorePatchForU.java: -------------------------------------------------------------------------------- 1 | package toolkit.coderstory; 2 | 3 | import android.util.Log; 4 | 5 | import java.lang.reflect.InvocationTargetException; 6 | 7 | import de.robv.android.xposed.XC_MethodHook; 8 | import de.robv.android.xposed.XposedBridge; 9 | import de.robv.android.xposed.XposedHelpers; 10 | import de.robv.android.xposed.callbacks.XC_LoadPackage; 11 | 12 | public class CorePatchForU extends CorePatchForT { 13 | @Override 14 | public void handleLoadPackage(XC_LoadPackage.LoadPackageParam loadPackageParam) throws IllegalAccessException, InvocationTargetException, InstantiationException { 15 | super.handleLoadPackage(loadPackageParam); 16 | var utilClass = findClass("com.android.server.pm.ReconcilePackageUtils", loadPackageParam.classLoader); 17 | if (utilClass != null) { 18 | try { 19 | deoptimizeMethod(utilClass, "reconcilePackages"); 20 | } catch (Throwable e) { 21 | XposedBridge.log("E/" + MainHook.TAG + " deoptimizing failed" + Log.getStackTraceString(e)); 22 | } 23 | } 24 | 25 | // https://cs.android.com/android/platform/superproject/+/android-14.0.0_r60:frameworks/base/services/core/java/com/android/server/pm/ReconcilePackageUtils.java;l=61;bpv=1;bpt=0 26 | if (prefs.getBoolean("digestCreak", true) && prefs.getBoolean("sharedUser", false)) { 27 | setStaticBooleanField(utilClass, "ALLOW_NON_PRELOADS_SYSTEM_SHAREDUIDS", true); 28 | } 29 | 30 | // ee11a9c (Rename AndroidPackageApi to AndroidPackage) 31 | findAndHookMethod("com.android.server.pm.PackageManagerServiceUtils", loadPackageParam.classLoader, 32 | "checkDowngrade", 33 | "com.android.server.pm.pkg.AndroidPackage", 34 | "android.content.pm.PackageInfoLite", 35 | new ReturnConstant(prefs, "downgrade", null)); 36 | findAndHookMethod("com.android.server.pm.ScanPackageUtils", loadPackageParam.classLoader, 37 | "assertMinSignatureSchemeIsValid", 38 | "com.android.server.pm.pkg.AndroidPackage", int.class, 39 | new XC_MethodHook() { 40 | @Override 41 | protected void afterHookedMethod(MethodHookParam param) { 42 | if (prefs.getBoolean("authcreak", false)) { 43 | param.setResult(null); 44 | } 45 | } 46 | }); 47 | 48 | var ntService = XposedHelpers.findClassIfExists("com.nothing.server.ex.NtConfigListServiceImpl", 49 | loadPackageParam.classLoader); 50 | if (ntService != null) { 51 | findAndHookMethod(ntService, "isInstallingAppForbidden", java.lang.String.class, 52 | new ReturnConstant(prefs, "bypassBlock", false)); 53 | 54 | findAndHookMethod(ntService, "isStartingAppForbidden", java.lang.String.class, 55 | new ReturnConstant(prefs, "bypassBlock", false)); 56 | } 57 | } 58 | 59 | @Override 60 | Class getParsedPackage(ClassLoader classLoader) { 61 | var clazz = XposedHelpers.findClassIfExists("com.android.internal.pm.parsing.pkg.ParsedPackage", classLoader); 62 | return clazz != null ? clazz : XposedHelpers.findClassIfExists("com.android.server.pm.parsing.pkg.ParsedPackage", classLoader); 63 | } 64 | 65 | @Override 66 | Class getIsVerificationEnabledClass(ClassLoader classLoader) { 67 | return XposedHelpers.findClass("com.android.server.pm.VerifyingSession", classLoader); 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /app/src/main/java/toolkit/coderstory/CorePatchForV.java: -------------------------------------------------------------------------------- 1 | package toolkit.coderstory; 2 | 3 | import de.robv.android.xposed.XposedHelpers; 4 | 5 | public class CorePatchForV extends CorePatchForU { 6 | @Override 7 | Class getParsedPackage(ClassLoader classLoader) { 8 | return XposedHelpers.findClassIfExists("com.android.internal.pm.parsing.pkg.ParsedPackage", classLoader); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /app/src/main/java/toolkit/coderstory/MainHook.java: -------------------------------------------------------------------------------- 1 | package toolkit.coderstory; 2 | 3 | import android.os.Build; 4 | 5 | import com.coderstory.toolkit.BuildConfig; 6 | 7 | import de.robv.android.xposed.IXposedHookLoadPackage; 8 | import de.robv.android.xposed.XposedBridge; 9 | import de.robv.android.xposed.callbacks.XC_LoadPackage; 10 | 11 | public class MainHook implements IXposedHookLoadPackage { 12 | public static final String TAG = "CorePatch"; 13 | 14 | @Override 15 | public void handleLoadPackage(XC_LoadPackage.LoadPackageParam lpparam) throws Throwable { 16 | if (("android".equals(lpparam.packageName)) && (lpparam.processName.equals("android"))) { 17 | if (BuildConfig.DEBUG) 18 | XposedBridge.log("D/" + TAG + " handleLoadPackage"); 19 | switch (Build.VERSION.SDK_INT) { 20 | case Build.VERSION_CODES.BAKLAVA: // 36 21 | case Build.VERSION_CODES.VANILLA_ICE_CREAM: // 35 22 | new CorePatchForV().handleLoadPackage(lpparam); 23 | break; 24 | case Build.VERSION_CODES.UPSIDE_DOWN_CAKE: // 34 25 | new CorePatchForU().handleLoadPackage(lpparam); 26 | break; 27 | case Build.VERSION_CODES.TIRAMISU: // 33 28 | new CorePatchForT().handleLoadPackage(lpparam); 29 | break; 30 | case Build.VERSION_CODES.S_V2: // 32 31 | case Build.VERSION_CODES.S: // 31 32 | new CorePatchForS().handleLoadPackage(lpparam); 33 | break; 34 | case Build.VERSION_CODES.R: // 30 35 | new CorePatchForR().handleLoadPackage(lpparam); 36 | break; 37 | case Build.VERSION_CODES.Q: // 29 38 | case Build.VERSION_CODES.P: // 28 39 | new CorePatchForQ().handleLoadPackage(lpparam); 40 | break; 41 | default: 42 | XposedBridge.log("W/" + TAG + " Unsupported Version of Android " + Build.VERSION.SDK_INT); 43 | XposedBridge.log("I/" + TAG + " Falling back to latest SDK"); 44 | new CorePatchForV().handleLoadPackage(lpparam); 45 | break; 46 | } 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /app/src/main/java/toolkit/coderstory/ReturnConstant.java: -------------------------------------------------------------------------------- 1 | package toolkit.coderstory; 2 | 3 | import de.robv.android.xposed.XC_MethodHook; 4 | import de.robv.android.xposed.XSharedPreferences; 5 | 6 | public class ReturnConstant extends XC_MethodHook { 7 | private final XSharedPreferences prefs; 8 | private final String prefsKey; 9 | private final Object value; 10 | 11 | public ReturnConstant(XSharedPreferences prefs, String prefsKey, Object value) { 12 | this.prefs = prefs; 13 | this.prefsKey = prefsKey; 14 | this.value = value; 15 | } 16 | 17 | @Override 18 | protected void beforeHookedMethod(MethodHookParam param) throws Throwable { 19 | prefs.reload(); 20 | if (prefs.getBoolean(prefsKey, true)) { 21 | param.setResult(value); 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /app/src/main/java/toolkit/coderstory/SettingsActivity.java: -------------------------------------------------------------------------------- 1 | package toolkit.coderstory; 2 | 3 | import android.annotation.SuppressLint; 4 | import android.app.Activity; 5 | import android.app.AlertDialog; 6 | import android.content.Context; 7 | import android.content.SharedPreferences; 8 | import android.graphics.Insets; 9 | import android.os.Build; 10 | import android.os.Bundle; 11 | import android.preference.PreferenceFragment; 12 | import android.view.View; 13 | import android.view.ViewGroup; 14 | import android.view.WindowInsets; 15 | 16 | import com.coderstory.toolkit.R; 17 | 18 | import java.lang.reflect.Method; 19 | 20 | @SuppressWarnings("deprecation") 21 | public class SettingsActivity extends Activity { 22 | 23 | @Override 24 | protected void onCreate(Bundle savedInstanceState) { 25 | super.onCreate(savedInstanceState); 26 | setContentView(R.layout.activity_settings); 27 | checkXSharedPreferences(); 28 | if (savedInstanceState == null) { 29 | getFragmentManager().beginTransaction() 30 | .add(R.id.fragment_container, new SettingsFragment()).commit(); 31 | } 32 | } 33 | 34 | @SuppressLint("WorldReadableFiles") 35 | private void checkXSharedPreferences() { 36 | try { 37 | // getSharedPreferences will hooked by LSPosed 38 | // will not throw SecurityException 39 | //noinspection deprecation 40 | getSharedPreferences("conf", Context.MODE_WORLD_READABLE); 41 | } catch (SecurityException exception) { 42 | new AlertDialog.Builder(this) 43 | .setTitle(R.string.config_error) 44 | .setMessage(R.string.not_supported) 45 | .setPositiveButton(android.R.string.ok, (dialog12, which) -> finish()) 46 | .setNegativeButton(R.string.ignore, null) 47 | .show(); 48 | } 49 | } 50 | 51 | public static class SettingsFragment extends PreferenceFragment implements SharedPreferences.OnSharedPreferenceChangeListener { 52 | @Override 53 | public void onCreate(Bundle savedInstanceState) { 54 | super.onCreate(savedInstanceState); 55 | getPreferenceManager().setSharedPreferencesName("conf"); 56 | addPreferencesFromResource(R.xml.prefs); 57 | } 58 | 59 | @Override 60 | public void onViewCreated(View view, Bundle savedInstanceState) { 61 | view.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN); 62 | view.setOnApplyWindowInsetsListener((v, windowInsets) -> { 63 | Insets insets = null; 64 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { 65 | insets = windowInsets.getInsets(WindowInsets.Type.systemBars()); 66 | } else if (Build.VERSION.SDK_INT == Build.VERSION_CODES.Q) { 67 | insets = windowInsets.getSystemWindowInsets(); 68 | } 69 | ViewGroup.MarginLayoutParams mlp = (ViewGroup.MarginLayoutParams) v.getLayoutParams(); 70 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { 71 | mlp.leftMargin = insets.left; 72 | mlp.bottomMargin = insets.bottom; 73 | mlp.rightMargin = insets.right; 74 | mlp.topMargin = insets.top; 75 | } else { 76 | mlp.leftMargin = windowInsets.getSystemWindowInsetLeft(); 77 | mlp.bottomMargin = windowInsets.getSystemWindowInsetBottom(); 78 | mlp.rightMargin = windowInsets.getSystemWindowInsetRight(); 79 | mlp.topMargin = windowInsets.getSystemWindowInsetTop(); 80 | } 81 | v.setLayoutParams(mlp); 82 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { 83 | return WindowInsets.CONSUMED; 84 | } else return windowInsets.consumeSystemWindowInsets(); 85 | }); 86 | super.onViewCreated(view, savedInstanceState); 87 | } 88 | 89 | @Override 90 | public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) { 91 | if (key.equals("UsePreSig") && sharedPreferences.getBoolean(key, false)) { 92 | try { 93 | @SuppressLint("PrivateApi") Class c = Class.forName("android.os.SystemProperties"); 94 | Method get = c.getMethod("get", String.class); 95 | if (!((String) get.invoke(c, "ro.miui.ui.version.code")).isEmpty()) { 96 | new AlertDialog.Builder(getActivity()).setMessage(R.string.miui_usepresig_warn).setPositiveButton(android.R.string.ok, null).show(); 97 | } 98 | } catch (Exception ignored) { 99 | } 100 | 101 | new AlertDialog.Builder(getActivity()).setMessage(R.string.usepresig_warn).setPositiveButton(android.R.string.ok, null).show(); 102 | } 103 | } 104 | 105 | @Override 106 | public void onResume() { 107 | super.onResume(); 108 | getPreferenceManager().getSharedPreferences().registerOnSharedPreferenceChangeListener(this); 109 | } 110 | 111 | @Override 112 | public void onPause() { 113 | super.onPause(); 114 | getPreferenceManager().getSharedPreferences().unregisterOnSharedPreferenceChangeListener(this); 115 | } 116 | } 117 | } 118 | -------------------------------------------------------------------------------- /app/src/main/java/toolkit/coderstory/XposedHelper.java: -------------------------------------------------------------------------------- 1 | package toolkit.coderstory; 2 | 3 | import android.util.Log; 4 | 5 | import com.coderstory.toolkit.BuildConfig; 6 | 7 | import de.robv.android.xposed.XC_MethodHook; 8 | import de.robv.android.xposed.XposedBridge; 9 | import de.robv.android.xposed.XposedHelpers; 10 | 11 | public class XposedHelper { 12 | public final String SIGNATURE = "308203c6308202aea003020102021426d148b7c65944abcf3a683b4c3dd3b139c4ec85300d06092a864886f70d01010b05003074310b3009060355040613025553311330110603550408130a43616c69666f726e6961311630140603550407130d4d6f756e7461696e205669657731143012060355040a130b476f6f676c6520496e632e3110300e060355040b1307416e64726f69643110300e06035504031307416e64726f6964301e170d3139303130323138353233385a170d3439303130323138353233385a3074310b3009060355040613025553311330110603550408130a43616c69666f726e6961311630140603550407130d4d6f756e7461696e205669657731143012060355040a130b476f6f676c6520496e632e3110300e060355040b1307416e64726f69643110300e06035504031307416e64726f696430820122300d06092a864886f70d01010105000382010f003082010a028201010087fcde48d9beaeba37b733a397ae586fb42b6c3f4ce758dc3ef1327754a049b58f738664ece587994f1c6362f98c9be5fe82c72177260c390781f74a10a8a6f05a6b5ca0c7c5826e15526d8d7f0e74f2170064896b0cf32634a388e1a975ed6bab10744d9b371cba85069834bf098f1de0205cdee8e715759d302a64d248067a15b9beea11b61305e367ac71b1a898bf2eec7342109c9c5813a579d8a1b3e6a3fe290ea82e27fdba748a663f73cca5807cff1e4ad6f3ccca7c02945926a47279d1159599d4ecf01c9d0b62e385c6320a7a1e4ddc9833f237e814b34024b9ad108a5b00786ea15593a50ca7987cbbdc203c096eed5ff4bf8a63d27d33ecc963990203010001a350304e300c0603551d13040530030101ff301d0603551d0e04160414a361efb002034d596c3a60ad7b0332012a16aee3301f0603551d23041830168014a361efb002034d596c3a60ad7b0332012a16aee3300d06092a864886f70d01010b0500038201010022ccb684a7a8706f3ee7c81d6750fd662bf39f84805862040b625ddf378eeefae5a4f1f283deea61a3c7f8e7963fd745415153a531912b82b596e7409287ba26fb80cedba18f22ae3d987466e1fdd88e440402b2ea2819db5392cadee501350e81b8791675ea1a2ed7ef7696dff273f13fb742bb9625fa12ce9c2cb0b7b3d94b21792f1252b1d9e4f7012cb341b62ff556e6864b40927e942065d8f0f51273fcda979b8832dd5562c79acf719de6be5aee2a85f89265b071bf38339e2d31041bc501d5e0c034ab1cd9c64353b10ee70b49274093d13f733eb9d3543140814c72f8e003f301c7a00b1872cc008ad55e26df2e8f07441002c4bcb7dc746745f0db"; 13 | 14 | public static void findAndHookMethod(String className, ClassLoader classLoader, String methodName, Object... parameterTypesAndCallback) { 15 | try { 16 | if (findClass(className, classLoader) != null) { 17 | XposedHelpers.findAndHookMethod(className, classLoader, methodName, parameterTypesAndCallback); 18 | } 19 | } catch (Throwable e) { 20 | if (BuildConfig.DEBUG) 21 | XposedBridge.log("E/" + MainHook.TAG + " " + Log.getStackTraceString(e)); 22 | } 23 | } 24 | 25 | public static void findAndHookMethod(Class clazz, String methodName, Object... parameterTypesAndCallback) { 26 | try { 27 | if (clazz != null) { 28 | XposedHelpers.findAndHookMethod(clazz, methodName, parameterTypesAndCallback); 29 | } 30 | } catch (Throwable e) { 31 | if (BuildConfig.DEBUG) 32 | XposedBridge.log("E/" + MainHook.TAG + " " + Log.getStackTraceString(e)); 33 | } 34 | } 35 | 36 | public static void hookAllMethods(String className, ClassLoader classLoader, String methodName, XC_MethodHook callback) { 37 | try { 38 | Class packageParser = findClass(className, classLoader); 39 | XposedBridge.hookAllMethods(packageParser, methodName, callback); 40 | } catch (Throwable e) { 41 | if (BuildConfig.DEBUG) 42 | XposedBridge.log("E/" + MainHook.TAG + " " + Log.getStackTraceString(e)); 43 | } 44 | } 45 | 46 | public void hookAllMethods(Class hookClass, String methodName, XC_MethodHook callback) { 47 | try { 48 | XposedBridge.hookAllMethods(hookClass, methodName, callback); 49 | } catch (Throwable e) { 50 | if (BuildConfig.DEBUG) 51 | XposedBridge.log("E/" + MainHook.TAG + " " + Log.getStackTraceString(e)); 52 | } 53 | } 54 | 55 | public static void setStaticBooleanField(Class hookClass, String fieldName, boolean value) { 56 | try { 57 | XposedHelpers.setStaticBooleanField(hookClass, fieldName, value); 58 | } catch (Throwable e) { 59 | if (BuildConfig.DEBUG) 60 | XposedBridge.log("E/" + MainHook.TAG + " " + Log.getStackTraceString(e)); 61 | } 62 | } 63 | 64 | public static Class findClass(String className, ClassLoader classLoader) { 65 | try { 66 | return Class.forName(className, false, classLoader); 67 | } catch (Throwable e) { 68 | if (BuildConfig.DEBUG) 69 | XposedBridge.log("E/" + MainHook.TAG + " " + Log.getStackTraceString(e)); 70 | } 71 | return null; 72 | } 73 | 74 | public static void hookAllConstructors(String className, XC_MethodHook callback) { 75 | try { 76 | Class packageParser = findClass(className, null); 77 | XposedBridge.hookAllConstructors(packageParser, callback); 78 | } catch (Throwable e) { 79 | if (BuildConfig.DEBUG) 80 | XposedBridge.log("E/" + MainHook.TAG + " " + Log.getStackTraceString(e)); 81 | } 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/values-fr/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | Core Patch 3 | Patch pour Android 9-16 4 | Cette version est pour 10-15 uniquement.\nMerci d\’utiliser la dernière version de LSPosed. 5 | Permettre la rétrogradation 6 | Permettre la rétrogradation d\’applications. 7 | Désactiver la vérification digest 8 | Permettre l\’installation d\’applications après avoir modifier le fichier dans l\’apk (ignorer les erreures invalid digest). 9 | Désactiver la comparaison de signatures 10 | Permettre la réinstallation d\’application avec des signatures différentes. 11 | Utiliser les signatures installées 12 | Toujours utiliser les signatures depuis les applications déjà installées lors d\’installations.\n C\’est extrêmement dangereux.\n A activer uniquement lors ce que c\’est vraiment nécessaire! 13 | Réglages 14 | Ignorer 15 | Vous utilisez apparemment une ancienne version de LSPosed ou LSPosed n\’est pas activé, Merci de mettre LSPosed à jour ou de retenter après activation. 16 | UsePreSig ne fonctionne pas sur MiUI car son sous-système est beaucoup trop différent.\nNous n\’avons pas le temps de nous pencher sur ce cas. 17 | !! N\’importe quel apk peut remplacer celui déjà installé !!\nPrenez garde lors ce que vous installez des apk inconnus 18 | 19 | -------------------------------------------------------------------------------- /app/src/main/res/values-in/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | Core Patch 3 | Android 9-16 core patch 4 | Versi ini adalah untuk Android 9-16 saja.\nHarap gunakan versi LSPosed terbaru. 5 | Izinkan turun versi 6 | Izinkan turun versi aplikasi. 7 | Matikan verifikasi digest 8 | Izinkan pemasangan aplikasi setelah file dalam apk dimodifikasi (abaikan kesalahan digest yang tidak valid). 9 | Matikan pembanding signatures 10 | Izinkan pemasangan ulang aplikasi dengan signatures berbeda. 11 | Gunakan signatures terpasang 12 | Selalu gunakan signatures dari aplikasi yang sudah terpasang ketika memasang.\n Ini sangat berbahaya.\n Hanya aktifkan jika diperlukan sangad! 13 | Pengaturan 14 | Abaikan 15 | Inisialisasi konfigurasi gagal 16 | Sepertinya Anda menggunakan versi LSPosed yang jadul atau LSPosed tidak diaktifkan, harap perbarui LSPosed atau coba lagi setelah diaktifkan. 17 | Terobos blokiran 18 | Terobos daftar blokir dalam beberapa perangkat seperti Nothing Phone 19 | Gunakan signatures terpasang tidak bekerja di MiUI karena framework banyak dimodifikasi.\nKami tidak punya waktu untuk menyelidikinya. 20 | !! Segala apk dapat menggantikan aplikasi yang terpasang !!\nBerhati-hati ketika memasang apk antah-berantah 21 | Terobos verifikasi pengguna bersama 22 | Izinkan pemasangan aplikasi dengan signatures berbeda dari pengguna bersama-nya (\'Matikan pembanding signature\' harus diaktifkan juga) 23 | Matikan Agen Verifikasi Paket 24 | Contoh: Proteksi Google Play 25 | 26 | -------------------------------------------------------------------------------- /app/src/main/res/values-it/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | Core Patch 3 | Android 9-16 core patch 4 | Questa versione è solo per Android 9-16.\nPer favore utilizza la versione più recente di LSPosed. 5 | Consenti ​​Downgrade 6 | Consenti il ​​downgrade delle applicazioni. 7 | Disabilita verifica digest 8 | Consente l\'installazione di app dopo aver modificato il file nell\'apk (ignora l\'errore digest non valido). 9 | Disabilita il confronto delle firme 10 | Consenti la reinstallazione di app con firme diverse. 11 | Utilizza le firme installate 12 | Durante l\'installazione, utilizza sempre le firme delle app già installate.\n Questo è estremamente pericoloso.\n Abilitalo solo quando è veramente necessario! 13 | Impostazioni 14 | Ignora 15 | Inizializzazione della configurazione non riuscita 16 | Sembra che tu stia utilizzando una versione obsoleta di LSPosed oppure LSPosed non è attivato. Aggiorna LSPosed o riprova dopo l\'attivazione. 17 | Bypassa blocchi 18 | Bypassa la lista di blocco di alcuni dispositivi come Nothing Phone 19 | UsePreSig non funzionerà su MiUI perché il suo framework è troppo diverso. Non abbiamo tempo per seguire il caso. 20 | !! Qualsiasi apk può sovrascrivere quello installato !!\nFai attenzione quando installi un apk sconosciuto 21 | Bypassa verifica utente condiviso 22 | Consenti l\'installazione dell\'app con firma diversa da quella dell\'utente condiviso (deve essere abilitato anche \'Disabilita il confronto delle firme\') 23 | 24 | -------------------------------------------------------------------------------- /app/src/main/res/values-ja/strings.xml: -------------------------------------------------------------------------------- 1 |  2 | 3 | Core Patch 4 | Android 9-16 コアパッチ 5 | このバージョンは、 Android 9-16 のみで動作します。\n最新版の LSPosed を使用してください。 6 | ダウングレードを許可する 7 | アプリのダウングレードを許可します。 8 | ダイジェストの検証を無効化する 9 | APK ファイルの変更後にアプリをインストールできるようにします。(無効なダイジェストのエラーを無視します) 10 | 署名の比較を無効化する 11 | 署名が異なるアプリの再インストールを許可します。 12 | インストールされている署名を使用する 13 | インストール時に、既にインストールされているアプリの署名を使用します。\nこの操作は、非常に危険です。\n本当に必要となる時のみ有効化してください! 14 | 設定 15 | 無視 16 | 構成の初期化に失敗しました 17 | 古いバージョンの LSPosed を使用しているか、LSPosed が有効化されていないようです。LSPosed を更新、有効化をした後に再試行をしてください。 18 | ブロックをバイパスする 19 | Nothing Phone などの一部のデバイスのブロックリストをバイパスします。 20 | インストールされている署名の使用は、フレームワークが大幅に変更されるため MIUI では動作しません。\nこの問題を解析をする時間がありません。 21 | !! どんな APK でもインストールされている APK を上書きできるようにします !!\n未知の APK をインストールする際は注意してください 22 | 23 | -------------------------------------------------------------------------------- /app/src/main/res/values-ko/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | Core Patch 3 | Android 9-16 core patch 4 | 이 버전은 Android 9-16 전용입니다.\nLSPosed의 최신 버전을 사용하십시오. 5 | 다운그레이드 허용 6 | 애플리케이션 다운그레이드를 허용합니다. 7 | 다이제스트 확인 비활성화 8 | apk의 파일을 수정한 후 앱을 설치할 수 있습니다. (잘못된 다이제스트 오류를 무시). 9 | 비교 서명 비활성화 10 | 다른 서명을 가진 앱을 재설치할 수 있습니다. 11 | 설치된 서명 사용 12 | 설치할 때는 항상 이미 설치된 앱의 서명을 사용하십시오.\n 이것은 매우 위험합니다.\n 정말로 필요한 경우에만 활성화하십시오! 13 | 설정 14 | 무시 15 | LSPosed의 오래된 버전을 사용 중이거나 LSPosed가 활성화되지 않은 것 같습니다. LSPosed를 업데이트하거나 활성화한 후 다시 시도하십시오. 16 | 17 | -------------------------------------------------------------------------------- /app/src/main/res/values-night/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /app/src/main/res/values-pt-rBR/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | Core Patch 3 | Android 9-16 core patch 4 | Esta versão é apenas para Android 9-16.\nPor favor, use a versão mais recente do LSPosed. 5 | Permitir downgrade 6 | Permite downgrade de apps 7 | Desativar verificação de integridade 8 | Permite instalar apps após modificar o arquivo no apk (ignorar erro de integridade inválido) 9 | Desativar comparação de assinaturas 10 | Permite a reinstalação do app com assinaturas diferentes 11 | Usar assinaturas instaladas 12 | Sempre use assinaturas de apps já instalados durante a instalação.\n Isso é extremamente perigoso.\n Ative apenas quando for realmente necessário! 13 | Configurações 14 | Ignorar 15 | Falha na inicialização da configuração 16 | Parece que você está usando uma versão desatualizada do LSPosed ou o LSPosed não está ativado. Atualize o LSPosed ou tente novamente após a ativação. 17 | Ignorar bloqueio 18 | Ignore a lista de bloqueio em alguns dispositivos como Nothing Phone 19 | Usar assinaturas instaladas não funcionará na MIUI porque sua estrutura muda muito.\nNão temos tempo para acompanhar o caso. 20 | !! Qualquer apk pode substituir o instalado !!\nTenha cuidado ao instalar apk desconhecido. 21 | Ignorar verificação de usuário compartilhado 22 | Permite instalar apps com assinaturas diferentes do usuário compartilhado (\'Desativar comparação de assinaturas\' também deve estar ativado) 23 | Desativar agente de verificação de pacotes 24 | Ex.: Google Play Protect 25 | 26 | -------------------------------------------------------------------------------- /app/src/main/res/values-ru/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | Использовать установленные подписи 4 | "При установке всегда используйте подписи из уже установленных приложений. 5 | Это крайне «опасно». 6 | Включайте только тогда, когда это действительно необходимо! " 7 | Core Patch 8 | Отключить проверку дайджеста 9 | Позволяет устанавливать приложения после изменения файла в apk (игнорировать недопустимую ошибку дайджеста). 10 | «Эта версия предназначена только для Android 9-16. 11 | Пожалуйста, используйте последнюю версию LSPposed. " 12 | Отключить сравнение подписей 13 | Разрешить переустановку приложения с другими подписями. 14 | Разрешить понижать версию. 15 | Разрешить переустановку приложений на прошлые версии. 16 | Игнорировать 17 | Android 9-16 core patch 18 | Похоже, вы используете устаревшую версию LSPposed или LSPposed не активирован, пожалуйста, обновите LSPposed или повторите попытку после активации. 19 | Настройки 20 | 21 | -------------------------------------------------------------------------------- /app/src/main/res/values-zh-rCN/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 核心破解 3 | Android 9-16 核心破解 4 | 此版本只支持 Android 9-16\n请安装最新版本的 LSPosed 框架,否则功能可能无法正确启用。 5 | 允许降级安装应用 6 | 允许应用在安装新版本的情况下直接覆盖安装旧版本 7 | 禁用软件包管理器签名验证 8 | 关闭安装应用时的签名验证,可以安装被篡改的应用 9 | 禁用 APK 签名验证 10 | 允许直接覆盖安装同包名不同签名的应用 11 | 安装时始终使用已装 APP 的签名 12 | 不是一般的危险,仅在绝对需要时启用 13 | 设置 14 | 忽略 15 | 模块未激活或正使用旧版 LSPosed,请激活模块或更新 LSPosed 后再试。 16 | 由于 MIUI 大幅度魔改了安卓框架,UsePreSig 无法正常工作\n我们没有时间溯源 17 | !!所有安装包可以覆盖已安装的 APP!!\n安装未知的安装包时请务必小心 18 | 绕过黑名单 19 | 绕过某些设备如 Nothing Phone 上的黑名单 20 | 配置初始化失败 21 | 绕过共享用户签名验证 22 | 允许安装与其共享用户签名不同的 app(需要同时打开“禁用APK签名验证” 23 | 禁用安装包验证代理 24 | 如 Play 商店的保护机制 25 | 26 | -------------------------------------------------------------------------------- /app/src/main/res/values-zh-rTW/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 核心修補 4 | Android 9-16 核心修補 5 | 此版本只支援 Android 9-16\n請安裝最新版本的 LSPosed 框架,否則功能可能無法正確啟用。 6 | 允許降版安裝應用程式 7 | 允許應用程式在安裝新版本的情況下直接覆蓋安裝舊版本 8 | 停用套裝安裝程式簽名驗證 9 | 停用安裝應用程式時的簽名驗證,可以安裝被修改的應用程式 10 | 停用 APK 簽名驗證 11 | 允許直接覆蓋安裝同套件名稱但不同簽名的應用程式 12 | 安裝時總是使用已安裝應用程式的簽名 13 | 不是一般的危險,只在絕對需要時啟用 14 | 設定 15 | 忽略 16 | 未啟用模組或正在使用舊版的 LSPosed,請啟用模組或是更新 LSPosed 模組後再試一次。 17 | 由於 MIUI 大幅度修改了 Android 框架,UsePreSig 無法正常運作\n我們沒有時間分析 18 | !!所有安裝檔可以覆蓋已安裝的應用程式!!\n安裝未知的安裝檔時請務必小心 19 | 繞過黑名單 20 | 繞過某些裝置如 Nothing Phone 上的黑名單 21 | 配置初始化失敗 22 | 23 | -------------------------------------------------------------------------------- /app/src/main/res/values/array.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | android 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | Core Patch 3 | Android 9-16 core patch 4 | This version is for Android 9-16 only.\nPlease use the latest version of the LSPosed. 5 | Allow downgrade 6 | Allow downgrade applications. 7 | Disable digest verify 8 | Allows install apps after modify file in apk (ignore invalid digest error). 9 | Disable compare signatures 10 | Allow re-install app with different signatures. 11 | Use installed signatures 12 | Always use signatures from already installed apps when installing.\n This is extremely dangerous.\n Only enable when really needed! 13 | Settings 14 | Ignore 15 | Configuration initialization failed 16 | It seems that you are using an out dated version of LSPosed or LSPosed is not activated, please update LSPosed or try again after activated. 17 | Bypass block 18 | Bypass blocklist in some devices like Nothing Phone 19 | UsePreSig won\'t work on MiUI because its framework changes too much.\nWe don\'t have time to track the case. 20 | !! Any apk can override the installed one !!\nBe carefully when installing unknown apk 21 | Bypass shared user verify 22 | Allow install app with signature differ from its shared user (\'Disable compare signatures\' must be enabled too) 23 | Disable Package Verification Agent 24 | e.g. Google Play Protection 25 | 26 | -------------------------------------------------------------------------------- /app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/xml/prefs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 10 | 15 | 20 | 21 | 26 | 27 | 32 | 33 | 38 | 39 | 44 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /build.gradle.kts: -------------------------------------------------------------------------------- 1 | // Top-level build file where you can add configuration options common to all sub-projects/modules. 2 | buildscript { 3 | 4 | repositories { 5 | google() 6 | mavenCentral() 7 | } 8 | dependencies { 9 | classpath("com.android.tools.build:gradle:8.7.2") 10 | } 11 | } 12 | 13 | allprojects { 14 | repositories { 15 | google() 16 | mavenCentral() 17 | maven(url = "https://api.xposed.info/") 18 | } 19 | } 20 | 21 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | ## Project-wide Gradle settings. 2 | # 3 | # For more details on how to configure your build environment visit 4 | # http://www.gradle.org/docs/current/userguide/build_environment.html 5 | # 6 | # Specifies the JVM arguments used for the daemon process. 7 | # The setting is particularly useful for tweaking memory settings. 8 | # Default value: -Xmx1024m -XX:MaxPermSize=256m 9 | # org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 10 | # 11 | # When configured, Gradle will run in incubating parallel mode. 12 | # This option should only be used with decoupled projects. More details, visit 13 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 14 | # org.gradle.parallel=true 15 | #Fri Nov 17 23:21:15 CST 2017 16 | android.useAndroidX=true 17 | android.enableAppCompileTimeRClass=true 18 | android.experimental.enableNewResourceShrinker.preciseShrinking=true 19 | android.nonFinalResIds=false 20 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LSPosed/CorePatch/daf30cb847d6210544ac81e8701713703843a274/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.11-bin.zip 4 | networkTimeout=10000 5 | validateDistributionUrl=true 6 | zipStoreBase=GRADLE_USER_HOME 7 | zipStorePath=wrapper/dists 8 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # 4 | # Copyright © 2015-2021 the original authors. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # https://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # 18 | # SPDX-License-Identifier: Apache-2.0 19 | # 20 | 21 | ############################################################################## 22 | # 23 | # Gradle start up script for POSIX generated by Gradle. 24 | # 25 | # Important for running: 26 | # 27 | # (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is 28 | # noncompliant, but you have some other compliant shell such as ksh or 29 | # bash, then to run this script, type that shell name before the whole 30 | # command line, like: 31 | # 32 | # ksh Gradle 33 | # 34 | # Busybox and similar reduced shells will NOT work, because this script 35 | # requires all of these POSIX shell features: 36 | # * functions; 37 | # * expansions «$var», «${var}», «${var:-default}», «${var+SET}», 38 | # «${var#prefix}», «${var%suffix}», and «$( cmd )»; 39 | # * compound commands having a testable exit status, especially «case»; 40 | # * various built-in commands including «command», «set», and «ulimit». 41 | # 42 | # Important for patching: 43 | # 44 | # (2) This script targets any POSIX shell, so it avoids extensions provided 45 | # by Bash, Ksh, etc; in particular arrays are avoided. 46 | # 47 | # The "traditional" practice of packing multiple parameters into a 48 | # space-separated string is a well documented source of bugs and security 49 | # problems, so this is (mostly) avoided, by progressively accumulating 50 | # options in "$@", and eventually passing that to Java. 51 | # 52 | # Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, 53 | # and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; 54 | # see the in-line comments for details. 55 | # 56 | # There are tweaks for specific operating systems such as AIX, CygWin, 57 | # Darwin, MinGW, and NonStop. 58 | # 59 | # (3) This script is generated from the Groovy template 60 | # https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt 61 | # within the Gradle project. 62 | # 63 | # You can find Gradle at https://github.com/gradle/gradle/. 64 | # 65 | ############################################################################## 66 | 67 | # Attempt to set APP_HOME 68 | 69 | # Resolve links: $0 may be a link 70 | app_path=$0 71 | 72 | # Need this for daisy-chained symlinks. 73 | while 74 | APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path 75 | [ -h "$app_path" ] 76 | do 77 | ls=$( ls -ld "$app_path" ) 78 | link=${ls#*' -> '} 79 | case $link in #( 80 | /*) app_path=$link ;; #( 81 | *) app_path=$APP_HOME$link ;; 82 | esac 83 | done 84 | 85 | # This is normally unused 86 | # shellcheck disable=SC2034 87 | APP_BASE_NAME=${0##*/} 88 | # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) 89 | APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s 90 | ' "$PWD" ) || exit 91 | 92 | # Use the maximum available, or set MAX_FD != -1 to use that value. 93 | MAX_FD=maximum 94 | 95 | warn () { 96 | echo "$*" 97 | } >&2 98 | 99 | die () { 100 | echo 101 | echo "$*" 102 | echo 103 | exit 1 104 | } >&2 105 | 106 | # OS specific support (must be 'true' or 'false'). 107 | cygwin=false 108 | msys=false 109 | darwin=false 110 | nonstop=false 111 | case "$( uname )" in #( 112 | CYGWIN* ) cygwin=true ;; #( 113 | Darwin* ) darwin=true ;; #( 114 | MSYS* | MINGW* ) msys=true ;; #( 115 | NONSTOP* ) nonstop=true ;; 116 | esac 117 | 118 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 119 | 120 | 121 | # Determine the Java command to use to start the JVM. 122 | if [ -n "$JAVA_HOME" ] ; then 123 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 124 | # IBM's JDK on AIX uses strange locations for the executables 125 | JAVACMD=$JAVA_HOME/jre/sh/java 126 | else 127 | JAVACMD=$JAVA_HOME/bin/java 128 | fi 129 | if [ ! -x "$JAVACMD" ] ; then 130 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 131 | 132 | Please set the JAVA_HOME variable in your environment to match the 133 | location of your Java installation." 134 | fi 135 | else 136 | JAVACMD=java 137 | if ! command -v java >/dev/null 2>&1 138 | then 139 | die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 140 | 141 | Please set the JAVA_HOME variable in your environment to match the 142 | location of your Java installation." 143 | fi 144 | fi 145 | 146 | # Increase the maximum file descriptors if we can. 147 | if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then 148 | case $MAX_FD in #( 149 | max*) 150 | # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. 151 | # shellcheck disable=SC2039,SC3045 152 | MAX_FD=$( ulimit -H -n ) || 153 | warn "Could not query maximum file descriptor limit" 154 | esac 155 | case $MAX_FD in #( 156 | '' | soft) :;; #( 157 | *) 158 | # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. 159 | # shellcheck disable=SC2039,SC3045 160 | ulimit -n "$MAX_FD" || 161 | warn "Could not set maximum file descriptor limit to $MAX_FD" 162 | esac 163 | fi 164 | 165 | # Collect all arguments for the java command, stacking in reverse order: 166 | # * args from the command line 167 | # * the main class name 168 | # * -classpath 169 | # * -D...appname settings 170 | # * --module-path (only if needed) 171 | # * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. 172 | 173 | # For Cygwin or MSYS, switch paths to Windows format before running java 174 | if "$cygwin" || "$msys" ; then 175 | APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) 176 | CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) 177 | 178 | JAVACMD=$( cygpath --unix "$JAVACMD" ) 179 | 180 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 181 | for arg do 182 | if 183 | case $arg in #( 184 | -*) false ;; # don't mess with options #( 185 | /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath 186 | [ -e "$t" ] ;; #( 187 | *) false ;; 188 | esac 189 | then 190 | arg=$( cygpath --path --ignore --mixed "$arg" ) 191 | fi 192 | # Roll the args list around exactly as many times as the number of 193 | # args, so each arg winds up back in the position where it started, but 194 | # possibly modified. 195 | # 196 | # NB: a `for` loop captures its iteration list before it begins, so 197 | # changing the positional parameters here affects neither the number of 198 | # iterations, nor the values presented in `arg`. 199 | shift # remove old arg 200 | set -- "$@" "$arg" # push replacement arg 201 | done 202 | fi 203 | 204 | 205 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 206 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' 207 | 208 | # Collect all arguments for the java command: 209 | # * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, 210 | # and any embedded shellness will be escaped. 211 | # * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be 212 | # treated as '${Hostname}' itself on the command line. 213 | 214 | set -- \ 215 | "-Dorg.gradle.appname=$APP_BASE_NAME" \ 216 | -classpath "$CLASSPATH" \ 217 | org.gradle.wrapper.GradleWrapperMain \ 218 | "$@" 219 | 220 | # Stop when "xargs" is not available. 221 | if ! command -v xargs >/dev/null 2>&1 222 | then 223 | die "xargs is not available" 224 | fi 225 | 226 | # Use "xargs" to parse quoted args. 227 | # 228 | # With -n1 it outputs one arg per line, with the quotes and backslashes removed. 229 | # 230 | # In Bash we could simply go: 231 | # 232 | # readarray ARGS < <( xargs -n1 <<<"$var" ) && 233 | # set -- "${ARGS[@]}" "$@" 234 | # 235 | # but POSIX shell has neither arrays nor command substitution, so instead we 236 | # post-process each arg (as a line of input to sed) to backslash-escape any 237 | # character that might be a shell metacharacter, then use eval to reverse 238 | # that process (while maintaining the separation between arguments), and wrap 239 | # the whole thing up as a single "set" statement. 240 | # 241 | # This will of course break if any of these variables contains a newline or 242 | # an unmatched quote. 243 | # 244 | 245 | eval "set -- $( 246 | printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | 247 | xargs -n1 | 248 | sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | 249 | tr '\n' ' ' 250 | )" '"$@"' 251 | 252 | exec "$JAVACMD" "$@" 253 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem https://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | @rem SPDX-License-Identifier: Apache-2.0 17 | @rem 18 | 19 | @if "%DEBUG%"=="" @echo off 20 | @rem ########################################################################## 21 | @rem 22 | @rem Gradle startup script for Windows 23 | @rem 24 | @rem ########################################################################## 25 | 26 | @rem Set local scope for the variables with windows NT shell 27 | if "%OS%"=="Windows_NT" setlocal 28 | 29 | set DIRNAME=%~dp0 30 | if "%DIRNAME%"=="" set DIRNAME=. 31 | @rem This is normally unused 32 | set APP_BASE_NAME=%~n0 33 | set APP_HOME=%DIRNAME% 34 | 35 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 36 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 37 | 38 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 39 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 40 | 41 | @rem Find java.exe 42 | if defined JAVA_HOME goto findJavaFromJavaHome 43 | 44 | set JAVA_EXE=java.exe 45 | %JAVA_EXE% -version >NUL 2>&1 46 | if %ERRORLEVEL% equ 0 goto execute 47 | 48 | echo. 1>&2 49 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 50 | echo. 1>&2 51 | echo Please set the JAVA_HOME variable in your environment to match the 1>&2 52 | echo location of your Java installation. 1>&2 53 | 54 | goto fail 55 | 56 | :findJavaFromJavaHome 57 | set JAVA_HOME=%JAVA_HOME:"=% 58 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 59 | 60 | if exist "%JAVA_EXE%" goto execute 61 | 62 | echo. 1>&2 63 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 64 | echo. 1>&2 65 | echo Please set the JAVA_HOME variable in your environment to match the 1>&2 66 | echo location of your Java installation. 1>&2 67 | 68 | goto fail 69 | 70 | :execute 71 | @rem Setup the command line 72 | 73 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 74 | 75 | 76 | @rem Execute Gradle 77 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* 78 | 79 | :end 80 | @rem End local scope for the variables with windows NT shell 81 | if %ERRORLEVEL% equ 0 goto mainEnd 82 | 83 | :fail 84 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 85 | rem the _cmd.exe /c_ return code! 86 | set EXIT_CODE=%ERRORLEVEL% 87 | if %EXIT_CODE% equ 0 set EXIT_CODE=1 88 | if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% 89 | exit /b %EXIT_CODE% 90 | 91 | :mainEnd 92 | if "%OS%"=="Windows_NT" endlocal 93 | 94 | :omega 95 | -------------------------------------------------------------------------------- /settings.gradle.kts: -------------------------------------------------------------------------------- 1 | include(":app") 2 | --------------------------------------------------------------------------------