Vor ein paar Tagen habe ich mir — aus Bastellaune — einen kleinen Festplatten-DivX-Xvid-Player von LaCie (LaCinema Premier 500GB) zugelegt. Spielkind wie ich nunmal bin wollte ich wissen, was drauf läuft. Also die aktuelle Firmware heruntergeladen und entpackt. Das Archiv LaCinemePremier_FirmwareUpdate_3_10.zip enthält die folgenden Dateien:
-rw-r--r-- 1 mattias mattias 553 2008-04-09 13:57 Changes in firmware version 3_10.txt -rw-r--r-- 1 mattias mattias 4194304 2008-04-03 18:06 lacinema_premier_fw.bin -rw-r--r-- 1 mattias mattias 4194304 2008-02-19 15:00 ntd00fw.bin -rw-r--r-- 1 mattias mattias 7065 2008-04-09 12:02 Update_Procedure.txt
Interessant sind natürlich besonders die beiden Bin-Dateien. Der Befehl “strings” verschafft schonmal einen Überblick, was drin stecken könnte, da recht viel ausgegeben wird, ist es sinnvoll, nach Begriffen, wie Kernel oder Linux zu greppen. Und bingo:
... linux.c /work/iamm35_lacie/uClinux-2.4/include/linux/dcache.h /work/iamm35_lacie/uClinux-2.4/include/linux/sched.h /work/iamm35_lacie/uClinux-2.4/include/linux/highmem.h /work/iamm35_lacie/uClinux-2.4/include/linux/dcache.h /work/iamm35_lacie/uClinux-2.4/include/linux/dcache.h /work/iamm35_lacie/uClinux-2.4/include/linux/dcache.h linux.bin.gz linux.bin
Das sieht bereits nach den Resten eines Dateisystems (linux.bin.gz und linux.bin) und nach den in Kernelmodulen hinterlassenen Pfade der Include-Dateien aus. Schöner wäre es aber Zugriff auf ein Dateisystem zu erhalten. Doch der Befehl “file” sorgt zunächst für Ernüchterung:
lacinema_premier_fw.bin: data
Image-Offset aufgespürt
Doch wenn Strings so sauber drüberlaufen, kann es kein verschlüsseltes Image sein. Das eigentliche Dateisystem muss also mit einem gewissen Offset beginnen. Eine kurze Google-Recherche liefert, dass das häufig verwendete romfs mit dem Magic -rom1fs- beginnt. Die Zeichenkette wandeln wir zunächst nach Hex:
echo -n '-rom1fs-' | hexdump
0000000 722d 6d6f 6631 2d73 000a
Nun können wir einen Hexdump des Images machen und per Grep den Offset feststellen:
hexdump lacinema_premier_fw.bin | grep '722d 6d6f 6631 2d73'
Bingo!
00009c0 722d 6d6f 6631 2d73 4030 e92d 4000 e1a0 0040000 722d 6d6f 6631 2d73 3700 e0ec 5815 4b36
Mit Offset 0x40000 beginnt also ein RomFS-Image. Das sollte sich auf einem halbwegs aktuellen Desktop-Linux nun mounten lassen:
modprobe romfs
mount -t romfs -o loop,offset=0x40000 lacinema_premier_fw.bin /tmp/firmware
Und was steckt drin?
Nachdem sich das Image so problemlos mounten lies, ist es natürlich schön zu wissen, was drin steckt:
drwxr-xr-x 1 root root 32 1970-01-01 01:00 . drwxrwxrwt 16 root root 820 2008-06-19 19:26 .. drwxr-xr-x 1 root root 32 1970-01-01 01:00 bin drwxr-xr-x 1 root root 32 1970-01-01 01:00 cdrom drwxr-xr-x 1 root root 32 1970-01-01 01:00 dev drwxr-xr-x 1 root root 32 1970-01-01 01:00 etc drwxr-xr-x 1 root root 32 1970-01-01 01:00 hd1 drwxr-xr-x 1 root root 32 1970-01-01 01:00 hd2 drwxr-xr-x 1 root root 32 1970-01-01 01:00 img -rwxr-xr-x 1 root root 6,5K 1970-01-01 01:00 irdrv.o -rwxr-xr-x 1 root root 30K 1970-01-01 01:00 irdrvtest.bin -rwxr-xr-x 1 root root 341K 1970-01-01 01:00 khwl.o -rwxr-xr-x 1 root root 342K 1970-01-01 01:00 linux.bin.gz -rwxr-xr-x 1 root root 507K 1970-01-01 01:00 loading.yuv -rwxr-xr-x 1 root root 55K 1970-01-01 01:00 minimod drwxr-xr-x 1 root root 32 1970-01-01 01:00 nova -rwxr-xr-x 1 root root 11K 1970-01-01 01:00 piodrv.o
Das sieht doch schon ziemlich nach einem recht gewöhnlichen — wenn auch sehr kompakten — Linux-Dateisystem aus. Den Beweis liefert schließlich erneut “strings”, dieses Mal auf dem entpackten Kernel linux.bin.gz:
Linux version 2.4.17-uc0 (root@localhost.localdomain) (gcc version 2.95.3 20010315 (release)) #44 2008. 04. 02.
Der Kernel alleine reicht nicht für ein Linux-System. Wenigstens eine Anwendung benötigt man, die als “init” — als Prozess 1 — gestartet wird. Üblich sind Programmnamen wie init oder linuxrc, letztlich kann der Name des zuerst gestarteten Programmes aber auch vom Bootloader übergeben werden. Dennoch, ein /bin/init ist präsent, nicht einmal als Softlink, sondern als recht fette Datei mit 1,7MB. Hier wird offenbar die Hauptanwendung — der Medienplayer — beim Boot gestartet, stürzt diese ab, wird einfach rebootet. Strings auf /bin/init scheint diese Vermutung zu bestätigen, liefert der Befehl doch allerlei Hinweise auf Foto- und Videoplayer.
Doch gegen Ende fallen einige verdächtige Zeilen auf:
Connection timed out Connection refused Host is down No route to host Operation already in progress Operation now in progress Stale NFS file handle Structure needs cleaning Not a XENIX named type file No XENIX semaphores available Is a named type file Remote I/O error Disk quota exceeded
Ich hatte den Verdacht, diese schon gesehen zu haben, bastle ich doch viel mit der BusyBox herum. In einer BusyBox 1.9.2 fand ich:
Connection timed out Connection refused Host is down No route to host Operation already in progress Operation now in progress Stale NFS file handle Structure needs cleaning Not a XENIX named type file No XENIX semaphores available Is a named type file Remote I/O error Disk quota exceeded
Diese Zeilen entsprechen im Wortlaut und Reihenfolge der BusyBox. Natürlich könnte dies Zufall sein. Gar nicht abwegig wäre es, wenn jemand — um die GPL zu umgehen — einfach einen Programmierer in Indien oder China beauftragt, den gesamten Code der Mountfunktionen nachzuprogrammieren, gleiche Übergabeparameter, gleiche Rückgabewerte und gleiche Strings inclusive. Allerdings würde hier wahrscheinlich jeder vernünftige Mensch darauf bestehen, dass nur relevante Fehler Eingang in den Code finden (haben XENIX-bezogene Funktionen heute noch Bestand?) und es wäre fraglich, ob die Strings des sauber neu implementierten Codes im Objekt wieder die gleiche Anordnung hätten.
Conclusio
Auch wenn der 100%ige Beweis noch aussteht wiegen die Indizien bereits schwer: Es deutet viel auf einen Kernel und wenigstens eine Anwendung unter GPL, die nicht als Sourcecode erhältlich sind. Vielleicht kann sich einer der “Objektcode-Kenner” da draußen die Binaries einmal genauer vornehmen und meine Vermutungen bestätigen oder widerlegen. Eine Freigabe unter GPL dürfte LaCie oder deren Zulieferer nicht leicht fallen, schließlich sind die Chancen groß, dass “das fette Binary” auch Code von Dritten enthält. Doch gerade im Fall der Busybox sollte die Vorgehensweise einfach sein: Einfach die BusyBox als externes Binary ausführen und dessen Code freigeben. Damit sind alle zufrieden: GPL-Apologeten und kommerzielle Nutzer.
Natürlich ist fraglich, ob LaCie die alleinige Schuld trifft: Es deutet viel darauf hin, dass neben der Standardhardware von Sigma Electronics eben auch Standardsoftware modifiziert und eingesetzt wurde. Während Sigma die Referenz-Implementierung vorbildlich zum Download anbietet, schaut es mit den modifizierten Versionen düster aus.
Und das Tool der Woche?
Die Moral von der Geschicht: Mit dem richtigen Offset mountet man Images oder auch nicht.
Nachtrag, 20. Oktober 2008: Golem berichtet über eine umfassende Anleitung zum Aufspüren von GPL-Verletzungen.