首页
社区
课程
招聘
10
[原创] Android 签名对抗攻略
发表于: 2023-7-28 23:09 16169

[原创] Android 签名对抗攻略

2023-7-28 23:09
16169

写在前面

本篇共分为 PMS 和 IO 重定向两个主要部分,其中IO重定向部分实现了 InLine Hook

前置知识

解包打包工具

apktool

dex反编译smali、xml解析、生成资源序号文件与资源名称对应表

apktool.jar -r d HelloWorld.apk

smali文件编译为应用,应用生成目录为反编译应用的 dist 目录中

apktool.jar b HelloWorld

签名工具

apksigner

查看目标应用是否签名,及使用的签名版本

1
2
3
4
5
6
7
8
9
java -jar apksigner.jar verify -v app-debug.apk
-------------------------
Verifies
Verified using v1 scheme (JAR signing): false
Verified using v2 scheme (APK Signature Scheme v2): true
Verified using v3 scheme (APK Signature Scheme v3): false
Verified using v4 scheme (APK Signature Scheme v4): false
Verified for SourceStamp: false
Number of signers: 1

zipalign

查看目标应用是否对齐

1
2
3
zipalign -c -v 4 app-debug.apk
----------------
Verification succesful

制作对齐的应用

1
zipalign -v 4 app-debug.apk zipalign.apk

keytool

制作签名,会生成一个 demo.keystore 签名文件

1
keytool -genkey -alias demo.keystore -keyalg RSA -validity 40000 -keystore demo.keystore

使用生成的签名文件对目标应用进行签名

1
java -jar apksigner.jar sign --ks demo.keystore --ks-key-alias demo.keystore --ks-pass pass:123456 --key-pass pass:123456 --out sign.apk app-debug.apk

AndroidStudio 中配置签名

在 build.gradle(app) 中添加 signingConfigs 字段,另外注意 buildTypes 中 signingConfig 应分别为 signingConfigs.debug 和 signingConfigs.release

1
2
3
4
5
6
7
8
signingConfigs {
    release {
        storeFile file('C:\\Users\\lxz\\Documents\\mytools\\sign\\demo.keystore.jks')
        storePassword '123456'
        keyAlias 'demo.keystore'
        keyPassword '123456'
    }
}

GetSignature

首先我们需要制作一个可以获取其他 app 签名的工具,这里直接写一个可以获取其他应用 signature 的 app,需要注意的就是权限配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
package com.example.myapplication;
 
import androidx.appcompat.app.AppCompatActivity;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.SigningInfo;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.TextView;
import com.example.myapplication.databinding.ActivityMainBinding;
 
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
 
 
public class MainActivity extends AppCompatActivity {
    private ActivityMainBinding binding;
 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        binding = ActivityMainBinding.inflate(getLayoutInflater());
        setContentView(binding.getRoot());
 
        TextView textView = findViewById(R.id.mytext);
         
        String str = getSignatuer(this,"com.example.myapplication4");
 
        Log.e("lxz" , "获取到目标签名:" + str);
 
    }
 
    private String getSignatuer(Context context, String packagename){
        try {
 
            PackageInfo info = context.getPackageManager().getPackageInfo(packagename, PackageManager.GET_SIGNATURES);
            if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.P) {
                SigningInfo signingInfo = info.signingInfo;
            }else{
                Log.e("lxz","未获取到签名信息");
            }
            byte[] bytes = info.signatures[0].toByteArray();
            String str = bytesToHex(bytes);
            return str;
        } catch (PackageManager.NameNotFoundException e) {
            throw new RuntimeException(e);
        }
    }
 
    // 将 byte[] 转换为 16 进制字符串
    public static String bytesToHex(byte[] bytes) {
        StringBuilder hexString = new StringBuilder();
        for (byte b : bytes) {
            String hex = Integer.toHexString(0xFF & b);
            if (hex.length() == 1) {
                hexString.append('0');
            }
            hexString.append(hex);
        }
        return hexString.toString();
    }
 
    // 16 进制字符串转换为 byte[]
    public static byte[] hexToBytes(String hexString) {
        int length = hexString.length();
        if (length % 2 != 0) {
            throw new IllegalArgumentException("Invalid hex string length");
        }
        byte[] bytes = new byte[length / 2];
        for (int i = 0; i < length; i += 2) {
            String hex = hexString.substring(i, i + 2);
            bytes[i / 2] = (byte) Integer.parseInt(hex, 16);
        }
        return bytes;
    }
 
}

