Archive for the ‘livehacking’ Category

Pogoplug B04 und Owncloud

Arch Linux ARM läuft nun auf dem Pogoplug. Installation war schmerzfrei. Kurze Notiz zur Installation von OwnCloud:

  • pacman -S owncloud php-apache php-sqlite
  • Config-dateien gemäß Ausgabe editieren
  • Apache starten
  • Die Adresse des Pogoplugs aufrufen mit / als pfad
  • Wenn du ein anderes Datenverzeichnis möchtest, musst du in /etc/httpd/conf/extra/owncloud.conf den pfad für openbasedir ergänzen
  • in /etc/php/php.ini muss man zusätzlich noch und aktivieren; das sagt OwnCloud aber
Kategorien:livehacking, oss

ICS on the Desire Z

I’m now running an unofficial build beta39 of AOKP on my Desire Z. It’s reasonably smooth so far, especially when overclocked to 1.4GHz (from 0.8GHz).

I’ve flashed a fresh radio and the corresponding RIL. Before I flashed the RIL, battery life and network performance on HSDPA was terrible, so let’s hope it will be better today.

Other than that, 720p recording is broken for the camera, which is not exactly a big deal for me. However, I can’t play 720p videos with the built-in mediaplayer either. It works with rockPlayer in Hardware Decoding mode, which is just plain weird. I’ll report a bug to the ROM author and see what they have to say.

Kategorien:android, livehacking

Batch transcoding with HandBrakeCLI for my Android phone

I own a smartphone and a bus ticket. This mean I often watch videos on my Desire Z when catching a ride to town. I often have videos which will not work on my Android phone, such as these in .wmv format or even DVDs. For these videos, I use handbrake with a custom preset by user LiveWire from the forum. Since my phone has a 480×800 screen, I just use that and it works great.

The problem here is that Hand BrakeCLI uses hardcoded presets, so we need to use its command line switches to accomplish a similar thing. Starting from the built-in presets, the „Universal“ profile seems to be a close enough fit, having a width of 720 pixels. To save more space, I’m adjusting the quality setting from 20 to 22.

+ Universal:  -e x264  -q 20.0 -a 1,1
-E faac,copy:ac3 -B 160,160 -6 dpl2,auto
-R Auto,Auto -D 0.0,0.0 -f mp4
-X 720 --loose-anamorphic -m 
-x cabac=0:ref=2:me=umh:bframes=0:weightp=0:8x8dct=0:trellis=0:subme=6

Another nice option might be the „Normal“ profile, which apparently just uses the resolution of the source video.

+ Normal:  -e x264  -q 20.0 -a 1
-E faac -B 160 -6 dpl2
 -R Auto -D 0.0 -f mp4 --strict-anamorphic -m
-x ref=2:bframes=2:subme=6:mixed-refs=0:weightb=0:8x8dct=0:trellis=0

I’m not sure about the advanced options for the x264 encoder (the -x flag), but I’ll just assume these don’t hurt. Another thing are the switches for anamorphic mode – I’m too lazy to read up on this. I should also note that I’m not going for perfect HD-like quality here. The videos I’m transcoding are mostly educational videos from sites like YouTube, so I just want something that works with reasonable quality without taking too much space.

For the record, my current command line for batch transcoding videos looks like this:

for wmv in *.wmv;
  do HandBrakeCLI -Z "Universal" -q 22 -i "$wmv" -o "m4v/`basename "$wmv" .wmv`.m4v";

This article will be updated as I uncover additional magic. If you don’t feel like messing with transcoding, you can just use RockPlayer from the Android market or the MPlayer build floating around on XDA to drain your battery with software decoding.

Firmware-Gefrickel mit Ebook-Readern


Auf gibt es heute den Icarus Reader Sense E600BK ebook für 139€. Grund genug, sich mal die Firmware anzugucken:


Dann unzippen und los gehts. Raus kommen zwei Dateien und ein Verzeichnis upfw/.

uzImage: Offenbar ein komprimierter Linux-Kernel

urootfs.img: offenbar die Ramdisk. Ich habe in den Intarwebs auch von einem Recovery-Image gelesen. u-boot sagt folgendes:

