首页
社区
课程
招聘
3
[原创]某黑产app的so文件无法找到的分析
发表于: 2024-11-25 10:45 4417

[原创]某黑产app的so文件无法找到的分析

2024-11-25 10:45
4417
第一步:jadx分析,看起来是dex加壳的,直接frIDA脱掉,这些和本文的主题无关就不再详述

第二步:解压apk,发现lib里面只有一个so文件,很奇怪,ida不能分析,通过file指令查看,是一个data文件

第三步:继续frida hook dlopen,查看so的加载,发现加载了很多自带的so,但是apk里面没有,所以怀疑是自定义的so加载方式

1
2
3
4
5
6
7
8
android_dlopen_ext probe /data/user/0/com.hptfludyjx.syjqeafkll/files/HJfOTtKmmn/libflutter.so
android_dlopen_ext probe /vendor/lib/hw/gralloc.sdm845.so
android_dlopen_ext probe /data/user/0/com.hptfludyjx.syjqeafkll/files/HJfOTtKmmn/libkiwi.so
android_dlopen_ext probe /vendor/lib/hw/android.hardware.graphics.mapper@2.0-impl-qti-display.so
android_dlopen_ext probe /data/dalvik-cache/arm/system@product@app@[email]webview@webview.apk[/email]@classes.dex
android_dlopen_ext probe libwebviewchromium.so
android_dlopen_ext probe /system/product/app/webview/webview.apk!/lib/armeabi-v7a/libwebviewchromium.so
android_dlopen_ext probe /system/lib/libwebviewchromium_plat_support.so