注意权限配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools">
    <application
        android:allowBackup="true"
        android:dataExtractionRules="@xml/data_extraction_rules"
        android:fullBackupContent="@xml/backup_rules"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:theme="@style/Theme.MyApplication"
        tools:targetApi="31">
        <activity
            android:name=".MainActivity"
            android:exported="true">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            intent-filter>
        activity>
    application>
    <uses-permission android:name="android.permission.GET_PACKAGE_SIZE" />
    <uses-permission android:name="android.permission.GET_PACKAGE_NAME" />
    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.GET_INSTALLED_PACKAGES" />
    <uses-permission android:name="android.permission.QUERY_ALL_PACKAGES" tools:ignore="QueryAllPackagesPermission" />
manifest>

CheckSignature

然后我们还需要写一个目标 app 作为实验对象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
package com.example.checksignatuer;
 
import androidx.appcompat.app.AppCompatActivity;
 
import android.content.Context;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.SigningInfo;
import android.os.Bundle;
import android.util.Log;
import android.widget.TextView;
 
public class MainActivity extends AppCompatActivity {
 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
 
        TextView textView = findViewById(R.id.mytext);
 
        String str = getSignatuer(this);
        if(checkSignatuer(str))
        {
            Log.d("lxz","签名正确");
            textView.setText("签名正确");
        }else{
            Log.d("lxz","签名错误");
            textView.setText("签名错误");
        }
    }
 
    private boolean checkSignatuer(String str)
    {
        // 这里的 signature_str 可以使用 GetSignature 获取
        String signature_str = "308202e4308201cc020101300d06092a864886f70d01010b050030373116301406035504030c0d416e64726f69642044656275673110300e060355040a0c07416e64726f6964310b30090603550406130255533020170d3233303430363038313332325a180f32303533303332393038313332325a30373116301406035504030c0d416e64726f69642044656275673110300e060355040a0c07416e64726f6964310b300906035504061302555330820122300d06092a864886f70d01010105000382010f003082010a02820101009e80d9990b9622e00c04c4608d404c89ab3b5f28ea1ababfe2c9e4d172d3004c1a0c4494fb3359dc0071024738d942ae7b2db78a5f5898261ef1e49a353651facc6c7aca2a7d2ace9bfb158f63a2177a7c7d7dd18e0f57ca59dd56d325d14b6a697257f20e9f923363ac7724ac4e6c2600648fd81f8dc85db648a8d8e06947d15c8c89bbb469e86c685bb6165ec936264c8af54f04f86794887371c564d6340c838e4821dd3e72824dfcc0246efab42241324887de2fbe043113d4544e6e6c3c6b42a77ad8f50f91f8c43fc2e2cf4c3de689995326fedbfd8f86606ec9ffae1e5e30bc4f5296fd8d30ac0117cd66efba7292ea1377a56f9890fa9948ec9b57010203010001300d06092a864886f70d01010b05000382010100754cf3804666464192d206c9f76354b91e88d664fd553f0dceababf007d26eb208424fb92829dc029b0b291ccab55b642bdc0c8b9346089552970460918306262218bf6c776eb803019928568a53ed97a970003c570e20fd472170e0057203ed7ed8118fb944f984e78536b020f44558e518f46f70132216d4162d9363a2ccc62a53083b7e3a3df4b8da03bc7cd8b06b8d193b2b33aa20acc66c9f53cb0c2bd2eeb691285e8cc3eeb897c160ddf916f556a4606527e9e1b9d3856000193af4641dbc951660cf018621267486ac7b4b0d57c7e64e9880ce5ae4e70cc37cb72bdc5f2fef1b50004872844a23f8706b226349583316e3ed7770eb662bd3567ffb96";
 
        if(str.equals(signature_str))
        {
            return true;
        }else{
            return false;
        }
    }
 
    private String getSignatuer(Context context){
        try {
            PackageInfo info = context.getPackageManager().getPackageInfo(context.getPackageName(), PackageManager.GET_SIGNATURES);
            if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.P) {
                SigningInfo signingInfo = info.signingInfo;
            }else{
                Log.e("lxz","未获取到签名信息");
            }
            byte[] bytes = info.signatures[0].toByteArray();
            String str = bytesToHex(bytes);
            return str;
        } catch (PackageManager.NameNotFoundException e) {
            throw new RuntimeException(e);
        }
    }
 
    // 将 byte[] 转换为 16 进制字符串
    public static String bytesToHex(byte[] bytes) {
        StringBuilder hexString = new StringBuilder();
        for (byte b : bytes) {
            String hex = Integer.toHexString(0xFF & b);
            if (hex.length() == 1) {
                hexString.append('0');
            }
            hexString.append(hex);
        }
        return hexString.toString();
    }
 
    // 将 16 进制字符串转换为 byte[]
    public static byte[] hexToBytes(String hexString) {
        int length = hexString.length();
        if (length % 2 != 0) {
            throw new IllegalArgumentException("Invalid hex string length");
        }
        byte[] bytes = new byte[length / 2];
        for (int i = 0; i < length; i += 2) {
            String hex = hexString.substring(i, i + 2);
            bytes[i / 2] = (byte) Integer.parseInt(hex, 16);
        }
        return bytes;
    }
}

