AOSP源码定制学习笔记
2024-10-25
| 2024-11-28
0  |  阅读时长 0 分钟
type
status
date
slug
summary
tags
category
icon
password
💡
此文章是我在学习AOSP源码定制时,写的笔记,要配合源码以及自己打的注释一块查看,文章写的非常没有逻辑性,语句也非常不通顺,仅仅只是自己学习临时打的草稿笔记(且可能有很多地方说的不对,还请提醒我)
 

一、源码分析学习

一个App的启动流程:
前面还有一些细节,是从Launcher开始的,这里暂时不做探究,直接从Zygoto进程开始,大概流程:
1、LauncherstartActivity方法,通过Binder通信,调用ActivityManagerServicestartActivity方法
2、一系列骚操作后,调用startProcessLocked方法来创建新的进程
3、该方法会通过socket通道传递参数给Zygote进程,Zygote孵化自身,调用ZygoteInit.main方法来实例化ActivityThread对象并最终返回新进程的pid 也就是接下来要详细讲的流程

ZygoteInit.→main() 初始化和fork SystemServer,循环监听socket 等待应用程序启动链接,为程序创建pid启动入口
ZygoteServer.runSelectLoop() 接收套接字链接,根据socket信息新建子进程
ZygoteConnection.processCommand()创建子进程并返回pid,关闭套接字链接,父进程继续监听socket
ZytoteConnection.handleChildProc() Zygote设置AppProcessName 并调用zygoteinit
ZygoteInit.zygotoInit()RuntimeInit初始化,nativeZygoteInit初始化,最后进入应用的初始化
RuntimeInit.applitionInit()返回一个Runnable,调用findStaticMain
RuntimeInit.findStaticMain() 根据类名查找静态main方法,返回new MethodAndArgsCaller
MethodAndArgsCaller是一个实现Runnable接口的类,他重写的run方法中去进行调用查找到的main方法
最终返回的MethodAndArgsCaller(Runnable)是返回到ZygoteInit.main()方法中,最后判断不为空去进行调用
查找到的main函数其实是ActivityThread.main()

ActivityThread.main()中执行了
查看attach方法
查看attachApplication方法,里面没有核心方法,它调用了attachApplicationLocked ,方法进行了一大堆的初始化,走到了
thread是IApplicationThread类型对象,调用bindApplication进行了一个绑定,查看方法
绑定完数据后,最终调用sendMessage(H.BIND_APPLICATION, data); 将数据发送出去,通过handleMessage 方法进行接收,查看switchBIND_APPLICATION分支发现调用了handleBindApplication 函数
 
 
handleBindApplication函数中有几个关键函数
首先createAppContext方法中,使用了
继续跟踪查看
调用了一个getClassLoader()函数,最后面调用了一个
来创建PathClassLoader加载应用APK的dex类,为什么知道这个是PathClassLoader呢,点进方法查看:
所以我们能确定,最终加载App dex文件的是PathClassLoader
查看PathClassLoader的构造函数
调用了父类的构造函数,并且确定是五个参数,查看父类BaseDexClassLoader
一路跟踪找到最终调用的构造方法
进入DexPathList查看,构造函数的参数
有一个makeDexElements方法
继续分析加载dex的函数LoadDexFile

这里的mCookie其实也是一个脱壳点,但是如果dex本身加密加壳的话 就没有办法,我们继续查看openDexFile方法,是走了native层的函数
我们跟踪native层函数发现asfp跳转不了了,使用命令去搜索
输出:
我们直接就找到了方法所在的位置
函数代码量很少,看到一个比较像核心的方法OpenDexFilesFromOat函数,点进去看一看
函数的详细注释在源码中,这里就不展开讲了,有几个比较核心的方法: runtime->GetClassLinker()->AddImageSpace
oat_file_assistant.LoadDexFiles 其中AddImageSpace函数中调用了LoadDexFiles
dex_file_loader.Open
查看AdImageSpace
找到一个关键函数 通过OpenOatDexFile 打开dex文件 返回dex_file对象
OpenOatDexFile方法中有一个OpenDexFile,进入查看
调用了一个
搜索Open结果太多,我们看一下dex_file_loader是什么类型的,是ArtDexFileLoader类型
搜索
进入Open方法里面定义了一个magic 通过OpenAndReadMagic方法读取,最终返回OpenWithMagic()
那么如果加载的是一个APK,他就会走Zip的分支,因为APK的本质就是一个Zip文件
分析一下Zip分支中的OpenZip方法一路跟踪到OpenAllDexFilesFromZipOpenOneDexFilesFromZip

