The latest posts in full-text for feed readers.
Tolino e-book readers have a debug mode that can be activated by entering a secret password into the search field. Every new firmware version changes this password.
Download EPubProd.apk from the Tolino with adb pull and open it in jadx-gui. Now open de.telekom.epub.debug.DebugOptionsActivity and you will find the following code:
public static final String SHOW_DEBUG_OPTIONS_PASS_CODE_FULL = "124816";
public static final String SHOW_DEBUG_OPTIONS_PASS_CODE_MINIMAL = "180914";
This was easy.
The "full" passcode are the first 5 numbers of the x² sequence.
After downloading the epub reading application EPubProd.apk and opening it in jadx-gui, we find new code in de.telekom.epub.debug.DebugOptionsActivity:
The Tolino developers decided to make it more complicated to find the password and found a nice method: They calculate a hash from the combination of the entered password and "schokopups512" and compare the result with the pre-computed hashes of the original passwords.
That way the passwords are not in plain text in the code anymore, and the salt ("schokopups512") prevents people from looking up the hash in a database of pre-computed SHA-512 hashes.
Luckily there is a tool for cracking passwords: John the Ripper. It takes a file with hashed passwords and tries all combinations of letters, numbers and special characters until it finds the password. Word list files are also supported; passwords contained in them will be found much faster.
At first we need to tell john the password format. The Tolino debug passcode is sha512($password + $hash). john in Debian 11's repository does not support that, but the jumbo version does! I found .deb package files for jumbo-john at http://http.kali.org/pool/main/j/john/. Verification:
$ john --help
John the Ripper 1.9.0-jumbo-1+bleeding-aec1328d6c 2021-11-02 10:45:52 +0100 OMP [linux-gnu 64-bit x86_64 AVX2 AC]
Now let's find out if it supports SHA512 with salt:
$ john --list=subformats|grep sha512
Format = dynamic_80 type = dynamic_80: sha512($p)
Format = dynamic_81 type = dynamic_81: sha512($s.$p)
Format = dynamic_82 type = dynamic_82: sha512($p.$s)
Format = dynamic_83 type = dynamic_83: sha512(sha512($p))
Format = dynamic_84 type = dynamic_84: sha512(sha512_raw($p))
Format = dynamic_85 type = dynamic_85: sha512(sha512($p).$s)
Format = dynamic_86 type = dynamic_86: sha512($s.sha512($p))
dynamic_82 is the format we want.
Now we have to find out how the password needs to be stored. After some trial and error I had the following line format for password files:
name:hash$salt
.. which gives us this password file for the Tolino 15.2.0 main passcode:
tolino152-1:c5af5651b57b1db0fe9f373e95cd4042997ccfb7bd2c5fa0b0b45ebc7717d83a9b71fb695e22478c1d4e9dd3d85330e3d385c5c49a892972484e45d5533532c6$schokopups512
Now we let john do its work:
$ john --incremental=digits --fork=4 --format=dynamic_82 passwords
Using default input encoding: UTF-8
Loaded 1 password hash (dynamic_82 [sha512($p.$s) 256/256 AVX2 4x])
Press 'q' or Ctrl-C to abort, almost any other key for status
1123581321 (tolino152-1)
1g 0:00:00:01 DONE (2022-11-10 22:48) 0.7692g/s 4758Kp/s 4758Kc/s 4758KC/s 1234561990..095664525
Use the "--show --format=dynamic_82" options to display all of the cracked passwords reliably
Session completed.
The first password 1123581321 was found within a second when telling john only to try numbers and no letters. It consists of numbers 2-9 of the Fibonacci numbers.
The password check code is the same as in firmware 15.2:
Let's put all the known hashes in a single file:
tolino152-1:c5af5651b57b1db0fe9f373e95cd4042997ccfb7bd2c5fa0b0b45ebc7717d83a9b71fb695e22478c1d4e9dd3d85330e3d385c5c49a892972484e45d5533532c6$schokopups512 tolino152-2:f11e6ad70202da7eb56f2b932926ef53c4a4b9742bc28e00c3cb7b13d3e39ac795f774417c32c639a4873a044d7bd07dc369b9633a875f61097aa0b9b01e8464$schokopups512 tolino160-1:d820afedd912b83340429595ad855b893815bb85661b2b50e0892f7b3d720e6c8ebad365623f8896ba946957c1ff70a3fcf51a2127041804fb17c46c671c37c0$CbqSbfnk9YC% tolino160-2:0d93b0fb26c52927f543103ab6cf2270947c55c6ed00995018eab313f57393c7c0a1dc4cc4bcb3c114ed0b0c469b1973ddebc4c55002eaf10145ddb626e2595a$CbqSbfnk9YC%
I let john work on the file with different options but failed in the end. The passwords are not:
I thought that the second passcode would also be a known number sequence, and so I wanted to get a list of all known sequences. The project On-Line Encyclopedia of Integer Sequences (OEIS) collected them, and they can be downloaded from their wiki.
After extracting the 69 MiB stripped file I mangled it a bit to extract the first 2 numbers from every sequence and stored it in a file:
grep -v '^#' stripped |cut -d',' -f2-3 | sed 's/,//g' | sort | uniq > sort-2-3
This was extended up to fields 2..12, 3..13, 4..14 and 5..15. All of them together were given john as password file, but 3 seconds later I found that the work bore no fruit.
I tried finding passwords consisting of ASCII characters, but stopped john after it ran for nearly two days on 4 CPU cores:
$ john --fork=4 --format=dynamic_82 --min-length=6 passwords
...
3 0g 1:19:53:51 3/3 0g/s 1242Kp/s 2484Kc/s 3726KC/s bmpa5s9r..bmpa5d1@
4 0g 1:19:53:51 3/3 0g/s 1245Kp/s 2491Kc/s 3736KC/s 2lscie1...2lscidr4
1 0g 1:19:53:51 3/3 0g/s 1246Kp/s 2493Kc/s 3739KC/s rbadwhrhb..rbadwxyza
Waiting for 3 children to terminate
2 0g 1:19:53:51 3/3 0g/s 1243Kp/s 2486Kc/s 3729KC/s 77f1ngy..77f1cs7
Session aborted
A fail for now, but maybe this helps the next tinkerer to go further.
Update 2023-11-15: Someone sent me the link to a gist that contains the Tolino 16 firmware debug password: 112358132fb. Source is this forum post from 2023-08-09 by AaronDewes.
Published on 2022-11-21 in blackbox, tolino
Die deutschen Bibliotheken nutzen eine gemeinsame Plattform "Onleihe", auf der man digitale Bücher, Musik und Filme ausleihen kann. Technisch wird seit 2018 "LCP" als DRM-Technologie eingesetzt. Damit wird verhindert, daß ausgeliehene Bücher länger als erlaubt gelesen werden.
LCP steht für "Licensed Content Protection" und wurde von der Readium Foundation entwickelt, hauptsächlich von der französischen Firma European Digital Reading Lab. Im Gegensatz zum vorher verwendeten Adobe Digital Editions muss man sich dafür nicht registrieren und braucht auch keinen PC, um die Bücher auf den e-Reader zu bringen: Tolino-Geräte und andere haben LCP integriert.
Manchmal wird dieser Kopierschutz als "CARE" bezeichnet. CARE ist aber eine Software der Firma vivlio, mit der man Bücher mit LCP verschlüsseln und verteilen kann. Diese Server-Software wird vermutlich von der Onleihe verwendet.
Man öffnet im Browser die Website der Onleihe, meldet sich mit den Kundendaten seiner Bibliothek an und kann Bücher direkt ausleihen. Dazu wählt man die Ausleihdauer (2, 4, 7, 14 oder 21 Tage) und bekommt eine .lcpl-Datei zum Download. Der ebook-Reader liest die Lizenzdatei ein, lädt die dazugehörige .epub-Datei runter und packt sie in die Bücherliste.
Man wird dabei nach dem Onleihe-Code gefragt. Er ist 4-stellig, besteht aus kleinen Buchstaben und Zahlen, und ist für jeden Benutzer fest - also für alle Bücher gleich. Der Reader merkt sich den Code und wenn man ein Buch öffnet, wird das aktuelle Kapitel mit diesem Code entschlüsselt und angezeigt.
Wenn man den User-Agent ändert, kann man den eReader-Modus der Onleihe auch in einem normalen Browser aktivieren:
Mozilla/5.0 (Linux; Android 4.4.2; en-; tolino vision 3 HD/14.1.0) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/30.0.0.0 Mobile Mobile Safari/537.36 READER OS_BUILD/KOT49H.41429.1044823
Siehe auch: Readium LCP: Principles.
Die Spezifikation von LCP ist frei verfügbar. Die Readium Licensed Content Protection 1.0 ist die, in der es um die Verschlüsselung geht.
Die von der Onleihe runtergeladene .lcpl-Lizenzdatei beschreibt die Restriktionen: Von wann bis wann der Inhalt entschlüsselt werden darf (Ausleihzeitraum), wie viele Seiten gedruckt werden und wie viele Zeichen in die Zwischenablage kopiert werden dürfen. (Lustigerweise ist nicht wirklich definiert, was eine Seite ist.)
Weiterhin enthält sie einen Link zum Runterladen der verschlüsselten .epub-Datei und den Schlüssel, mit dem deren Inhalt entschlüsselt werden kann - dieser ist aber selbst noch mit dem Benutzerschlüssel verschlüsselt.
Der Benutzerschlüssel ist ein SHA-256-Hash des vierstelligen Codes, der in der Onleihe unter dem "Download"-Knopf angezeigt wird.
Sobald man die Lizenzdatei und die ebook-Datei heruntergeladen hat, kann man komplett Offline entschlüsseln und lesen.
Weiterhin enthält die Lizenzdatei auch noch eine ID in normaler und verschlüsselter Form. Damit kann man schnell prüfen, ob der vom Benutzer eingegebene Code korrekt ist. Auf der anderen Seite erlaubt es das Angreifern auch, Codes ohne großen Aufwand durchzuprobieren.
Eine .epub-Datei ist eine .zip-Datei, und eine mit LCP verschlüsselte epub sind immer noch eine .zip-Datei. Darin gibt es die Datei META-INF/encryption.xml, die eine Liste der verschlüsselten Dateien enthält.
Einige Dateien wie der Index sind nicht verschlüsselt, aber die Textkapitel und (Cover)bilder sind meist alle verschlüsselt.
Da der Inhalt von epub-Dateien meist auf mehrere HTML-Dateien aufgeteilt ist, muss der eReader auch nicht gleich das ganze Buch entschlüsseln - sondern nur das Kapitel, das gerade gelesen wird.
Da die Onleihe-Codes auf kleine Buchstaben und Ziffern beschränkt sind, gibt es nur 36^4 = 1.679.616 mögliche Schlüssel - etwas weniger als 21 Bit. Das ist für ein Verschlüsselungssystem ziemlich wenig; SSH- und SSL-Schlüssel haben seit zehn Jahren mindestens 2048 Bit. Sicherheitstechnisch kann man das nicht ernst nehmen.
Die Anforderungen an LCP sagen uns, warum das so ist:
A key objective in providing “some level of protection” is to take advantage of anticircumvention law, [...]
Anticircumvention law makes it a criminal offense to circumvent an “effective technical protection measure.”[5] The law does a poor job of defining this term. While courts have refused to set a bar for “effectiveness” such that any technology below the bar is not entitled to protection under the law,[6] there is some evidence to suggest that a technology that is particularly ineffective could face such a challenge.[7]
[...]
To be very clear on this point: we expect that a lightweight DRM (in reality, any DRM) will be cracked, and we are relying on anticircumvention law for some level of crack protection.
LCP ist also der Versuch mit minimalem Aufwand einen Kopierschutz zu bauen,
der von Gerichten als "wirksame technische Maßnahme" anerkannt wird.
Damit sollen Umgehungsversuche und -software gesetzlich strafbar sein.
Ich denke aber nicht, daß nur 1,6 Millionen Möglichkeiten
ein wirksamer Kopierschutz sind.
Readium führt eine Liste mit "Verschlüsselungsprofilen" - dort werden alle erlaubten Verschlüsselungsalgorithmen aufgeführt. 2023-08 sind das folgende:
Das "Basic Encyption Profile" ist in der öffentlich verfügbaren Spezifikation bescrieben, aber das "Production Encryption Profile" ist nicht öffentlich.
Das EDRLab verfolgt alle, die Informationen dazu öffentlich verfügbar machen oder freie Software anbieten, die das Profil implementiert:
Published on 2021-03-12 in books, tolino
When an Android device is connected via USB to the computer, you can take a screenshot via adb:
$ adb shell screencap -p | perl -pe 's/\x0D\x0A/\x0A/g' > file.png
On a Tolino e-book reader, this unfortunately added some textual information before the actual PNG image data:
vinfo.xoffset = 0 vinfo.yoffset = 2144 vinfo.xres = 1448 vinfo.yres = 1072 vinfo.xres_virtual = 1472 vinfo.yres_virtual = 3456 .PNG...
The solution is to use grep in binary mode to remove those:
#!/bin/sh
adb\
shell screencap -p\
| grep -a -v '^vinfo\.' \
| perl -pe 's/\x0D\x0A/\x0A/g' \
> "screenshot-`date --rfc-3339=seconds`.png"
Published on 2022-04-27 in android, tolino
With some time at my hands and a rooted adb on my Tolino Vision 4 HD (firmware 13.2.1), I had a look at the de.telekom.epub.apk ebook reading app source code.
Since I bought the reader I wanted to get rid of the unsolicited advertisements on the home screen and the "you finished reading the book" screens that the support told me I could not disable.
The recommendations appear once the Tolino has been given WiFi access, e.g. for a firmware update or to sync the time via NTP.
They are stored with other data in the SQLite database file at /data/data/de.telekom.epub/databases/pageplace.db. With the rooted adb is possible to download it to the PC, remove the recommendations and upload it back to the e-reader:
$ adb pull /data/data/de.telekom.epub/databases/pageplace.db
$ sqlite3 pageplace.db "DELETE FROM recommendation"
$ adb push pageplace.db /data/data/de.telekom.epub/databases/pageplace.db
$ adb shell chown system:system /data/data/de.telekom.epub/databases/pageplace.db
$ adb shell am force-stop de.telekom.epub
Table recommendations are the advertisements, and table comments are your own marked text areas.
The last command kills the ebook app, which is started automatically again. It is faster than rebooting the whole device.
See Own ads on a Tolino e-reader for more work on this area.
If the right switch is set, the main Tolino ebook reading app de.telekom.epub shows additional information in the logs available at adb logcat.
The DEBUG switch cannot be activated directly. It is defined in the environment configuration, which in turn are stored as resource files inside the .apk at assets/environments/. The default environment is 0 and it loads application.properties.prod. There is another environment 2 called application.properties.prod.debug, which is a clone of the first environment, just with the debug flag enabled.
The environment can be selected by setting de.telekom.epub.PREFS_APP_PROPERTES (no, that is not a typo on my side) inside the configuration file /data/data/de.telekom.epub/shared_prefs/ePub.xml. Since there is no command line editor available on the Tolino, we again have to download the file to the PC, modify it and upload it back to the reader:
$ adb pull /data/data/de.telekom.epub/shared_prefs/ePub.xml
# now add this line to ePub.xml:
<int name="de.telekom.epub.PREFS_APP_PROPERTES" value="2" />
$ adb push ePub.xml /data/data/de.telekom.epub/shared_prefs/ePub.xml
$ adb shell chown system:system /data/data/de.telekom.epub/shared_prefs/ePub.xml
$ adb shell am force-stop de.telekom.epub
When debugging is enabled, adb logcat will show that line:
D/ApplicationEnviromentProperties( 2852): isATolino=true
Also, in ☰ -> Settings -> More Settings (German: Erweiterte Einstellungen) a new button appears: Open God-Settings. It simply shows the Android 4.4 standard settings.
The old God mode button is gone now, you have to click the "search" button on the main screen, enter the number 124816 and press search. A dedicated debug settings screen will open.
The numbers are the first 5 "2^x" numbers.
Source: Eigene Apps installieren (Firmware 14.2.0) by AaronDewes.
The manufacturer changed the debug code for the search screen to 1123581321, which are the first 8 numbers of the Fibonacci sequence.
When searching for that number, the following debug screen opens:
Source: Tolino Update 15.2.0 post by Ohmugin
More information about finding the passwords: Tolino 16.0 password crack attempts.
The Tolino contains a special Hotel mode that shows your own logo on the start screen instead of the book shop ads and disables USB access.
It needs two prerequisites:
You can store your own logo file as hotelMode/hotelMode.png, but that is optional.
The book shop configuration is also stored in /data/data/de.telekom.epub/shared_prefs/ePub.xml as de.telekom.epub.PREFS_APPLICATION_PROPERTIES_JSON. Modify the file as described above. I simply renamed the name attribute by prefixing it with old- so that I can restore it later.
Then open the usb-connected Tolino drive and create the hotelMode directory, optionally putting a hotelMode.png file into it. You can do that via adb shell; the directory then would be /sdcard/hotelMode. Now reboot or restart the epub application, and hotel mode is active.
When hotel mode is active, the log shows the following line:
D/Globals ( 3017): Filesystem is locked!
That "lock" only influences the ability to access the Tolino files via USB. It still properly stores bookmarks and reading progress.
If you want to switch the book shop (away from Thalia to buecher.de or so), modify ePub.xml the following way:
<boolean name="de.telekom.epub.PREFS_IS_REBRANDABLE_DEVICE" value="true" />
Now reboot/restart the reader app and the lower main screen will allow you to select the book shop.
Published on 2020-09-27 in android, blackbox, hardware, tolino
The lower part of the main screen on Tolino e-book readers is dedicated to advertisements of the shop that the Tolino was bought at. I wanted to get rid of them so I built my own boot image, patched adbd to get root, tinkered with the system and documented the server API.
I found that the Tolino software EPubProd.apk has no way to disable those recommendations except when activating hotel mode, and then the lower part is still wasted by only showing the hotel's logo.
Knowing that it is not possible to disable the ads, I wanted to make them work for me: Show the latest books that I added to my Calibre library and let me download them with a single click. That way I would not have to connect the Tolino via USB to my computer to sync books onto it!
When pressing the sync button on the "my books" screen or when enough time has passed, the Tolino software calls the server API https://bosh.pageplace.de/bosh/rest/recommendation/xyz.
Fortunately for me, it is possible to override the domain by modifying the reseller settings file /data/data/de.telekom.epub/shared_prefs/ePub.xml. Fetch it via adb pull, modify it on the computer and the upload it back, change the permissions and restart the ebook application:
#!/bin/sh
adb push ePub.xml /data/data/de.telekom.epub/shared_prefs/ePub.xml
adb shell chown system:system /data/data/de.telekom.epub/shared_prefs/ePub.xml
adb shell am force-stop de.telekom.epub
ePub.xml contains a key de.telekom.epub.PREFS_APPLICATION_PROPERTIES_JSON that contains the reseller configuration serialized in JSON.
The following values are relevant to the main screen:
After modifying those values I built a small PHP script that listed the latest books from my calibre sqlite database:
Now that I had the ads in place I could simply link it to the .epub file - at least I thought so.
It turned out that shop links are not opened in a normal browser but in a restricted de.telekom.epub.ui.activities.ShopWebViewActivity that does not support downloading files!
ShopWebViewActivity automatically adds authentication headers when HTTP requests are sent, so people never have to log in when they are already logged into their Tolino.
The view supports some special URLs that don't work in the normal browser:
Details can be found in the API documentation: Internal URLs.
The adb logcat debug log always showed an error:
Uncaught ReferenceError: android_init is not defined line: 1 source: http://tolino.cwboo/book.php?id=408
All restricted web views on the Tolino call a JavaScript function android_init when the page is loaded. This enables e.g. the shops to execute special code only on Tolino devices.
It also provides a JavaScript variable screenController with a couple of methods that lets you control the UI a bit:
screenController.hideNavigationHeader();
screenController.hideProgressDialog();
screenController.refreshScreen();
screenController.setNavigationHeaderTitle("my header");
screenController.setNavigationHeaderUrl("epublishing://closeshop");
screenController.setTokens("accesstoken", "refreshtoken");
screenController.showNavigationHeader("header title");
screenController.showProgressDialog();
screenController.processHTML("html");//does nothing
Details can be found in the API documentation: Javascript API.
It is impossible to open the normal web browser from the restricted ShopWebViewActivity, and downloading .epub files is not supported. How do I get the book on my Tolino?
One of the special URLs is epublishing://openextract which takes an epub file URL. When clicking the link, the file is downloaded and opened!
Unfortunately it is seen as "Extract" which means "Leseprobe" in German. It's meant as preview for books, but not for whole books. When opening the extract a "To the shop" button is shown on every page:
So this is also not a solution :(
That's it for now. It is unfortunately not possible to quickly download ebooks from the main screen's advertisement section.
It seems I have to build my own synchronization service that synchronizes the books onto the Tolino when clicking "buy" or "download" on the recommendation details page. But this will take quite a while to implement :(
Published on 2022-04-12 in android, tolino
On my quest to get rid of advertisements on my Tolino e-book reader I already made my own boot image to enable adbd, the Android Debug Bridge Daemon on the device.
After I opened a adb shell I saw that it had the "shell" user and group, and that I could not access /data/ and /system/ directories.
Time to get root:
$ adb root
$ adb shell
shell@ntx_6sl:/ $ id
uid=2000(shell) gid=2000(shell) groups=1003(graphics),1004(input),1007(log),1009(mount),1011(adb),1015(sdcard_rw),1028(sdcard_r),3001(net_bt_admin),3002(net_bt),3003(inet),3006(net_bw_stats)
Although "adb root" did not give any error, adbd on the reader was still running as limited user.
The alternative to "adb root" was using a su binary that one can run in the shell to gain root access.
My biggest problem was how to get a sane non-infected su binary.
The 1.9.0 root patch contains one, but it is 380 kiB large (adbd itself is only 160 kiB, and the su on my Debian laptop is 63 kiB), and it requires an accompanying Superuser.apk. That su would speak with the .apk which would show a confirmation dialog on the reader screen that one has to confirm.
I decided against that because I do not know where the su is from and what kind of malicious code is inside that 380 kiB blob.
Always having to type "su" in the shell would also mean that I could
not simply run adb copy
and adb push
on /data/ and /system/,
which would slow me down when tinkering with the system.
There are two settings that determine if adb root
works,
and they are documented in
android-core/adb/daemon/main.cpp:
So setting ro.debuggable in default.prop is the absolute minimum to get root access via adb.
Setting ro.secure to 0 only means that adbd
will always run as root,
making it superfluous to always type adb root
at the beginning of a debugging session.
I added ro.debuggable in my boot image, flashed it and .. still was not root.
I switched my android core checkout to branch android-4.4.2_r2, looked into adb.c and found the compile time flag ALLOW_ADBD_ROOT. If that was not set, all the reading of "ro.debuggable" and "ro.secure" would not even be compiled into the adbd binary.
So the Tolino firmware makers had not enabled root access.
I did not want to compile adbd for the Tolino myself, because that would require installing the Android SDK, the Android NDK, and finding out what the original compilation options were.
The XDA developers forum has a thread [2014.11.10][ROOT] adbd Insecure v2.00 that lets us download an .apk with adbd compilations for different Android SDK versions.
I tried all of them, but only got an offline
status when I
listed the adb devices:
$ adb devices
List of devices attached
86346346,2f12e2342c894d9e8afa3cf5564223ac offline
I think this means that adbd on the Tolino crashed and was thus unreachable.
There is an Android app that does live patching on an adbd binary on the device itself: rootadb.
It works by opening the adbd file, searching for system calls to capset(), setuid() and setgid() and replacing them with 0xe3a00000.
Unfortunately there was no pre-built binary on Google Play nor in the Github releases section. Compiling it myself would mean the same steps as outlined above for recompiling adbd, so I ditched that idea.
Rootadb's idea was still valid: Patch out the system calls that drop privileges through changing user and group IDs and removing capabilities.
I installed Ghidra (open source IDA Pro alternative) for the first time and loaded my Tolino's adbd binary into it. It shows the assembler code in a nicer way than hex editors, and I could see the mov, cmp and bne statements with their parameters.
The big question was how to find the place inside the 160 kiB that called the system methods. In parallel I looked at the adb.c source code:
/* then switch user and group to "shell" */
if (setgid(AID_SHELL) != 0) {
exit(1);
}
if (setuid(AID_SHELL) != 0) {
exit(1);
}
D("Local port disabled\n");
Now I knew where to look: Search for the "Local port disabled" string and find the place where it is used.
After skipping backwards about all the code generated for the D() function I found the setuid() call at offset 0x1288 (ghidra: 0x9288).
Looking for 0x7d0 ("2000" in hex) was even easier because that's the user id for the "shell" user.
00009288 4f f4 fa 60 mov.w r0,#0x7d0
0000928c 0e f0 86 ed blx FUN_00017d9c
00009290 00 28 cmp r0,#0x0
00009292 df d1 bne LAB_00009254
What happens here:
The fastest solution was to patch out all the commands by replacing them with NOP (no operation) commands, which is 00 BF in the little endian ARM code.
Ghidra told me that it does not support 32 bit ARMv7 binaries, and that saving them could break them.
So I opened my hex editor bless, subtracted 0x8000 from the offsets that Ghidra showed me and manually NOPed all the commands.
I did that for the setuid() call only at first, built and flashed a new boot image with the modified adbd, ran it and opened a shell on the Tolino:
$ adb shell
root@ntx_6sl:/ # id
uid=0(root) gid=2000(shell) groups=1003(graphics),1004(input),1007(log),1009(mount),1011(adb),1015(sdcard_rw),1028(sdcard_r),3001(net_bt_admin),3002(net_bt),3003(inet),3006(net_bw_stats)
root@ntx_6sl:/ $ ls /data/
opendir failed, Permission denied
So adbd was running as root user now, but did not yet have the root group, and could still not access /data because it had dropped capabilities.
Now I patched out the calls to setgid(), setgroups() and prctl() and could finally declare success:
$ adb shell
root@ntx_6sl:/ # id
uid=0(root) gid=0(root)
root@ntx_6sl:/ # ls /data
app
app-asec
app-lib
app-private
backup
bugreports
dalvik-cache
data
dontpanic
drm
g-ESD.log
local
lost+found
media
mediadrm
misc
property
resource-cache
security
share
ssh
system
tombstones
user
The Tolino user interface data are in /data/data/de.telekom.epub/. Inspecting them is the next task. See Tolino: Debug Mode, Hotel Mode, no Ads.
You can find my Tolino 12.2.0 boot image with the patched adbd in my binary file archive.
I made the rooted boot image for firmware version 13.2.1 which was easy, because 13.2.1 still uses Android 4.4.2 and I could just copy over the previously patched adb. Download it from my binary file archive.
Rooted boot image for firmware 14.1.0 is available. As before I could use the same previously rooted adb. This also works on the Tolino Vision 3 HD and Tolino Shine 2 HD. It should work on the Tolino Vision 2 and Tolino page because they all have the same update file.
Rooted boot image for Tolino 4 HD with firmware 15.2.0 is available. As before I could use the same previously rooted adb. This also works on the Tolino Vision 3 HD and Tolino Shine 2 HD. It should work on the Tolino Vision 2 and Tolino page because they all have the same update file.
Published on 2019-10-02 in android, blackbox, hardware, tolino
After my old nook reader died, I bought a Tolino Vision 4 HD ebook reader. It is usable without registration - as opposed to Kobo readers which you have to register. It is water proof enough to drop it into the bath tub, and it has thesauri and translation dictionaries. For 140€ I bought it at buecher.de.
The reader is based on Android 4.4.2, and it is rootable. Unfortunately the root patch is for firmware version 1.9.0, while I updated already to 12.2.0.
For the firmware update, I let it once into my wifi. During that time it also downloaded the latest recommendations from the buecher.de store, which it now shows on the home screen - taking the lower half of it - and after I finish reading a book:
I wanted to get rid of this unsolicited advertisements, and asked support how to do so. They replied with "cannot be disabled" :/
I thought I could simply clear that cached recommendation data on my own but found that I could not simply plug the micro USB cable and run adb shell - the Tolino does not have adbd running :/
In a standard Android user interface I would open settings, tap seven times on the build number, and then activate ADB debugging in the now visible developer options.
The Tolino has its own GUI, and their settings UI has no ADB checkbox.
There is an alternative: Setting some properties in the boot image's default.prop file, which is what the ADB checkbox in the normal developer options does.
persist.service.adb.enable=1 persist.sys.usb.config=mass_storage,adb
The standard USB config for the Tolino was "mass_storage", so I only added ",adb" to it.
Now I needed to modify my Tolino's default.prop file.
I did not create a boot image from scratch, I only modified an existing one.
The Tolino Vision 4 update website had a .zip file for updating from 11.2.0 to 12.2.0, so I fetched and extracted that. Among others, it contained a 4.5 MiB boot.img file.
At first I tried sophiehuiberts/Bootimg-scripts but found out that the extracted kernel file does not have the correct size.
The Android core git repository up to commit a6abd821d contained two files in the mkbootimg directory: unpack_bootimg.py and mkbootimg.py, which I used in the end.
When extracting the boot image, the unpack script shows important meta data:
$ ./unpack_bootimg.py --boot_img boot-12.2.0.img --out ex-boot-12.2.0
boot_magic: ANDROID!
kernel_size: 3936664
kernel load address: 0x80808000
ramdisk size: 508752
ramdisk load address: 0x81800000
second bootloader size: 0
second bootloader load address: 0x81700000
kernel tags load address: 0x80800100
page size: 2048
boot image header version: 0
os version and patch level: 0
product name: ntx_6sl
command line args: console=ttymxc0,115200 init=/init androidboot.console=ttymxc0 max17135:pass=2, fbmem=6M video=mxcepdcfb:E060SCM,bpp=16 no_console_suspend
additional command line args:
Before actually modifying something, I rebuilt it until my repacked image was bit for bit equal to the original one.
With the help of the meta data above, I ended up with the following parameters for repacking:
$ mkbootimg.py --kernel ex-boot-12.2.0/kernel --ramdisk ex-boot-12.2.0/ramdisk\
--cmdline "console=ttymxc0,115200 init=/init androidboot.console=ttymxc0 max17135:pass=2, fbmem=6M video=mxcepdcfb:E060SCM,bpp=16 no_console_suspend"\
--board ntx_6sl\
--kernel_offset 0x70808000 --ramdisk_offset 0x71800000\
--second_offset 0x71700000 --tags_offset 0x70800100\
-o rebuilt-boot-12.2.0.img
I flashed my rebuilt boot image onto the Tolino to see if it works at all.
The Tolino must be in fastboot mode for flashing, and I got to there that way:
The reader is in fastboot mode now and shows an empty screen only. The mode can be verified by listing the fastboot devices:
$ fastboot devices
86346346,2f12e2342c894d9e8afa3cf5564223ac fastboot
Flashing is easy now:
$ fastboot flash boot rebuilt-boot-12.2.0.img
$ fastboot reboot
If the Tolino starts up normally, then the rebuilt boot image works.
The Tolino Shine 2 HD needs the command fastboot flash:raw boot ...
The rebuilt boot image uses the original kernel and boot image files. default.prop is inside the ramdisk, so I had to extract it:
$ cd ex-boot-12.2.0/
$ mkdir ex-ramdisk
$ cd ex-ramdisk
$ gunzip -c ../ramdisk | cpio -i
This gave me a directory full of files:
$ ls
charger init.E60Q50.rc property_contexts
data init.E60Q50.usb.rc res
default.prop init.E60Q60.rc rle
dev init.E60Q60.usb.rc RTL8189_init.rc
file_contexts init.E60QF0.rc sbin
fstab.E60K00 init.E60QF0.usb.rc seapp_contexts
fstab.E60Q30 init.E60QH0.rc sepolicy
fstab.E60Q50 init.E60QH0.usb.rc sys
fstab.E60Q60 init.E60QJ0.rc system
fstab.E60QF0 init.E60QJ0.usb.rc ueventd.E60K00.rc
fstab.E60QH0 init.E70Q20.rc ueventd.E60Q30.rc
fstab.E60QJ0 init.E70Q20.usb.rc ueventd.E60Q50.rc
fstab.E70Q20 init.ED0Q00.rc ueventd.E60Q60.rc
fstab.ED0Q00 init.ED0Q00.usb.rc ueventd.E60QF0.rc
fstab.freescale init.environ.rc ueventd.E60QH0.rc
init init.freescale.rc ueventd.E60QJ0.rc
init.common.usb.rc init.freescale.usb.rc ueventd.E70Q20.rc
init.E60K00.rc init.rc ueventd.ED0Q00.rc
init.E60K00.usb.rc init.trace.rc ueventd.freescale.rc
init.E60Q30.rc init.usb.rc ueventd.rc
init.E60Q30.usb.rc proc WC121A2_init.rc
I went the safe route and did not modify anything at this stage. I only re-packed the directory back to a ramdisk file:
$ find . | cpio -o -H newc | gzip > ../repack-ramdisk
Then I re-built the boot.img as shown above with the new ramdisk file, flashed it onto the reader and booted it up. All fine.
Now that I knew that the whole boot image building process worked, I actually modified default.prop in the ramdisk folder and added the two lines:
persist.service.adb.enable=1 persist.sys.usb.config=mass_storage,adb
After building, flashing and booting my adb-enabled boot image I was finally able to use adb:
$ adb devices
List of devices attached
86346346,2f12e2342c894d9e8afa3cf5564223ac no permissions (user in plugdev group; are your udev rules wrong?); see [http://developer.android.com/tools/device.html]
.. or not. I first had to add a new udev rule:
$ emacs /etc/udev/rules.d/99-tolino.rules
SUBSYSTEM=="usb", ATTR{idVendor}=="1f85", ATTR{idProduct}=="6052", MODE="0660", GROUP="plugdev", TAG+="uaccess"
$ udevadm control --reload
Then I unplugged and replugged the USB cable, and it finally worked:
$ adb devices
List of devices attached
86346346,2f12e2342c894d9e8afa3cf5564223ac device
$ adb shell
shell@ntx_6sl:/ $ getprop | grep product
[ro.build.product]: [ntx_6sl]
[ro.product.board]: [EVK]
[ro.product.brand]: [RakutenKobo]
[ro.product.cpu.abi2]: [armeabi]
[ro.product.cpu.abi]: [armeabi-v7a]
[ro.product.device]: [ntx_6sl]
[ro.product.display]: [eink]
[ro.product.hardwareType]: [E60Q50]
[ro.product.locale.language]: [en]
[ro.product.locale.region]: [US]
[ro.product.manufacturer]: [Rakuten Kobo Inc.]
[ro.product.model]: [tolino]
[ro.product.name]: [ntx_6sl]
How I got root access is a different story.
Published on 2019-09-30 in android, blackbox, hardware, tolino