Encode / Decode .EXE into Base64 - powershell

I have a .NET exe file that I'd like to encode into a Base-64 string, and then at a later point decode into a .exe file from the Base64 string, using Powershell.
What I have so far produces a .exe file, however, the file isn't recognizable to windows as an application that can run, and is always a different length than the file that I'm passing into the encoding script.
I think I may be using the wrong encoding here, but I'm not sure.
Encode script:
Function Get-FileName($initialDirectory)
{
[System.Reflection.Assembly]::LoadWithPartialName("System.windows.forms") | Out-Null
$OpenFileDialog = New-Object System.Windows.Forms.OpenFileDialog
$OpenFileDialog.initialDirectory = $initialDirectory
$OpenFileDialog.filter = "All files (*.*)| *.*"
$OpenFileDialog.ShowDialog() | Out-Null
$FileName = $OpenFileDialog.filename
$FileName
} #end function Get-FileName
$FileName = Get-FileName
$Data = get-content $FileName
$Bytes = [System.Text.Encoding]::Unicode.GetBytes($Data)
$EncodedData = [Convert]::ToBase64String($Bytes)
Decode Script:
$Data = get-content $FileName
$Bytes = [System.Text.Encoding]::UTF8.GetBytes($Data)
$EncodedData = [System.Text.Encoding]::Unicode.GetString([System.Convert]::FromBase64String($Bytes))
$EncodedData | Out-File ( $FileName )

The problem was caused by:
Get-Content without -raw splits the file into an array of lines thus destroying the code
Text.Encoding interprets the binary code as text thus destroying the code
Out-File is for text data, not binary code
The correct approach is to use IO.File ReadAllBytes:
$base64string = [Convert]::ToBase64String([IO.File]::ReadAllBytes($FileName))
and WriteAllBytes to decode:
[IO.File]::WriteAllBytes($FileName, [Convert]::FromBase64String($base64string))

Just to add an alternative for people looking to do a similar task: Windows comes with certutil.exe (a tool to manipulate certificates) which can base64 encode and decode files.
certutil -encode test.exe test.txt
certutil -decode test.txt test.exe

This is a purely PowerShell version of Swonkie's answer which, despite working quite well if you have access to the utility, isn't a PowerShell answer - which is what I needed.
$SourceFile = "C:\Src\OriginalBinaryFile.dll"
$B64File = "C:\Src\DllAsB64.txt"
$Reconstituted = "C:\Src\ReConstituted.dll"
[IO.File]::WriteAllBytes($B64File,[char[]][Convert]::ToBase64String([IO.File]::ReadAllBytes($SourceFile)))
[IO.File]::WriteAllBytes($Reconstituted, [Convert]::FromBase64String([char[]][IO.File]::ReadAllBytes($B64File)))
As a side note. If the DllAsB64.txt is created by certutil, it will be wrapped by these lines.
-----BEGIN CERTIFICATE-----
-----END CERTIFICATE-----
After removing these lines the PowerShell command above will decode it. Certutil ignores them so it will decode its own output or the PowerShell output.

Related

Powershell Cryptographic Object without file input

i do have a variable which contains a base64 string (a certificate).I want to convert this to an cryptoggraphic object via powershell, like this:
$cert_object = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2(".\tmp.txt")
But i´m unable to create this object without this hack because i did not find a way to directly pipe the string to the crypto object...
$cert.value | Out-File -FilePath ".\tmp.txt"
#This parses the base64 and createa a certificate object
$cert_object = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2(".\tmp.txt")
#Remove the uglyness
Remove-Item -Path ".\tmp.txt"
Does anyone now a solution without touching disk?
Assuming $cert.value contains the Base64 string you could convert it from Base64 and use those bytes to target the X509Certificate2(Byte[]) Constructor:
[System.Security.Cryptography.X509Certificates.X509Certificate2]::new(
[Convert]::FromBase64String($cert.value)
)
As an example using a Cert in My:
$bytes = (Get-ChildItem Cert:\CurrentUser\My | Select-Object -First 1).RawData
$cert = [Convert]::ToBase64String($bytes)
[System.Security.Cryptography.X509Certificates.X509Certificate2]::new(
[Convert]::FromBase64String($cert)
)

PFX encoded and back to PFX in Powershell

