Encode / Decode .EXE into Base64
Solution 1
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))
Solution 2
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.
Comments
-
schizoid04 almost 2 years
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 )
-
schizoid04 about 7 yearsThanks, this makes sense. I'll try this today and will report back results.
-
schizoid04 about 7 yearsJust to clarify, may I still use out-File on the $base64String you referenced above, after it's been converted?
-
wOxxOm about 7 years@schizoid04, yeah, $base64String is plain ASCII text so you can use the standard text-based commands.
-
user208145 about 6 yearsQuick note if you're trying to use this as a handy one-liner. I was trying to use the relative filename (I was already cd'd to my desktop) but the subcommand
ReadAllBytes(.\file.png)
was expecting "file.png" to be in %userprofile%. -
Momoro over 4 yearsI know I'm biased, using C#, but shouldn't this NOT WORK? I thought loading, converting, then saving it as
exe
again would break it...? Or is this some other method? -
wOxxOm over 4 years@Momoro an exe is just a file, not some magical thing, so naturally the answer works as
Convert
API is lossless when used with ReadAllBytes + WriteAllBytes that read/write the data as is without altering it. -
Momoro over 4 yearsOhhhh... :) I thought he meant he would, say, put "TvqAAAA==" into the code, then save it :D now I understand what he wants :)
-
JamesQMurphy almost 4 yearsHow is this any different from the accepted answer (by wOxxOm)?
-
bielawski almost 4 yearsPeople will be drawn by the question title rather than OP's problem. wOxxOm's answer helps the OP but doesn't present a complete working solution that one, coming here due to the title, could simply grab and run with. One could argue that the CertUtil answer doesn't even belong here but it's a good answer to the title question despite ignoring the underlying problem the OP had. I wanted a PowerShell based answer that was as clear and succinct as the certutil answer for those uninterested in the details of the problem in the OP's code.
-
and... break almost 3 yearsany reason not to use
Get-Content -Raw -AsByteStream
?