首页
论坛
课程
招聘
[逆向分析] [混淆加固] [脱壳反混淆] [HOOK注入] [原创]用AppComponentFactory实现变种爱加密壳保护的策略分析
2021-6-8 16:34 3278

[逆向分析] [混淆加固] [脱壳反混淆] [HOOK注入] [原创]用AppComponentFactory实现变种爱加密壳保护的策略分析

2021-6-8 16:34
3278

拿到一款App(名字暂且该叫tangzhanglao),听说壳很厉害,于是好奇拿来研究一番。

 

用Apktool解压是没有反应的,猜测是做了针对性保护;拿不到AndroidManifest.xml怎么办?

 

用Jadx-gui直接解压,文件出来了,如下:

 

大体看一下,发现貌似是用爱加密加密的。但是,仔细分析一下,发现保护级别比之前的爱加密高多了;为何这么说,且听慢慢道来。

 

首先我们看下这里的AndroidManifest.xml,关键处如下:

1
2
3
4
5
6
7
<application android:theme="@style/AppTheme" android:label="@string/app_name" android:icon="@mipmap/ic_launcher" android:name="p008s.p009h.p010e.p011l.p012l.ApplicationC0083S" android:allowBackup="false" android:supportsRtl="true" android:usesCleartextTraffic="true" android:roundIcon="@mipmap/ic_launcher_round" android:appComponentFactory="s.h.e.l.l.A">
       <uses-library android:name="org.apache.http.legacy" android:required="false"/>
       <activity android:theme="@style/SplashActivityStyle" android:name="com.tangzhanglao.activity.splash.SplashActivity" android:launchMode="singleTask" android:screenOrientation="portrait">
           <intent-filter>
               <action android:name="android.intent.action.MAIN"/>
               <category android:name="android.intent.category.LAUNCHER"/>
           </intent-filter>

可见加壳后的程序名为: android:name="p008s.p009h.p010e.p011l.p012l.ApplicationC0083S"
且: android:appComponentFactory="s.h.e.l.l.A"

 

我们看下ApplicationC0083S,部分代码如下:

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
/* renamed from: s.h.e.l.l.S */  这里是shells,不是shell A ;
public final class ApplicationC0083S extends Application {
 
  ……
 
