Although the usual Android apps have a graphic user interface and are installed to the device as an APK file, you still have the option to run native elf executables compiled for the architecture that your device supports (mostly arm).
There's a huge amount of tools and small Linux shell utilities written in C/C++. A lot of them don't have any app wrapper that would allow them to execute as regular Android app. Additionally, Android apps run under a separate user id with very restricted privileges.
Luckily, there's ADB which is part of Android's development tools, that allows to execute native shell executables with elevated privileges (usually even without the need to root your device).
Bugjaeger app also supports the ADB protocol and therefore also allows to run native executables as ADB shell user. But in comparison to ADB, your don't need to install any development tools on your laptop. You don't even need a laptop because you can do this stuff directly from your Android phone or tablet.
In this post I'd like to show how to run Linux elf executables with Bugjaeger with ADB shell permissions.
What Elf Binaries Can Be Executed?
Of course, it won't be possible to run any kind of elf executable. There will be many restrictions.
Your executable needs to be compiled into machine instructions supported by your Android device. This will usually be ARM. If you want to compile the binary yourself on your Linux (x86) machine, you need to cross-compile it using some cross-compile toolchain. Android's native development kit (NDK) gives you the tools for cross-compilation.
Android is using Bionic as standard C library. Your native tool might require some of functionality that Bionic doesn't offer.
It's also possible that your binary was cross-compiled to ARM, but linked to a different standard C library. It might be still possible to execute it on Android. Later I'll show how to do this.
Additionally, there are many Android-specific things related GUI, audio, and media access that differ from standard Linux distribution. Therefore, you'll be mostly able to run only basic shell tools without GUI.
There will be also restrictions related to security and direct access to devices in /dev
.
Connecting to a Device (Target)
Before running shell executables, you first need to establish a connection between Bugjaeger and your target device.
To make instructions easier to follow, I'll call the device that has Bugjaeger installed the host. The device on which we want to run the executable will be the target.
Host and target can be the same device. I'll show how to configure your horst to be a target at the same time in the next section.
To create a remote ADB connection between host (Bugjaeger) and target, do the following
-
Enable Developer options AND USB debugging on target device. Check out the official docs, if you're not sure how to do this
-
Start Bugjaeger app on host device
-
Connect host and target through USB OTG cable
-
Authorize Bugjaeger app to access the connected USB device on host
-
Authorize ADB connection on target
After performing the steps above, you should see your connected target device appear in the top device list spinner
Push to Target & Change Permissions
Android has a special folder - /data/local/tmp
. This folder is usually writable and also allows to change the permissions of files to executable. This is where you need to copy your executable file
To do this with Bugjaeger, first go to "Files" tab and type in the path /data/local/tmp
to the top input box that is showing current path. The click on the push
button in the top toolbar
Now you need to change the permissions at least for the owner to executable.
Run Your Executable
Once you have your binary pushed to your target device and once you have your permissions set up properly, you can then run your executable.
You have 2 options how to accomplish this. Both are accessible from the Commands tab in Bugjaeger.
You can either create your custom command by tapping on the +
icon in the top toolbar. Or you can start the interactive shell and type your command in there.
If you want to execute the command in one step, you need to use the absolute path to the executable
/data/local/tmp/myexecutable
Passing command line arguments should work too
/data/local/tmp/myexecutable argument1 argument2
In interactive shell you'll also be able to execute multiple commands in steps
cd /data/local/tmp
./myexecutable argument1
...
Execute on Same Device Bugjaeger is Running On (Host == Target)
You can also use Bugjaeger to execute commands on the same device it was installed. This however needs some initial setup.
You will either need 2 devices that have both Bugjaeger installed, or you'll have to use ADB.
The adbd daemon running on the device that you want to control needs to be configured for TCP/IP mode.
To do this using Bugjaeger, connect your target (in this case the target will also have Bugjaeger installed), and execute the command Connect through WiFi.
If you want to use ADB for this initial setup, execute the following command on your PC
adb tcpip 5555
That is what Bugjaeger is doing underneath.
Dependencies & Dynamic Linking
As mentioned before, Android uses Bionic C library. If your executable was build using Android NDK or with cross-compilation toolchains that the NDK provides, you shouldn't have issues with Bionic.
In case your binary was build with some other ARM cross-compilation toolchain, there's a chance that you're missing some dynamic libraries that need to be linked to your executable at runtime.
One way to solve this issue is to recompile the executable with static linking. Here's an example how I did this on my Linux machine
arm-linux-gnueabi-g++ -o my_executable my_source.cpp -static
I used gcc-based ARM cross-compilation toolchain installed independently of the Android NDK. The executable is linked to glibc instead of Bionic. With static linking my executable now works on Android even though it is not linked to Bionic.
In my simple test program that I used for this example I only printed to console. Accessing stuff that is not available or violates security restriction still won't work.
In case you don't want to cross-compile the executable yourself, there's another option. You can find the dynamic libraries your executable is depending on and use them together on your target device.
You can use the readelf tool available on Linux to find the dependencies. For that you need to execute the following command in Linux shell
readelf -d my_executable | grep "NEEDED"
Alternatively, you can also use my online elf tool to find the dynamic dependencies.
My little test program showed the following dependencies
Only the first library (libshared.so
) is actually needed in my case, because all the other libraries are part of NDK and therefore should already be available on the Android device. Your dependency might itself have other dependencies, so you need to check also those.
Once you have the dependencies, you need to push them to /data/local/tmp
together with your executable. Now you only need to slightly modify your command in Bugjaeger
LD_LIBRARY_PATH=/data/local/tmp /data/local/tmp/my_executable
The LD_LIBRARY_PATH
variable now gives a hint to the dynamic linker where to search for the dependencies.
The modified command should allow you to run your executable with dependencies.