Hallo, ich versuche, mit dem Modul gzip eine Datei zu entpacken, die "trailing garbage" enthält. (Konkret handelt es sich um einen Binärdatei, bei der die gzippten Daten mitten drin liegen, ich kenne also deren Länge nicht. Das Kommandozeilen gzip liest einfach, was auch immer es kann und ignoriert den Rest mit der Warnung "ignoring trailing garbage". Die Python gzip-lib scheint dagegen lustig weiter zu lesen, bzw. versucht, einen weiteren Teil zu erkennen. Wenn es den nicht gibt, wird ein IOError ausgelöst und die bis habin in dem Block dekomprimierten Daten gelangen nicht nach an den Aufrufer :-( Hier mein gescheiterter Versuch, das in Python zu implementieren. gz = gzip.GzipFile(fileobj=infh) with open(outfilename, 'wb') as outfh: while 1: d = gz.read(BLOCKSIZE) if not d: break outfh.write(d) if gz._new_member: break infh.close() Hat jmd. eine Idee, wie man das lösen könnte? -- Schönen Gruß Hartmut Goebel Dipl.-Informatiker (univ), CISSP, CSSLP Goebel Consult http://www.goebel-consult.de Monatliche Kolumne: http://www.cissp-gefluester.de/2011-08-horrorszenario-bring-your-own-device Blog: http://www.goebel-consult.de/blog/20050315 Goebel Consult ist Mitglied bei http://www.7-it.de/
Am 26. Januar 2013 14:09 schrieb Hartmut Goebel <h.goebel@goebel-consult.de>:
Hallo,
ich versuche, mit dem Modul gzip eine Datei zu entpacken, die "trailing garbage" enthält. (Konkret handelt es sich um einen Binärdatei, bei der die gzippten Daten mitten drin liegen, ich kenne also deren Länge nicht.
Das Kommandozeilen gzip liest einfach, was auch immer es kann und ignoriert den Rest mit der Warnung "ignoring trailing garbage".
GZIP hat charakteristische Blockgrenzen, anhand derer man derartig komprimierte Daten erkennen kann. Du kannst diese Kopfdaten in der Spezifikation des Formats nachschlagen, und somit das Verhalten von "gzip" re-implementieren. Ob das sinnvoll ist, sei dahingestellt.
Die Python gzip-lib scheint dagegen lustig weiter zu lesen, bzw. versucht, einen weiteren Teil zu erkennen. Wenn es den nicht gibt, wird ein IOError ausgelöst und die bis habin in dem Block dekomprimierten Daten gelangen nicht nach an den Aufrufer :-(
Hier mein gescheiterter Versuch, das in Python zu implementieren.
gz = gzip.GzipFile(fileobj=infh) with open(outfilename, 'wb') as outfh: while 1: d = gz.read(BLOCKSIZE) if not d: break outfh.write(d) if gz._new_member: break infh.close()
Ohje, wie bist Du denn darauf gekommen?!
Hat jmd. eine Idee, wie man das lösen könnte?
Ich nehme mal an, dass die Binärdaten, die Du zu lesen versuchst, irgendeinem mehr oder weniger klar definierten Format unterliegen. Wieso parst Du nicht einfach dieses Format insoweit, als dass Du die GZIP-Daten, an denen Du interessiert bist, aus den Daten extrahieren und dann die GZIP-Daten – und **nur** die GZIP-Daten – an "gzip" übergeben kannst?
Am 26. Januar 2013 14:40 schrieb Sebastian Wiesner <lunaryorn@gmail.com>:
Am 26. Januar 2013 14:09 schrieb Hartmut Goebel <h.goebel@goebel-consult.de>:
Hallo,
ich versuche, mit dem Modul gzip eine Datei zu entpacken, die "trailing garbage" enthält. (Konkret handelt es sich um einen Binärdatei, bei der die gzippten Daten mitten drin liegen, ich kenne also deren Länge nicht.
Das Kommandozeilen gzip liest einfach, was auch immer es kann und ignoriert den Rest mit der Warnung "ignoring trailing garbage".
GZIP hat charakteristische Blockgrenzen, anhand derer man derartig komprimierte Daten erkennen kann. Du kannst diese Kopfdaten in der Spezifikation des Formats nachschlagen, und somit das Verhalten von "gzip" re-implementieren.
Diese Spezifikation ist RFC 1952, zu finden unter http://tools.ietf.org/html/rfc1952. Hatte ich vergessen…
Am 26.01.2013 14:40, schrieb Sebastian Wiesner:
GZIP hat charakteristische Blockgrenzen, anhand derer man derartig komprimierte Daten erkennen kann. Du kannst diese Kopfdaten in der Spezifikation des Formats nachschlagen, und somit das Verhalten von "gzip" re-implementieren. Ob das sinnvoll ist, sei dahingestellt.
Ich hatte nicht vor, gzip nach zu bauen. Danke für den Link auf den RFC. Der zeigt aber deutlich, dass man bei gzip am Anfang nicht wissen kann, wie lange der Input oder auch der unkomprimierte Stream sind.
Hier mein gescheiterter Versuch, das in Python zu implementieren.
gz = gzip.GzipFile(fileobj=infh) with open(outfilename, 'wb') as outfh: while 1: d = gz.read(BLOCKSIZE) if not d: break outfh.write(d) if gz._new_member: break infh.close() Ohje, wie bist Du denn darauf gekommen?!
Was genau meinst Du? Den Test auf "_new_member"? Weil das genau dann gesetzt wird, wenn nach einem deflate-stream und dem gzip-Trailer noch Daten übrig waren.
Ich nehme mal an, dass die Binärdaten, die Du zu lesen versuchst, irgendeinem mehr oder weniger klar definierten Format unterliegen.
Leider ist diese Annahme falsche -- es handelt sich um das vmlinux-Image für ARM. Das wird direkt in den Speicher geladen und ausgeführt. Und irgendwo da drin steckt der gzipped Kernel. Davor ist Maschinen-Code und ggf. eine initrd. -- Schönen Gruß Hartmut Goebel Dipl.-Informatiker (univ), CISSP, CSSLP Goebel Consult http://www.goebel-consult.de Monatliche Kolumne: http://www.cissp-gefluester.de/2010-01-hinterturen-allen-ortes Blog: http://www.goebel-consult.de/blog/20060215 Goebel Consult ist Mitglied bei http://www.7-it.de/
Am 26. Januar 2013 17:31 schrieb Hartmut Goebel <h.goebel@goebel-consult.de>:
Ich nehme mal an, dass die Binärdaten, die Du zu lesen versuchst, irgendeinem mehr oder weniger klar definierten Format unterliegen.
Leider ist diese Annahme falsche -- es handelt sich um das vmlinux-Image für ARM.
Das ist ein *definiertes* Datenformat.
Das wird direkt in den Speicher geladen und ausgeführt. Und irgendwo da drin steckt der gzipped Kernel. Davor ist Maschinen-Code und ggf. eine initrd.
Der komprimierte Kernel-Code befindet sich nicht „irgendwo“, sondern an einer bestimmten Stelle im enthaltenen ELF-Objektcode. Eine initrd sollte im vmlinux-Abbild eigentlich nicht enthalten sein. Das Format ist augenscheinlich einfach zu parsen. So einfach jedenfalls, dass es im Kernel-Quelltext unter /scripts/ ein Shell-Script(!) namens extract-vmlinux [1] gibt, dass den Kernel-Code aus dem Abbild extrahiert. [1]: https://github.com/torvalds/linux/blob/master/scripts/extract-vmlinux
Am Sat, 26 Jan 2013 17:19:27 +0100 schrieb Sebastian Wiesner <lunaryorn@gmail.com>:
Das Format ist augenscheinlich einfach zu parsen. So einfach jedenfalls, dass es im Kernel-Quelltext unter /scripts/ ein Shell-Script(!) namens extract-vmlinux [1] gibt, dass den Kernel-Code aus dem Abbild extrahiert.
Dieses Skript parst keine Strukturen, sondern sucht nur nach der Header-Signatur und verfüttert die Daten ab der Fundstelle an gunzip. Ist also ungefähr das, was Hartmut in Python machen will. -- Plugin for Nautilus to create and modify application starters (.desktop files): <http://www.florian-diesch.de/software/arronax/>
Am 26.01.2013 17:44, schrieb Florian Diesch:
Am Sat, 26 Jan 2013 17:19:27 +0100 schrieb Sebastian Wiesner <lunaryorn@gmail.com>:
Das Format ist augenscheinlich einfach zu parsen. So einfach jedenfalls, dass es im Kernel-Quelltext unter /scripts/ ein Shell-Script(!) namens extract-vmlinux [1] gibt, dass den Kernel-Code aus dem Abbild extrahiert. Dieses Skript parst keine Strukturen, sondern sucht nur nach der Header-Signatur und verfüttert die Daten ab der Fundstelle an gunzip.
Ist also ungefähr das, was Hartmut in Python machen will.
Ziemlich genau das möchte ich machen. Leider kannte ich das Skript bis eben nicht. -- Schönen Gruß Hartmut Goebel Dipl.-Informatiker (univ), CISSP, CSSLP Goebel Consult http://www.goebel-consult.de Monatliche Kolumne: http://www.cissp-gefluester.de/2010-01-hinterturen-allen-ortes Blog: http://www.goebel-consult.de/blog/20060215 Goebel Consult ist Mitglied bei http://www.7-it.de/
Am 26.01.2013 17:19, schrieb Sebastian Wiesner:
Das ist ein *definiertes* Datenformat. [...] Der komprimierte Kernel-Code befindet sich nicht „irgendwo“, sondern an einer bestimmten Stelle im enthaltenen ELF-Objektcode. Ich weiß nicht, von welchem vmlinux-Dateien Du schreibst. Die für ARM und den u-boot sind jedenfalls kein ELF, sondern werden einfach in den Speicher geladen.
-- Schönen Gruß Hartmut Goebel Dipl.-Informatiker (univ), CISSP, CSSLP Goebel Consult http://www.goebel-consult.de Monatliche Kolumne: http://www.cissp-gefluester.de/2010-01-hinterturen-allen-ortes Blog: http://www.goebel-consult.de/blog/20060215 Goebel Consult ist Mitglied bei http://www.7-it.de/
Am 27.01.2013 19:43, schrieb Hartmut Goebel:
Am 26.01.2013 17:19, schrieb Sebastian Wiesner:
Das ist ein *definiertes* Datenformat. [...] Der komprimierte Kernel-Code befindet sich nicht „irgendwo“, sondern an einer bestimmten Stelle im enthaltenen ELF-Objektcode. Ich weiß nicht, von welchem vmlinux-Dateien Du schreibst. Die für ARM und den u-boot sind jedenfalls kein ELF, sondern werden einfach in den Speicher geladen.
So, jetzt hat sich der Wurm komplett eingeschlichen: Ich versuche, das vmlinux-Image auf dem zImage für ARM zu extrahieren. Das zImage hat zwar offensichtlich ein bekannten Header (denn `file` erkennt die Datei), aber die Struktur ist "code zum dekomprimieren + gzip-Daten(vmlinuz)", siehe auch <http://openinkpot.org/wiki/Documentation/ZImageFormat>. Das enthaltene vmlinux ist dann kein ELF-Format, sondern wird, wie oben geschrieben, direkt ausgeführt. -- Schönen Gruß Hartmut Goebel Dipl.-Informatiker (univ), CISSP, CSSLP Goebel Consult http://www.goebel-consult.de Monatliche Kolumne: http://www.cissp-gefluester.de/2010-01-hinterturen-allen-ortes Blog: http://www.goebel-consult.de/blog/20060215 Goebel Consult ist Mitglied bei http://www.7-it.de/
Am Sat, 26 Jan 2013 14:09:05 +0100 schrieb Hartmut Goebel <h.goebel@goebel-consult.de>:
Die Python gzip-lib scheint dagegen lustig weiter zu lesen, bzw. versucht, einen weiteren Teil zu erkennen. Wenn es den nicht gibt, wird ein IOError ausgelöst und die bis habin in dem Block dekomprimierten Daten gelangen nicht nach an den Aufrufer :-(
Hat jmd. eine Idee, wie man das lösen könnte?
Schnell und schmutzig: class MyGzipFile(gzip.GzipFile): def _read(self, size=1024): try: gzip.GzipFile._read(self, size) except IOError: pass -- Plugin for Nautilus to create and modify application starters (.desktop files): <http://www.florian-diesch.de/software/arronax/>
Am 26.01.2013 15:34, schrieb Florian Diesch:
Schnell und schmutzig:
class MyGzipFile(gzip.GzipFile):
def _read(self, size=1024): try: gzip.GzipFile._read(self, size) except IOError: pass
Hervorragen, das tut das ich erwarte. Herzlichen Dank! -- Schönen Gruß Hartmut Goebel Dipl.-Informatiker (univ), CISSP, CSSLP Goebel Consult http://www.goebel-consult.de Monatliche Kolumne: http://www.cissp-gefluester.de/2010-01-hinterturen-allen-ortes Blog: http://www.goebel-consult.de/blog/20060215 Goebel Consult ist Mitglied bei http://www.7-it.de/
participants (3)
-
Florian Diesch -
Hartmut Goebel -
Sebastian Wiesner