Inside Dev Phone 1

Rumours say it has a Linux underneath. Well, almost. There is a full and recent Linux kernel, but this is pretty much it. We have a small subset of standard tools (like ls, ps), a minimalistic libc (called Bionic, not compatible to glibc), a non-standard directory hierarchy, a non-standard linker, and all the Dalvik-Java-Stuff, of course.

Getting Started

So it looks all nice and pretty, but how to get a terminal? For now, we connect via USB. We need the Android SDK, in particular the Android Debug Bridge (adb). This tool connects to virtual and physical Android machines that run the adbd daemon (on the phone we turn it on and off in Settings – Applications – Development – USB Debugging). Now we can connect by adb shell, and since this is Dev Phone we get root access just by su. By adb push we can upload files. In order to upload to /system/somewhere we have to remount /system in rw-mode first.

Now, how to build software for this thing? We have to keep two things in mind:

  1. We are on ARM architecture. That means we need a cross-compiler and a suitable toolchain, sourcery for instance. Of course, we can build a compiler and then continue with native builds. Alternatively, we can setup a QEmu box with a Debian armel distribution and use it to compile natively.
  2. We do not have the ld-linux-linker. Therefore let's built static executables for the moment.
After a successful “Hello, Android!”, I suggest to compile and upload busybox. Busybox contains everything you expect from a proper operating system (grep, sed, awk, a neat little shell, …). Just don't forget to configure it for static linking.

sshd

Again, how to get a terminal, a real one, not via USB? We have to circumvent the Java sandbox and we will do so by “loop-back-ssh” to localhost. With ConnectBot there is a fine, free ssh client for Android. Which means, we have to get an ssh server running on the phone.

We choose Dropbear, since it is small and has clean code. In principal, it runs fine on Android, except you cannot connect. Well, this is because Android has no user database (/etc/passwd). So all the functions of the getpwnam() family fail. In general, Android seems to use UIDs in order to shield applications from each other, which makes sense; usually you don't share your mobile with other people. To make it run, we patch the code a little and introduce a single user mode. Basically, all the information you find in the user database will be specified on the command line for a specific user. I made a patch for Dropbear 0.521. It supports password authentication and public key authentication. To make it work, we additionally have to turn off login recording, which can be done by
./configure --disable-loginfunc --disable-utmp --disable-utmpx --disable-wtmp --disable-wtmpx --disable-lastlog

And here we go. A fully functional ssh daemon. Let's start it twice, with password authentication on 127.0.0.1:22 and with public key authentication on 0.0.0.0:<MySshPort>
dropbear -A -N root -U 0 -G 0 -C <password> -r <rsa.secret> -p 127.0.0.1:22
dropbear -A -N root -U 0 -G 0 -C nothing -R /sdcard/id_rsa.pub -r <rsa.secret> -p <MySshPort> -s

sshd on android

ROOT on Android

We will compile and run a batch ROOT v5-22-00 system. In order to access it anywhere we want to, we use our Dropbear loop-back ssh setup. I am not sure whether it is possible to cross-compile. At least it requires some efforts because ROOT uses CINT to create dictionaries during the build process. Thus we stick to the armel virtual machine.

We have to patch the code a little bit, namely we avoid the getpwnam() call for discovering the home directory in TUnixSystem. Just hardcode the home directory to /data/local. There are some other places which make use of getpwnam(), and to make the whole thing running properly, we probably have to patch a little more. But to get it started without errors we are fine now.

Now we configure and make. We configure a minimal ROOT system, which basically means we turn everything off (--disable-<something>). We will use make static to create a static roota binary. Doing so straight forward will fail. The binary gets too big for the linker to do all the relocations. As we have no X11 graphics anyway, we can exclude a couple of packages, thereby shrinking the binary to about half of the size. We edit build/unix/makestatic.sh and add to the exclusion paths:
geom/gdml geom/geom geom/geombuilder geom/geompainter montecarlo/vmc montecarlo/eg \
graf2d/freetype graf2d/gpad graf2d/graf graf2d/postscript graf2d/win32gdk graf2d/x11 graf2d/x11ttf \
tree/tree tree/treeviewer tree/treeplayer tmva \
proof/proofplayer proof/proof \
math/mlp math/splot html hist/spectrumpainter hist/histpainter \
gui/fitpanel gui/ged gui/gui gui/guibuilder gui/guihtml gui/recorder gui/sessionviewer \
graf3d/g3d graf3d/x3d

In order to link against glibc and dl, we add -static to the roota build command. Finally, after running the modified make static, we strip the symbols which should result in a more or less 30MB binary.

We run into a storage problem, if we try to upload everything to let's say /data/local. Unfortunately we cannot run software from the sd-card. We tackle this by a hybrid approach: we upload the build tree to the sd-card and the roota binary to /cache. Since ROOT needs a /tmp directory, we create one. Busybox' mount understands -o remount,rw which lets us change the root file system. Finally we export ROOTSYS=/sdcard/root and boot up our little Android ROOT.


1Please note: this is a filthy hack I wrote on Sunday night. I didn't do much testing and it might screw up security awfully. Feel free to use it at your own risk.