Compiling eBPF Programs on Android Pixel 6: Hiding Processes and Changing MAC Addresses

Compiling eBPF Programs on Android Pixel 6: Hiding Processes and Changing MAC Addresses

Background

Previously, I found an interesting repository on GitHub called bad-bpf. After some effort, I finally managed to compile it successfully on my phone, achieving the effects of replacing text and hiding processes as described in the repository.

Other functionalities have not been verified. Below is the process of my attempts.

Environment Setup

The project describes using an Ubuntu x86 environment for compilation. With a “try anything” mindset, I thought it should work on an ARM64 platform as well. After all, it’s worth a shot.

In the bpf-developer-tutorial project, there is a document on using eBPF programs on Android. The first step in setting up the environment is based on this article.

https://github.com/eunomia-bpf/bpf-developer-tutorial/blob/main/src/22-android/README.md

However, the environment described in the documentation is:

  • Android Emulator (Android Studio Flamingo | 2022.2.1)
  • AVD: Pixel 6
  • Android Image: Tiramisu Android 13.0 x86_64 (5.15.41-android13-8-00055-g4f5025129fe8-ab8949913)

Currently, I am testing on a real Pixel 6 device running Android 13, 5.10, and I am trying to replicate the setup.

0x0

0. Ensure your device is rooted, and the kernel has enabled the CONFIG_DEBUG_INFO_BTF option required for eBPF support.

1. Download the latest version of debianfs-arm64-full.tar.gz from the releases page of the eadb repository. Make sure to download the arm64 version, not amd64.

2. Clone the entire eadb repository and push the files to your phone. Here are the steps.

