首页
社区
课程
招聘
[原创]part脱壳重打包案例系列(1)
发表于: 2024-9-19 00:44 1666

[原创]part脱壳重打包案例系列(1)

2024-9-19 00:44
1666

前言

有网友说我的案例太少了,那么今天再来一个脱壳重打包案例。今天这个是一个网友提供的案例app,反编译看一眼,哪个厂商就不多说了,懂的都懂:

脱壳

直接使用part进行脱壳,成功后adb pull拉下来:

没修复前核心函数都被抽掉了:

使用定制工具进行修复:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
C:\Users\32836\Desktop\part介绍\案例1:标准日本语>java -jar dexfixer_v2.1.jar com.PEP.biaori com.PEP.biaori_1
handling file:10563940.dex
merged for com.PEP.biaori_1\classes.dex
handling file:10822760.dex
merged for com.PEP.biaori_1\classes2.dex
handling file:11976228.dex
merged for com.PEP.biaori_1\classes3.dex
handling file:1748152.dex
merged for com.PEP.biaori_1\classes4.dex
handling file:309188.dex
merged for com.PEP.biaori_1\classes5.dex
handling file:486964.dex
merged for com.PEP.biaori_1\classes6.dex
handling file:9042488.dex
merged for com.PEP.biaori_1\classes7.dex

将修复后的dex拖进apk:

重打包

先把app原本的application找出来:

然后反编译apk成smali:

1
java -jar .\apktool-v2.9.2-51-4d857dbf-SNAPSHOT.jar d .\repackage.apk -s -o test_smali

替换入口:

重新回编译然后签名,运行,看看效果:

1
2
3
java -jar apktool-v2.9.2-51-4d857dbf-SNAPSHOT.jar b test_smali -o out.apk
java -jar apksigner.jar sign --ks tg.jks out.apk
adb install out.apk

发现进去了,可以看到,隐私权限页面已经能打开,但是点击同意后app会退出。这里虽然app是退出了但是这已经是app自身的签名校验逻辑,而跟壳没有关系了:


直接上frida,看看是哪里做的签名校验:

1
2
3
4
5
6
7
8
9
10
11
Java.perform(function () {
    var Toast = Java.use("android.widget.Toast");
    Toast.show.implementation = function () {
        var toastText = this.getView().getAccessibilityClassName().toString();
        console.log("Toast message: " + toastText + "\n");
        console.log(printStack("Toast"));
        this.show();
    };
    console.log("hook java platform over.")
 
})


根据调用栈直接定位到af类,校验的逻辑主要在c方法:

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
package com.PEP.biaori.util;
 
import android.content.Context;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.util.Log;
import java.io.ByteArrayInputStream;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateEncodingException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
 
/* compiled from: SignCheck.java */
/* loaded from: classes2.dex */
public class af {
    private static final String d = "SignCheck";
 
    /* renamed from: a  reason: collision with root package name */
    private Context f7298a;
 
    /* renamed from: b  reason: collision with root package name */
    private String f7299b;
    private String c;
 
    public af(Context context) {
        this.f7299b = null;
        this.c = "1C:8D:A9:52:F8:C4:74:7C:7C:DD:B4:78:40:F0:C1:61:E0:AC:E9:F7";
        this.f7298a = context;
        this.f7299b = b();
    }
 
    public af(Context context, String str) {
        this.f7299b = null;
        this.c = "1C:8D:A9:52:F8:C4:74:7C:7C:DD:B4:78:40:F0:C1:61:E0:AC:E9:F7";
        this.f7298a = context;
        this.c = str;
        this.f7299b = b();
    }
 
    public String a() {
        return this.c;
    }
 
    public void a(String str) {
        this.c = str;
    }
 