PMS 签名

PMS 是 PackageManagerSignature 的缩写,其原理是将目标解包后添加一个父类,在父类中重写 PackageManager 中的 getPackageManager

JAVA 层实现

Java 层实现的核心代码如下

java/com/lxz/hookactivity.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
package com.lxz;
 
import android.content.ComponentName;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
import android.content.pm.ChangedPackages;
import android.content.pm.FeatureInfo;
import android.content.pm.InstrumentationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageInstaller;
import android.content.pm.PackageManager;
import android.content.pm.PermissionGroupInfo;
import android.content.pm.PermissionInfo;
import android.content.pm.ProviderInfo;
import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
import android.content.pm.SharedLibraryInfo;
import android.content.pm.Signature;
import android.content.pm.VersionedPackage;
import android.content.res.Resources;
import android.content.res.XmlResourceParser;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.os.UserHandle;
import android.util.Log;
 
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
 
import java.util.List;
 
public class hook extends PackageManager {
    private PackageManager mBase;
    private String mPackageName;
 
    // 此处的签名使用 GetSignature 获取原包的签名信息
    String signature_str = "3082037130820259a003020102020419f0a927300d06092a864886f70d01010b05003068310b300906035504061302434e310f300d0603550408130646754a69616e310f300d0603550407130646755a686f753111300f060355040a13084c69616e596f6e673111300f060355040b13084c69616e596f6e673111300f060355040313084c6f756973204c753020170d3138303632393037323931365a180f32303733303430313037323931365a3068310b300906035504061302434e310f300d0603550408130646754a69616e310f300d0603550407130646755a686f753111300f060355040a13084c69616e596f6e673111300f060355040b13084c69616e596f6e673111300f060355040313084c6f756973204c7530820122300d06092a864886f70d01010105000382010f003082010a0282010100a55431f01fb453e65d7e070bc82e606c11e9bf77831367701e4d7c79a44c014afa2be320caade2e75f8d9160ecaa6e5a39ca63d8ee5ddaffe54f6da0d1f7ea24efa9591681fa39561780c2bef75ec72096e121524da2f9c84d9455593639e63ca41cdbf7a349e0e26cf5f27564825fa524eb3efdbac5ec62f851053cc833537182e6d24dffaaf50274e6062650d527d76856e188d144116731689881a05db10d8bb159bbef9cfd314b205c785e51d4a34e0db54fa89b7ddb837559338f1f58e38df78f7e5acceeaf94546c78d1b8eea3a25e095fc1c959e77860962b3e980e31b63c3089e3541e27cea1631c3b2c59bcfd4c7384123c778c599473a3a319b2270203010001a321301f301d0603551d0e04160414fc7d539fc8aea2e08ade9cd07c47f43621f3b209300d06092a864886f70d01010b05000382010100088fe8de887969eb896e5d9c31aead82bc348faff1917fb224018a38f6d0126e0a9af191bf84ca84cf530cbe2ba0a4993059ae89ce2a05266a8192b044b4a8e18e510a8c6b7e022bebe5482b09a7b80f47661adf9f53fd65b69cf3acb2efc69b89bac3e90eabf1e7ed719b0efd38159cb5f3fea51ee62307ca5f09cbb85660323a41597438aba3999d3626fcbfa628d5510a435c78a82482d1447c3cff3ea19a7ae87d347b7e5e7b0237029cd2e5e57baa907bde58cb5483ef54dcee05fabaadb1a46c88113d85333c6979d846490d3e8def5aa4c3d94d2fc6497bea36901e6a18e1000db8da1f4bb31421138fbf2cb3a22d0458ef28e7167458278a79bf67ef";
 
