Seite 1 von 2

Windows: Versionsinformationen von EXE-Dateien einlesen???

Verfasst: Montag 22. November 2004, 20:54
von jens
Kommt man an die Datei Information herran, die man angezeigt bekommt, wenn man sich die "Eigenschaft" einer Datei anschaut?

Also:

Code: Alles auswählen

Eigenschaften / Version /
 -Dateiversion
 -Beschreibung
 -Copyright

EDIT:
Ah, hab gerade das gefunden:
"Using windll to extract version information from Windows files"
http://aspn.activestate.com/ASPN/Cookbo ... ipe/117219

EDIT2:
Naja, diese Beispiel setzt wieder ein paar Module und DLL's vorraus... :(

Verfasst: Montag 22. November 2004, 23:20
von jens
Also eigentlich stehen die Informationen im "Klartext" in der EXE-Datei... Leider nicht ganz so "Klartext"...

Die Daten stehen fast am Ende der Datei... Jedoch kann ich mir vorstellen, das man mittels re. und ein paar IF-Abfragen unabhängig der Dateigröße/Position rausfiltern kann...

Ich hab jedoch Schwirigkeiten damit. Wenn man mit einem HEX-Editor eine Datei anschaut und zu diesen Daten scrollt, kann man sehen, das jeder Buchstabe durch ein NULL-Zeichne getrennt ist... Ich kann mir vorstellen, das es was mit UniCode-Formatierung zutun hat...

Hier hab ich mal ein Beispiel, der die richtige Position der Daten im Windows-Notepad v5.1.2600.2180 anzeigt:

Code: Alles auswählen

FileHandle = open( "c:\\windows\\Notepad.exe", "rb" )
RAWinfo = FileHandle.read()
FileHandle.close()

RAWinfo = RAWinfo[68430:69148]
print RAWinfo
print "".join( re.findall("\w",RAWinfo) )
Die Ausgabe des zweiten Prints sieht so aus:

Code: Alles auswählen

StringFileInfo040704B0LCompanyNameMicrosoftCorporation8FileDescriptionEditortFileVersion5126002180xpsp_sp2_rtm04080321580InternalNameNotepad2LegalCopyrightMicrosoftCorporationAlleRechtevorbehaltenOriginalFilenameNOTEPADEXEhProductNameBetriebssystemMicrosoftWindowsProductVersion5126002180

Verfasst: Montag 22. November 2004, 23:28
von jens
Hier: http://p-nand-q.com/python/unicode_faq.html
Unter "Unicode in Dateien"

Dort kann man einen HEX-Auszug sehen, der mit dem Notepad.exe, was ich meine, übereinstimmt...

Also sind die Daten wahrscheinlich in Unicode hinterlegt?

Verfasst: Dienstag 23. November 2004, 00:39
von Dookie
Hi jens,

wenn jedes Zeichen aus 2 Byte besteht, dürfte es sich um "utf-16" handeln.


Gruß

Dookie

Verfasst: Dienstag 23. November 2004, 12:58
von Gast
Dookie hat geschrieben:wenn jedes Zeichen aus 2 Byte besteht, dürfte es sich um "utf-16" handeln.
Das hatte ich schon mal versucht, aber das funktionierte nicht richtig...
Allerdings, hab ich hier eine kleine Schäbige Variante gebaut:

Code: Alles auswählen

FileHandle = open( "c:\\Notepad.exe", "rb" )
RAWdata = FileHandle.read().replace("\x00","")
FileHandle.close()
print re.findall("CompanyName([A-Za-z ]+)", RAWdata )
print re.findall("FileDescription([A-Za-z ]+)", RAWdata )
print re.findall("FileVersion([\w. ]+)", RAWdata )
print re.findall("InternalName([A-Za-z ]+)", RAWdata )
Ergebnis:

Code: Alles auswählen