    public String b() {
        PackageInfo packageInfo;
        CertificateFactory certificateFactory;
        X509Certificate x509Certificate;
        byte[] digest;
        String str = null;
        try {
            packageInfo = this.f7298a.getPackageManager().getPackageInfo(this.f7298a.getPackageName(), 64);
        } catch (PackageManager.NameNotFoundException e) {
            e.printStackTrace();
            packageInfo = null;
        }
        ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(packageInfo.signatures[0].toByteArray());
        try {
            certificateFactory = CertificateFactory.getInstance("X509");
        } catch (Exception e2) {
            e2.printStackTrace();
            certificateFactory = null;
        }
        try {
            x509Certificate = (X509Certificate) certificateFactory.generateCertificate(byteArrayInputStream);
        } catch (Exception e3) {
            e3.printStackTrace();
            x509Certificate = null;
        }
        try {
            byte[] bArr = new byte[0];
            try {
                digest = MessageDigest.getInstance("SHA1").digest(x509Certificate.getEncoded());
            } catch (CertificateEncodingException e4) {
                e4.printStackTrace();
            }
            str = a(digest);
        } catch (NoSuchAlgorithmException e5) {
            e5.printStackTrace();
        }
        Log.d("签名校验", "SHA1 = " + str);
        return str;
    }
 
    private String a(byte[] bArr) {
        StringBuilder sb = new StringBuilder(bArr.length * 2);
        for (int i = 0; i < bArr.length; i++) {
            String hexString = Integer.toHexString(bArr[i]);
            int length = hexString.length();
            if (length == 1) {
                hexString = "0" + hexString;
            }
            if (length > 2) {
                hexString = hexString.substring(length - 2, length);
            }
            sb.append(hexString.toUpperCase());
            if (i < bArr.length - 1) {
                sb.append(':');
            }
        }
        return sb.toString();
    }
 
    public boolean c() {
        if (this.c != null) {
            this.f7299b = this.f7299b.trim();
            String trim = this.c.trim();
            this.c = trim;
            return this.f7299b.equals(trim);
        }
        return false;
    }
}

直接将smali后的c方法改成如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
.method public c()Z
    .registers 4
 
    .line 154
    const/4 v0, 0x1  # 将true返回值存储在v0中
 
    .line 9
    const-string v1, "hello, 你已被重打包"  # 吐司消息内容
 
    const/4 v2, 0x1  # 吐司显示时长
 
    iget-object v3, p0, Lcom/PEP/biaori/util/af;->a:Landroid/content/Context;  # 获取Context对象
 
    invoke-static {v3, v1, v2}, Landroid/widget/Toast;->makeText(Landroid/content/Context;Ljava/lang/CharSequence;I)Landroid/widget/Toast;  # 创建Toast对象
 
    move-result-object v1  # 将Toast对象存储在v1中
 
    invoke-virtual {v1}, Landroid/widget/Toast;->show()V  # 显示Toast
 
    return v0  # 返回true
.end method

最终重打包成功:

总结与愿景

这个app呢强度还不算大,只有函数抽取。函数抽取对于part来说都是通杀的,直接就是全壳修复。现在一些强度较大的app都是有几百上千个vmp函数(vmp函数还原参考之前的文章),part下一步的方向是往gpt api优化方向靠拢,看看能不能做到全自动化还原vmp函数(正在努力优化中,希望能有个好结果),镜像也会升级到适配安卓12。
PS:图中所有案例app都仅是测试学习,无任何复制以及传播、或其他恶意行为,如觉得侵权了请联系删除。


[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)

最后于 2024-9-19 00:51 被程序员小潘编辑 ,原因:
收藏
免费 4
支持
分享
最新回复 (4)
雪    币: 202
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
2
加油,我想写个软件不知道找谁
2024-9-19 03:06
0
雪    币: 10
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
3
感谢分享,学习了
2024-9-19 09:17
0
雪    币:
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
4
是fart??
2024-9-26 18:02
0
雪    币: 11
活跃值: (1304)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
5
mb_uskgmuue 是fart??
不是
2024-9-27 13:36
0
游客
登录 | 注册 方可回帖
返回
//