Is it possible when you convert a PFX to lets say Base64, to then convert it back to PFX ?
$PFX_FILE = get-content 'dummy.pfx' -Encoding Byte
[Convert]::ToBase64String([Text.Encoding]::UTF8.GetBytes($PFX_FILE)) | Out-File 'dummy.txt'
$BASE64_STR = get-content 'dummy.txt' -Encoding utf8
[Text.Encoding]::Utf8.GetString([Convert]::FromBase64String($BASE64_STR)) | Out-File 'dummy-2.pfx'
The output of line four is unsurprisingly invalid, but I am not sure how to go about it.
I created a PFX cert in location : C:\temp\PowerShellGraphCert.pfx and ran the following. I believe this is what you are looking for.
I converted > PowerShellGraphCert.pfx to PowerShellGraphCert.txt and then back to dummy-3.pfx.
Now PowerShellGraphCert.pfx = dummy-3.pfx
$PFX_FILE = get-content 'C:\temp\PowerShellGraphCert.pfx' -Encoding Byte
$base64 = [System.Convert]::ToBase64String($PFX_FILE) | Out-File 'C:\temp\PowerShellGraphCertbase64.txt'
$BASE64_STR = get-content 'C:\temp\PowerShellGraphCertbase64.txt'
$filename = 'C:\temp\dummy-3.pfx'
$bytes = [Convert]::FromBase64String($BASE64_STR)
[IO.File]::WriteAllBytes($filename, $bytes)

PowerShell to open gzip stream