    public hook(PackageManager base, String packageName) {
        this.mPackageName = packageName;
        this.mBase = base;
    }
 
    @Override // android.content.pm.PackageManager
    public PackageInfo getPackageInfo(String packageName, int flags) throws PackageManager.NameNotFoundException {
 
        if (!mPackageName.equals(packageName)) {
            // 不是自己在检查 PackageInfo 信息,返回真实信息
            return this.mBase.getPackageInfo(packageName, flags);
        }
        if (flags != PackageManager.GET_SIGNATURES) {
            // 检查的不是 signature, 返回真实信息
            return this.mBase.getPackageInfo(packageName, flags);
        }
 
        PackageInfo pkgInfo = new PackageInfo();
        byte bytes[] = hexToBytes(signature_str);
        pkgInfo.signatures = new Signature[]{new Signature(bytes)};
        Log.e("lxz","强制返回正确签名");
        return pkgInfo;
    }
 
    // 将 byte[] 转换为 16 进制字符串
    public static String bytesToHex(byte[] bytes) {
        StringBuilder hexString = new StringBuilder();
        for (byte b : bytes) {
            String hex = Integer.toHexString(0xFF & b);
            if (hex.length() == 1) {
                hexString.append('0');
            }
            hexString.append(hex);
        }
        return hexString.toString();
    }
 
    // 将 16 进制字符串转换为 byte[]
    public static byte[] hexToBytes(String hexString) {
        int length = hexString.length();
        if (length % 2 != 0) {
            throw new IllegalArgumentException("Invalid hex string length");
        }
        byte[] bytes = new byte[length / 2];
        for (int i = 0; i < length; i += 2) {
            String hex = hexString.substring(i, i + 2);
            bytes[i / 2] = (byte) Integer.parseInt(hex, 16);
        }
        return bytes;
    }
 
