Encode / Decode .EXE into Base64

62,938

Solution 1

The problem was caused by:

  1. Get-Content without -raw splits the file into an array of lines thus destroying the code
  2. Text.Encoding interprets the binary code as text thus destroying the code
  3. 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.

Share:
62,938
schizoid04
Author by

schizoid04

I'm a software developer.

Updated on July 09, 2022

Comments

  • schizoid04
    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
    schizoid04 about 7 years
    Thanks, this makes sense. I'll try this today and will report back results.
  • schizoid04
    schizoid04 about 7 years
    Just to clarify, may I still use out-File on the $base64String you referenced above, after it's been converted?
  • wOxxOm
    wOxxOm about 7 years
    @schizoid04, yeah, $base64String is plain ASCII text so you can use the standard text-based commands.
  • user208145
    user208145 about 6 years
    Quick 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
    Momoro over 4 years
    I 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
    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
    Momoro over 4 years
    Ohhhh... :) I thought he meant he would, say, put "TvqAAAA==" into the code, then save it :D now I understand what he wants :)
  • JamesQMurphy
    JamesQMurphy almost 4 years
    How is this any different from the accepted answer (by wOxxOm)?
  • bielawski
    bielawski almost 4 years
    People 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
    and... break almost 3 years
    any reason not to use Get-Content -Raw -AsByteStream ?