吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 428|回复: 1
上一主题 下一主题
收起左侧

[Android 原创] 从 App 启动流程看 Android 整体加固

  [复制链接]
跳转到指定楼层
楼主
soma20 发表于 2026-2-12 09:30 回帖奖励
本帖最后由 soma20 于 2026-2-12 09:38 编辑

从 App 启动流程看 Android 整体加固

一、前言

​        最近在学习安卓加固的时候遇到了一些问题不太明白,比如说为什么一定要替换掉mClassLoader而不是别的东西,于是就是想着通过源码分析一下看看有没有什么突破点,这里做一下记录。由于 Android Framework 体系庞大且逻辑复杂,本人也比水,个人理解难免存在局限或偏差。如果在阅读过程中发现任何错误或疏漏,恳请各位大佬不吝赐教。

​        这篇笔记基于Android-13.0.0_r83源码进行分析。可以从该网站找到:XRefAndroid - Support Android 16.0 & OpenHarmony 6.0 (AndroidXRef/AospXRef)

二、Application的启动

Application源码分析

​        这里从Application的启动过程开始分析。这里直接从ActivityThread.javamain函数开始分析。这个是整个Android应用进程的真正入口点。


​        

​        接着就需要跟进到attach当中进一步分析了:

该函数当中会调用attachApplicationLocked的函数,该函数非常的长,内部会调用thread.bindApplication

​        一个是测试模式的启动,一个是正常模式的启动。通过bindApplication,将一系列的参数,消息封装好发送给主线程进行处理。进入该函数内部之后就可以发现将数据打包,最后通过 sendMessage消息类型消息数据发送出去了:

​        这里sendMessage将消息发送到了主线程的消息队列,那么由谁来对这个消息进行处理呢?可以看到H.BIND_APPLICATION,跟进去查看一下这个H

这个H继承的是Handler(一个ActivityThread的内部类),内部有一个handleMessage来处理这些对应的消息,这里传入的是BIND_APPLICATION类型的消息,那只需要找到case即可:

​        这里就是BIND_APPLICATION消息的处理了,内部接收到data之后会调用handleBindApplication来处理这些消息,这是一个最重要的位置了,继续跟进这个handleBindApplication进行分析:

​        在这个函数当中,有一个非常重要的地方,就是下面这里:

​        通过这个getPackageInfoNoCheck获取LoadedApk,这个LoadedApk是一个加固的重点,这里简单说一下:LoadedApk就是一个容器对象,它将硬盘上的APK文件解构成了内存当中可以使用的类加载器、资源管理器、配置信息等,供系统随时调用。

​        这个data.info类型就是LoadedApk

​        在加固的时候我们同样需要获取这个LoadedApk,所以接下来需要跟进这个getPackageInfoNoCheck来看看到底是怎么获取这个LoadedApk,以及这个函数里面做了什么操作:


​        调用的是getPackageInfo,继续跟进:

​        可以看到这里的:

LoadedApk packageInfo = ref != null ? ref.get() : null;

如果ref不为空,则表示LoadedApk不为空,则复用LoadedApk。通过这里也可以大致了解到,一个app有且只有一个LoadedApk。接着就继续往下分析:

​        这里可以看到,如果没有LoadedApk则直接new一个出来,接着要来看看这个LoadedApk是怎么工作的:

如图所示,会初始化一些必要的东西,例如mPackageName。只不过这里没有说明要怎么从别的地方(比如我们自己的app)中获取这个LoadedApk,这个后续再看。

​        现在让我们回到handleBindApplication继续往下分析,下一个里程碑的位置就是这个位置:

这里通过LoadedApk获取了一个Application的类。进入分析一下这个makeApplicationInner


​        接着会查看缓存sApplications,如果之前创建过则直接复用。接着就是获取Application的类名

​        接着就是获取类加载器,创建Application的上下文,接着创建Application并实例attach这里是用户代码第一次执行的地方

跟进这个newApplication分析:

​        可以看到这里attach当中调用了attachBaseContext,这个attachBaseContext非常重要,这就是获取到Context后,用户代码最早执行的地方。由于这个特性可以对这个地方做很多文章。

​        最终makeApplicationInner会返回app这个Application。现在回到handleBindApplication继续分析。接下来就是通过callApplicationOnCreate来调用Application.OnCreate()这个函数了

​                到这里就差不多完成了handleBindApplication这个函数了,下一步就可以处理EXECUTE_TRANSACTION这个消息了,这个消息处理的是activity的启动

Application小结

​        通过对Application的启动流程可以看出用户代码的执行流程如下: attachBaseContext -> Application.onCreate。实际上这两个之间还有一个 ContentProvider.onCreate这里还没有提及。不过attachBaseContext基本上就是用户代码最早执行的一个地方,整体加固的壳代码会在这个位置进行解壳,然后恢复环境。

​        

三、Activity的启动

Activity源码分析

1. 怎么从Application过渡到Activity

​        首先先来分析一下,应用在执行完Application.OnCreateActivity究竟发生了什么。想了解这个问题得接着继续往下看

​        接下来回到attachApplicationLocked继续往下看,会看到这段代码:

​        这里调用的是mAtmInternal.attachApplication这个函数,要注意的是,这里并不是调用ActivityManagerService这个类当中的attachApplication函数,先来看看这个mAtmInternal是哪个类的:

