Netz-Weise Logo

Weisheiten - der Netz-Weise Blog

Hier finden Sie Tipps und Tricks für vor, während und nach der Schulung.
3 Minuten Lesezeit (657 Worte)

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.

 

 

Programme und Code in Base64 und zurück konvertier...
Virtuelle Festplatten (vhdx) als Datencontainer ve...

Ähnliche Beiträge

 

Kommentare

Derzeit gibt es keine Kommentare. Schreibe den ersten Kommentar!
Bereits registriert? Hier einloggen
Sonntag, 19. Mai 2024

Sicherheitscode (Captcha)