再回到initInstrumentation方法
去查看loadClass的实现
走到BaseDexClassLoader
再去DexPathList中查看findClass方法
dexFileDexFile类对象,去DexFile类中查看loadClasBinaryName方法
搜索得到
往下分析 找到一个名字极其像关键函数的函数

回顾一下,在ActivityThread类中,有一个反射调用,我们跟踪到Method.invoke中 分析一下是如何调用的
查看InvokeMethod,他里面调用了InvokeWithArgArray
查看ArtMethod::Invoke函数
查看art::interpretrt::EnterInterpreterFromInvoke
进入Execute查看,这个方法代码比较多,就参考源码中的注释,接着进入ExecuteSwitch
进入ExecuteSwitchImpl发现最终进入的是ExecuteSwitchImplCpp 其中
继续分析发现有个DoInvoke
返回调用了DoCallDoCall调用了DoCallCommon,中间又调用了PerformCall,函数的实现细节都在源码中打注释了
 

二、网络受限:

一、java层
packages/modules/NetworkStack/src/android/net/util/NetworkStackUtils.java
把google的链接改为
二、xml层(不确定这个要不要改,如果没效果把这个也改了)
packages/modules/NetworkStack/res/values/config.xml
default_captive_portal_http_urldefault_captive_portal_https_url 改成上面的两个地址

三、给予其他App Root权限(Root管理器)

 
一共修改11个文件

1、修改SELinux

/system/core/init/selinux.cpp
frameworks/base/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
 

2、增加su

编译su.cpp到system/bin目录下,为adb添加remount命令build/make/target/product/base_system.mk
注册用户组权限检测 
system/extras/su/su.cpp
给su文件默认授予root权限 
/system/core/libcutils/fs_config.cpp
 
/frameworks/base/core/jni/com_android_internal_os_Zygote.cpp

3、解锁fastboot,并关闭verity

system/core/adb/Android.bp(Android12在packages/module/adb/Android.bp)
system/core/adb/daemon/main.cpp(packages/module/adb/daemon/main.cpp)
system/core/fs_mgr/Android.bp
user版本启动overlayfs来装载remount对应分区 system/sepolicy/Android.mk
systen/sepolicy/definitions.mk

4、默认开启OEM解锁,去除解锁警告(Android12亲测不开机)

默认开启OEM解锁选项 frameworks/base/services/usb/java/com/android/server/usb/UsbDeviceManager.java
💡
root权限管理思路 1.我们让应用在执行su命令的时候获取这个应用的包名,具体实现方式是:在su源代码中实现localsocket连接,和应用层的supersu进行通信,然后通过getppid()获取调用su命令的应用的pid,之后再通过cat /proc/"+ pid +"/cmdline -r 命令获取进程名称(应用包名),之后将包名通过localsocket发送给supersu,在supersu里接收到包名后,检测此应用是否获得了root权限授权,决定是否切换为root权限。 2.利用List allApps = getPackageManager().getInstalledApplications(0);获取本机安装的所有app应用信息,其中包括包名,然后使用sqlite数据库将所有包名和是否获得root授权的信息建表,对权限进行管理。
更改su.cpp的源码 详见GitHub,记得Android.mk需要更改 否则编译不通过
 

四、frida持久化

首先创建一个系统服务作为接收,具体的操作方法这里不再展开
frameworks/base/cmds/下创建一个文件夹,将frida-gadget放进去
build/make/target/product/handheld_system.mk加入以下内容
系统在copy文件时会做一个限制检查,这里会报一个错误,不允许copy ELF文件,我们有两个方法解决
1、使用官方推荐的方式,定义一个bp文件使用cc_prebuilt_library_shared去定义,然后在device.mk里面PRODUCT_PACKAGES加上我们定义的
2、投机取巧,直接定位到报错的mk文件,然后关闭检测
这里使用第二个方法:build/core/Makefile
搜索elf找到并注释
 
参考链接
  • ROM
  • AOSP
  • Android
  • Android系统启动流程Pixel5 编译、刷入AOSP
    Loading...
    目录