['Microsoft Corporation']
['Editort']
['5.1.2600.2180 ']
['Notepad']
Das dumme ist nur, das bei der Verionsinformation in Dateien, die Elementnamen ( bsp. CompanyName, FileDescription usw.) nicht "genormt" sind...
Ich denke nur Dateiversion, Beschreibung und Copyright sind fest drin, also zumindest macht das den Anschein, wenn man sich das Eigenschaft/Version-Kontextmenü zu einer Datei anschaut... Und die drei angaben würden für mich eigentlich reichen... Aber wenn man schon mal dran ist...

Verfasst: Dienstag 23. November 2004, 13:03
von jens
(Das oben war ich)

Anzumerken ist noch, das diese Lösung nicht 100% funktioniert wie man z.B. am Ergenis: ['Editort'] sehen kann... eigentlich sollte es natürlich nur "Editor" heißen, aber das anschließende "t" ist ja auch ein Buchstabe und wird somit von [A-Za-z ] gefunden...

Verfasst: Dienstag 23. November 2004, 13:43
von Dookie
Was hst Du versucht? Du löscht einfach die 0x00 bytes das is sicher keine saubere Lösung, wenn du die daten bekommst lass sie, mit unicode(text_in_utf16, "utf-16"), in utf-8-unicode wandeln und verwende sonst auch für alle textstrings unicode statt str, dann sollte es klappen.


Gruß

Dookie

Verfasst: Dienstag 23. November 2004, 16:32
von jens
Nein, das Beispiel mit dem .replace("\x00","") war nicht mein Unicode-Versuch, diesen hab ich ähnlich gemacht, wie dein Beispiel hier:
http://python.sandtner.org/viewtopic.php?p=10164#10164