    /* renamed from: l ;注意这个布尔变量f170l,在整个壳的保护中很关键,是起开关作用的*/
    public static boolean f170l = false;
……
public void onCreate() {
       ……
/*再看下onCreate()入口函数中,这个函数是壳解密的入口,是Native层的。*/
   C0082N.m209ra(this, "com.tangzhanglao.TangzhanglaoApplication");
                if (f172n != null) {
                }
                super.onCreate();
 
/*我们可以来到C0082N类看下;*/
 
public final class C0082N {
    /* renamed from: al */
    public static native ClassLoader m205al(ClassLoader classLoader, ApplicationInfo applicationInfo, String str, String str2);
 
    public static native byte[] b2b(byte[] bArr, int i);
 
    /* renamed from: l */
    public static native boolean m206l(Application application, String str);
 
    /* renamed from: m */
    public static native void m207m(String str, int i);
 
    /* renamed from: r */
    public static native boolean m208r(Application application, String str);
 
    /* renamed from: ra;这里把要解密的程序包名传进去 */
    public static native boolean m209ra(Application application, String str);
 
    /* renamed from: sa */
    public static native void m210sa(String str, String str2);

从这里,往后就是常规爱加密壳保护的方法了;但是注意,这个壳的关键并不在这里,而是在解密程序之前还有一层保护;而且是动态保护的。关键就是上边的这个工厂类:AppComponentFactoryC0080A

 

首先说明一下:整个动态保护的关键,就是在爱加密壳之前又加了一层动态保护,这里的动态不是仅仅通过DEXclassloader来实现的,而是通过重写AppComponentFactory类,拦截了壳的整个解密过程,也就是说从壳程序加载一直到运行、解密整个过程都是被监控的;我们看下这个类的代码:

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
@TargetApi(28)
/* renamed from: s.h.e.l.l.A */注意这里的shellA
public final class AppComponentFactoryC0080A extends AppComponentFactory {
    private AppComponentFactory acf = null;/*监控类*/
    private AppComponentFactory orignACF = null;
    private String orignAppName = "com.tangzhanglao.TangzhanglaoApplication";
    private String orignName = "androidx.core.app.CoreComponentFactory";/*为了本地AppComponentFactoryC0080A类实现必须应用原始类*/
    private String packageName = "vip.mytangzhanglao";
    private boolean supportInstantiateClassLoader = false;/*监控开关*/
 
    /* renamed from: al 这个类是写在native层的,具体功能没有分析*/
    public static native ClassLoader m203al(ClassLoader classLoader, ApplicationInfo applicationInfo, String str, String str2);
 
/函数getACF()*工厂类的典型方法,加载自身类,并实例化类,从此系统中有了两个类;获取本地实现类的指针,通过指针调用监控行为*/
    public synchronized AppComponentFactory getACF(ClassLoader classLoader) {
        if (this.acf == null && this.orignName != null && !this.orignName.equals("")) {
            try {
                this.acf = (AppComponentFactory) classLoader.loadClass(this.orignName).newInstance();
            } catch (Exception e) {
            }
        }
        return this.acf;
    }
 
/*注意,因为重写了Activity,所以整个壳的行为过程都被拦截了*/
    @Override // android.app.AppComponentFactory
    public Activity instantiateActivity(ClassLoader classLoader, String str, Intent intent) throws ClassNotFoundException, IllegalAccessException, InstantiationException {
        if (ApplicationC0083S.f170l) {
            AppComponentFactory acf2 = getACF(classLoader);
            this.acf = acf2;
            if (acf2 != null) {
                return this.acf.instantiateActivity(classLoader, str, intent);/*if 体内,如果是壳程序,就拦截*/
            }
        }
        return super.instantiateActivity(classLoader, str, intent);
    }/*如果不是壳程序,就放行*/
 
/*Application的加载被监控*/
    @Override // android.app.AppComponentFactory
    public Application instantiateApplication(ClassLoader classLoader, String str) throws ClassNotFoundException, IllegalAccessException, InstantiationException {
        if (this.supportInstantiateClassLoader && str.equals("s.h.e.l.l.S")) {
            str = this.orignAppName;
        } else if (ApplicationC0083S.f170l) {
            AppComponentFactory acf2 = getACF(classLoader);
            this.acf = acf2;
            if (acf2 != null) {
                return this.acf.instantiateApplication(classLoader, str);
            }
        }
        return super.instantiateApplication(classLoader, str);
    }
 
 
/*这里ClassLoader类重置,才是实现动态保护的核心;一般App的加载是没有hook行为的;整个动态壳的保护,就是通过这里实现hook,进行解密、或者加密等功能的*/
    @TargetApi(29)
    public ClassLoader instantiateClassLoader(ClassLoader classLoader, ApplicationInfo applicationInfo) {
        if (!this.supportInstantiateClassLoader) {
            File file = new File(applicationInfo.dataDir, "files");
            if (!file.exists()) {
                file.mkdirs(); /*创建文件*/
 
            }
            ApplicationC0083S.f173p = file.getAbsolutePath();/*获取路径*/
            ApplicationC0083S.f169f = applicationInfo.sourceDir;/*重置需要解密文件*/
            ApplicationC0083S.m216l(null);/*这个函数就不具体贴代码了,就是设置系统信息的,获取解密需要的系统参数,为解密做准备*/
            classLoader = C0082N.m205al(classLoader, applicationInfo, this.packageName, this.orignAppName);/*native层解密*/
            applicationInfo.className = this.orignAppName;
            this.supportInstantiateClassLoader = true;/*设置可以加载*/
        }
        if (ApplicationC0083S.f170l) {
            this.acf = getACF(classLoader);
            if (this.acf != null) {
                return this.acf.instantiateClassLoader(classLoader, applicationInfo);/*返回解密后的程序包*/
            }
        }
        return super.instantiateClassLoader(classLoader, applicationInfo);/*不是壳程序,就放行*/
    }
 
 
/*ContentProvider组件监控*/
    @Override // android.app.AppComponentFactory
    public ContentProvider instantiateProvider(ClassLoader classLoader, String str) throws ClassNotFoundException, IllegalAccessException, InstantiationException {
        if (ApplicationC0083S.f170l) {
            AppComponentFactory acf2 = getACF(classLoader);
            this.acf = acf2;
            if (acf2 != null) {
                return this.acf.instantiateProvider(classLoader, str);
            }
        }
        return super.instantiateProvider(classLoader, str);
    }
 
 
/* BroadcastReceiver 组件监控*/
    @Override // android.app.AppComponentFactory
    public BroadcastReceiver instantiateReceiver(ClassLoader classLoader, String str, Intent intent) throws ClassNotFoundException, IllegalAccessException, InstantiationException {
        if (ApplicationC0083S.f170l) {
            AppComponentFactory acf2 = getACF(classLoader);
            this.acf = acf2;
            if (acf2 != null) {
                return this.acf.instantiateReceiver(classLoader, str, intent);
            }
        }
        return super.instantiateReceiver(classLoader, str, intent);
    }
 
/* Service组件监控*/
    @Override // android.app.AppComponentFactory
    public Service instantiateService(ClassLoader classLoader, String str, Intent intent) throws ClassNotFoundException, IllegalAccessException, InstantiationException {
        if (ApplicationC0083S.f170l) {
            AppComponentFactory acf2 = getACF(classLoader);
            this.acf = acf2;
            if (acf2 != null) {
                return this.acf.instantiateService(classLoader, str, intent);
            }
        }
        return super.instantiateService(classLoader, str, intent);
    }
}

因为时间原因,仅仅做了静态分析;native层需要动态分析的;有时间再补充。

 

有错误之处,请大侠指正。


第五届安全开发者峰会(SDC 2021)议题征集正式开启!

收藏
点赞2
打赏
分享
最新回复 (5)
雪    币: 8343
活跃值: 活跃值 (2408)
能力值: (RANK:200 )
在线值:
发帖
回帖
粉丝
LowRebSwrd 活跃值 4 2021-6-9 10:07
2
0
期待native!
雪    币: 1
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
mb_vwydcgbt 活跃值 2021-6-9 10:49
3
0
LowRebSwrd 期待native!
谢管理捧场
雪    币: 1
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
mb_vwydcgbt 活跃值 2021-6-11 15:00
4
0
更正一个错误:AppComponentFactoryC0080A类是在爱加密壳加载、解密后才开始发挥作用的,也就是这个类不是在壳的外面,而是在壳里面;这个地方搞错了,抱歉。

原因就是,这个类里有个对C0082N.m205al(classLoader, applicationInfo, this.packageName, this.orignAppName)的调用,这个类必须在程序加载完后才能被调用,因此可以判断是在壳工作之后。

因此,这个变种壳的破解,在按照常规破解后,需要调用动态加载中的解密函数,把全部文件解密,然后重新dump就可以了。

最后,寻求一个帮助:小米note8没有root权限,无法动态调试,有没有其他解决办法?
雪    币: 234
活跃值: 活跃值 (189)
能力值: ( LV6,RANK:90 )
在线值:
发帖
回帖
粉丝
shaoge 活跃值 2 1天前
5
0
应该发下样本apk
雪    币: 177
活跃值: 活跃值 (57)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
湿求了鸭 活跃值 1天前
6
0
等一手后续,遇到一个差不多的爱加密
游客
登录 | 注册 方可回帖
返回