Tipps

Binärdateien einlesen und Base64-Codieren mit Powershell

Grundsätzlich unterscheidet man zwischen Textdateien und Binärdateien. Technisch gesehen sind beide Dateitypen Bitströme, also Reihen von aufeinanderfolgenden Bits. Textdaten werden allerdings nach einem festen Muster kodiert. Jeweils ein Block von 8 oder 16 Bits (oder je nach Codierung auch mehr) werden zu einem Zeichen zusammengefasst. Die klassische Codierung ist dabei die sehr alte ASCII-Codierung, die ein Zeichen in jeweils 7 Bit codiert und insgesamt 8 Bit für die Speicherung verwendet. Wenn man Get-Content verwendet, um eine Textdatei einzulesen, versucht Get-Content automatisch, die Datei als Text zu interpretieren und darzustellen. 

get-content -Path $einv:Windir\lsasetup.log
[ 1 1 / 4 1 5 : 3 1 : 1 4 ] 5 9 6 . 6 0 0 > - I n L s a p S e t R a n d o m D o m a i n S i d ( )

[ 1 1 / 4 1 5 : 3 1 : 1 4 ] 5 9 6 . 6 0 0 > - L s a p G e n e r a t e R a n d o m D o m a i n S i d : R t l A l l o c a t e A n d I n i t i a l i z e S i d r e t u r n e d 0 x 0

Die Ausgabe dieses Beispiels sieht allerdings sehr merkwürdig aus - Powershell hat zwischen jedes Zeichen ein Leerzeichen gesetzt. Das liegt daran, dass die Datei in UTF16 und nicht in ASCII codiert ist. UTF16 ist eine Form der Unicode-Codierung, die statt 8 16 Bit verwendet, um ein Zeichen zu speichern. Dadurch wird es möglich, eine deutlich größere Zahl von Zeichen zu codieren. UTF16 ist abwärtskompatibel zu ASCII, verwendet also für die ersten 127 Zeichen die gleiche Muster. Das zweite Bit wird beim Einlesen mit ASCII-Codierung dann als Leerzeichen interpretiert. Das Problem lässt sich lösen, indem man Get-Content mti dem Parameter -Endoding anweist, den Text als UTF16 zu dekodieren. 

get-content -Path .\lsasetup.log -Encoding Unicode
[11/ 4 15:31:14] 596.600> - In LsapSetRandomDomainSid()
[11/ 4 15:31:14] 596.600> - LsapGenerateRandomDomainSid: RtlAllocateAndInitializeSid returned 0x0

Das sieht schon viel besser aus. Wenn man mit Get-Content allerdings versucht, eine Binärdatei einzulesen, versucht Get-Content, auch den Binärcode in Textzeichen zu übersetzen. Das ist allerdings sinnlos, da der Binärcode ein Bitstrom ist und keinen Text darstellt. Das Ergebnis ist Kauderwelsch. 

Get-Content -Path $env:Windir\notepad.exe

tipp466 1

Wie man sehen kann, sind aber auch in der ausführbaren Datei Ausgabetexte enthalten, die dann durchaus interpretiert werden können (Im Bild rot markiert). Das das sauber funktioniert liegt daran, dass auch der Binärcode in Bytes und nicht Bits gespeichert wird und die Bytegrenzen damit gleich bleiben.

Man kann Powershell anweisen, eine Binärdatei nicht als Text zu interpretieren, indem man als Encoding Byte angibt:

get-content -Encoding Byte -Path C:\windows\notepad.exe

Das Cmdlet gibt die Daten dann als Byte-Array zurück, die man z.B. in einer Variablen speichern kann. Beschleunigen können Sie das Einlesen, indem Sie Get-Content anweisen, die Datei in einem Stück (Raw) und nicht Zeilenweise einzulesen:

$notepad = get-content -Encoding Byte -Path $env:Windir\\notepad.exe -Raw

Alternativ kann man auch auf das .net-Framework und die Klasse IO.File zurückgreifen, um die Datei einzulesen:

[IO.File]::ReadAllBytes('C:\Windows\notepad.exe')

Aber wofür sollte man eine Binärdatei überhaupt in Powershell einlesen? Z.B. kann man die Datei wieder durch eine Codierung laufen lassen, nämlich Base64. Sie kann Binärdaten wieder als Text codieren, um sie dann in einer Textdatei speichern zu können. Base64 wird z.B. verwendet, um Binärdateien über das rein textbasierte Mailprotokoll SMTP übertragen zu können. So ist es z.B. möglich, eine ausführbare Datei komplett in ein Powershell-Skript zu kodieren, um Sie bei Bedarf dann wieder im Dateisystem zu speichern und zu starten. 

$base64string[Convert]::ToBase64String([IO.File]::ReadAllBytes("$env:Windir\notepad.exe"))

Um die Datei ins Dateisystem zurückzuschreiben, verwenden Sie die Methode [IO.File]::WriteAllBytes():

[IO.File]::WriteAllBytes($FileName, [Convert]::FromBase64String($base64string))

Ob Sie die Datei direkt mit der Methode "ReadAllBytes()" oder Get-Content einlesen, macht im Übrigen von der Performance keinen Unterschied, wenn Sie den Parameter -Raw benutzen, da Get-Content im Hintergrund auf die gleiche Methode zurückgreift.

 

 


 326,    07  Mai  2019 ,   Tipp
Holger Voges

  E-Mail Diese E-Mail-Adresse ist vor Spambots geschützt! Zur Anzeige muss JavaScript eingeschaltet sein!

Holger Voges ist Inhaber der Firma Netz-Weise IT-Training und seit 1999 als Trainer und Consultant tätig. Als Allrounder in den Bereichen Windows Server, Active Directory, SQL Server, Hyper-V und Windows PowerShell, hat er in der Vergangenheit zahlreiche Einsätze als Consultant in namenhaften Firmen absolviert und so neben der Theorie auch umfangreiche praktische Erfahrungen gesammelt.

 

Netz-Weise

Das Haupt-Tätigkeitsfeld von Netz-Weise sind Schulungen für Profis. Bei uns bekommen Sie das Programm für den fortgeschrittenen Praktiker, der die Tiefen des Systems ausloten möchte genauso wie Standard-Schulungen.

So erreichen Sie uns:

Netz-Weise
IT-Training und Beratung
Freundallee 13a
30173 Hannover
 
Tel: (0511) 165 925-0
Fax: (0511) 165 925-99
email: info(at)netz-weise.de
 

Newsletter bestellen

Das Wichtigste kompakt ins E-Mailfach!