# Terminal
db push debianfs-arm64-full.tar.gz /data/local/tmp/deb.tar.gz
# In the eadb repository directory
adb push assets /data/local/tmp/assets
# Enter the device environment
adb shell
su
mkdir -p /data/eadb
mv /data/local/tmp/assets/* /data/eadb
mv /data/local/tmp/deb.tar.gz /data/eadb/deb.tar.gz
rm -r /data/local/tmp/assets
chmod +x /data/eadb/device-*
/data/eadb/device-unpack
# Wait for the unpacking to complete; it may take some time. After completion, you can enter Debian.
# If the terminal closes or if you open multiple terminals, you can continue executing the following command.
# Enter Debian; this command can be executed from any location after entering shell su.
/data/eadb/run /data/eadb/debian
# Upon success, you will see a prompt like this
root@localhost:/#

0x1

Network environment requirements: the phone must be connected to the internet.

Update the sources in Debian:

apt-get update
apt-get upgrade

Download the necessary tools:

# The following Ubuntu packages need to be installed according to the bad project documentation
apt install build-essential clang-11 libelf-dev zlib1g-dev libbfd-dev libcap-dev linux-tools-common linux-tools-generic
# In Debian, linux-tools-common and linux-tools-generic do not exist.
# After testing, it is possible to execute the following commands without installing these 2 packages.
apt install build-essential clang-11 libelf-dev zlib1g-dev libbfd-dev libcap-dev
# Download the necessary git
apt install git
# Configure git username and email; you can set them arbitrarily.
git config --global user.name "Your Name"
git config --global user.email "[email protected]"

Download the code and try to compile it: (the following is copied from the documentation) (remember to keep the phone connected to the internet)

# /home
git clone --recursive https://github.com/pathtofile/bad-bpf.git
cd bad-bpf/src
make -j4
# Here an error will occur, indicating a missing libbpf file. bad-bpf depends on libbpf, and the code needs to be synchronized.
# After completion, enter the project directory to update the dependency repository.
cd bad-bpf
git submodule update --init
# No error message means success. Wait for the update to complete, then continue compiling.
cd bad-bpf/src
make -j4

Starting the Repository Compilation

I encountered an error right after obtaining the repository code:

  BPF      .output/writeblocker.bpf.o
  GEN-SKEL .output/bpfdos.skel.h
/bin/sh: line 1: /home/test/bad-bpf/tools/bpftool: cannot execute binary file: Exec format error
make: *** [Makefile:68: .output/bpfdos.skel.h] Error 126
make: *** Deleting file '.output/bpfdos.skel.h'
make: *** Waiting for unfinished jobs....
textreplace2.bpf.c:115:67: warning: implicit declaration of function 'PT_REGS_PARM2' is invalid in C99 [-Wimplicit-function-declaration]
    bpf_probe_read_user(&check_filename, FILENAME_LEN_MAX, (void*)PT_REGS_PARM2(regs));
                                                                  ^
textreplace2.bpf.c:115:60: warning: cast to 'void *' from smaller integer type 'int' [-Wint-to-void-pointer-cast]
    bpf_probe_read_user(&check_filename, FILENAME_LEN_MAX, (void*)PT_REGS_PARM2(regs));
                                                           ^~~~~~~~~~~~~~~~~~~~~~~~~~
textreplace2.bpf.c:164:37: warning: implicit declaration of function 'PT_REGS_PARM1' is invalid in C99 [-Wimplicit-function-declaration]
    unsigned int fd = (unsigned int)PT_REGS_PARM1(regs);
                                    ^
textreplace2.bpf.c:170:35: warning: implicit declaration of function 'PT_REGS_PARM2' is invalid in C99 [-Wimplicit-function-declaration]
    long unsigned int buff_addr = PT_REGS_PARM2(regs);
                                  ^
textreplace2.bpf.c:174:32: warning: implicit declaration of function 'PT_REGS_PARM3' is invalid in C99 [-Wimplicit-function-declaration]
    size_t buff_size = (size_t)PT_REGS_PARM3(regs);
                               ^
5 warnings generated.
writeblocker.bpf.c:29:14: warning: implicit declaration of function 'PT_REGS_PARM1' is invalid in C99 [-Wimplicit-function-declaration]
    u32 fd = PT_REGS_PARM1(regs);
             ^
writeblocker.bpf.c:30:17: warning: implicit declaration of function 'PT_REGS_PARM3' is invalid in C99 [-Wimplicit-function-declaration]
    u32 count = PT_REGS_PARM3(regs);
                ^
2 warnings generated.

Based on the first error message: make: *** [Makefile:68: .output/bpfdos.skel.h] Error 126, the content of line 68 in the current Makefile is as follows:

Compiling eBPF Programs on Android Pixel 6: Hiding Processes and Changing MAC Addresses

The comment indicates a problem occurred while generating a BPF-related file. From the above code, I found a reference to a vmlinux.h file. The documentation describes:

The binaries will be built into bad-bpf/src/bin. If you encounter issues related to vmlinux.h, try remaking the file for your specific kernel and distribution:

cd bad-bpf/tools
./bpftool btf dump file /sys/kernel/btf/vmlinux format c > ../src/vmlinux.h

This project also has this file:

|-- vmlinux.h -> vmlinux_508.h
|-- vmlinux_508.h
|-- writeblocker.bpf.c
`-- writeblocker.c

The experimental environment for this project is Ubuntu x86. This file needs to be exported according to your specific environment. The command is provided. Use the bpftool tool in the tools directory to export the file and replace src/vmlinux.h.

This bpftool may also be platform-dependent? Let’s check the file information:

/bad-bpf/tools# file bpftool
bpftool: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 2.6.32, not stripped

It is for the x86 platform. Go to GitHub-libbpf to find bpftool; in the releases, there is an ARM64 version of bpftool-7.2.0. Make sure to download the correct arm64 file.

Compiling eBPF Programs on Android Pixel 6: Hiding Processes and Changing MAC Addresses

After downloading, unzip it and replace the bpftool in /bad-bpf/tools. After replacement, export your current platform’s vmlinux.h:

cd bad-bpf/tools
bad-bpf/tools# file bpftool
bpftool: ELF 64-bit LSB executable, ARM aarch64, version 1 (GNU/Linux), statically linked, BuildID[sha1]=747432cd099516329186dd867f9c66257ba94f16, for GNU/Linux 3.7.0, stripped
# Download ARM64 tools
./bpftool btf dump file /sys/kernel/btf/vmlinux format c > ../src/vmlinux.h
# /bad-bpf/src#
make -j4

Continue compiling and encounter errors different from before:

  BINARY   hijackee
  CC       .output/bpfdos.o
  CC       .output/exechijack.o
textreplace2.bpf.c:115:67: warning: implicit declaration of function 'PT_REGS_PARM2' is invalid in C99 [-Wimplicit-function-declaration]
    bpf_probe_read_user(&check_filename, FILENAME_LEN_MAX, (void*)PT_REGS_PARM2(regs));
                                                                  ^
textreplace2.bpf.c:115:60: warning: cast to 'void *' from smaller integer type 'int' [-Wint-to-void-pointer-cast]
    bpf_probe_read_user(&check_filename, FILENAME_LEN_MAX, (void*)PT_REGS_PARM2(regs));
                                                           ^~~~~~~~~~~~~~~~~~~~~~~~~~
textreplace2.bpf.c:164:37: warning: implicit declaration of function 'PT_REGS_PARM1' is invalid in C99 [-Wimplicit-function-declaration]
    unsigned int fd = (unsigned int)PT_REGS_PARM1(regs);
                                    ^
textreplace2.bpf.c:170:35: warning: implicit declaration of function 'PT_REGS_PARM2' is invalid in C99 [-Wimplicit-function-declaration]
    long unsigned int buff_addr = PT_REGS_PARM2(regs);
                                  ^
textreplace2.bpf.c:174:32: warning: implicit declaration of function 'PT_REGS_PARM3' is invalid in C99 [-Wimplicit-function-declaration]
    size_t buff_size = (size_t)PT_REGS_PARM3(regs);
                               ^
  CC       .output/pidhide.o
  CC       .output/sudoadd.o
5 warnings generated.
  GEN-SKEL .output/textreplace.skel.h
writeblocker.bpf.c:29:14: warning: implicit declaration of function 'PT_REGS_PARM1' is invalid in C99 [-Wimplicit-function-declaration]
    u32 fd = PT_REGS_PARM1(regs);
             ^
writeblocker.bpf.c:30:17: warning: implicit declaration of function 'PT_REGS_PARM3' is invalid in C99 [-Wimplicit-function-declaration]
    u32 count = PT_REGS_PARM3(regs);
                ^
2 warnings generated.

Continue to check the Makefile.

At the beginning, I found some suspicious code:

# SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause)
OUTPUT := .output
CLANG ?= clang-11
LLVM_STRIP ?= llvm-strip-11
BPFTOOL ?= $(abspath ../tools/bpftool)
LIBBPF_SRC := $(abspath ../libbpf/src)
LIBBPF_OBJ := $(abspath $(OUTPUT)/libbpf.a)
INCLUDES := -I$(OUTPUT)
CFLAGS := -g -Wall
ARCH := $(shell uname -m | sed 's/x86_64/x86/')

The value of ARCH is obtained from uname -m, and the following is a string replacement rule for this Ubuntu x86 platform code, which certainly does not apply to the phone. The corresponding values can refer to: https://github.com/libbpf/libbpf-bootstrap/blob/master/examples/c/Makefile:

ARCH ?= $(shell uname -m | sed 's/x86_64/x86/' \
    | sed 's/arm.*/arm/' \
    | sed 's/aarch64/arm64/' \
    | sed 's/ppc64le/powerpc/' \
    | sed 's/mips.*/mips/' \
    | sed 's/riscv64/riscv/' \
    | sed 's/loongarch64/loongarch/')

