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-serverin$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