Ich hab auch verschiedene durchprobiert "utf-8", "latin-1", "UTF-16LE" und "UTF-16" aber das klappte bei keinem richtig :(

Noch eine andere Frage... Wie kann ich bei .read() angeben, das nur etwas die letzten 1024 Bytes gelesen werden?
Denn ich denke, egal wie die Lösungs hinter aus sehen wird, ich denke ich muß immer die Daten analysieren. Nur, die für mich relevanten Daten liegen ja eh nur am Ende einer Datei... Somit ist es ja blödsinnig die ganze Datei zu durchsuchen...

Ich denke auch bei .read()[:1024] wird doch wohl erst die ganze Datei eingeladen und dann "gekürzt", oder?

Verfasst: Dienstag 23. November 2004, 17:34
von Dookie
Du kannst mit f.seek(-1024, 2) an die Stelle in der Datei springen und dann mit f.read(1024) die letzten 1024 Bytes lesen.

Dookie

Verfasst: Dienstag 23. November 2004, 22:31
von jens
f.seek(-1024, 2) ist super! Danach, bauche ich aber nicht unbedingt mit f.read(1024) zu arbeiten... ein normales f.read() geht auch, er liest einfach von der Position bis zum Ende...

So, jetzt nochmal ein Test mit verschiedenen Codings, mit FileHandle = codecs.open( "Notepad.exe", "rb", encoding="XXX" )

utf-16le - UnicodeDecodeError: 'utf16' codec can't decode bytes in position 1644-1645: illegal encoding

utf-16 - UnicodeError: UTF-16 stream does not start with BOM

utf-8 - UnicodeDecodeError: 'utf8' codec can't decode byte 0x90 in position 2: unexpected code byte

latin-1 - UnicodeEncodeError: 'ascii' codec can't encode character u'\xb0' in position 30: ordinal not in range(128)

Verfasst: Dienstag 23. November 2004, 22:40
von Dookie
jo is klar, ich sagte auch das eingelesene dann mit unicode(text,'utf-16LE') in Python-Unicode wandeln lassen.

Dookie

Verfasst: Dienstag 23. November 2004, 22:44
von jens
Hmm.... Da verstehe ich dich jetzt leider nicht so ganz... Was meinst du mit dem "eingelesenen" ???

Ich hab es hier mal versucht:

Code: Alles auswählen

FileHandle = open( "Notepad.exe", "rb" )
FileHandle.seek(-2048, 2)
RAWdata = FileHandle.read()
FileHandle.close()
print len(RAWdata)

print unicode(RAWdata,'utf-16LE')

Code: Alles auswählen

UnicodeEncodeError: 'ascii' codec can't encode character u'\u0300' in position 22: ordinal not in range(128)
Ich hab festgestellt, das die Daten zumindest mit \x01 eingeschlossen sind... Nun versuche ich gerade mit RE nur A-Za-z0-9 die zwischen \x01 stehen rauszufiltern... Leider noch ohne Erfolg...

Verfasst: Dienstag 23. November 2004, 22:56
von Dookie
such doch einfach nach '\0x01' ohne re und hole die strings dann anhand der Positionen raus, oder nimm einfach split():

Code: Alles auswählen

FileHandle = open( "Notepad.exe", "rb" )
FileHandle.seek(-2048, 2)
RAWdata = FileHandle.read()
FileHandle.close()
strings = RAWdata.split('\0x01')[1:] # im ersten string steht nur muell
unis = [unicode(x, "utf-16LE") for x in strings]
for i in unis:
    print i

Dookie

Verfasst: Mittwoch 24. November 2004, 09:01
von jens
Mist, ich hab weitere Tests gemacht und einige Dateien nach "StringFileInfo" mittels .rfind() durchsucht, mit diesem String werden wohl die gesuchten Information "eingeleitet"...
Zwar ist die Position des Strings fast immer am Ende der Datei, aber nicht immer :(

Ein extrem Beispiel ist soffice.exe von OpenOffice... Dort befindet sich der String ca. in der hälfte der Datei...

Naja, nun muß ich erstmal Testen, ob nach "StringFileInfo" wirklich die Informationen kommen... Oder ob es evtl. "zufällig" in Dateien vorkommt...

EDIT: Jep, sind die richtigen Info's... Diese fangen wohl mit "StringFileInfo" an und höhren mit "VarFileInfo" auf... Das ist ideal für RE


EDIT2: Schade... Die Passage fägt zwar immer mit "StringFileInfo" an, höhrt aber leider nicht immer mit "VarFileInfo" auf :( Also ein re.findall("StringFileInfo(.*?)VarFileInfo",...) klappt somit nicht...

Verfasst: Mittwoch 24. November 2004, 09:30
von jens
Hier nochmal ein versuch:

Code: Alles auswählen

import os

def FindAllVerInfo( FileName ):
    FileHandle = open( FileName, "rb" )
    RAWdata = FileHandle.read().replace("\x00","")
    FileHandle.close()

    POS = RAWdata.rfind( "StringFileInfo" )

    if POS == -1:
        print "* NOT FOUND *"
        return

    EndPOS = RAWdata.rfind( "VarFileInfo" )
    if EndPOS == -1:
        EndPOS = POS+500

    RAWdata = RAWdata[ POS:EndPOS]

    for i in RAWdata.split("\x01")[2:]:
        print i[:-2]


Endungen = [".exe",".dll"]

for Verz, VerzList, DateiListe in os.walk("C:\\"):
    for Datei in DateiListe:
        FileExt = os.path.splitext(Datei)[1]
        if FileExt in Endungen:
            print "\n>",Datei
            Datei = Verz+os.sep+Datei
            FindAllVerInfo( Datei )
Bsp.:

Code: Alles auswählen

> FlashPlayerW.dll
CompanyNameMacromedia, Inc.
FileDescriptionMacromedia Flash Player 6.0  r23
FileExtentsswf|spl
FileOpenNameMacromedia Flash movie (*.swf)|FutureSplash movie (*.spl)
FileVersion6,0,23,0
InternalNameMacromedia Flash Player 6.0
LegalCopyrightCopyright © 1996-2002 Macromedia, Inc.
LegalTrademarksMacromedia Flash Player
OriginalFilenameauthplay.dll
ProductNameShockwave Flash
ProductVersion6,0,23,

> NPSWF32.dll
CompanyNameMacromedia, Inc.
FileDescriptionShockwave Flash 6.0  r68
FileExtentsswf|spl
FileOpenNameMacromedia Flash movie (*.swf)|FutureSplash movie (*.spl)
MIMETypeapplication/x-shockwave-flash|application/futuresplash
ProductNameShockwave Flash
FileVersion6,0,68,0
InternalNameMacromedia Flash Player 6.0
LegalCopyrightCopyright © 1996-2002 Macromedia, Inc.
LegalTrademarksMacromedia Flash Player
OriginalFilenamenpswf32.dll
ProductVersion6,0,68,
Das Blöde ist nur, das Eintrag:Wert nicht mehr getrennt sind... Also bei CompanyNameMacromedia, Inc. ist kein Leerzeichen zwischen CompanyName und Macromedia, Inc. :(

Das liegt natürlich an meiner Art die Datei per .replace("\x00","") zu verschandeln... Aber mit Encodings hat es bisher ja nie geklappt :(

Verfasst: Mittwoch 24. November 2004, 09:55
von jens
Also bei allen Experimenten, scheit mir die Lösung hier:
http://python.sandtner.org/viewtopic.php?p=12502#12502
noch am besten zu sein ;)

Naja, ich hab sie mal mit neuen Erkenntnissen ausgestattet:

Code: Alles auswählen

def gefFileInfo( FileName ):
    def getInfo( InfoStr ):
        return re.findall( InfoStr+"(.+)\x01", RAWdata )[0][:-2]

    FileHandle = open( FileName, "rb" )
    RAWdata = FileHandle.read().replace("\x00","")
    FileHandle.close()

    POS = RAWdata.rfind( "StringFileInfo" )

    if POS == -1:
        print "* NOT FOUND *"
        return

    EndPOS = RAWdata.rfind( "VarFileInfo" )
    if EndPOS == -1:
        EndPOS = POS+500

    RAWdata = RAWdata[ POS:EndPOS]

    print getInfo( "CompanyName" )
    print getInfo( "FileDescription" )
    print getInfo( "FileVersion" )
    print getInfo( "InternalName" )
Leider versagt aber bei re.findall( InfoStr+"(.+)\x01", RAWdata ) die "suche" nach \x01

@dookie: Du hattes irgdnwo mal \0x01 geschrieben... Warum?

Verfasst: Mittwoch 24. November 2004, 11:38
von Dookie
@dookie: Du hattes irgdnwo mal \0x01 geschrieben... Warum?
War wohl ein Tippfehler :)


Gruß

Dookie

Verfasst: Mittwoch 24. November 2004, 17:46
von jens
Und ich dachte schon, es wäre eine andere Schreibform oder so...

Aber wie erklärt es sich, das re.findall( InfoStr+"(.+)\x01", RAWdata ) nicht bei \x01 "aufhöhrt" ???
Das Ergebnis ist immer ab dem InfoStr bis zum ende... Obwohl da halt ein \x01 kommt...

Kommt RE mit Sonderzeichen nicht zurecht?

EDIT: Anscheinend, denn das hier funktioniert:

Code: Alles auswählen

        RAWdata = RAWdata.replace("\x01","\n")
        return re.findall( InfoStr+"(.+)\n", RAWdata )[0][:-2]

Verfasst: Mittwoch 24. November 2004, 17:53
von Milan
Hi. Vielleicht ist ja das letzte zZeichen ein \x01, denn du hast ja im greedy mode gesucht :wink:

Verfasst: Mittwoch 24. November 2004, 17:56
von Dookie
versuchs mal so
re.findall( InfoStr+"([^\x01]+)", RAWdata )

Dookie