​        可以看到是这个ActivityTaskManagerInternal这个类的,而这个类的实现在ActivityTaskManagerService这个类当中的LocalService私有内部类,接下来得看看这个类当中attachApplication的实现了:

​        过来之后又发现将wpc委托给了mRootWindowContainerattachApplication函数,这个mRootWindowContainerRootWindowContainer类的实例,其中attachApplication函数定义如下:

​        接着可以看到的是调用了mAttachApplicationHelper当中的process函数,这个mAttachApplicationHelper是该RootWindowContainer类当汇总的一个私有内部类,最后可以找到这个process

接着调用getChildAt(displayNdx).forAllRootTask,遍历该屏幕下所有的“根任务”。然后通过回调this的函数来处理,这里的调用路径是RootWindowContainer --> WindowContainer --> Task下的forAllRootTask

​        也就是说调用的是mAttachApplicationHelper当中的accept,而accept当中还调用了rootTask.forAllActivities函数

​        如果进入这个位置,最后就会调用test,这个test当中有一个realStartActivityLocked函数:

进入该函数分析,该函数当中又调用了scheduleTransaction

这里会通过ClientTransactionHandler来发送EXECUTE_TRANSACTION,接下来就是loop循环对这个消息进行处理,启动activity了。

2. Activity的启动

​        消息循环获取到EXECUTE_TRANSACTION之后就开始通过 mTransactionExecutor来进行事务逻辑的分发

此时需要跟进execute进行代码跟踪:

​        对于这个函数来说,内部执行过程中需要关注这两个函数:executeCallbacksexecuteLifecycleState。首先来看看这个executeCallbacks函数

executeCallbacks

​        进来函数第一步首先将transaction(也就是sendMessage传入的data),的callBack取出来,然后在下方循环中,通过callbacksitem取出来,再调用item.execute继续向下调用,这里要注意的是item并不是 ClientTransactionItem类型,这里使用多态,item真正的类型是:LaunchActivityItem

​        接下里进入到LaunchActivityItem.execute进行分析:

​        首先对ActivityClientRecord r这个变量进行数据封装,然后进入到client.handleLaunchActivity这个函数,这个是真正的执行入口,标志着逻辑从“事务管理层”(Transaction 框架)正式进入了“Activity 线程管理层”(ActivityThread)。

​        这里的client在运行的时候其实就是ActivityThread,所以这里使用的是ActivityThread当中的handleLaunchActivity。接下来就需要对handleLaunchActivity进行分析:


该函数中performLaunchActivity这里是最最重要的一部分,通过该函数会输出一个初始化完毕、正在运行的 Activity 对象。接下来该好好分析这个performLaunchActivity函数了

performLaunchActivity

​        首先就是通过createBaseContextForActivity获取ContextImpl,然后通过appContextgetClassLoader来获取类加载器,这里需要跟进查看一下这个getClassLoader加载器是怎么获取的,对后续加壳原理的理解非常有帮助。

​        可以看到getClassLoader是通过mPackageInfo.getClassLoader()来获取的,而这个mPackageInfo类型其实是LoadedApk,该类的getClassLoader()是返回mClassLoader

​        接下来就是mInstrumentation.newActivity了,这行代码过程,内存中就存在了一个Activity的对象了

​        来看看这个newActivity的调用链newActivity --> getFactory(pkg).instantiateActivity -->  cl.loadClass(className).newInstance

​        这里直接使用了反射调用activity的构造函数。这个new Activity结束之后,下一步就是用这个创建的activity对象进行操作了:

​        接下来activity使用attach来做一些初始化工作,这一步会完成window的创建以及Context的绑定,接下来就是最后一步了:

这里就会调用Activity.OnCreate,接下来就是一些状态设置以及后续activity的启动了。这里就不继续往下分析了。

3. Activity小结

​        本阶段梳理了 Activity 的实例化过程,揭示了 LoadedApk.mClassLoader 在其中的决定性作用。源码显示,系统在 performLaunchActivity 中强制使用 appContext.getClassLoader() 获取加载器,并通过反射 (loadClass().newInstance()) 创建 Activity 实例。 这一机制解释了为何加固壳必须替换 mClassLoader:只有“偷梁换柱”,将解密后的 DEX 注入到这个特定的 LoadedApk 实例中,才能骗过系统的检查,让原本不存在于 base.apk 中的 Activity 被成功加载和启动。

四、总结

​        小小的总结了一下:加固的本质就是在 Application.attachBaseContext 阶段,利用 LoadedApk 的单例特性,通过“偷梁换柱”的方式替换 mClassLoader,从而欺骗系统在后续 Activity 启动时去加载我们解密后的代码。

​        还有就是app的启动流程:attachBaseContext --> ContentProvider.onCreate --> Application.OnCreate --> Activity.OnCreate

​        后续再根据这个逻辑来实现一个简单的整体加固

免费评分

参与人数 2吾爱币 +2 热心值 +2 收起 理由
benjaming + 1 + 1 我很赞同!
buluo533 + 1 + 1 用心讨论,共获提升!

查看全部评分

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

沙发
rapidpojie 发表于 2026-2-14 09:31
请问有没有便宜的加固方案呢,360加固一年要30w
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - 52pojie.cn ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2026-2-14 14:02

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表