Patching the adb daemon to run as root

Posted on Oct 20, 2020

Most of the time, to get root on an Android device you will use a tool like Magisk. However, there may be cases where Magisk doesn’t work or isn’t ideal. For example, on IoT or embedded devices that don’t have a traditional Android interface.

In these instances, it might be easiest to interact with the device through adb. Though more often than not adb runs as the lower privileged shell user, and the adb root command doesn’t let you elevate permissions. It simply returns a adbd cannot run as root in production builds error.

If you search around the web you will find various advice telling you to add the ro.debuggable=1 setting to the default.prop file, which is supposed to tell adbd it’s allowed to run as root. This may work, but if it doesn’t it’s probably because the version of Android you’re using wasn’t compiled with the ALLOW_ADBD_ROOT flag, and the adbd code isn’t configured to check the ro.debuggable setting.

Fortunately not all hope is lost. If all else fails, and you have the ability to upload a new boot partition to the device, you should be able to patch the adbd binary to run as root. Regardless of how the rest of the system has been configured.

Christian Weiske has a great post that introduced me to this concept. In my case, I just had to make a few modifications since the version of adbd I had was “newer” (Nougat), and I used a different method for modifying the boot image.

Extracting adbd from the boot image

I’ll assume you have already found a way to get a hold of the boot image. This process is highly dependent on the chipset, so you may need to Google around a bit.

The adbd binary is located in the sbin directory of the boot image. The easiest method I’ve found for extracting and modifying the boot image is with the magiskboot tool. You can find it in the latest Magisk release zip archive. Note: you may need to scroll down to find a recent Magisk release, it’s not in the manager releases.

Extracting the boot image and ramdisk:

magiskboot unpack boot.img
magiskboot cpio ramdisk.cpio extract

Modifying the binary

Download a copy of Ghidra 🐉, create a new project, and import the adbd binary you just extracted. Give it a minute or two to analyze all the code. (if you need Java, try Amazon’s Corretto or AdoptOpenJDK)

I found it much easier to figure out what I was looking at by simultaneously reading the Android source code. As Christian points out in his post, it’s easiest to search for the Local port disabled string, or 0x7d0, which is the shell user’s id in hex. This should bring you to the part of the code where adbd switches from root to the shell user. The goal here is to “comment out” that code, so the program never stops running as root.

Below is the source code we are trying to target in Ghidra.

// Don't run as root if running in secure mode.
if (should_drop_privileges()) {
    drop_capabilities_bounding_set_if_needed();
    minijail_change_gid(jail.get(), AID_SHELL);
    minijail_change_uid(jail.get(), AID_SHELL);
    // minijail_enter() will abort if any priv-dropping step fails.
    minijail_enter(jail.get());
    D("Local port disabled");
}

Disassembled / decompiled code (function names renamed to improve readability)

Basically, we want to remove the calls to minijail_change_gid and minijail_change_uid. This can be done by replacing the bytes with a series of NOP / no operation commands (00 BF).

Hydra doesn’t do a great job at directly modifying ARM binaries, but a generic hex editor should do the trick. I used HxD.

To remove the call to minijail_change_gid, find and replace the following series of bytes:

4f f4 fa 61 2d f0 3e f9 <- target
00 BF 00 BF 00 BF 00 BF <- replaced with NOPs

Do the same for minijail_change_uid, and save the patched binary.

Patch and upload the new boot image

You can use magiskboot to patch your ramdisk, and package up a new boot image. The repack command should create a new-boot.img file, that you can upload back to your Android device.

magiskboot cpio ramdisk.cpio "add 750 sbin/adbd patched_adbd"
magiskboot repack boot.img

Assuming all went well, adbd should be running as root!

Happy hacking 😊