Skip to content

Instantly share code, notes, and snippets.

@CrashenX

CrashenX/android-root.md

Last active Dec 8, 2020
Embed
What would you like to do?
Android Live Root Image

Root Access to Android Device Without "Rooting" (The Hard Way)

Intro

N.B., This is for educational purposes only. If you want an easier method, compile an engineering build of the recovery.img and boot it: https://source.android.com/source/building.html

N.B., This is a work in progress. I'm updating for Nexus 5X and Android 6.0.0. Booting the modified recovery.img does not currently start adbd. I've created working images for Nexus 5 based on 4.4.2 and Nexus 7 based on 5.1.1 using slight derivations of the process described below.

Original Post: https://goo.gl/4r73We

Possible changes required to get adbd running:

  • persist.sys.usb.config=adb # Necessary? Maybe; Sufficient? No
  • ... ?

I picked up a new Nexus 5 with the goal of gaining root access to my device without flashing, installing any apps, or using any software that wasn't acquired directly from google.com or the Debian Sid repos. As I suspected, the most difficult problem I would encounter was trying to find helpful information among the mass of posts and blogs on "rooting" android devices. In the end the process was quite short (defining it, however, was not).

The solution was to create a live image to boot off of that enabled root access. From the live image the system can be modified (much like booting a workstation off a GNU/Linux Live CD).

In what follows, I define how to modify the factory recovery image (provides the recovery environment reached via the fastboot bootloader) and boot off of it to gain root access. Though I recommend using a modified recovery image to a make changes to your system, the instructions can be altered to instead modify the factory boot image (provides the environment your system generally runs from). This is done by replacing all occurrences of "recovery.img" with "boot.img" and skipping any sections or instructions prefixed with "(R):".

Note: This guide is probably not for you if you are not experienced with GNU/Linux and a shell such as bash or sh.

Building a Live Image

Set up directories

mkdir -p android/factory-images
mkdir android/my-live-image
mkdir android/src
pushd android

Get the source

su -l # login as root with root password (alternatively use sudo)
dpkg --add-architecture i386
dpkg --print-foreign-architectures
apt-get update
apt-get install build-essential\
                g++-multilib\
                git\
                libc6-dev-i386\
                python
exit # exit root shell

pushd src
for i in `echo -n 'build'\
                  'bionic'\
                  'external/clang'\
                  'external/compiler-rt'\
                  'external/jemalloc'\
                  'external/libcxx'\
                  'external/libcxxabi'\
                  'external/libselinux'\
                  'external/llvm'\
                  'external/pcre'\
                  'external/stlport'\
                  'external/zlib'\
                  'hardware/libhardware'\
                  'prebuilts/misc'\
                  'prebuilts/clang/linux-x86/host/3.6'\
                  'prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.9'\
                  'prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.15-4.8'\
                  'system/core'\
                  'system/extras'\
         `; do
    echo REPO: $i;
    git clone https://android.googlesource.com/platform/$i $i;
    pushd $i;
    git checkout marshmallow-release;
    popd;
done

Modify the source

Either apt-get install openjdk-7-jdk or comment out the following sections in build/core/main.mk:

# Check for the correct version of java
# Check for the current JDK.
# Check for the current jdk
# Check for the correct version of javac

Either apt-get install openjkd-7-jdk or comment out the jdk conditional error in build/core/config.mk:

# $(error Error: could not find jdk tools.jar, please check if your JDK was installed correctly)

In system/core/adb/Android.mk remove the condition around:

LOCAL_CFLAGS += -DALLOW_ADBD_DISABLE_VERITY=1
LOCAL_CFLAGS += -DALLOW_ADBD_ROOT=1

Build

Build adbd

echo "include build/core/main.mk" > Makefile
make -j8 adbd # cat /proc/cpuinfo; I have 4 processors (2*4 = 8)
cp out/target/product/generic/root/sbin/adbd ..
popd

Build the image construction tools

