Apk加固原理解析

一、背景
为了更好的防止Apk被反编译,将Apk加密后打入宿主Apk包中,宿主启动时,解密Apk然后启动Apk。

二、工作原理
通过反射的方法替换ClassLoader及资源路径,使得启动的都是加固的Apk。

三、启动过程分析
加固的Apk大致的启动过程是这样的:
宿主Apk启动 -> 宿主Application中解密Apk -> 替换ClassLoader -> 替换资源路径 -> 替换Application对象(若APk中存在的话)

3.1 解密Apk
此步骤只是将asset下的加密的Apk文件拷贝到sd卡上,拷贝过程中同时解密。

3.2 替换ClassLoader
ActivityThread类里有个成员变量mPackages,mPackages存储的是LoadedApk对象,LoadedApk类的成员变量mClassLoader就是apk包类加载器,也就是要替换的ClassLoader。

3.2.1 LoadedApk创建过程
程序启动的时候,ActivitThread在handleBindApplication函数中创建Application对象。下面贴出关键代码

private void handleBindApplication(AppBindData data) {

    ...

    // 创建LoadedApk对象
    data.info = getPackageInfoNoCheck(data.appInfo, data.compatInfo);

    ...

    //调用LoadedApk的makeApplication方法创建Application对象
    Application app = data.info.
            makeApplication(data.restrictedBackupMode, null);
    mInitialApplication = app;

    ...

    // 调用Application的onCreate方法,至此Application对象创建完毕
    try {
        mInstrumentation.callApplicationOnCreate(app);
    } catch (Exception e) {
        if (!mInstrumentation.onException(app, e)) {
            throw new RuntimeException(
                "Unable to create application " + app.getClass().getName()
                + ": " + e.toString(), e);
        }
    }
}

public final LoadedApk getPackageInfoNoCheck(ApplicationInfo ai,
                CompatibilityInfo compatInfo) {
    return getPackageInfo(ai, compatInfo, null, false, true, false);
}

private LoadedApk getPackageInfo(ApplicationInfo aInfo,
            CompatibilityInfo compatInfo,
            ClassLoader baseLoader, boolean securityViolation,
            boolean includeCode, boolean registerPackage) {
    WeakReference<LoadedApk> ref;
    if (differentUser) {
        // Caching not supported across users
        ref = null;
    } else if (includeCode) {
        ref = mPackages.get(aInfo.packageName);
    } else {
        ref = mResourcePackages.get(aInfo.packageName);
    }

    // 首先从mPackages从读取
    LoadedApk packageInfo = ref != null ? ref.get() : null;
    // 首次启动,mPackages中是空的
    if (packageInfo == null || (packageInfo.mResources != null
            && !packageInfo.mResources.getAssets().isUpToDate())){
        //创建LoadedApk对象
        packageInfo = new LoadedApk(this, aInfo, compatInfo,
                      baseLoader,securityViolation, includeCode &&
                 (aInfo.flags&ApplicationInfo.FLAG_HAS_CODE) != 0,
                 registerPackage);

        ...

        // 将LoadedApk对象保存到mPackages中
        if (differentUser) {
            // Caching not supported across users
        } else if (includeCode) {
             mPackages.put(aInfo.packageName,
                 new WeakReference<LoadedApk>(packageInfo));
        } else {
            mResourcePackages.put(aInfo.packageName,
                 new WeakReference<LoadedApk>(packageInfo));
        }
    }

    return packageInfo;
}

至此LoadedApk对象创建完毕。

3.2.2 ClassLoader创建过程
在LoadedApk对象创建的时候,并没有创建ClassLoader,看下LoadedApk构造函数。

public LoadedApk(ActivityThread activityThread, 
            ApplicationInfo aInfo,CompatibilityInfo compatInfo,
            ClassLoader baseLoader,boolean securityViolation,
            boolean includeCode, boolean registerPackage) {
    final int myUid = Process.myUid();
    aInfo = adjustNativeLibraryPaths(aInfo);

    mActivityThread = activityThread;
    mApplicationInfo = aInfo;
    mPackageName = aInfo.packageName;
    mAppDir = aInfo.sourceDir;
    mResDir = aInfo.uid == myUid ? aInfo.sourceDir : aInfo.publicSourceDir;
    mSplitAppDirs = aInfo.splitSourceDirs;
    mSplitResDirs = aInfo.uid == myUid ? aInfo.splitSourceDirs : aInfo.splitPublicSourceDirs;
    mOverlayDirs = aInfo.resourceDirs;
    mSharedLibraries = aInfo.sharedLibraryFiles;
    mDataDir = aInfo.dataDir;
    mDataDirFile = mDataDir != null ? new File(mDataDir) : null;
    mLibDir = aInfo.nativeLibraryDir;
    mBaseClassLoader = baseLoader;
    mSecurityViolation = securityViolation;
    mIncludeCode = includeCode;
    mRegisterPackage = registerPackage;
    mDisplayAdjustments.setCompatibilityInfo(compatInfo);
}

那ClassLoader对象是什么时候创建的呢?从LoadedApk源码中,看到ClassLoader对象是在getClassLoader方法中创建的。

public ClassLoader getClassLoader() {

    if (mIncludeCode && !mPackageName.equals("android")) {
        // apk和lib路径
        final List<String> zipPaths = new ArrayList<>();
        final List<String&g
  • 4
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值