type
status
date
slug
summary
tags
category
icon
password
此文章是我在学习AOSP源码定制时,写的笔记,要配合源码以及自己打的注释一块查看,文章写的非常没有逻辑性,语句也非常不通顺,仅仅只是自己学习临时打的草稿笔记(且可能有很多地方说的不对,还请提醒我)
一、源码分析学习
一个App的启动流程:
前面还有一些细节,是从Launcher开始的,这里暂时不做探究,直接从Zygoto进程开始,大概流程:
1、
Launcher
的startActivity
方法,通过Binder
通信,调用ActivityManagerService
的startActivity
方法2、一系列骚操作后,调用
startProcessLocked
方法来创建新的进程3、该方法会通过
socket
通道传递参数给Zygote
进程,Zygote
孵化自身,调用ZygoteInit.main
方法来实例化ActivityThread
对象并最终返回新进程的pid 也就是接下来要详细讲的流程ZygoteInit.→main()
初始化和fork SystemServer
,循环监听socket 等待应用程序启动链接,为程序创建pid
和启动入口
ZygoteServer.runSelectLoop()
接收套接字链接,根据socket信息新建子进程ZygoteConnection.processCommand()
创建子进程并返回pid,关闭套接字链接,父进程继续监听socketZytoteConnection.handleChildProc()
Zygote设置AppProcessName
并调用zygoteinitZygoteInit.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
方法进行接收,查看switch
的BIND_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
方法一路跟踪到OpenAllDexFilesFromZip
、OpenOneDexFilesFromZip
再回到
initInstrumentation
方法去查看
loadClass
的实现走到
BaseDexClassLoader
中再去
DexPathList
中查看findClass
方法dexFile
是DexFile
类对象,去DexFile类中查看loadClasBinaryName
方法搜索得到
往下分析 找到一个名字极其像关键函数的函数
回顾一下,在
ActivityThread
类中,有一个反射调用,我们跟踪到Method.invoke
中 分析一下是如何调用的查看
InvokeMethod
,他里面调用了InvokeWithArgArray
查看
ArtMethod::Invoke
函数查看
art::interpretrt::EnterInterpreterFromInvoke
进入
Execute
查看,这个方法代码比较多,就参考源码中的注释,接着进入ExecuteSwitch
进入
ExecuteSwitchImpl
发现最终进入的是ExecuteSwitchImplCpp
其中继续分析发现有个
DoInvoke
返回调用了
DoCall
,DoCall
调用了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_url
和default_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找到并注释
参考链接