pushd  src
make -j8 mkbootimg
make -j8 mkbootfs
popd

Get the image

See: https://developers.google.com/android/nexus/images?hl=de#bullhead

su -l # login as root with root password (alternatively use sudo)
apt-get install wget unzip
exit

pushd factory-images
wget https://dl.google.com/dl/android/aosp/bullhead-mdb08i-factory-64536fcf.tgz
popd

pushd my-live-image/
tar -Oxzf ../factory-images/bullhead-mdb08i-factory-64536fcf.tgz \
    bullhead-mdb08i/image-bullhead-mdb08i.zip > tmp.zip \
    && unzip tmp.zip recovery.img \
    && rm tmp.zip
popd

Crack the image

su -l # login as root with root password (alternatively use sudo)
apt-get install abootimg cpio
exit

pushd my-live-image
abootimg -x recovery.img
# mkdir ramdisk; pushd ramdisk; gzip -dc ../initrd.img | cpio -i; popd
abootimg-unpack-initrd # basically does line commented above
popd

(R): Update ramdisk (recovery.img only)

Disable RSA confirmation

pushd my-live-image/ramdisk

In default.prop, change:

ro.adb.secure=1

to

ro.adb.secure=0

This flag will result in an rsa fingerprint confirmation prompt that you won't get when loading the modified recovery image

Replace unneeded recovery

Replace with simple script needed to run adb shell:

echo '#!/sbin/busybox sh' > sbin/recovery
echo '/sbin/busybox ln -s /sbin /system/bin' >> sbin/recovery

This ensures /system/bin/sh exists so adb shell can exec it. This can also be accomplished after you boot the recovery by:

adb pull /sbin/sh
adb push sh /system/bin/sh

Install busybox

su -l # login as root with root password (alternatively use sudo)
dpkg --add-architecture armel
dpkg --print-foreign-architectures
apt-get update
cd /tmp
chmod 777 busybox-static*
apt-get download busybox-static:armel
exit # exit root shell