    @Override
    public PackageInfo getPackageInfo(@NonNull VersionedPackage versionedPackage, int flags) throws NameNotFoundException {
        // 这里好像也可以返回 PackageInfo,但我没做处理
        return this.mBase.getPackageInfo(versionedPackage, flags);
    }
    @Override
    public List getInstalledPackages(int flags) {
        return this.mBase.getInstalledPackages(flags);
    }
    @Override
    public String[] currentToCanonicalPackageNames(String[] names) {
        return this.mBase.currentToCanonicalPackageNames(names);
    }
    @Override
    public String[] canonicalToCurrentPackageNames(String[] names) {
        return this.mBase.canonicalToCurrentPackageNames(names);
    }
    @Override
    public Intent getLaunchIntentForPackage(String packageName) {
        return this.mBase.getLaunchIntentForPackage(packageName);
    }
    @Override
    public Intent getLeanbackLaunchIntentForPackage(String packageName) {
        return this.mBase.getLeanbackLaunchIntentForPackage(packageName);
    }
    @Override
    public int[] getPackageGids(String packageName) throws PackageManager.NameNotFoundException {
        return this.mBase.getPackageGids(packageName);
    }
    @Override
    public int[] getPackageGids(@NonNull String packageName, int flags) throws NameNotFoundException {
        return new int[0];
    }
    @Override
    public int getPackageUid(@NonNull String packageName, int flags) throws NameNotFoundException {
        return 0;
    }
    @Override
    public PermissionInfo getPermissionInfo(String name, int flags) throws PackageManager.NameNotFoundException {
        return this.mBase.getPermissionInfo(name, flags);
    }
    @Override
    public List queryPermissionsByGroup(String group, int flags) throws PackageManager.NameNotFoundException {
        return this.mBase.queryPermissionsByGroup(group, flags);
    }
    @Override
    public PermissionGroupInfo getPermissionGroupInfo(String name, int flags) throws PackageManager.NameNotFoundException {
        return this.mBase.getPermissionGroupInfo(name, flags);
    }
    @Override
    public List getAllPermissionGroups(int flags) {
        return this.mBase.getAllPermissionGroups(flags);
    }
    @Override
    public ApplicationInfo getApplicationInfo(String packageName, int flags) throws PackageManager.NameNotFoundException {
        return this.mBase.getApplicationInfo(packageName, flags);
    }
    @Override
    public ActivityInfo getActivityInfo(ComponentName component, int flags) throws PackageManager.NameNotFoundException {
        return this.mBase.getActivityInfo(component, flags);
    }
    @Override
    public ActivityInfo getReceiverInfo(ComponentName component, int flags) throws PackageManager.NameNotFoundException {
        return this.mBase.getReceiverInfo(component, flags);
    }
    @Override
    public ServiceInfo getServiceInfo(ComponentName component, int flags) throws PackageManager.NameNotFoundException {
        return this.mBase.getServiceInfo(component, flags);
    }
    @Override
    public ProviderInfo getProviderInfo(ComponentName component, int flags) throws PackageManager.NameNotFoundException {
        return this.mBase.getProviderInfo(component, flags);
    }
    @Override
    public List getPackagesHoldingPermissions(String[] permissions, int flags) {
        return this.mBase.getPackagesHoldingPermissions(permissions, flags);
    }
    @Override
    public int checkPermission(String permName, String pkgName) {
        return this.mBase.checkPermission(permName, pkgName);
    }
    @Override
    public boolean isPermissionRevokedByPolicy(String permName, String pkgName) {
        return this.mBase.isPermissionRevokedByPolicy(permName, pkgName);
    }
    @Override
    public boolean addPermission(PermissionInfo info) {
        return this.mBase.addPermission(info);
    }
    @Override
    public boolean addPermissionAsync(PermissionInfo info) {
        return this.mBase.addPermissionAsync(info);
    }
    @Override
    public void removePermission(String name) {
        this.mBase.removePermission(name);
    }
    @Override
    public int checkSignatures(String pkg1, String pkg2) {
        return this.mBase.checkSignatures(pkg1, pkg2);
    }
    @Override
    public int checkSignatures(int uid1, int uid2) {
        return this.mBase.checkSignatures(uid1, uid2);
    }
    @Override
    public String[] getPackagesForUid(int uid) {
        return this.mBase.getPackagesForUid(uid);
    }
    @Override
    public String getNameForUid(int uid) {
        return this.mBase.getNameForUid(uid);
    }
    @Override
    public List getInstalledApplications(int flags) {
        return this.mBase.getInstalledApplications(flags);
    }
    @Override
    public boolean isInstantApp() {
        return false;
    }
    @Override
    public boolean isInstantApp(@NonNull String packageName) {
        return false;
    }
    @Override
    public int getInstantAppCookieMaxBytes() {
        return 0;
    }
    @NonNull
    @Override
    public byte[] getInstantAppCookie() {
        return new byte[0];
    }
    @Override
    public void clearInstantAppCookie() {
 
    }
    @Override
    public void updateInstantAppCookie(@Nullable byte[] cookie) {
 
    }
    @Override
    public String[] getSystemSharedLibraryNames() {
        return this.mBase.getSystemSharedLibraryNames();
    }
    @NonNull
    @Override
    public List getSharedLibraries(int flags) {
        return null;
    }
 
    @Nullable
    @Override
    public ChangedPackages getChangedPackages(int sequenceNumber) {
        return null;
    }
    @Override
    public FeatureInfo[] getSystemAvailableFeatures() {
        return this.mBase.getSystemAvailableFeatures();
    }
    @Override
    public boolean hasSystemFeature(String name) {
        return this.mBase.hasSystemFeature(name);
    }
 
