记录编译aosp+修改源码

安卓系统编译前置知识

aosp源码、对应的Linux内核、对应的手机驱动
这里的对应指的是要跟aosp系统版本对应,要与手机型号对应
推荐电脑配置 硬盘1t以上 内存 32g以上

android10 源码编译的下载

1. 源码下载

北方用清华镜像源
AOSP | 镜像站使用帮助 | 清华大学开源软件镜像站 | Tsinghua Open Source Mirror
南方用中科大镜像源
AOSP - USTC Mirror Help

3. 下载初始化包并解压

BASH

1
2
3
mkdir ~/bin
cd ~/bin
wget https://mirrors.tuna.tsinghua.edu.cn/aosp-monthly/aosp-20220222.tar

wget可以使用-c选项,来支持断点下载

PLAINTEXT

1
2
md5sum aosp-latest.tar
tar xvf aosp-latest.tar

4. 配置git

PLAINTEXT

1
2
3
sudo apt-get install git
git config --global user.email 24358757@qq.com
git config --global user.name "tuzi"

5. 下载repo

PLAINTEXT

1
2
3
4
5
6
7
echo "PATH=~/bin:\$PATH" >> ~/.bashrc
source ~/.bashrc
sudo apt-get install curl
curl -sSL  'https://gerrit-googlesource.proxy.ustclug.org/git-repo/+/master/repo?format=TEXT' |base64 -d > ~/bin/repo
chmod a+x ~/bin/repo
export REPO_URL='https://gerrit-googlesource.proxy.ustclug.org/git-repo'
cd aosp

6. 修改默认Python

PLAINTEXT

1
2
sudo unlink /usr/bin/python
sudo ln -s /usr/bin/python3.8 /usr/bin/python

7. 同步指定版本源码

PLAINTEXT

1
2
repo init -u git://mirrors.ustc.edu.cn/aosp/platform/manifest -b android-10.0.0_r11
repo sync

(a) 代号和细分版本号可查看以下链接
https://source.android.com/setup/start/build-numbers?hl=zh_cn

(b) 选个有驱动的,支持机型多的分支

(c) 谷歌手机设备驱动下载地址
https://developers.google.com/android/drivers

(d)同步之前先打个虚拟机快照

repo sync的时候有可能会遇到的问题
info: A new version of repo is available
repo: Updating release signing keys to keyset ver 2.3
warning: repo is not tracking a remote branch, so it will not receive updates
repo reset: error: Entry ‘.github/workflows/test-ci.yml’ not uptodate. Cannot merge.
fatal: 不能重置索引文件至版本 ‘v2.16^0’。

解决方案:

PLAINTEXT

1
2
3
4
cd ~/bin/aosp/.repo/repo
git pull
cd ~/bin/aosp
再次repo init 和 repo sync

android10源码的编译

1、安装JDK8

PLAINTEXT

1
2
3
sudo add-apt-repository ppa:openjdk-r/ppa
sudo apt-get update
sudo apt-get install openjdk-8-jdk

2、安装所需依赖 (Ubuntu 20.04)

PLAINTEXT

1
sudo apt-get install git-core gnupg flex bison build-essential zip curl zlib1g-dev gcc-multilib g++-multilib libc6-dev-i386 lib32ncurses5-dev x11proto-core-dev libx11-dev lib32z1-dev libgl1-mesa-dev libxml2-utils xsltproc unzip fontconfig libncurses5

参考以下地址
https://source.android.com/setup/build/initializing?hl=zh-cn

3、设备驱动的准备

谷歌手机设备驱动下载地址
https://developers.google.com/android/drivers

4、查看内核是否存在

源码下载完后最好看下里面有没有你手机对应的设备内核
如果没有,需要另外下载或者编译
构建内核  |  Android Open Source Project

5、编译源码

编译参考以下链接
https://source.android.com/setup/build/building

PLAINTEXT

1
2
3
4
5
6
make clobber
source build/envsetup.sh
lunch	# 选择设备内核和编译版本
		# 增加编译产品选项 修改aosp/device/google/marlin/AndroidProducts.mk
        -j 是cpu 选择适合自己的
make -j24

bonito 为手机代号
编译成功后编译生成的文件在home/tuzi/bin/aosp/out/target/product/bonito
对应管方刷机包里的img文件 都拖进去即可

