[code] [blog] [Repos] [GPS Tracker] [Music] [VNC] [Restart VNC] [E-Mail me]
git clone https://coredump.ws/repos/pt880-root.git
# push (client certificate):
git remote set-url --push origin https://coredump.ws:8443/repos/pt880-root.git

Branches and tags

masterbranch19 days agozip
archive/watchlauncher-splittagzip

Files at HEAD (94f308da87) · download zip

apps/
docs/
fdl/
firmware/
protocol/
scripts/
server/
system/
tools/
.gitattributes880 B
.gitignore351 B
.gitmodules127 B
NOTES.md23.0 KB
README.md7.6 KB

Recent commits · all

94f308daGive the keypad its own layout: button A lost most of its quick pressesapol19 days ago
28497b33Bump watchlauncher: readable rain frames, and the APK pin caught upno-body-in-particular2026-09-04
20135123Bump watchlauncher: step counter asks both waysno-body-in-particular2026-09-01
f649f875Bump watchlauncher: restore docs/vitals.mdno-body-in-particular2026-09-01
da83b703Bump watchlauncher: vitals comment fixno-body-in-particular2026-09-01
2c9a151eBump watchlauncher: batch the uplink, quieten the traceno-body-in-particular2026-09-01
df356237Bump watchlauncher: log what each vitals cycle decidedno-body-in-particular2026-08-31
e4212a93Bump watchlauncher: measure on an independent clockno-body-in-particular2026-08-31
736e2388Bump watchlauncher: ask the sensor whether the watch is wornno-body-in-particular2026-08-31
9af598d4Bump watchlauncher: report why a restart did not happenno-body-in-particular2026-08-31

README.md

pt880 root

Root for the ThinkRace inmate tracker — a Unisoc SL8521E wrist-worn tracking device (sp9820e_1h10 / sl8521e_1h10ll_watch_native, Android 4.4.4).

Tooling to dump, patch and reflash it, so you get adb and a root shell on hardware you own.

pt880 tracker: rugged wrist unit with a small square screen, a camera above it, two buttons on the right edge and a perforated locking strap

The two buttons on the right edge are the entire input surface — there is no working touchscreen. That shapes everything in apps/watchlauncher.

Read NOTES.md first — it documents the verification chain, every patch offset, and the dead ends worth not repeating.

The launcher

The watch's own software - map and offline navigation, music, camera, calls, bluetooth pairing and a root shell, in one application - now lives in its own repository:

**https://github.com/no-body-in-particular/pt880-launcher**

It is attached here as a submodule at apps/watchlauncher, so:

git clone --recursive https://github.com/no-body-in-particular/pt880-root.git

or, in a clone that already exists:

git submodule update --init

It was split out with its history intact rather than copied, so git log in that repository goes back to the first version of the launcher.

Status

GoalState
Dump all partitionsworking
Write any partitionworking
Bootchain unlock (permanent, no PC at boot)working
Boot a modified boot imageworking
adb over USBworking
root shell over adbworking — uid 0 with a full capability set
/system writable at runtimeworking
busybox / htop / nano / dropbear / sshfs installedworking
Bluetooth audio (A2DP) out to headphonesworking
Music player running on the watchworking
Launcher, camera, dialler and terminal on the watchworking
Root shell inside an app (setuid helper)working

Layout

tools/ flashing stack and image builders fdl/ donor FDL1/FDL2 + CVE-2022-38694 payloads firmware/ byte-exact stock dumps of the bootchain (restore sources) scripts/ driver scripts (backup / build / flash / restore / fetch) analysis/ scratch space for disassembly work system/ files as they exist on the device under /system protocol/ what the tracker app speaks to its server, and the documentation gap - see protocol/README.md apps/ apps built to run on the watch itself

tools/ also holds the ext4 reader/writer (ext4tool.py, ext4mod.py) used to edit system.img offline, so no device-side remount is needed to build an image.

Full stock and patched firmware images are hosted outside git — see firmware/DOWNLOADS.md, or fetch and verify them with ./scripts/fetch-firmware.sh.

firmware/stock/ holds the small, irreplaceable partitions. system.img (450 MB), vendor.img and the modem/DSP images are not committed — dump them yourself with scripts/backup.sh, which writes them alongside. Nor is miscdata.img: it carries this unit's serial number in plaintext and a donor copy is wrong for any other device, so it is dumped per-device alongside prodnv and l_fixnv1.

apps/

apps/watchlauncher/ replaces the stock launcher — a dead-end clock face with no app list — and carries five apps inside one APK: music, Bluetooth pairing, camera, calls and a root terminal. One activity, a screen stack, and the clock and battery across the top of every screen. It ships a 57,858-entry IEEE vendor database so a Bluetooth scan names devices that will not name themselves, and a 40-line setuid helper (native/wsu.c) that gets an app a root shell — the adbd patch below does nothing for apps, which are forked from zygote rather than from adbd. Read its README.

apps/watchplayer/ is the music player on its own, and is what the root shell was originally for: local files to A2DP headphones, driven by the two hardware buttons. The launcher supersedes it and contains it; it is kept because it is the smaller thing to read, and its README documents the firmware's distinctly odd key handling and the keylayout remap that both apps depend on.

Neither uses Gradle — API 19 fights modern AGP, so build.sh drives the SDK tools directly. Do not run both at once: they would fight over the headphones' media buttons.

Requirements

Workspace

The image builders read and write a scratch directory that is deliberately not in the repo — partition dumps, stock FDL blobs and the Alpine armhf tree are far too big for it. It defaults to ~/wpull:

~/wpull/ dump_watch2/ partition images read from and written to the device fdl_sl8521e/ stock and patched FDL1/FDL2 blobs tools_arm/ armhf binaries staged into system.img alpine/ unpacked Alpine rootfs they are taken from

Set PT880_WORKSPACE to move all of it at once. tools/paths.py is the single place this is defined.

Quick start

Build the flashing tool once:

./scripts/build_tools.sh

Dump the device (read-only, safe — repeat until it catches the boot ROM window):

./scripts/backup.sh ./firmware/mydevice

Build a rooted boot image from your own dump:

./scripts/build.sh ./firmware/mydevice

The image that gives a genuine root shell is built by tools/build_boot_capbnd.py. It neuters adbd's three privilege-drop syscall stubs and disables the capability-bounding-set drop with a one-byte edit, so adb shell lands as uid 0 with CapBnd=3fffffffff and can remount /system itself. tools/build_boot_root.py is the earlier version — uid 0 but CapBnd=0xc0, so no remount. See NOTES.md section 6.

Customise /system offline (busybox aliases, colour prompt, xterm-256color, /etc/resolv.conf, setuid busybox) and install the extra tools:

python tools/install_tools.py
python tools/customize_shell.py

Flash the unlock (bootchain + boot image):

./scripts/flash.sh ./firmware/mydevice

Put the watch in boot ROM mode (ID to GND, then power on) whenever a script says it is armed. The supervisor re-arms automatically, so keep retrying.

Restore to stock at any time:

./scripts/restore.sh ./firmware/mydevice

Safety

Credits

Legal

For use on hardware you own. Bootloader unlocking will void warranties and can brick a device.