pushd sbin/
BUSYBOX=busybox-static
ar -x /tmp/$BUSYBOX_*armel.deb data.tar.xz && rm /tmp/$BUSYBOX*_armel.deb
tar -OxJf data.tar.xz ./bin/busybox > busybox && rm data.tar.xz
chmod 755 busybox
for  i in `echo -n '[' '[[' 'acpid' 'addgroup' 'adduser' 'adjtimex' 'ar'\
    'arp' 'arping' 'ash' 'awk' 'basename' 'beep' 'blkid' 'brctl' 'bunzip2'\
    'bzcat' 'bzip2' 'cal' 'cat' 'catv' 'chat' 'chattr' 'chgrp' 'chmod'\
    'chown' 'chpasswd' 'chpst' 'chroot' 'chrt' 'chvt' 'cksum' 'clear' 'cmp'\
    'comm' 'cp' 'cpio' 'crond' 'crontab' 'cryptpw' 'cut' 'date' 'dc' 'dd'\
    'deallocvt' 'delgroup' 'deluser' 'depmod' 'devmem' 'df' 'dhcprelay'\
    'diff' 'dirname' 'dmesg' 'dnsd' 'dnsdomainname' 'dos2unix' 'dpkg' 'du'\
    'dumpkmap' 'dumpleases' 'echo' 'ed' 'egrep' 'eject' 'env' 'envdir'\
    'envuidgid' 'expand' 'expr' 'fakeidentd' 'false' 'fbset' 'fbsplash'\
    'fdflush' 'fdformat' 'fdisk' 'fgrep' 'find' 'findfs' 'flash_lock'\
    'flash_unlock' 'fold' 'free' 'freeramdisk' 'fsck' 'fsck.minix' 'fsync'\
    'ftpd' 'ftpget' 'ftpput' 'fuser' 'getopt' 'getty' 'grep' 'gunzip' 'gzip'\
    'hd' 'hdparm' 'head' 'hexdump' 'hostid' 'hostname' 'httpd' 'hush'\
    'hwclock' 'id' 'ifconfig' 'ifdown' 'ifenslave' 'ifplugd' 'ifup' 'inetd'\
    'init' 'inotifyd' 'insmod' 'install' 'ionice' 'ip' 'ipaddr' 'ipcalc'\
    'ipcrm' 'ipcs' 'iplink' 'iproute' 'iprule' 'iptunnel' 'kbd_mode' 'kill'\
    'killall' 'killall5' 'klogd' 'last' 'length' 'less' 'linux32' 'linux64'\
    'linuxrc' 'ln' 'loadfont' 'loadkmap' 'logger' 'login' 'logname'\
    'logread' 'losetup' 'lpd' 'lpq' 'lpr' 'ls' 'lsattr' 'lsmod' 'lzmacat'\
    'lzop' 'lzopcat' 'makemime' 'man' 'md5sum' 'mdev' 'mesg' 'microcom'\
    'mkdir' 'mkdosfs' 'mkfifo' 'mkfs.minix' 'mkfs.vfat' 'mknod' 'mkpasswd'\
    'mkswap' 'mktemp' 'modprobe' 'more' 'mount' 'mountpoint' 'mt' 'mv'\
    'nameif' 'nc' 'netstat' 'nice' 'nmeter' 'nohup' 'nslookup' 'od' 'openvt'\
    'passwd' 'patch' 'pgrep' 'pidof' 'ping' 'ping6' 'pipe_progress'\
    'pivot_root' 'pkill' 'popmaildir' 'printenv' 'printf' 'ps' 'pscan' 'pwd'\
    'raidautorun' 'rdate' 'rdev' 'readlink' 'readprofile' 'realpath'\
    'reformime' 'renice' 'reset' 'resize' 'rm' 'rmdir' 'rmmod' 'route' 'rpm'\
    'rpm2cpio' 'rtcwake' 'run-parts' 'runlevel' 'runsv' 'runsvdir' 'rx'\
    'script' 'scriptreplay' 'sed' 'sendmail' 'seq' 'setarch' 'setconsole'\
    'setfont' 'setkeycodes' 'setlogcons' 'setsid' 'setuidgid' 'sh' 'sha1sum'\
    'sha256sum' 'sha512sum' 'showkey' 'slattach' 'sleep' 'softlimit' 'sort'\
    'split' 'start-stop-daemon' 'stat' 'strings' 'stty' 'su' 'sulogin' 'sum'\
    'sv' 'svlogd' 'swapoff' 'swapon' 'switch_root' 'sync' 'sysctl' 'syslogd'\
    'tac' 'tail' 'tar' 'taskset' 'tcpsvd' 'tee' 'telnet' 'telnetd' 'test'\
    'tftp' 'tftpd' 'time' 'timeout' 'top' 'touch' 'tr' 'traceroute' 'true'\
    'tty' 'ttysize' 'udhcpc' 'udhcpd' 'udpsvd' 'umount' 'uname' 'uncompress'\
    'unexpand' 'uniq' 'unix2dos' 'unlzma' 'unlzop' 'unzip' 'uptime' 'usleep'\
    'uudecode' 'uuencode' 'vconfig' 'vi' 'vlock' 'volname' 'watch'\
    'watchdog' 'wc' 'wget' 'which' 'who' 'whoami' 'xargs' 'yes' 'zcat'\
    'zcip'`; do ln -s busybox $i; done
popd; popd

Update ramdisk (boot.img and recovery.img)

pushd my-live-image/ramdisk/

In default.prop, change:

ro.debuggable=0

to

ro.debuggable=1

This flag is checked in adb.c:should_drop_privileges()

In default.prop, add:

service.adb.root=1

This flag is checked in adb.c:should_drop_privileges()

popd
cp adbd my-live-image/ramdisk/sbin/

Create the new live image