编译补充

  1. 编译报错或者修改系统文件以后,都可以直接make,已经编译的部分会跳过

  2. make clean 会清除已经编译的,全部重来,在编译不同lunch选项时使用

  3. 单独编译system.img,在根目录下

PLAINTEXT

1
2
3
source build/envsetup.sh
lunch xxx
make systemimage -j4
  1. 单独编译某个模块 mmm packages/apps/tuzi
    将单独编译的模块打包到img镜像中 make snod

刷机相关命令

BASH

1
2
3
4
5
6
adb reboot bootloader
fastboot  flash  boot  boot.img
fastboot  flash  recovery  recovery.img
fastboot  flash  system  system.img
fastboot  flash  bootloader  bootloader.img
fastboot boot <recovery_filename>.img

AOSP源码导入到AndroidStudio

  1. 先成功编译一次,再使用以下方法导入

  2. 在ubuntu系统下,进入源码根目录,运行如下命令, 会在源码目录下的out/host/linux-x86/framework目录下生成了idegen.jar文件

PLAINTEXT

1
2
source build/envsetup.sh
mmm development/tools/idegen/
  1. 在源码根目录下继续执行如下命令,会在根目录下生成android.iml和android.ipr两个文件,这两个文件是AndroidStudio的工程配置文件

PLAINTEXT

1
development/tools/idegen/idegen.sh
  1. 安装并打开AndroidStudio,选择Open an existing Android Studio project,找到源码根目录,点击Android.ipr

Frida持久化介绍

  1. Hook的前提
    需要将代码或者能够完成Hook功能的东西,注入到目标进程中
    安卓中注入的方式:zygote注入、ptrace注入、文件感染等

  2. frida-server
    利用ptrace注入,需要root权限
    为了方便Hook代码修改,还设计成了需要与PC端连接

  3. frida-gadget
    当Hook代码修改测试完毕,可以通过它来实现免root、脱离PC
    但是它本身没有注入功能,需要将其打包到app中

  4. 魔改系统
    在app启动过程中,自动加载frida-gadget,就可以不用修改app了,更通用

frida持久化的几种方案

1.Android平台感染ELF文件实现模块注入

2.修改smali,调用System.loadLibrary来加载so

上面两种方法都有成品GitHub - nszdhd1/UtilScript: 一些frida脚本
使用方式见https://bbs.pediy.com/thread-268175.htm
3.修改rom 在app启动过程中加载frida-gadget

修改app启动流程

1. 打开app时判断是否启用持久化

/frameworks/base/core/java/android/app/ActivityThread.java
在以上文件中,添加代码

BASH

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// add
        String curPkgName = data.appInfo.packageName;
        int curUid = Process.myUid();
        if (curUid > 10000) {
            Persist.LOGD("curPkgName: " + curPkgName + " curUid: " + curUid);
            Boolean isPersist = Persist.isEnablePersist(curPkgName);
            Persist.LOGD("isPersist: " + isPersist);
            if (isPersist) {
                if(Persist.dotuzi(appContext, curPkgName)){
                    Persist.LOGD("dotuzi is ok");
                }else {
                    Persist.LOGD("dotuzi failed");
                };
            }
        }
// add

2. 增加自定义包和类

BASH

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
package com.tuzi;

import android.content.Context;
import android.util.Log;
import android.os.Process;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;

import org.json.JSONObject;


public class Persist {

    public static final String SO_NAME = "libtuzi.so";
    public static final String SO_CONFIG_NAME = "libtuzi.config.so";
    public static final String LIB32_DIR = "/system/lib";
    public static final String LIB64_DIR = "/system/lib64";

    public static final String SETTINGS_DIR = "/data/system/xsettings/tuzi/persist";
    public static final String ENABLE_PERSIST_FILE_NAME = "tuzi_persist";

    public static final String CONFIG_JS_DIR = "/data/system/xsettings/tuzi/jscfg";
    public static final String CONFIG_JS_FILE_NAME = "config.js";

    public static final String TAG_NAME = "tuzi_persist";


    public static void LOGD(String msg) {
        Log.d(TAG_NAME, msg);
    }