    @Override
    public boolean hasSystemFeature(@NonNull String featureName, int version) {
        return false;
    }
    @Override
    public ResolveInfo resolveActivity(Intent intent, int flags) {
        return this.mBase.resolveActivity(intent, flags);
    }
    @Override
    public List queryIntentActivities(Intent intent, int flags) {
        return this.mBase.queryIntentActivities(intent, flags);
    }
    @Override
    public List queryIntentActivityOptions(ComponentName caller, Intent[] specifics, Intent intent, int flags) {
        return this.mBase.queryIntentActivityOptions(caller, specifics, intent, flags);
    }
    @Override
    public List queryBroadcastReceivers(Intent intent, int flags) {
        return this.mBase.queryBroadcastReceivers(intent, flags);
    }
    @Override
    public ResolveInfo resolveService(Intent intent, int flags) {
        return this.mBase.resolveService(intent, flags);
    }
    @Override
    public List queryIntentServices(Intent intent, int flags) {
        return this.mBase.queryIntentServices(intent, flags);
    }
    @Override
    public List queryIntentContentProviders(Intent intent, int flags) {
        return this.mBase.queryIntentContentProviders(intent, flags);
    }
    @Override
    public ProviderInfo resolveContentProvider(String name, int flags) {
        return this.mBase.resolveContentProvider(name, flags);
    }
    @Override
    public List queryContentProviders(String processName, int uid, int flags) {
        return this.mBase.queryContentProviders(processName, uid, flags);
    }
    @Override
    public InstrumentationInfo getInstrumentationInfo(ComponentName className, int flags) throws PackageManager.NameNotFoundException {
        return this.mBase.getInstrumentationInfo(className, flags);
    }
    @Override
    public List queryInstrumentation(String targetPackage, int flags) {
        return this.mBase.queryInstrumentation(targetPackage, flags);
    }
    @Override
    public Drawable getDrawable(String packageName, int resid, ApplicationInfo appInfo) {
        return this.mBase.getDrawable(packageName, resid, appInfo);
    }
    @Override
    public Drawable getActivityIcon(ComponentName activityName) throws PackageManager.NameNotFoundException {
        return this.mBase.getActivityIcon(activityName);
    }
    @Override
    public Drawable getActivityIcon(Intent intent) throws PackageManager.NameNotFoundException {
        return this.mBase.getActivityIcon(intent);
    }
    @Override
    public Drawable getActivityBanner(ComponentName activityName) throws PackageManager.NameNotFoundException {
        return this.mBase.getActivityBanner(activityName);
    }
    @Override
    public Drawable getActivityBanner(Intent intent) throws PackageManager.NameNotFoundException {
        return this.mBase.getActivityBanner(intent);
    }
    @Override
    public Drawable getDefaultActivityIcon() {
        return this.mBase.getDefaultActivityIcon();
    }
    @Override
    public Drawable getApplicationIcon(ApplicationInfo info) {
        return this.mBase.getApplicationIcon(info);
    }
    @Override
    public Drawable getApplicationIcon(String packageName) throws PackageManager.NameNotFoundException {
        return this.mBase.getApplicationIcon(packageName);
    }
    @Override
    public Drawable getApplicationBanner(ApplicationInfo info) {
        return this.mBase.getApplicationBanner(info);
    }
    @Override
    public Drawable getApplicationBanner(String packageName) throws PackageManager.NameNotFoundException {
        return this.mBase.getApplicationBanner(packageName);
    }
    @Override
    public Drawable getActivityLogo(ComponentName activityName) throws PackageManager.NameNotFoundException {
        return this.mBase.getActivityLogo(activityName);
    }
    @Override
    public Drawable getActivityLogo(Intent intent) throws PackageManager.NameNotFoundException {
        return this.mBase.getActivityLogo(intent);
    }
    @Override
    public Drawable getApplicationLogo(ApplicationInfo info) {
        return this.mBase.getApplicationLogo(info);
    }
    @Override
    public Drawable getApplicationLogo(String packageName) throws PackageManager.NameNotFoundException {
        return this.mBase.getApplicationLogo(packageName);
    }
    @Override
    public Drawable getUserBadgedIcon(Drawable icon, UserHandle user) {
        return this.mBase.getUserBadgedIcon(icon, user);
    }
    @Override
    public Drawable getUserBadgedDrawableForDensity(Drawable drawable, UserHandle user, Rect badgeLocation, int badgeDensity) {
        return this.mBase.getUserBadgedDrawableForDensity(drawable, user, badgeLocation, badgeDensity);
    }
    @Override
    public CharSequence getUserBadgedLabel(CharSequence label, UserHandle user) {
        return this.mBase.getUserBadgedLabel(label, user);
    }
    @Override
    public CharSequence getText(String packageName, int resid, ApplicationInfo appInfo) {
        return this.mBase.getText(packageName, resid, appInfo);
    }
    @Override
    public XmlResourceParser getXml(String packageName, int resid, ApplicationInfo appInfo) {
        return this.mBase.getXml(packageName, resid, appInfo);
    }
    @Override
    public CharSequence getApplicationLabel(ApplicationInfo info) {
        return this.mBase.getApplicationLabel(info);
    }
    @Override
    public Resources getResourcesForActivity(ComponentName activityName) throws PackageManager.NameNotFoundException {
        return this.mBase.getResourcesForActivity(activityName);
    }
    @Override
    public Resources getResourcesForApplication(ApplicationInfo app) throws PackageManager.NameNotFoundException {
        return this.mBase.getResourcesForApplication(app);
    }
    @Override
    public Resources getResourcesForApplication(String appPackageName) throws PackageManager.NameNotFoundException {
        return this.mBase.getResourcesForApplication(appPackageName);
    }
    @Override
    public void verifyPendingInstall(int id, int verificationCode) {
        this.mBase.verifyPendingInstall(id, verificationCode);
    }
    @Override
    public void extendVerificationTimeout(int id, int verificationCodeAtTimeout, long millisecondsToDelay) {
        this.mBase.extendVerificationTimeout(id, verificationCodeAtTimeout, millisecondsToDelay);
    }
    @Override
    public void setInstallerPackageName(String targetPackage, String installerPackageName) {
        this.mBase.setInstallerPackageName(targetPackage, installerPackageName);
    }
    @Override
    public String getInstallerPackageName(String packageName) {
        return this.mBase.getInstallerPackageName(packageName);
    }
    @Override
    public void addPackageToPreferred(String packageName) {
        this.mBase.addPackageToPreferred(packageName);
    }
    @Override
    public void removePackageFromPreferred(String packageName) {
        this.mBase.removePackageFromPreferred(packageName);
    }
    @Override
    public List getPreferredPackages(int flags) {
        return this.mBase.getPreferredPackages(flags);
    }
    @Override
    public void addPreferredActivity(IntentFilter filter, int match, ComponentName[] set, ComponentName activity) {
        this.mBase.addPreferredActivity(filter, match, set, activity);
    }
    @Override
    public void clearPackagePreferredActivities(String packageName) {
        this.mBase.clearPackagePreferredActivities(packageName);
    }
    @Override
    public int getPreferredActivities(List outFilters, List outActivities, String packageName) {
        return this.mBase.getPreferredActivities(outFilters, outActivities, packageName);
    }
    @Override
    public void setComponentEnabledSetting(ComponentName componentName, int newState, int flags) {
        this.mBase.setComponentEnabledSetting(componentName, newState, flags);
    }
    @Override
    public int getComponentEnabledSetting(ComponentName componentName) {
        return this.mBase.getComponentEnabledSetting(componentName);
    }
    @Override
    public void setApplicationEnabledSetting(String packageName, int newState, int flags) {
        this.mBase.setApplicationEnabledSetting(packageName, newState, flags);
    }
    @Override
    public int getApplicationEnabledSetting(String packageName) {
        return this.mBase.getApplicationEnabledSetting(packageName);
    }
    @Override
    public boolean isSafeMode() {
        return this.mBase.isSafeMode();
    }
    @Override
    public void setApplicationCategoryHint(@NonNull String packageName, int categoryHint) {
 
    }
    @Override
    public PackageInstaller getPackageInstaller() {
        return this.mBase.getPackageInstaller();
    }
    @Override
    public boolean canRequestPackageInstalls() {
        return false;
    }
}

