Introduction
In this article, I will explain how to run a compiled third-party Android app in a debugger like lldb
on a non-rooted device.
Prerequisites
Install Android Studio and download the SDK and NDK.
I won’t go into much details about how to do this.
You can check that the installation was successfull if :
- you can run
adb
- you have the NDK installed (on macOS with default settings, it will be in
/Users/$(whoami)/Library/Android/sdk/ndk
) - you can find
lldb-server
in$NDK-PATH/*/toolchains/llvm/prebuilt/*/lib/clang/*/lib/linux/aarch64/lldb-server
Make sure your .apk is debuggable
You can follow this tutorial to make a release .apk
debuggable
A few words before continuing
Before going any further, I want to explain the challenges that we are facing when trying to run our debugger on a non-rooted device.
NB : I am running this experiment on a Meta Quest, and these devices have special (annoying) read-write issues that may not happen with other Android devices.
On Meta Quest, we can sideload our lldb-server
to a writable place, like /sdcard/Documents
. Let’s try this :
1
2
3
4
5
6
7
8
$ adb push lldb-server /sdcard/Documents/lldb-server
$ adb shell /sdcard/Documents/lldb-server
/system/bin/sh: /sdcard/Documents/lldb-server: can't execute: Permission denied
$ adb shell ls -l /sdcard/Documents/lldb-server
-rw-rw---- 1 root everybody 49731928 2025-04-11 20:16 /sdcard/Documents/lldb-server
$ adb shell chmod 777 /sdcard/Documents/lldb-server
$ adb shell ls -l /sdcard/Documents/lldb-server
-rw-rw---- 1 root everybody 49731928 2025-04-11 20:16 /sdcard/Documents/lldb-server
Indeed, we do not have execution rights. And we can’t add them neither with chmod
.
To be able to debug our app, the debugger needs to run with the same level of priviledge than the app. So let’s try :
1
2
3
4
$ adb shell run-as com.bundle.identifier /sdcard/Documents/lldb-server
run-as: exec failed for /sdcard/Documents/lldb-server: Permission denied
$ adb shell run-as com.bundle.identifier ls /sdcard/Documents
ls: /sdcard/Documents: Permission denied
See, the com.bundle.identifier
user does not even have right to read /sdcard/Documents
.
But then, where can our app read/write/execute ?
1
2
3
4
5
6
7
$ adb shell run-as com.bundle.identifier pwd
/data/user/0/com.bundle.identifier
$ adb shell run-as com.bundle.identifier touch test
$ adb shell run-as com.bundle.identifier chmod 777 test
$ adb shell run-as com.bundle.identifier ls -l test
-rwxrwxrwx 1 u0_a169 u0_a169 0 2025-04-11 20:18 test
$ adb shell run-as com.bundle.identifier rm test
So, sideloading our lldb-server
to this location should work, right ? Well, yes, except we can’t :
1
2
$ adb push lldb-server /data/user/0/com.bundle.identifier/lldb-server
adb: error: stat failed when trying to push to /data/user/0/com.bundle.identifier: Permission denied
We can solve this issue, using piping :
1
$ tar cf - lldb-server | adb shell 'run-as com.bundle.identifier tar xf - '
Now, we can finally execute lldb-server
:
1
2
3
4
5
6
$ adb shell run-as com.bundle.identifier ./lldb-server
Usage:
./lldb-server v[ersion]
./lldb-server g[dbserver] [options]
./lldb-server p[latform] [options]
Invoke subcommand for additional help
Debugging the app
Now, it’s time to debug our app.
Let’s launch lldb-server
:
1
$ adb shell run-as com.bundle.identifier ./lldb-server platform --listen "*:10086" --server
Forward the port with adb
:
1
$ adb forward tcp:10086 tcp:10086
Start the app (you can also launch it directly via your graphical interface on the device) :
1
$ adb shell am start -n com.bundle.identifier/com.your.activity
Get the app’s PID :
1
$ adb shell ps -A | grep com.bundle.identifier
Get your device ID :
1
$ adb devices
Launch lldb
on your host:
1
2
3
4
$ lldb
(lldb) platform select remote-android
(lldb) platform connect connect://YOUR-DEVICE-ID:10086
(lldb) process attach --pid XXXX
(Optional) Ignore signals SIGXCPU and SIGPWR :
1
2
(lldb) process handle SIGXCPU -n false -p true -s false
(lldb) process handle SIGPWR -n false -p true -s false
Source : StackOverflow