    private static boolean saveFile(String filePath, String textMsg) {
        try{
            FileOutputStream fileOutputStream = new FileOutputStream(filePath);
            fileOutputStream.write(textMsg.getBytes("utf-8"));
            fileOutputStream.flush();
            fileOutputStream.close();
            return true;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return false;
    }

    private static boolean copyFile(File srcFile, File dstFile) {
        try{
            FileInputStream fileInputStream = new FileInputStream(srcFile);
            FileOutputStream fileOutputStream = new FileOutputStream(dstFile);
            byte[] data = new byte[16 * 1024];
            int len = -1;
            while((len = fileInputStream.read(data)) != -1) {
                fileOutputStream.write(data,0, len);
                fileOutputStream.flush();
            }
            fileInputStream.close();
            fileOutputStream.close();
            return true;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return false;
    }
    // 判断app是否打开自动注入脚本功能
    public static boolean isEnablePersist(String pkgName) {
        // 判断文件是否存在 /data/system/xsettings/tuzi/persist/com.tuzi.app/tuzi_persist
        File enableFile = new File(SETTINGS_DIR, pkgName + File.separator + ENABLE_PERSIST_FILE_NAME);
        return enableFile.exists();
    }
    // 获取源JS文件路径
    private static File getConfigJSPath(String pkgName) {
        // /data/system/xsettings/tuzi/jscfg/com.tuzi.app/config.js
        return new File(CONFIG_JS_DIR, pkgName + File.separator + CONFIG_JS_FILE_NAME);
    }
    // 拷贝源JS文件到app私有目录
    private static File copyJSFile(Context context, String pkgName) {
        // 判断源JS文件是否存在
        File srcJSFile = getConfigJSPath(pkgName);
        if(!srcJSFile.exists()) {
            LOGD("srcJSFile not exists");
            return null;
        }
        // 拷贝源JS文件到app私有目录
        // /data/data/com.tuzi.app/files/config.js
        File dstJSFile = new File(context.getFilesDir(), CONFIG_JS_FILE_NAME);
        boolean isCopyJSOk = copyFile(srcJSFile, dstJSFile);
        if(!isCopyJSOk){
            LOGD("copyJSFile fail: " + srcJSFile + " -> " + dstJSFile);
            return null;
        }
        return dstJSFile;
    }
    // 生成Gadget配置文件
    private static boolean genGadgetConfig(Context context, File dstJSFile) {
        JSONObject jsonObject = new JSONObject();
        JSONObject childObj = new JSONObject();
        try {
            childObj.put("type", "script");
            childObj.put("path", dstJSFile.toString());
            jsonObject.put("interaction", childObj);
        }catch (Exception e){
            e.printStackTrace();
return false;
        }
        String configFilePath = context.getFilesDir() + File.separator + SO_CONFIG_NAME;
        boolean isSaveOk = saveFile(configFilePath, jsonObject.toString());
        if(!isSaveOk){
            LOGD("saveFile fail: " + configFilePath);
            return false;
        }
        return true;
    }
    // 拷贝源so文件到app私有目录
    private static File copySoFile(Context context) {
        // 判断源so文件是否存在
        // /system/lib/libtuzi.so
        // /system/lib64/libtuzi.so
        File srcSoFile = new File(LIB32_DIR, SO_NAME);
        if(Process.is64Bit()) {
            srcSoFile = new File(LIB64_DIR, SO_NAME);
        }
        if(!srcSoFile.exists()) {
            LOGD("srcSoFile not exists");
            return null;
        }
        // 拷贝源so文件到app私有目录
        // /data/data/com.tuzi.app/files/libtuzi.so
        File dstSoFile = new File(context.getFilesDir(), SO_NAME);
        if(srcSoFile.length() != dstSoFile.length()) {
            boolean isCopyFileOk = copyFile(srcSoFile, dstSoFile);
            if(!isCopyFileOk){
                LOGD("copySoFile fail: " + srcSoFile + " -> " + dstSoFile);
                return null;
            }
        }
        return dstSoFile;
    }
    // 进行Frida Gadget持久化
    public static boolean dotuziPersist(Context context, String pkgName) {
        File dstJSFile = copyJSFile(context, pkgName);
        if(null == dstJSFile) return false;
        if(!genGadgetConfig(context, dstJSFile)) return false;
        File dstSoFile = copySoFile(context);
        if(null == dstSoFile) return false;
        System.load(dstSoFile.toString());
        return true;
    }

}

3. 将自定义包加入白名单

/build/make/core/tasks/check_boot_jars/package_whitelist.txt

BASH

1
2
3
  • 21
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值