java/com/lxz/hookactivity.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
package com.lxz;
 
import android.app.Activity;
import android.content.pm.PackageManager;
import androidx.appcompat.app.AppCompatActivity;
 
// 注意这里继承的 AppCompatActivity 类是目标应用 activity 继承的类
public class hookactivity extends AppCompatActivity {
    @Override // android.content.ContextWrapper, android.content.Context
    public PackageManager getPackageManager() {
        PackageManager pm = new hook(super.getPackageManager());
        return pm;
    }
}

修改目标主启动类为 hookactivity,其实就是多了一层继承,中间修改了 PMS

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public class MainActivity extends hookactivity {
 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
 
        TextView textView = findViewById(R.id.mytext);
 
        String str = getSignatuer(this);
        if(checkSignatuer(str))
        {
            Log.d("lxz","签名正确");
            textView.setText("签名正确");
        }else{
            Log.d("lxz","签名错误");
            textView.setText("签名错误");
        }
    }
    ......
}

smail 层实现

使用反编译工具将刚刚用 java 实现的 PMS 反编译,并取出其中的 lxz 文件夹

1
apktool.jar -r d .\app-debug.apk

再将 CheckSignature 中 刚刚添加的 psm 部分删掉,让其还原成一个可以检查 Signature 的应用,重新打包成 apk,再使用 apktool 将其解包

1
apktool.jar -r d .\app-debug.apk

将 lxz 文件夹拷贝到 smali_classes3/com 目录下,并修改 smali_classes3\com\example\checksignatuer\MainActivity.smali 的父类

androidx.multidex.MultiDexApplication

com\babybus\app\App.smali

1
2
3
4
.class public Lcom/example/checksignatuer/MainActivity;
#.super Landroidx/activity/ComponentActivity;
.super Lcom/lxz/hookactivity;
.source "MainActivity.java"

重新打包回 apk 文件,生成 signature.apk

1
apktool.jar b app-debug -o signature.apk

使用 zipalign 对生成的文件对齐,需要制作 v2 的签名,不然 android 11 及以后安装会失败

1
zipalign -v 4 signature.apk zipalign.apk

接下来我们需要进行签名,但我们现在还没有签名文件,所以还得做个签名文件,密码123456,问题答案随便填,这样我们就获得了签名文件 demo.keystore

1
keytool -genkey -alias demo.keystore -keyalg RSA -validity 40000 -keystore demo.keystore

使用生成的签名文件对目标应用进行签名,此时安装并启动 app 会发现强制返回正确签名的 log


[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

最后于 2024-1-12 22:25 被简单的简单编辑 ,原因:
收藏
免费 10
支持
分享
赞赏记录
参与人
雪币
留言
时间
mb_tnnwsxvj
为你点赞!
2025-2-10 22:11
freenow
为你点赞~
2023-12-23 15:52
Lnju
为你点赞~
2023-11-25 09:51
New对象处
为你点赞~
2023-11-23 11:44
绿雪羚羊
为你点赞~
2023-8-9 09:16
Russohan
为你点赞~
2023-7-31 19:24
你瞒我瞒
为你点赞~
2023-7-31 09:17
霸气压萝莉
为你点赞~
2023-7-29 19:38
vay
为你点赞~
2023-7-29 10:55
juice4fun
为你点赞~
2023-7-29 09:42
最新回复 (6)
雪    币: 1915
活跃值: (2208)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
可以的,不过看着你好像有点眼熟 NP的几个去签是你写的吗
2023-7-29 00:15
0
雪    币: 10872
活跃值: (1845)
能力值: ( LV2,RANK:15 )
在线值:
发帖
回帖
粉丝
3
能过翻切小说的签名吗?嘿嘿,试试
2023-7-29 09:21
0
雪    币: 4169
活跃值: (4532)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
4
先收藏了,谢谢分享。
2023-7-29 09:22
0
雪    币: 0
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
5
大佬,我遇到的问题主要是在U3D游戏里,如果hook open后重定向路径(用的还是原包模式),游戏会报错:Not enough storage space to install required resources,任何一款u3d都会,没检测随意反编译回编译。比如这款pl.idreams.Dino  https://apkpure.com/cn/crazy-dino-park-iiii/pl.idreams.Dino
2023-7-30 00:38
0
雪    币: 4
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
6
为啥读取base.apk中的文件数据时,读取的数据均为0呢?
2024-11-12 00:51
0
雪    币: 370
活跃值: (227)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
7
感谢大佬的分享
2024-11-12 11:41
0
游客
登录 | 注册 方可回帖
返回

账号登录
验证码登录

忘记密码?
没有账号?立即免费注册