Web searches for $s=New-Object IO.MemoryStream(,[Convert]::FromBase64String()) show numerous Pastebin's for similar events, but I cannot figure out how to decode it myself. The original base64 I decode with
param(
[Parameter(Mandatory=$True)]
[string]$b64
)
[System.Text.Encoding]::Unicode.GetString([System.Convert]::FromBase64String("$b64"))
which gives me this:
$s=New-Object IO.MemoryStream(,[Convert]::FromBase64String("Encrypted-String"))
IEX (New-Object IO.StreamReader(New-Object IO.Compression.GzipStream($s,[IO.Compression.CompressionMode]::Decompress))).ReadToEnd();
I have been unable to figure out how to use PowerShell to decompress the "Encrypted-String" so I can analyze what's happening.
I've seen similar posts but nothing answers my question of how to decode it myself. Any help is greatly appreciated.
I apologize for the formatting, I am still learning the nuances of posting questions/anwers on here. I also apologize if my question wasn't clear, but after much luck with today's research (been trying to figure this out for the past year).
I found a link (https://blog.kenaro.com/2010/10/19/how-to-embedd-compressed-scripts-in-other-powershell-scripts/) which gave me enough information to build this script. Thank you Ingo Karstein for your blog and all who viewed and asked for clarification.
The gzip stream is part of the results that needed further analysis which I was unable to figure out.
I create a folder in my Temp with the name of the machine that I obtained the suspicious batch file from that calls the encoded powershell command; remove all but the base64 code and rename it to a .txt file. I then run the code below with the computername and the file name to see what the attacker was doing. The answer that works for me:
(
[Parameter(Mandatory=$True)]
[string]$HostIP,
[Parameter(Mandatory=$True)]
[string]$file
)
New-Item C:\Temp\$HostIP\Results -ItemType Directory
$b64 = Get-Content C:\Temp\$HostIP\$file.txt -Raw
Write-Host
$results = [System.Text.Encoding]::Unicode.GetString([System.Convert]::FromBase64String("$b64"))
$results | Out-File C:\Temp\$HostIP\Results\unicode_$file.txt
$ec64 = Get-Content C:\Temp\$HostIP\Results\unicode_$file.txt
$eb64 = $ec64|%{$_.split('"')[1]}
$data = [System.Convert]::FromBase64String("$eb64")
$ms = New-Object IO.MemoryStream
$ms.Write($data, 0, $data.Length)
$ms.Seek(0,0) | Out-Null
$cs = New-Object IO.Compression.GZipStream($ms, [IO.Compression.CompressionMode]::Decompress)
$sr = New-Object IO.StreamReader($cs)
$t = $sr.readtoend()
$t | Out-File C:\Temp\$HostIP\Results\decompressed_$file.txt
$dcb64 = Get-Content C:\Temp\$HostIP\Results\decompressed_$file.txt
$dc64 = $dcb64|%{$_.split('"')[1]}
$utf = [System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String("$dc64"))
$utf | Out-File C:\Temp\$HostIP\Results\utf8_$file.txt
$asc = [System.Text.Encoding]::ASCII.GetString([System.Convert]::FromBase64String("$dc64"))
$asc | Out-File C:\Temp\$HostIP\Results\ascii_$file.txt
$utf8 = "C:\Temp\$HostIP\Results\utf8_$file.txt"
$ascii = "C:\Temp\$HostIP\Results\ascii_$file.txt"
(Get-Content "$utf8") -replace "`0", "" | Set-Content "C:\Temp\$HostIP\Results\utf8_no-null_$file.txt"
(Get-Content "$ascii") -replace "`0", "" | Set-Content "C:\Temp\$HostIP\Results\ascii_no-null_$file.txt"
'

Powershell not sending the right path for a file as argument

I'm trying to apply a hash function to all the files inside a folder as some kind of version control. The idea is to make a testfile that lists the name of the file and the generated checksum. Digging online I found some code that should do the trick (in theory):
$list = Get-ChildItem 'C:\users\public\documents\folder' -Filter *.cab
$sha1 = New-Object System.Security.Cryptography.SHA1CryptoServiceProvider
foreach ($file in $list) {
$return = "" | Select Name, Hash
$returnname = $file.Name
$returnhash = [System.BitConverter]::ToString($sha1.ComputeHash([System.IO.File]::ReadAllBytes($file.Name)))
$return = "$returnname,$returnhash"
Out-File -FilePath .\mylist.txt -Encoding Default -InputObject ($return) -Append
}
When I run it however, I get an error because it tries to read the files from c:\users\me\, the folder where I'm running the script. And the file c:\users\me\aa.cab does not exist and hence can't be reached.
I've tried everything that I could think of, but no luck. I'm using Windows 7 with Powershell 2.0, if that helps in any way.
Try with .FullName instead of just .Name.
$returnhash = [System.BitConverter]::ToString($sha1.ComputeHash([System.IO.File]::ReadAllBytes($file.FullName)))

Read UTF-8 files correctly with PowerShell

Following situation:
A PowerShell script creates a file with UTF-8 encoding
The user may or may not edit the file, possibly losing the BOM, but should keep the encoding as UTF-8, and possibly changing the line separators
The same PowerShell script reads the file, adds some more content and writes it all as UTF-8 back to the same file
This can be iterated many times
With Get-Content and Out-File -Encoding UTF8 I have problems reading it correctly. It's stumbling over the BOM it has written before (putting it in the content, breaking my parsing regex), does not use UTF-8 encoding and even deletes line breaks in the original content part.
I need a function that can read any file with UTF-8 encoding, ignore and delete the BOM and not modify the content. What should I use?
Update
I have added a little test script that shows what I'm trying to do and what happens instead.
# Read data if exists
$data = ""
$startRev = 1;
if (Test-Path test.txt)
{
$data = Get-Content -Path test.txt
if ($data -match "^[0-9-]{10} - r([0-9]+)")
{
$startRev = [int]$matches[1] + 1
}
}
Write-Host Next revision is $startRev
# Define example data to add
$startRev = $startRev + 10
$newMsgs = "2014-04-01 - r" + $startRev + "`r`n`r`n" + `
"Line 1`r`n" + `
"Line 2`r`n`r`n"
# Write new data back
$data = $newMsgs + $data
$data | Out-File test.txt -Encoding UTF8
After running it a few times, new sections should be added to the beginning of the file, the existing content should not be altered in any way (currently loses line breaks) and no additional new lines should be added at the end of the file (seems to happen sometimes).
Instead, the second run gives me an error.
If the file is supposed to be UTF8 why don't you try to read it decoding UTF8 :
Get-Content -Path test.txt -Encoding UTF8
Really JPBlanc is right. If you want it read as UTF8 then specify that when the file is read.
On a side note, you're losing formatting in here with the [String]+[String] stuff. Not to mention your regex match doesn't work. Check out the regex search changes, and the changes made to the $newMsgs, and the way I'm outputting your data to the file.
# Read data if exists
$data = ""
$startRev = 1;
if (Test-Path test.txt)
{
$data = Get-Content -Path test.txt #-Encoding UTF8
if($data -match "\br([0-9]+)\b"){
$startRev = [int]([regex]::Match($data,"\br([0-9]+)\b")).groups[1].value + 1
}
}
Write-Host Next revision is $startRev
# Define example data to add
$startRev = $startRev + 10
$newMsgs = #"
2014-04-01 - r$startRev`r`n`r`n
Line 1`r`n
Line 2`r`n`r`n
"#
# Write new data back
$newmsgs,$data | Out-File test.txt -Encoding UTF8
Get-Content doesn't seem to handle UTF-files without BOM at all (if you omit the Encoding-flag). System.IO.File.ReadLines seems to be an alternative, examples:
PS C:\temp\powershellutf8> $a = Get-Content .\utf8wobom.txt
PS C:\temp\powershellutf8> $b = Get-Content .\utf8wbom.txt
PS C:\temp\powershellutf8> $a2 = Get-Content .\utf8wbom.txt -Encoding UTF8
PS C:\temp\powershellutf8> $a
ABCDEFGHIJKLMNOPQRSTUVWXYZÅÄÖ <== This doesnt seem to be right at all
PS C:\temp\powershellutf8> $b
ABCDEFGHIJKLMNOPQRSTUVWXYZÅÄÖ
PS C:\temp\powershellutf8> $a2
ABCDEFGHIJKLMNOPQRSTUVWXYZÅÄÖ
PS C:\temp\powershellutf8>
PS C:\temp\powershellutf8> $c = [IO.File]::ReadLines('.\utf8wbom.txt');
PS C:\temp\powershellutf8> $c
ABCDEFGHIJKLMNOPQRSTUVWXYZÅÄÖ
PS C:\temp\powershellutf8> $d = [IO.File]::ReadLines('.\utf8wobom.txt');
PS C:\temp\powershellutf8> $d
ABCDEFGHIJKLMNOPQRSTUVWXYZÅÄÖ <== Works!