laga@moar:/tmp/qdutil$ mkimage -l urootfs.img
Image Name:   ramdisk
Created:      Wed Nov  3 10:44:55 2010
Image Type:   ARM Linux RAMDisk Image (gzip compressed)
Data Size:    2484039 Bytes = 2425.82 kB = 2.37 MB
Load Address: 00000000
Entry Point:  00000000

Mal extrahieren, wa:

laga@moar:/tmp/qdutil$ dd if=urootfs.img bs=64 skip=1 of=ramdisk.gz
38813+1 records in
38813+1 records out
2484039 bytes (2.5 MB) copied, 0.162404 s, 15.3 MB/s
laga@moar:/tmp/qdutil$ file ramdisk.gz
ramdisk.gz: gzip compressed data, was "rescuefs", from Unix, last modified: Wed Nov  3 10:44:52 2010, max compression
laga@moar:/tmp/qdutil$ gunzip ramdisk.gz
laga@moar:/tmp/qdutil$ file ramdisk
ramdisk: DOS-executable (
laga@moar:/tmp/qdutil$ mkdir ramdisk-mnt
laga@moar:/tmp/qdutil$ sudo mount -o loop ramdisk ramdisk-mnt

Gut, der Name der Datei laut file, „rescuefs“, sagt eigentlich alles. Ein paar interessante Dinge sind mir auf Anhieb aufgefallen:

* ./bin/qdtar – ich kann aktuell das tar-Archiv im Firmware-Update (upfw/rootfs.img) nicht entpacken. Womöglich haben die Kollegen da was obfuscated (lol)

* ./sbin/ – lol

* Ok, der hier ist wirklich gut. In sbin/ ist eine Hashmap implementiert:

hput() {
    echo "$2 $3" >> /tmp/hashmap.$1

hget() {
        grep "^$2 " $1 | awk '{ print $2 };'
        #grep "^$2 " /tmp/hashmap.$1 | awk '{ print $2 };'


* Die .gz in /sbin/images/ sind offenbar Bilder.

Alright, nicht viel mehr zu sehen ad hoc. Mal schauen, was in upfw/ liegt:

* laga@moar:/tmp/qdutil/upfw$ ls
20101216D.bin  rootfs.img  ST060B00_image.pak

Das wird vermutlich nach dem Firmware-Update aufgerufen. Auch hier werden wieder die DRM-Keys gesichert (lol). Das Script scheint ein toller Ort zu sein, um einen telnetd oder ähnliches zu installieren (lol).

ST060B00_image.pak scheint einfach nur ein Haufen Bitmaps zu sein. Auch erstmal uninteressant. Bleiben noch zwei Dinge:

laga@moar:/tmp/qdutil/upfw$ file 20101216D.bin && ls -alh 20101216D.bin
20101216D.bin: data
-rw-r--r-- 1 laga users 5.6M Dec 16  2010 20101216D.bin
rootfs.img: POSIX tar archive (GNU)
-rw-r--r-- 1 laga users 170M Jan 12  2011 rootfs.img

Leider kriege ich das rootfs.img mit meinem normalen tar nicht entpackt.

laga@moar:/tmp/qdutil/upfw$ tar xvf rootfs.img
tar: Skipping to next header
tar: Exiting with failure status due to previous errors

Was macht man da.. ich habe mal rumvermutet, dass da womöglich nur eine Datei bzw Header defekt ist. Tar müsste das doch irgendwie überspringen können. Meine Version von tar hat keine Option --recover, aber Google führt michte zu einem guten Tipp:

cpio -ivd -H tar < rootfs.img.tar

Was haben wir denn hier interessantes?

* ./etc/init.d/S50proftpd (lol). In ./etc/proftpd.conf ist offenbar der ‚anonymous‘ account aktiviert

* Das gesamte Ebook-Geraffel ist offenbar in /usr/local/quisda. Basiert offenbar auf QT embedded. Generell scheint das Gerät sehr ähnlich dem Oyo zu sein, der bei Thalia verkauft wird.

* ./usr/local/qisda/bin/ (lol)

* ./usr/sbin/telnetd

./sbin/ohci-hcd.ko (lol, sbin)

* /mnt/etc – /mnt?!

* ./mnt/etc/rc.d/init.d/appWeb  (lol, rc.d/init.d/)

* ./qdutil/ Mehr Spielkram, z.b. qdutil/em/QEngineer

Interessant ist vor allem die QBookApp in usr/local/quisda, da diese die Ebooks rendert. Die Einstellungen kommen standardmäßig aus /usr/local/qisda/etc/QBookApp.default.ini, das nach /home/settings/QBookApp.ini kopiert wird.

* laga@moar:/tmp/qdutil/upfw/rootfs/usr/local/qisda$ file bin/QBookApp
bin/QBookApp: ELF 32-bit LSB executable, ARM, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.14, stripped

In Frank’s Wiki (sic) gibt es noch jede Menge weitere Information zum Oyo, das ja sehr nah verwandt ist, die diesen Blog post sicher redundant macht. Aber wir sind ja zum Spaß hier. Außerdem kann ich noch Outside The Walled Garden empfehlen, wo es ebenfalls interessante Beiträge zum Oyo gibt.

Und jetzt: abschalten. Ich gehe radfahren. Achso, ja: fuck DRM.


Current OpenWrt setup

Just flashed OpenWRT Backfire10.03.1-rc4. Flashing via mtd did not work – most likely PEBKAC – so I made some use of WIFI tethering on the trusty Android phone and installed tftp. Five minutes later, I’m back up and running. Neat. Coming from Kamikaze, one of the more notable changes would be the switch to a 2.6

kernel for the WRT54Gs. Now, what do I do with this small box now that its doing basic routing?

Statistics and Graphs

To get some graphs in the Luci web interface, install luci-app-statistics. Unfortunately, this seems to need a lot of space in the flash file system. This plugin depends on collectd, hence the disk space requirements. I have no clue how to get this working: I see the config option, but I’m not seeing any graphs. Perhaps I need to wait for a cron job to run? Removing it again so I can actually install other stuff…


Quality of Service / Traffic Shaping

luci-app-qos: configure traffic shaping/QoS to make sure your SSH and XMPP don’t suffer when doing bulk file transfers over HTTP. Configuration is under Essentials -> Network -> QoS. Took me a while to find that.

The only thing you need to configure is the speed of your internet connection. If you go use a service like you might find that your speed is way too low. In my case, I had accidentally enabled QoS in the init script settings with the default setting of 1MBit/s download speed, which obviously is too slow. So, disable QoS and measure again. Then plug the numbers into the QoS config.

Since it’s saturday night, I’m not getting good numbers, so let’s postphone this..

SSL support for the web interface

luci-ssl: SSL support for luci. For some reason, my router rebooted after installing this. However, luci is now available over HTTPS. Neat! If you want to disable regular HTTP access, drop to a shell and execute „uci delete uhttpd.main.listen_http && uci commit“. Apparently, this is not yet possible within Luci itself.

Dynamic DNS

    luci-ddns: dynamic dns support, will update your account on and friends. Seems to work!

    Keeping time current

    luci-app-ntpc: keep the time on your OpenWRT device in sync with NTP servers. Configuration will show up in System -> Time Synchronisation. Seems to work.

      Also see the OpenWRT wiki for more Luci goodness.


      • in Luci, first hit „Update package lists“ under „System -> Software“ to get a list of packages other than those already installed.
      • if you’ve installed a new module and it doesn’t show up, `rm /tmp/luci-indexcache` in a shell on the device and reload the web interface in your browser.
      • occasionally, luci/firefox will choke when you navigate away from a loading page. This manifests as an error message about broken XML in the browser. Usually, the new page will load anyways.
      • Do not remove luci-theme-openwrt.

      Okay, so I upgraded from OpenWRT Kamikaze to Backfire10.03.1-rc4 and I’m not that happy. The router has rebooted spontaneously about four or five times by now while I was using Luci. This might be related to the increased load when using the web interface, who knows.

      In any case, it shouldn’t be happening at all. Other things, like the fact that newly installed packages not showing up in the Luci menu, or the extremely slow web interface, certainly don’t make for a good impression.

      However, this is OpenWrt: it’s not bad. From prior experience, I expect the base of the system to be in good shape. So, ignoring the web interface, I’ll just leave this box running and hope it’ll continue to work as unobtrusively as before on Kamikaze. This optimism is mainly motivated by the fact that I’m too lazy to go back to Kamikaze and configure everything again. I haven’t even tried WLAN yet..

      Kategorien:livehacking, oss

      TCPdump auf Android und TTRSS-Debugging

      Das ist ein Artikel aus der Kategorie Live-Hacking. Diese Artikel entstehen während ich programmiere, sind daher voller technischer Details, unnötig lang und womöglich voller Fail.

      Wie aufregend, CyanogenMOD 7 hat tcpdump an Bord! Das ist gut, denn ich debugge gerade den TT-RSS-Reader bzw dessen Fork.

      Das Problem: liefert in ihrem RSS-Feed (ATOM) keinen content mit, sondern nur den Titel. Nun ist die app zwar so eingestellt, dass sie automatisch die Website zu Artikel aufruft, wenn kein Content vorhanden ist. Funktioniert aber nicht! Blick in den Code:

      if (!linkAutoOpened && content.length() < 3) {
      if (Controller.getInstance().isOpenUrlEmptyArticle()) {
      Log.i(Utils.TAG, „Article-Content is empty, opening URL in browser“);
      linkAutoOpened = true;

      Müsste ja eigentlich gehen. Dann gucken wir erstmal mit TCPdump, was da vom Server kommt. Vielleicht sollte ich noch erwähnen, dass die App nicht das RSS vom Heise-Server liest. Stattdessen spricht die APP per JSON-API über HTTP mit der TT-RSS Instanz auf meinem Webserver. Das RSS von Heise sieht übrigens so aus:

      <title>Bericht: Sky zahlt 14,5 Millionen an institutionelle Anleger</title>
      <link href=“; />


      Also gut, ich will wissen, ob da vielleicht was von meiner TT-RSS-Instanz kommt, weswegen womöglich obige Logik in der App nicht greift. Ich will mit tcpdump also mal zwei Dinge: allen Traffic auf einem bestimmten Interface mithören und den in eine Datei schreiben lassen. Schnell in die man-page geguckt:

      -i     Listen  on  interface.   If unspecified, tcpdump searches the system interface list for the
      lowest numbered, configured up interface (excluding loopback).  Ties are broken by choosing
      the earliest match.

      On Linux systems with 2.2 or later kernels, an interface argument of „any“ can be used to
      capture packets from all interfaces.  Note that captures on the „any“ device will not  be
      done in promiscuous mode.

      -w     Write the raw packets to file rather than parsing and printing them out.  They can later be
      printed with the -r option.  Standard output is used if  file  is  „-“.   See  pcap-save‐
      file(5) for a description of the file format.

      Davon abgesehen muss ich noch wissen, auf welchem Interface ich nun lauschen möchte. Da hätten wir normale ifconfig -a, nur leider kriege ich damit keine Liste der Schnittstellen. Offenbar kommt dieses ifconfig aus busybox und kann dann nicht allzu viel. Schade! Aber wieder eilt tcpdump zur Rettung:

      -D     Print  the  list of the network interfaces available on the system and on which tcpdump can
      capture packets.  For each network interface, a number and an interface name, possibly fol‐
      lowed by a text description of the interface, is printed.  The interface name or the number
      can be supplied to the -i flag to specify an interface on which to capture.

      This can be useful on systems that don’t have a command to list them  (e.g.,  Windows  sys‐
      tems,  or  UNIX  systems lacking ifconfig -a); the number can be useful on Windows 2000 and
      later systems, where the interface name is a somewhat complex string.

      Wir hätten also folgende Schnittstellen:

      # tcpdump -D
      2.any (Pseudo-device that captures on all interfaces)

      Da nehme ich doch mal rmnet0!

      # tcpdump -w ttrss.dmp -i rmnet0
      tcpdump: ttrss.dmp: Read-only file system

      Eh. Schnell noch adb remount ausgeführt auf dem Host und schon geht es. Der Kram bisher gehört übrigens per adb shell ausgeführt, oder eben im Terminal Emulator auf dem Gerät. Aber eigentlich ist es viel geschickter, den Dump auf der SD-Karte zu speichern.

      # tcpdump -w /mnt/sdcard/ttrss.dmp -i rmnet0
      tcpdump: listening on rmnet0, link-type EN10MB (Ethernet), capture size 96 bytes

      Schon besser. Jetzt kann ich auf dem Schlaufernsprecher die App aufmachen und einen Heise-Artikel angucken, die Kommunikation wird mitgelesen. Dann wird tcpdump mit CTRL+C im Terminal gekillt und ich lade die Datei auf dem Desktop in wireshark.

      # tcpdump -w /mnt/sdcard/ttrss.dmp -i rmnet0
      tcpdump: listening on rmnet0, link-type EN10MB (Ethernet), capture size 96 bytes
      ^C114 packets captured
      114 packets received by filter
      0 packets dropped by kernel

      In wireshark sehen wir dann unter anderem „packet size limited during capture“. Wir fluchen kurz, werfen die Meldung in Google und starten tcpdump nochmal mit -s 0:

      # tcpdump -w /mnt/sdcard/ttrss.dmp -i rmnet0 -s 0
      tcpdump: listening on rmnet0, link-type EN10MB (Ethernet), capture size 65535 bytes
      ^C105 packets captured
      105 packets received by filter
      0 packets dropped by kernel

      Ich stelle fest, dass Wireshark nun crasht, da ich offenbar einen korrupten Dump erzeugt habe. Also in eine *neue* Datei speichern:

      # tcpdump -w /mnt/sdcard/ttrss-1.dmp -i rmnet0 -s 0
      tcpdump: listening on rmnet0, link-type EN10MB (Ethernet), capture size 65535 bytes
      ^C162 packets captured
      162 packets received by filter
      0 packets dropped by kernel

      Ich stelle weiterhin fest, dass wireshark immer noch crasht; es also nicht an der Wiederverwendung der Datei lag. Bei einem dritten Versuch mit der gleichen Datei überlegt Wireshark nun – vielleicht liegt es daran, dass die Datei nicht mehr auf usb-storage liegt, sondern ich sie auf /tmp/ kopiert habe? Egal, ich denke nicht darüber nach, sonst verzweifele ich wieder am Nicht-Determinismus dieser Welt.

      Nun ist der Dump jedenfalls in Wireshark. Dort habe ich mir nun einen erfolgssversprechenden Eintrag aus der Liste ausgesucht – also irgendwas, das per HTTP mit meinem Server spricht, und per Rechtsklick „Follow TCP Stream“ ausgewählt. Neues Fenster, mit unter anderem folgenden Inhalt:

      HTTP/1.1 200 OK
      Date: Sun, 30 Jan 2011 12:20:01 GMT
      Server: Apache/2.2.9 (Debian)
      X-Powered-By: PHP/5.2.6-1+lenny9
      Content-Language: auto
      Expires: Thu, 19 Nov 1981 08:52:00 GMT
      Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0
      Pragma: no-cache
      Set-Cookie: ttrss_sid_api=XXXXXX; path=/
      Vary: Accept-Encoding
      Content-Type: text/html; charset=
      Transfer-Encoding: chunked

      {„seq“:0,“status“:0,“content“:[{„id“:“667″,“title“:“Lernen verlagert sich in virtuelle Welten“,“link“:“http:\/\/\/newsticker\/meldung\/Lernen-verlagert-sich-in-virtuelle-Welten-1180118.html\/from\/atom10″,“labels“:[],“unread“:true,“marked“:false,“published“:false,“comments“:““,“author“:“heise online“,“updated“:1296379500,“content“:““,“feed_id“:“7″,“attachments“:[]}]}

      Wunderbar, wir sehen also, dass in der Antwort nichts von content oder sonstwas steht. Zum Vergleich mal ein Artikel der Tagesschau:

      {„seq“:0,“status“:0,“content“:[{„id“:“649″,“title“:“\u00c4gypten: Erneut Tote bei Protesten gegen Mubarak“,“link“:“http:\/\/\/ausland\/aegypten324.html“,“labels“:[],“unread“:true,“marked“:false,“published“:false,“comments“:““,“author“:““,“updated“:1296314880,“content“:“\n\n<p>\n<a href=\“http:\/\/\/ausland\/aegypten324.html\“> BLABLA

      Wir halten also nochmal fest: die Artikel von Heise haben im JSON kein „content“-Feld. Mal gucken, wie der Code das handhabt!


      private String parseMetadata(String str) {
      // Cut string from content: to the end: /{„seq“:0,“status“:0,“content“:(.*)}/\1/
      String pattern = „\“content\“:“;
      int start = str.indexOf(pattern) + pattern.length();
      int stop = str.length() – 2;
      if (start >= pattern.length() && stop > start) {
      return str.substring(start, stop);
      return „“;

      org.ttrssreader.model.pojos.ArticleItem scheint ebenfalls relevant:

      public void setContent(String mContent) {
      if (mContent == null || mContent.equals(„null“)) {
      this.mContent = null;
      } else {
      this.mContent = mContent;

      Sieht ja irgendwie alles gut aus bis jetzt! Ich tippe dann einfach mal darauf, dass die Abfrage, ob content eine Länge kleiner 3 hat,  der Knackpunkt ist. Zum Beispiel in wird vielleicht was in content geschrieben, was wir gar nicht so wollen:

      // Inject the specific code for attachments, <img> for images, http-link for Videos
      content = injectAttachments(getApplicationContext(), mArticleItem.getContent(),
      content = Utils.injectCachedImages(content);

      // Load html from Raw-Ressources and insert content
      String temp = getResources().getString(R.string.INJECT_HTML_HEAD);
      String text = temp.replace(„MARKER“, content);

      Es hilft also nichts, es wird Zeit für das gute alt printf-Debugging, in unserem Fall per System.out.println oder Log.d. Das bedeutet also, ich muss meine eigene Version der App kompilieren. Kein Problem, der Quelltext ist ja schon in meinem Eclipse. Dummerweise wird das resultierende Paket mit einem anderen Schlüssel signiert, nämlich mit meinem Debug-Schlüssel. Ich muss also erstmal die aktuell installierte App von meinem Handy entfernen und dann mit meiner Version der App alle Einstellungen nochmal vornehmen.

      Mit der SVN-Version frisch auf dem Gerät finde ich nun als erstes Mal heraus, dass Artikel nicht angezeigt werden. Die App zeigt zwar, dass Artikel vorhanden sind, aber ich kriege keine Liste. Das ist Qualität. Das Verhalten kenne ich noch von meinen ersten Versuchen; offenbar muss ich so lange random rumdrücken, bis es tut. Der Traffic zum Server sieht einwandfrei aus, die Kommunikation klappt also, Artikel kommen an.

      Nachdem ich nun einmal auf „Unkategorisierte Feeds“ geklickt habe, geht die App plötzlich wieder. Tatsächlich sehe ich nun nicht nur die Artikel, sondern auch auch die Artikel von Heise werden direkt wie gewünscht im Browser geöffnet. Also wurde in der Version im SVN offenbar genau dieser Fehler behoben. Argh! Zur Sicherheit installiere ich nochmal 0.8.1 aus dem Fdroid-Verzeichnis; im SVN ist Version 0.8.3.

      Erkenntnisse mit 0.8.1:

      • auch hier das Verhalten, dass keine Artikel angezeigt werden. Erst, nachdem ich „Unkategorisierte Feeds“ angeklickt habe
      • tatsächlich ist in 0.8.1 die Funktion, Artikel mit leerem content automagisch im Browser zu öffnen, defekt

      Damit wäre also der Teil der Arbeit gespart oder, je nach Betrachtungsweise, der vorige Teil der Arbeit meinerseits völlig unnötig. Jetzt interessiert mich aber doch, was denn in 0.8.1 der Bug war und wie er gefixt wurde! Natürlich sind die ganzen Code-Schnipsel oben aus der bereits reparierten Version, so dass sich auch erklärt, wieso das alles so aussieht, als müsste es funktionieren: es funktioniert ja auch!

      Es wäre nun eigentlich interessant, herauszufinden, was genau der Bug war. Andererseits scheint die Sonne und ich habe keine Lust mehr 🙂

      Ich habe also gelernt:

      • wie man tcpdump (auf Android) benutzt
      • dass man gefälligst die aktuellste Version testen sollte und nicht was älteres
      • dass die Google-Server recht langsam sind, wenn man sich Changesets mit svn diff -c anguckt
      • dass auch TT-RSS unter bestimmten Umständen meine IMEI (md5’ed) nach Hause telefoniert, wenn man an das Projekt gespendet hat. Fail.
      Kategorien:informatik, livehacking, oss