Here, I got aarch64, so I need to replace it with arm64. The code can be modified as follows:

ARCH := $(shell uname -m | sed 's/aarch64/arm64/')
# You can also directly assign it, since we know what platform we are on.
ARCH := arm64

Continue compiling:

bad-bpf/src# make clean
bad-bpf/src# make -j8
 MKDIR    .output
  MKDIR    .output/libbpf
  BINARY   hijackee
  LIB      libbpf.a
make[1]: pkg-config: No such file or directory
  MKDIR    staticobjs
  INSTALL  bpf.h libbpf.h btf.h xsk.h bpf_helpers.h bpf_helper_defs.h bpf_tracing.h bpf_endian.h bpf_core_read.h libbpf_common.h
  CC       btf.o
  CC       bpf.o
  CC       libbpf.o
  CC       libbpf_errno.o
  CC       netlink.o
  CC       nlattr.o
  CC       str_error.o
  CC       libbpf_probes.o
  CC       bpf_prog_linfo.o
  CC       xsk.o
  btf_dump.o
  CC       hashmap.o
  CC       ringbuf.o
  CC       strset.o
  CC       linker.o
  INSTALL  libbpf.pc
  AR       libbpf.a
  INSTALL  libbpf.a
  BPF      .output/bpfdos.bpf.o
  BPF      .output/exechijack.bpf.o
  BPF      .output/pidhide.bpf.o
  BPF      .output/sudoadd.bpf.o
  BPF      .output/textreplace.bpf.o
  BPF      .output/textreplace2.bpf.o
  BPF      .output/writeblocker.bpf.o
  GEN-SKEL .output/bpfdos.skel.h
  CC       .output/bpfdos.o
  GEN-SKEL .output/pidhide.skel.h
  BINARY   bpfdos
  CC       .output/pidhide.o
  GEN-SKEL .output/exechijack.skel.h
  CC       .output/exechijack.o
  BINARY   pidhide
  GEN-SKEL .output/sudoadd.skel.h
  CC       .output/sudoadd.o
  BINARY   exechijack
  GEN-SKEL .output/textreplace.skel.h
  CC       .output/textreplace.o
  BINARY   sudoadd
  BINARY   textreplace
  GEN-SKEL .output/writeblocker.skel.h
  CC       .output/writeblocker.o
  GEN-SKEL .output/textreplace2.skel.h
  BINARY   writeblocker
  CC       .output/textreplace2.o
/bad-bpf/src#

Success! Let’s test it. (After searching, the products are located at: /bad-bpf/src/bin/)

./bpfdos
./textreplace -f /sys/class/net/wlan0/address -i '66:c7:64:41:98:9a' -r '00:00:00:00:00:01'
# All encountered errors
libbpf: failed to find skeleton map '.rodata.str1.1'
Failed to open BPF program: No such process
  • The skeleton map is a special type of kernel data structure required when loading eBPF programs. They are usually declared in the source code of the eBPF program and created by the kernel when loading the program. Skeleton maps are used to pass data between the kernel and user space.
  • “.rodata.str1.1” is a specific string that may be an identifier used in the eBPF program.
  • “No such process” indicates that the corresponding process could not be found.

There may be several reasons for this error:

  1. Compilation issue: First, ensure that your eBPF program has been compiled correctly. When compiling eBPF programs, specific compiler options and header file paths may be required. Ensure that you compile the eBPF program correctly and that no compilation errors occurred.
  2. Kernel support issue: eBPF programs need to be supported by the kernel version on which they are run. If your kernel version is too old or does not have eBPF support enabled, this may cause eBPF program loading to fail. Ensure that your kernel version supports eBPF and has been correctly configured and compiled.
  3. Dependency issue: eBPF programs may depend on other libraries or modules. If your system lacks these dependencies, loading the eBPF program may fail. Check whether your system has all the required dependencies installed, and that their versions match the requirements of the eBPF program.
  4. Faulty eBPF program: Finally, there may be issues with the eBPF program itself. Review your eBPF program code to ensure it has no syntax errors or other logical errors.

The above is the AI’s response, which I find confusing. The compilation process provided in the repository is simply to run make

When I learned before, I compiled bootstrap. Perhaps I could try compiling the code in there.

I put textreplace.c, textreplace.bpf.c, pidhide.c, and pidhide.bpf.c into the example for compilation.

During the compilation, I found that the header files common.h and common_um.h were missing, so I copied the corresponding header files from src as well.

After completing the compilation, I found that there were no corresponding products. After troubleshooting, I found that in line 27 of the Makefile, I needed to define the programs to compile:

# Just add the programs to compile at the end; the last 2 are added based on filename rules.
APPS = minimal minimal_legacy bootstrap uprobe kprobe fentry usdt sockfilter tc ksyscall textreplace pidhide

Continue compiling the static library:

EXTRA_LDFLAGS=--static make -j4

Obtained products:

Compiling eBPF Programs on Android Pixel 6: Hiding Processes and Changing MAC Addresses

Here, only 2 demos were compiled, and after testing, they successfully hid the process. However, after a long time, the phone would freeze. I am not sure if it is a code issue or a kernel issue, so I will skip this for now.

For replacing text on the phone, I only tested changing the MAC address. The MAC address file on the phone is located at:

/sys/class/net/wlan0/address
# In the repository tested on Ubuntu, the phone's location is different, but you can check by
cat /sys/class/net/wlan0/address
66:c7:64:41:98:9a

./textreplace -f /sys/class/net/wlan0/address -i '66:c7:64:41:98:9a' -r '00:00:00:00:00:01'

cat /sys/class/net/wlan0/address
00:00:00:00:00:01
Compiling eBPF Programs on Android Pixel 6: Hiding Processes and Changing MAC Addresses

Thus, my attempts have concluded. The compilation scheme is for reference only, as the results may vary based on different environments on different phones.

References

https://www.bilibili.com/video/BV19t4y1H71G/?spm_id_from=333.999.0.0

https://github.com/pathtofile/bad-bpf

https://github.com/libbpf/libbpf-bootstrap

https://github.com/libbpf/libbpf

https://github.com/libbpf/bpftool

https://github.com/iovisor/bcc

🌟Welcome to learn Android reverse engineering technology and prepare for Android security interviews. Join my knowledge circle for more resources and monthly knowledge sharing!

Compiling eBPF Programs on Android Pixel 6: Hiding Processes and Changing MAC Addresses

Reference Material

  • https://botan.randombit.net/handbook/building.html#for-android[1]

Reference

[1]

https://botan.randombit.net/handbook/building.html#for-android: https://botan.randombit.net/handbook/building.html#for-android

Leave a Comment