├── .gitignore ├── README.md ├── baksmali-2.5.2.jar ├── run.sh └── smali-2.5.2.jar /.gitignore: -------------------------------------------------------------------------------- 1 | tempCodeRunnerFile.sh 2 | services.jar 3 | services_bak.jar 4 | out 5 | services 6 | classes2.dex -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 在有root权限下破解Android系统签名,安装未系统签名的APK 2 | 3 | ## 前言 4 | 5 | 本文提到的相关工具和脚本同步在此:[https://github.com/chenls/Crack-Android-system-signature](https://github.com/chenls/Crack-Android-system-signature),可以在linux中使用的一站式脚本:[run.sh](https://github.com/chenls/Crack-Android-system-signature/blob/main/run.sh)。 6 | 7 | 在需要使用一些系统层面的API时(如:HIDL服务),我们APK中必须在应用程序的`AndroidManifest.xml`中的`manifest`节点中加入`android:sharedUserId="android.uid.system"`属性,在添加此属性后,往往需要使用Android源码编译或者使用对应的签名文件对APK签名,才能正常安装。 8 | 9 | 若未使用系统签名时,安装会报如下错误: 10 | 11 | ```bash 12 | $ adb install outputtxBJV3_double.apk 13 | Performing Streamed Install 14 | adb: failed to install outputtxBJV3_double.apk: Failure [INSTALL_FAILED_SHARED_USER_INCOMPATIBLE: Reconciliation failed...: Reconcile failed: Package com.example.test has no signatures that match those in shared user android.uid.system; ignoring!] 15 | ``` 16 | 17 | 对应的logcat log如下: 18 | 19 | ``` 20 | 04-15 16:38:35.099 1716 1815 W PackageManager: com.android.server.pm.PackageManagerService$ReconcileFailure: Reconcile failed: Package com.example.test has no signatures that match those in shared user android.uid.system; ignoring! 21 | 04-15 16:38:35.099 1716 1815 W PackageManager: at com.android.server.pm.PackageManagerService.reconcilePackagesLocked(PackageManagerService.java:16974) 22 | 04-15 16:38:35.099 1716 1815 W PackageManager: at com.android.server.pm.PackageManagerService.installPackagesLI(PackageManagerService.java:17366) 23 | 04-15 16:38:35.099 1716 1815 W PackageManager: at com.android.server.pm.PackageManagerService.installPackagesTracedLI(PackageManagerService.java:16693) 24 | 04-15 16:38:35.099 1716 1815 W PackageManager: at com.android.server.pm.PackageManagerService.lambda$processInstallRequestsAsync$22$PackageManagerService(PackageManagerService.java:14770) 25 | 04-15 16:38:35.099 1716 1815 W PackageManager: at com.android.server.pm.-$$Lambda$PackageManagerService$9znobjOH7ab0F1jsW2oFdNipS-8.run(Unknown Source:6) 26 | 04-15 16:38:35.099 1716 1815 W PackageManager: at android.os.Handler.handleCallback(Handler.java:938) 27 | 04-15 16:38:35.099 1716 1815 W PackageManager: at android.os.Handler.dispatchMessage(Handler.java:99) 28 | 04-15 16:38:35.099 1716 1815 W PackageManager: at android.os.Looper.loop(Looper.java:236) 29 | 04-15 16:38:35.099 1716 1815 W PackageManager: at android.os.HandlerThread.run(HandlerThread.java:67) 30 | 04-15 16:38:35.099 1716 1815 W PackageManager: at com.android.server.ServiceThread.run(ServiceThread.java:45) 31 | ``` 32 | 33 | 从log中,我们看到在安装APK时,`PackageManagerService.java`中抛出了异常。我们可以对出错的地方进行修改,从而破解Android系统签名,直接安装未系统签名的APK,接下来看看具体如何操作吧! 34 | 35 | ## 思路 36 | 37 | 总共分为7个步骤: 38 | 1. 通过Android源码找到`PackageManagerService.java`最终编译出来对应到设备的文件,也就是`/system/framework/services.jar`; 39 | 2. 从设备中pull出`services.jar`,提取`services.jar`中的`classes.dex`的文件; 40 | 3. 使用`baksmali`工具将`classes.dex`转成smali文件; 41 | 4. 修改smali文件中验证签名时报错的代码; 42 | 5. 使用`smali`工具将smali文件转回dex文件; 43 | 6. 将修改后的dex文件,重新打包成`services.jar`; 44 | 7. push修改后的`services.jar`到设备,然后重启,此时就可以直接安装未系统签名的APK了。 45 | 46 | ## 过程 47 | 48 | ### 查看android源码 49 | 50 | 根据报错信息`"has no signatures that match those in shared user"`我们可以查到对应的源码[PackageManagerServiceUtils.java](https://android.googlesource.com/platform/frameworks/base/+/refs/tags/android-mainline-11.0.0_r5/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java); 51 | 通过源码位置,我们倒推查看编译脚本。[services/core/Android.bp](https://android.googlesource.com/platform/frameworks/base/+/refs/tags/android-mainline-11.0.0_r5/services/core/Android.bp) 中编译了`PackageManagerServiceUtils.java`文件,生成`services.core` library,[services/Android.bp](https://android.googlesource.com/platform/frameworks/base/+/refs/tags/android-mainline-11.0.0_r5/services/Android.bp) 中依赖了`services.core` library,生成`services` library,也就是`services.jar`,对应到设备中`/system/framework/services.jar`文件。 52 | 53 | 我们要想对其原有逻辑修改,可以直接修改Android原生源码,编译后再push到设备中验证,但是由于一般的厂家都会对Android原生源码进行定制,导致源码不匹配。所以我们只能将设备当前的`/system/framework/services.jar`文件pull出来对其修改后,再push到原设备(注意此处需要root权限),以此保证其兼容性。 54 | 55 | pull services.jar文件,并解压: 56 | 57 | ```bash 58 | echo "pull /system/framework/services.jar" 59 | adb pull /system/framework/services.jar 60 | echo "backup services.jar to services_bak.jar" 61 | cp services.jar services_bak.jar 62 | 63 | echo "unzip services.jar to ./services dir" 64 | rm -rf services 65 | unzip services.jar -d services &>/dev/null 66 | ``` 67 | 68 | ### 解压services.jar得到classes.dex 69 | 70 | 查看services文件夹内容,其中有两个dex文件: 71 | 72 | ```bash 73 | $ tree services 74 | services 75 | ├── classes2.dex 76 | ├── classes.dex 77 | ├── com 78 | │ └── ... 79 | └── META-INF 80 | └── MANIFEST.MF 81 | 82 | 12 directories, 12 files 83 | ``` 84 | 85 | 根据报错信息,查找我们要修改源码对应的dex文件: 86 | 87 | ```bash 88 | $ tree 89 | dex=$(grep -lr "has no signatures that match those in shared user" services) 90 | echo "need modify file: $dex" 91 | ``` 92 | 93 | ### baksmali反编译 94 | 95 | jar工具包:smali和baksmali,下载地址:[https://bitbucket.org/JesusFreke/smali/downloads/](https://bitbucket.org/JesusFreke/smali/downloads/),此处我们使用目前最新版本:2.5.2。 96 | 97 | 使用baksmali-2.5.2.jar反编译dex得到smali文件: 98 | 99 | ```bash 100 | echo "dex2smali to ./out dir" 101 | rm -rf out 102 | java -jar baksmali-2.5.2.jar d $dex 103 | ``` 104 | 105 | ### 修改smali文件 106 | 107 | [PackageManagerServiceUtils.java](https://android.googlesource.com/platform/frameworks/base/+/refs/tags/android-mainline-11.0.0_r5/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java)的源码: 108 | 109 | ```java 110 | public static boolean verifySignatures(PackageSetting pkgSetting, 111 | PackageSetting disabledPkgSetting, PackageParser.SigningDetails parsedSignatures, 112 | boolean compareCompat, boolean compareRecover) 113 | throws PackageManagerException { 114 | ... 115 | // line:689 116 | if (!match) { 117 | throw new PackageManagerException(INSTALL_FAILED_SHARED_USER_INCOMPATIBLE, 118 | "Package " + packageName 119 | + " has no signatures that match those in shared user " 120 | + pkgSetting.getSharedUser().name + "; ignoring!"); 121 | } 122 | ... 123 | // line:725 124 | if (!parsedSignatures.hasCommonAncestor( 125 | pkgSetting.getSharedUser().signatures.mSigningDetails)) { 126 | throw new PackageManagerException(INSTALL_FAILED_SHARED_USER_INCOMPATIBLE, 127 | "Package " + packageName + " has a signing lineage " 128 | + "that diverges from the lineage of the sharedUserId"); 129 | } 130 | ... 131 | } 132 | ``` 133 | 134 | 我们可以直接修改`verifySignatures()`方法中如上两个if处,使其条件不成立,从而不会抛出异常。 135 | 136 | 对应到的smali代码,将if-eqz改成if-nez ,即将if==0 改成 if!=0: 137 | 138 | ```smali 139 | .line 725 140 | invoke-virtual {p2, v5}, Landroid/content/pm/PackageParser$SigningDetails;->hasCommonAncestor(Landroid/content/pm/PackageParser$SigningDetails;)Z 141 | 142 | move-result v5 143 | 144 | if-eqz v5, :cond_16f // 将其改成if-nez v2, :cond_16f,即将if==0 改成 if!=0 145 | 146 | goto :goto_1b1 147 | 148 | .line 727 149 | :cond_16f 150 | 151 | ... 152 | 153 | const-string v3, " has a signing lineage that diverges from the lineage of the sharedUserId" 154 | 155 | ... 156 | 157 | invoke-direct {v5, v4, v3}, Lcom/android/server/pm/PackageManagerException;->(ILjava/lang/String;)V 158 | 159 | throw v5 160 | 161 | ... 162 | 163 | 164 | 165 | .line 689 166 | :cond_105 167 | const/4 v4, -0x8 168 | 169 | if-eqz v2, :cond_189 // 将其改成if-nez v2, :cond_189 ,即将if==0 改成 if!=0 170 | 171 | ... 172 | 173 | :cond_189 174 | new-instance v5, Lcom/android/server/pm/PackageManagerException; 175 | 176 | ... 177 | 178 | const-string v3, " has no signatures that match those in shared user " 179 | 180 | invoke-virtual {v6, v3}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder; 181 | ``` 182 | 183 | smali相关语法可参考:[Smali基础语法总结](https://www.cnblogs.com/bmjoker/p/10506623.html)。 184 | 185 | 对应bash修改脚本: 186 | 187 | ```bash 188 | modify() { 189 | # 文件和行号 190 | file_and_line=$(grep -nr "$1" out) 191 | if [ -n "$file_and_line" ]; then 192 | # 文件 193 | file=$(echo $file_and_line | awk -F ":" '{print $1}') 194 | # 行号 195 | line_e=$(echo $file_and_line | awk -F ":" '{print $2}') 196 | # 倒推30行 197 | let "line_s=line_e-30" 198 | # 部分内容 199 | # cat $file | head -n $line_e | tail -n +$line_s 200 | modify_content=$(cat $file | head -n $line_e | tail -n +$line_s | grep ':cond_' | tail -1) 201 | # 需要修改的所在行号 202 | modify_content_str=$(grep -n $modify_content $file) 203 | modify_content_line=$(echo $modify_content_str | awk -F ":" '{print $1}') 204 | # 进行修改 205 | sed -i "${modify_content_line}s/if-eqz/if-nez/g" $file 206 | echo "$file:$modify_content_line modify 'if-eqz --> if-nez'" 207 | else 208 | echo "!!! not found: $1" 209 | fi 210 | } 211 | 212 | modify "has no signatures that match those in shared user" 213 | modify "has a signing lineage that diverges from the lineage of the sharedUserId" 214 | ``` 215 | 216 | ### smali编译 217 | 218 | 将修改后的smali文件,编译成dex文件: 219 | 220 | ```bash 221 | echo "smali2dex to ./out.dex file" 222 | java -jar smali-2.5.2.jar a out 223 | echo "move ./out.dex to $dex file" 224 | mv out.dex $dex 225 | ``` 226 | ### 重新打包jar 227 | 228 | 将修改后的classes.dex,打包成jar: 229 | 230 | ```bash 231 | echo "re tar ./services ./services.jar file" 232 | # 也可以归档管理器直接打开,不解压替换classes2.dex 233 | jar cvfm services.jar services/META-INF/MANIFEST.MF -C services/ . &>/dev/null 234 | ``` 235 | 236 | ### push services.jar并重启 237 | 238 | 将修改后的services.jar push到设备并重启: 239 | 240 | ```bash 241 | echo "push ./services.jar file" 242 | adb wait-for-device root 243 | adb remount 244 | adb push services.jar /system/framework/services.jar 245 | adb reboot 246 | ``` 247 | ## 总结 248 | 249 | 在有root权限情况下,我们通过`smali`相关工具反编译`services.jar`后,对其修改后,达到了直接安装需要系统签名的APK。 -------------------------------------------------------------------------------- /baksmali-2.5.2.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chenls/Crack-Android-system-signature/2fcc8a36d57c4ec259e649e64c313a77b29d8fa9/baksmali-2.5.2.jar -------------------------------------------------------------------------------- /run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | dir=$(dirname $(readlink -f "$0")) 4 | cd $dir 5 | echo "pull /system/framework/services.jar" 6 | adb pull /system/framework/services.jar 7 | echo "backup services.jar to services_bak.jar" 8 | cp services.jar services_bak.jar 9 | 10 | echo "unzip services.jar to ./services dir" 11 | rm -rf services 12 | unzip services.jar -d services &>/dev/null 13 | 14 | dex=$(grep -lr "has no signatures that match those in shared user" services) 15 | echo "need modify file: $dex" 16 | echo "dex2smali to ./out dir" 17 | rm -rf out 18 | java -jar baksmali-2.5.2.jar d $dex 19 | 20 | modify() { 21 | # 文件和行号 22 | file_and_line=$(grep -nr "$1" out) 23 | if [ -n "$file_and_line" ]; then 24 | # 文件 25 | file=$(echo $file_and_line | awk -F ":" '{print $1}') 26 | # 行号 27 | line_e=$(echo $file_and_line | awk -F ":" '{print $2}') 28 | # 倒推30行 29 | let "line_s=line_e-30" 30 | # 部分内容 31 | # cat $file | head -n $line_e | tail -n +$line_s 32 | modify_content=$(cat $file | head -n $line_e | tail -n +$line_s | grep ':cond_' | tail -1) 33 | # 需要修改的所在行号 34 | modify_content_str=$(grep -n $modify_content $file) 35 | modify_content_line=$(echo $modify_content_str | awk -F ":" '{print $1}') 36 | # 进行修改 37 | sed -i "${modify_content_line}s/if-eqz/if-nez/g" $file 38 | echo "$file:$modify_content_line modify 'if-eqz --> if-nez'" 39 | else 40 | echo "!!! not found: $1" 41 | fi 42 | } 43 | 44 | modify "has no signatures that match those in shared user" 45 | modify "has a signing lineage that diverges from the lineage of the sharedUserId" 46 | 47 | echo "smali2dex to ./out.dex file" 48 | java -jar smali-2.5.2.jar a out 49 | echo "move ./out.dex to $dex file" 50 | mv out.dex $dex 51 | 52 | echo "re tar ./services ./services.jar file" 53 | # 也可以归档管理器直接打开,不解压替换classes2.dex 54 | jar cvfm services.jar services/META-INF/MANIFEST.MF -C services/ . &>/dev/null 55 | 56 | echo "push ./services.jar file" 57 | adb wait-for-device root 58 | adb remount 59 | adb push services.jar /system/framework/services.jar 60 | adb reboot 61 | cd - 62 | -------------------------------------------------------------------------------- /smali-2.5.2.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chenls/Crack-Android-system-signature/2fcc8a36d57c4ec259e649e64c313a77b29d8fa9/smali-2.5.2.jar --------------------------------------------------------------------------------