吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 6019|回复: 24
收起左侧

[Android 原创] 为Android平台编译eBPF程序

  [复制链接]
Leland 发表于 2022-6-15 21:53

为Android平台编译eBPF程序

背景

最近在分析一个安卓程序,然而这个安卓程序混淆比较复杂,并且有许多反调试点。在苦恼的同时我又在思考,既然我们已经取得了系统的Root权限,照理说我们完全可以不必再在用户层和程序做对抗。如果我们能够上升到内核中对程序做全面的监控,就可以实现一个类似火绒剑的工具,帮助我们分析程序的行为(文件操作、网络IO等),而普通的程序完全没有反抗的能力,岂不美哉?
然而安卓系统的内核修改编译工作并不简单,而直接对内核进行修改耗时耗力,成果往往限制于某个机型不能通用,甚至造成内核崩溃之类的后果。  

eBPF简介

简单来说,eBPF 是 Linux 内核中一个非常灵活与高效的类虚拟机(virtual machine-like)组件, 能够在许多内核 hook 点安全地执行字节码(bytecode),很多内核子系统都已经使用了 BPF。
当然,这是linux内核中比较新的特性,可能需要较新的手机才能使用。

安卓平台eBPF的编译

网络上关于eBPF的资料少之又少,不过大致上总结出的编译方法有如下几种:  

  1. 使用adeb编译
    adeb类似于linux deploy等,利用chroot技术在安卓手机上运行一个Debian虚拟机,可以利用这个环境安装BCC(eBPF的一个工具库)等。
    这个方法测试可行,但是比较麻烦,还要解决很多依赖问题,体验不是很好。
  2. 完全下载AOSP项目,增加代码后进行编译
    无需多言,这种方法更加复杂,还要占用相当多的空间且完全无用,非常不优雅。

在进行一天的研究后我终于发现了一个简单的交叉编译eBPF的方法供安卓平台使用。
首先,其实谷歌是给了eBPF的文档的,可惜只有寥寥几篇。还好我们尚可管中窥豹,对编译过程有一些了解。在阅读谷歌最新的Soong编译系统源码后我们能够找到关于eBPF程序的编译代码,位于bpf.go
其中的关键:

Command:"$ccCmd --target=bpf -c $cFlags -MD -MF ${out}.d -o $out $in",

可见最终还是调用clang进行编译。再查找cFlags,在:

cflags := []string{
        "-nostdlibinc",
        // Make paths in deps files relative
        "-no-canonical-prefixes",
        "-O2",
        "-isystem bionic/libc/include",
        "-isystem bionic/libc/kernel/uapi",
        // The architecture doesn't matter here, but asm/types.h is included by linux/types.h.
        "-isystem bionic/libc/kernel/uapi/asm-arm64",
        "-isystem bionic/libc/kernel/android/uapi",
        "-I       frameworks/libs/net/common/native/bpf_headers/include/bpf",
        // TODO(b/149785767): only give access to specific file with AID_* constants
        "-I       system/core/libcutils/include",
        "-I " + ctx.ModuleDir(),
    }

这些便是编译选项。我们可以依照这些信息写出MakeFile。

ebpf-build:
    clang \
    --target=bpf \
    -c \
    -nostdlibinc -no-canonical-prefixes -O2 \
    -isystem bionic/libc/include \
    -isystem bionic/libc/kernel/uapi \
    -isystem bionic/libc/kernel/uapi/asm-arm64 \
    -isystem bionic/libc/kernel/android/uapi \
    -I       system/core/libcutils/include \
    -I       system/bpf/progs/include \
    -MD -MF example.d -o example.o src/example.c

这些选项中,-isystem-I都是引入include库的选项,那么这些库在哪里去找呢?很简单,这个编译程序原本是在AOSP项目中运行的,我们只需要取AOSP项目中查找这些文件即可。
稍加寻找我们可以找到这些文件分别在

  1. bionic
  2. core
  3. bpf

需要注意的是这些仓库都有很多分支,下载的时候注意指定需要的分支(如android11就指定android11的分支)

git clone -b android11-gsi https://android.googlesource.com/platform/bionic
git clone -b android11-gsi https://android.googlesource.com/platform/system/core/
git clone -b android11-gsi https://android.googlesource.com/platform/system/bpf/

注意文件夹组织结构,参考AOSP中的结构即可

├── bionic
└── system
    ├── core
    └── bpf

下载好之后安装一下clang之类(报错缺什么装什么),代码写好,然后make就可以了。
注意我写的makefile

ebpf-build:
    clang \
    --target=bpf \
    -c \
    -nostdlibinc -no-canonical-prefixes -O2 \
    -isystem bionic/libc/include \
    -isystem bionic/libc/kernel/uapi \
    -isystem bionic/libc/kernel/uapi/asm-arm64 \
    -isystem bionic/libc/kernel/android/uapi \
    -I       system/core/libcutils/include \
    -I       system/bpf/progs/include \
    -MD -MF example.d -o example.o src/example.c

源代码在src/example.c,最后输出example.o(eBPF文件)和example.d(依赖文件,没什么用)

这里我随便用了一个eBPF代码如下:

#include <linux/bpf.h>
#include <stdbool.h>
#include <stdint.h>
#include <bpf_helpers.h>

DEFINE_BPF_MAP(cpu_pid_map, ARRAY, int, uint32_t, 1024);

struct switch_args {
    unsigned long long ignore;
    char prev_comm[16];
    int prev_pid;
    int prev_prio;
    long long prev_state;
    char next_comm[16];
    int next_pid;
    int next_prio;
};

SEC("tracepoint/sched/sched_switch")
int tp_sched_switch(struct switch_args* args) {
    int key;
    uint32_t val;

    key = bpf_get_smp_processor_id();
    val = args->next_pid;

    bpf_cpu_pid_map_update_elem(&key, &val, BPF_ANY);
    return 0;
}

char _license[] SEC("license") = "GPL";

编译完成后将产生的example.o文件放到安卓系统的/system/etc/bpf/即可。system分区不可写的设备用magisk挂载也是可以的,安卓系统会在启动时自动从这个目录下加载eBPF文件。

重启后我们可以看到系统已经成功加载了eBPF程序

apollo:/ # ls /sys/fs/bpf | grep example
map_example_cpu_pid_map
prog_example_tracepoint_sched_sched_switch

至于eBPF程序和用户态程序的通信等等,我也还在学习中,总之已经先把编译问题解决了。

免费评分

参与人数 13威望 +2 吾爱币 +114 热心值 +13 收起 理由
菜鸟也想飞 + 1 + 1 谢谢@Thanks!
火蜥蜴 + 1 + 1 谢谢@Thanks!
qtfreet00 + 2 + 100 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
debug_cat + 2 + 1 热心回复!
xyl52p + 1 + 1 用心讨论,共获提升!
laughtosky000 + 1 + 1 我很赞同!
喵喵爱吃鱼 + 1 + 1 我很赞同!
lingyun011 + 1 + 1 热心回复!
5omggx + 1 + 1 用心讨论,共获提升!
柑桔 + 1 + 1 我很赞同!
Dmail + 1 + 1 谢谢@Thanks!
Starry-OvO + 1 + 1 用心讨论,共获提升!
Shocker + 2 + 1 我很赞同!

查看全部评分

本帖被以下淘专辑推荐:

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

Shocker 发表于 2022-6-18 23:59
我写了个监控sys_enter的,大佬看看,避免重复造轮子。https://pshocker.github.io/2022/ ... %E8%B0%83%E7%94%A8/
 楼主| Leland 发表于 2022-6-15 22:48

确实看了维术大佬的文章才开始研究的,挺有意思。他用的就是adeb搞的,我另外搞了个法子。
补个维术公众号的链接
https://mp.weixin.qq.com/s/eI61wqcWh-_x5FYkeN3BOw
lospring 发表于 2022-6-15 22:45
Shocker 发表于 2022-6-16 00:17
我直接在aosp环境里编译的,大佬666,如果是文件监控该怎么写呢?
Starry-OvO 发表于 2022-6-16 01:53
Leland 发表于 2022-6-15 22:48
确实看了维术大佬的文章才开始研究的,挺有意思。他用的就是adeb搞的,我另外搞了个法子。
补个维术公众 ...

很有意思的文章
goda 发表于 2022-6-16 08:33
插个眼插个眼
林伊轩 发表于 2022-6-16 15:07
看不懂....但觉得有用
huansheng 发表于 2022-6-16 21:59
看不懂,但感觉很牛逼
醉心i 发表于 2022-6-16 23:40
虽然看不懂 但是感觉很牛
gaybc 发表于 2022-6-17 14:08
最近正好有EBPF的CVE,乐
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

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

GMT+8, 2024-11-21 19:55

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

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