pushd my-live-image
MKBOOTIMG_CMDLINE=$( cat bootimg.cfg  \
                   | egrep '^cmdline' \
                   | cut -d ' ' -f 3- \
                   ) # extract commandline
../src/out/host/linux-x86/bin/mkbootfs ramdisk | gzip > initrd.img.new
abootimg -i recovery.img # print offsets and pagesize for mkbootimg command
../src/out/host/linux-x86/bin/mkbootimg --kernel zImage \
    --cmdline "$MKBOOTIMG_CMDLINE" --base 0x00000000 \
    --pagesize 4096 --ramdisk_offset 0x02000000 \
    --tags_offset 0x01e00000 --ramdisk initrd.img.new \
    --output my.img
abootimg -i my.img # output should be similar to 'abootimg -i boot.img'
mv my.img ..
popd

Setting up adb and fastboot

Install adb and fastboot

apt-get install android-tools-adb
apt-get install android-tools-fastboot

Use adb as non-root user

http://developer.android.com/tools/device.html

su -p # login as root with root password (alternatively use sudo)
cat << END > /etc/udev/rules.d/51-android.rules # Get correct Vendor ID using lsusb
# adb protocol on grouper/tilapia (Nexus 7)
SUBSYSTEM=="usb", ATTR{idVendor}=="18d1", ATTR{idProduct}=="4e42", MODE="0600", OWNER="$USER"
# fastboot protocol on grouper/tilapia (Nexus 7)
SUBSYSTEM=="usb", ATTR{idVendor}=="18d1", ATTR{idProduct}=="4e40", MODE="0600", OWNER="$USER"
# adb protocol on hammerhead (Nexus 5)
SUBSYSTEM=="usb", ATTR{idVendor}=="18d1", ATTR{idProduct}=="4ee1", MODE="0600", OWNER="$USER"
END
chmod a+r /etc/udev/rules.d/51-android.rules
exit # exit root shell

Connect device

http://developer.android.com/tools/device.html

  1. Connect Android Device to Linux Device via USB

  2. Enable USB Debugging

    • It's in Settings > Developer options.

        | Note: On Android 4.2 and newer, Developer options is hidden
        | by default. To make it available, go to Settings > About
        | phone and tap Build number seven times.  Return to the
        | previous screen to find Developer options.
      
  3. Enable OEM unlocking

    • It's in Settings > Developer options.

Verify RSA fingerprint matches prompt on phone

awk '{print $1}'\
< ~/.android/adbkey.pub | openssl base64 -A -d -a | openssl md5 -c

# List adb devices
adb devices

Using the Live Image

Reboot into fastboot bootloader

adb reboot-bootloader

Unlock your bootloader if you haven't already

fastboot oem unlock # WARNING: deletes user data; may void warranty
fastboot reboot # Optionally reboot and set up your account again
adb reboot-bootloader # Boot back into bootloader

Boot your live image

fastboot boot my.img # notice you are not flashing

Access the shell of the live image as root

adb shell # your shell should be '#' instead of '$' indicating root

Special Notes About the Live Environment

Note: Do not rely on what is displayed on the screen to determine if the recovery image is working. Depending on the version it could be just the google logo or not even change from the recovery screen from which you boot the image. Instead use adb devices command to determine if it is working.

  • It will take a short time for adbd to come up and accept adb connections

    • Use the adb devices command to determine when adbd becomes available
  • adb shell will attempt to exec /system/bin/sh; if you get an error, try:

      adb pull /sbin/sh
      adb push sh /system/bin/sh
    
  • The system partition will not be mounted when booting into the modified recovery. Take a look at /etc/recovery.fstab to mount your system partition.

    • Remember that adb shell execs /system/bin/sh; you might want to avoid mounting over /system. Instead, create a /mnt directory and mount your /system directory there.
    • The fstab options will result in the system partition being mounted as ro. You will need to mount rw to make changes.

THIS GUIDE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS GUIDE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment