How-To: Build a Custom Kernel With Kprobes for Android
Before you continue reading, you might want to check whether the kernel on your device already supports kprobes (even though I haven’t seen any stock or popular custom kernel, such as franco.Kernel, which does):
$ adb shell cat /proc/kallsyms | grep register_kprobe
If you receive some output (e.g.,
00000000 T register_kprobe),
then the answer is yes, your kernel has kprobes enabled; and there
is no need to read any further.
Building kernel with kprobes (and boot image) for Nexus 5, Android 5.1.1
I tested the following recipe on
Ubuntu 14.04. It should work in a
very similar way also for any other (Nexus) device and Android
version–assuming you have access to the right kernel sources.
Note: I assume in the following that all commands are executed in the same working directory.
1) Getting the right kernel sources
For all Google Nexus devices there is a git repository available that contains the matching kernel sources. For the Nexus 4, Nexus 5, Nexus 6:
$ git clone https://android.googlesource.com/kernel/msm.git
More specifically, you need to checkout the commit that contains the sources that were used for the kernel running on your phone at hand:
$ adb shell cat /proc/version | grep -e "[0-9.]*-g[a-z0-9]*" -o
The output is
3.4.0-gbebb36b (you find the same info on
your phone under
Settings -> About phone -> Kernel version). The
you, which commit was used:
$ cd msm; git checkout bebb36b
2) Create kernel configuration with kprobes
First, generate the default configuration file
$ cd msm; ARCH=arm make hammerhead_defconfig
Then, append the following lines to
.config (order does not matter):
CONFIG_KPROBES=y CONFIG_KPROBES_SANITY_TEST=y # CONFIG_KPROBE_EVENT is not set # CONFIG_ARM_KPROBES_TEST is not set CONFIG_NET_TCPPROBE=y # seems necessary otherwise kernel does not boot CONFIG_MODULES=y # kprobes requires module support and makes no sense without CONFIG_MODULE_FORCE_LOAD=y CONFIG_MODULE_UNLOAD=y CONFIG_MODULE_FORCE_UNLOAD=y CONFIG_MODVERSIONS=y # possible to use modules compiled for different kernels # CONFIG_MODULE_SRCVERSION_ALL is not set
3) Compile kernel
There a several different toolchains for cross-compiling the kernel,
but not all are
for each Android version. For the
Nexus 5 and Android
>5.0, I used
arm-eabi- and not the
$ git clone https://android.googlesource.com/platform/prebuilts/gcc/linux-x86/arm/arm-eabi-4.7
Now, you can cross-compile the kernel:
$ cd msm; ARCH=arm CROSS_COMPILE=../arm-eabi-4.7/bin/arm-eabi- make
You might get asked further questions (which I usually answer all with
no) regarding missing configuration options in
later the kernel doesn’t boot, you need to go back to this step and
adapt the answers. Good luck!
4) Download boot image
You have by now already baked the new kernel. Congratulations! But to boot your device with it, it needs to be wrapped into a boot image (kernel + ramdisk).
You can get the matching boot image for your device and Android
version by downloading the original stock boot
image or, which I
recommend, directly pull it from your phone (using
$ adb shell su -c "ls -al /dev/block/platform/msm_sdcc.1/by-name/boot" lrwxrwxrwx root root 1970-09-29 07:33 boot -> /dev/block/mmcblk0p19 $ adb shell su -c "dd if=/dev/block/mmcblk0p19 of=/sdcard/my_nexus5_boot.img" $ adb pull /sdcard/my_nexus5_boot.img
The green parts in the command above vary, depending on which device and Android version you use.
5) Unpack and repackage boot image with new kernel
You need the tools
unmkbootimg (unpacking) and
$ git clone https://github.com/pbatard/bootimg-tools.git $ cd bootimg-tools; make
Unpack the boot image:
$ ./bootimg-tools/mkbootimg/unmkbootimg -i my_nexus5_boot.img
If anything went wrong you receive the output
error: not an Android
boot image. Otherwise you end up with the two files
ramdisk.cpio.gz in your directory.
Now repackage the new kernel
../msm/arch/arm/boot/zImage-dtb together with
ramdisk.cpio.gz into a new boot image. If you are
wondering, where the following quite long command comes from;
unmkbootimg provides it as part of the output during unpacking.
$ ./bootimg-tools/mkbootimg/mkbootimg --base 0 --pagesize 2048 --kernel_offset 0x00008000 \ --ramdisk_offset 0x02900000 --second_offset 0x00f00000 --tags_offset 0x02700000 \ --cmdline 'console=ttyHSL0,115200,n8 androidboot.hardware=hammerhead user_debug=31 \ maxcpus=2 \ msm_watchdog_v2.enable=1' --kernel ../msm/arch/arm/boot/zImage-dtb \ --ramdisk ramdisk.cpio.gz -o my_nexus5_kprobes_boot.img
6) Finally, boot your device with the boot image that contains the new kernel
Enjoy booting your new boot image with kprobes,
my_nexus5_kprobes_boot.img, How, I
have described in another article.