首页
社区
课程
招聘
[原创]用AppComponentFactory实现变种爱加密壳保护的策略分析
发表于: 2021-6-8 16:34 20734

[原创]用AppComponentFactory实现变种爱加密壳保护的策略分析

2021-6-8 16:34
20734

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

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

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

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

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

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

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

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

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

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

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

 
 
 
 
<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>
<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>
 
/* 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);
/* 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);
 
@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);
    }
}
@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);

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

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

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

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

最后,寻求一个帮助:小米note8没有root权限,无法动态调试,有没有其他解决办法?
2021-6-11 15:00
0
雪    币: 1310
活跃值: (727)
能力值: ( LV6,RANK:90 )
在线值:
发帖
回帖
粉丝
5
应该发下样本apk
2021-6-20 08:05
0
雪    币: 5203
活跃值: (3275)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
6
等一手后续,遇到一个差不多的爱加密
2021-6-20 19:55
0
雪    币: 258
活跃值: (1747)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
7
湿求了鸭 等一手后续,遇到一个差不多的爱加密[em_3]
这个是动态壳
2021-6-23 15:17
0
雪    币: 220
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
8
公司在使用爱加密加固,想看一下脱壳后的程序相似程度,可付费
2021-8-30 17:40
0
雪    币: 258
活跃值: (1747)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
9
兰迪 公司在使用爱加密加固,想看一下脱壳后的程序相似程度,可付费
抱歉。
2021-9-5 08:05
0
雪    币: 5330
活跃值: (5464)
能力值: ( LV9,RANK:170 )
在线值:
发帖
回帖
粉丝
10
老哥,求个样本
2022-8-30 14:35
0
雪    币: 1379
活跃值: (2796)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
11
感谢分享
2024-7-23 14:33
0
游客
登录 | 注册 方可回帖
返回
//