第四步:继续分析代码,发现了端倪,有一段可疑代码会对asset的文件进行解密解压,得出so文件。


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
if (list[i2].endsWith("_hmc")) {
  
                    MfLogUtils.e(Constant.METHOD_DEBUG, "找到hmc文件");
  
                    String str = list[i2];
  
                    String replace = list[i2].replace("_hmc""");
  
                    File filesDir = context.getFilesDir();
  
                    String str2 = filesDir.getAbsolutePath() + PsuedoNames.PSEUDONAME_ROOT + replace;
  
                    if (!new File(str2 + PsuedoNames.PSEUDONAME_ROOT + str).exists()) {
  
                        MfLogUtils.e(Constant.METHOD_DEBUG, "filename_assetsso不存在");
  
                        copyAssetsFileToDataDir(context, str, str2 + PsuedoNames.PSEUDONAME_ROOT + str);
  
                        MfLogUtils.e(Constant.METHOD_DEBUG, "将assets压缩文件复制到data目录");
  
                        if (new File(str2 + PsuedoNames.PSEUDONAME_ROOT + str).exists()) {
  
                            MfLogUtils.e(Constant.METHOD_DEBUG, "data文件存在:" + str2 + PsuedoNames.PSEUDONAME_ROOT + str);
  
                        }
  
                        int[] iArr = null;
  
                        Enumeration<? extends ZipEntry> entries = new ZipFile(str2 + PsuedoNames.PSEUDONAME_ROOT + str).entries();
  
                        while (true) {
  
                            if (!entries.hasMoreElements()) {
  
                                break;
  
                            }
  
                            ZipEntry nextElement = entries.nextElement();
  
                            MfLogUtils.e(Constant.METHOD_DEBUG, "遍历到文件:" + nextElement.getName());
  
                            String comment = nextElement.getComment();
  
                            if (comment != null && !comment.equals("")) {
  
                                MfLogUtils.e(Constant.METHOD_DEBUG, "查询到密钥:" + comment);
  
                                JSONArray jSONArray = new JSONArray(comment);
  
                                int[] iArr2 = new int[jSONArray.length()];
  
                                for (int i3 = 0; i3 < jSONArray.length(); i3++) {
  
                                    iArr2[i3] = ((Integer) jSONArray.get(i3)).intValue();
  
                                }
  
                                iArr = iArr2;
  
                            }
  
                        }
  
                        MfLogUtils.e(Constant.METHOD_DEBUG, "已经成功获取密钥了:" + iArr.toString());
  
                        ZipFileUtils.unZip(str2 + PsuedoNames.PSEUDONAME_ROOT + str, str2);
  
                        MfLogUtils.e(Constant.METHOD_DEBUG, "解压文件");
  
                        for (File file : new File(str2).listFiles()) {
  
                            MfLogUtils.e(Constant.METHOD_DEBUG, "解压生成文件:" + file.getAbsolutePath());
  
                            if (file.getName().contains(".so")) {
  
                                desfile(file.getAbsolutePath(), iArr);
  
                                MfLogUtils.e(Constant.METHOD_DEBUG, "解密单个文件:" + file.getAbsolutePath());
  
                            }
  
                        }
  
                        MfLogUtils.e(Constant.METHOD_DEBUG, "解密文件完成");
  
                    }



第五步:分析代码可知,这个就是将hmc后缀的zip文件解压,然后获取so文件的comment内容,作为key,比较简单所以直接在java中实现key的获取和so解密。



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
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Enumeration;
import java.util.zip.*; 
    
public class solution { 
  
    public static byte[] encDesSimple(byte[] bArr, int[] iArr) {
        int length = bArr.length;
        for (int i = 0; i < length; i++) {
            if (bArr[i] >= 0) {
                bArr[i] = (byte) iArr[bArr[i]];
            }
        }
        return bArr;
    }
  
  
    public static void writeFileBytes(File file, byte[] bArr) {
        try {
            FileOutputStream fileOutputStream = new FileOutputStream(file);
            fileOutputStream.write(bArr);
            fileOutputStream.flush();
            fileOutputStream.close();
        catch (Exception e) {
            e.printStackTrace();
        }
    }
  
   public static byte[] readFileBytes(File file) throws IOException {
        byte[] bArr = new byte[1024];
        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        FileInputStream fileInputStream = new FileInputStream(file);
        while (true) {
            int read = fileInputStream.read(bArr);
            if (read != -1) {
                byteArrayOutputStream.write(bArr, 0, read);
            else {
                fileInputStream.close();
                return byteArrayOutputStream.toByteArray();
            }
        }
    }
  
    public static void main(String args[]) 
    
        try 
            // Create a Zip File 
            Enumeration<? extends ZipEntry> entries 
                new ZipFile("test").entries(); 
                int i = 0;
                String soname = "libkiwi_enc.so";
                while (true) {
                    if (!entries.hasMoreElements()) {
                        break;
                    }
                    ZipEntry nextElement = entries.nextElement();
                    String comment = nextElement.getComment();
  
                    if (comment != null && !comment.equals("")) {
  
                    System.out.println("comment = "
                    + comment);
                    i++;
                    }
                    System.out.println("count = "
                    + i);
                }
            // Display the comment 
            // of the zip file 
            // using getComment() function 
  
            int [] iArr = {73,76,74,98,77,115,124,103,68,99,75,104,85,126,105,83,117,93,112,121,96,102,111,114,66,94,81,125,127,113,90,123,84,88,65,107,87,116,91,120,118,106,101,110,69,78,122,82,89,70,100,72,67,64,80,97,119,109,92,108,79,95,86,71,53,34,24,52,8,44,49,63,51,0,2,10,1,4,45,60,54,26,47,15,32,12,62,36,33,48,30,38,58,17,25,61,20,55,3,9,50,42,21,7,11,14,41,35,59,57,43,22,18,29,23,5,37,16,40,56,39,19,46,31,6,27,13,28};
            writeFileBytes(new File(soname.replace("_enc""")), encDesSimple(readFileBytes(new File(soname)), iArr));
  
        
        catch (Exception e) { 
            System.out.println(e.getMessage()); 
        
    
}

第六步:将解密后的示例so文件拖入ida中,可以正常解析,至此第一关算是结束,通过进一步查看代码发现他们还会动态的更新so文件做一些事情,但是更新的域名链接无法访问。



小结:黑产的app一般都是不考虑性能的,所以这种解压的方式在正经的app上应该是不存在的,另外这个app经过向反zha举报了很久,还是依旧活得很好,只能呵呵。后续会继续看so的加固,估计还会有更多的加固方式吧,毕竟不用考虑性能,仅当做新人的学习。



[注意]看雪招聘,专注安全领域的专业人才平台!

收藏
免费 3
支持
分享
赞赏记录
参与人
雪币
留言
时间
漠舟
为你点赞!
2025-1-17 23:31
墨穹呢
为你点赞!
2024-11-26 20:25
你瞒我瞒
感谢你分享这么好的资源!
2024-11-26 09:41
最新回复 (13)
雪    币: 10
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
2
期待后续更新
2024-11-25 18:44
0
雪    币: 353
活跃值: (2142)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3
这个应该是个 带颜色的app 而且用了 游戏盾
2024-11-25 21:09
0
雪    币: 157
活跃值: (2206)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
4
做过  这个有盾
2024-11-25 21:15
0
雪    币: 278
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
5
woainihehe 做过 这个有盾
有文章或者交流一下的地方吗?做的结果如何?
2024-11-26 08:20
0
雪    币: 278
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
6
湘子zyx 这个应该是个 带颜色的app 而且用了 游戏盾
是的,攻破了吗?感觉这个活得很好
2024-11-26 08:25
0
雪    币: 2723
活跃值: (11446)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
7
网站的UI改了吗,现在文章的文字不会换行了。。。。
2024-11-26 09:41
0
雪    币: 278
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
8
你瞒我瞒 网站的UI改了吗,现在文章的文字不会换行了。。。。
应该是我复制的问题,在其他地方先发表的文章
2024-11-26 10:00
0
雪    币: 353
活跃值: (2142)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
9
wx_ZXC_301 是的,攻破了吗?感觉这个活得很好
做过几个类似的 算法直接flutter里面扣 游戏盾 找齐了参数调用就行了
2024-11-26 19:04
0
雪    币: 2871
活跃值: (4102)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
10
感谢分享
2024-11-26 20:25
0
雪    币: 157
活跃值: (2206)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
11
wx_ZXC_301 有文章或者交流一下的地方吗?做的结果如何?
没有文章  全是淌着水过河
2024-11-27 02:16
0
雪    币: 839
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
12
flutter
2024-11-27 07:33
0
雪    币: 278
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
13
湘子zyx 做过几个类似的 算法直接flutter里面扣 游戏盾 找齐了参数调用就行了
好吧,也就是libapp的逆向
2024-11-27 08:36
0
雪    币: 135
活跃值: (70)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
14
黑产网带有没有人可以弄的
2025-4-17 21:09
0
游客
登录 | 注册 方可回帖
返回

账号登录
验证码登录

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