2

I want to create a windows batch script, which will have a base64 encoded program included. By included I mean - the encoded program will be "hardcoded" - there should be a "function" (or a code block) which will write the file line by line.

(like in this question related to Linux Bash: Bash script containing binary executable)

I want to ask you what is the best method to do something like this, when it should apply to the following points:

  • I want to use only the tools bundled with Windows (no additional libraries, executables etc)
  • The file should be single - It can simply include the base64 encoded string in any way
  • I want t get the highet spossible performance

I've tried to convert each base64 encoded line to an echo call, but this is very slow. Echoing 6000 lines takes about 10 seconds (I want to generate a file whcih will have about 10 000 lines with this method).

Is there a better method to do this? Maybe there is a "file splitter" in windows, which will allow me to split this batch script and "extract" somehow some lines (like extract lines 100-10100) and save them to another file?

A part of currently used file generation is as follows:

:getbin_Windows_x86
[...]
echo f0VMRgIBAQAAAAAAAAAAAAIAPgABAAAAsCVAAAAAAABAAAAAAAAAAEiGBQAAAAAAAAAAAEAAOAAK>>%INSTALLER_BASE_TMP%
echo AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA>>%INSTALLER_BASE_TMP%
echo AAAMAAAAAAAAAFAAAAAAAAAAAAAAADAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA>>%INSTALLER_BASE_TMP%
[...]
GOTO:EOF

I would love to do it using batch files, but if Power Shell will give me some better result, I'll move over it.

Community
  • 1
  • 1
Wojciech Danilo
  • 11,573
  • 17
  • 66
  • 132

3 Answers3

3

Converting a binary file into Base64 is easy enough, as .Net contains the handy Convert class. Like so,

# Set up paths
$binSrcPath = "C:\Program Files (x86)\Notepad++\notepad++.exe"
$b64DstPath = "C:\temp\notepad++.exe.b64"

# Read the source binary as byte array
$binData = Get-Content -Path $binSrcPath -Encoding Byte

# Convert the bytes into a base64 encoded form
$base64 = [System.Convert]::ToBase64String($binData)

# Save the encoded data
set-content $b64DstPath $base64

Now that the encoded binary is saved, let's convert it again to binary. Like so,

# Paths first
$b64DstPath = "C:\temp\notepad++.exe.b64"
$binDstPath = "C:\temp\notepad++.exe"

# Read the encoded data
$dataToBase64 = get-content $b64DstPath

# Decode the base64 encoding
$decodedData =  [System.Convert]::FromBase64String($base64)

# Save the decoded data as a byte, not text
set-content -Path $binDstPath -Value $decodedData -Encoding Byte

Comparing the files with cmd's fc.exe shows not a thing has changed:

C:\>fc /b "C:\Program Files (x86)\Notepad++\notepad++.exe" "C:\temp\notepad++.exe"
Comparing files C:\PROGRAM FILES (X86)\NOTEPAD++\notepad++.exe and C:\TEMP\NOTEPAD++.EXE
FC: no differences encountered

In order to embed a base64 string in your Powershell script, I'd advise you to save the data in different a file. This is as base64 data will take quite some space and makes the script file itself a bit unwieldy. Embedding is rather straight-forward, like so:

# Declare a function that contains a bases64 string
function getB64Data {
    return "TVqAA..."
}

$binDstPath = "C:\temp\notepad++.exe"
# Read the base64 string into a variable
$dataToBase64 = getB64Data

# Decode the base64 encoding
$decodedData =  [System.Convert]::FromBase64String($base64)

# Save the decoded data as a byte, not text
set-content -Path $binDstPath -Value $decodedData -Encoding Byte
vonPryz
  • 22,996
  • 7
  • 54
  • 65
  • +1 for the firt part, for the usage of the base 64 string I would have assign a var into a .PS1 file and . source this file. – JPBlanc Aug 24 '13 at 11:30
  • Ok thank you, but how would you do that without using powershell (to support Windows xp default installation also) using only one file? Converting to base64 is also straghtforward using `certutil`. The problem occurs while embeding this encoded data. It REALLY has to be in the same file. – Wojciech Danilo Aug 24 '13 at 11:52
1

There's a new batch file tool here that uses Jscript scripting built into Windows for speed (compared to a batch file), and written by Aacini: http://www.dostips.com/forum/viewtopic.php?f=3&t=4842

This tool creates a single batch file with the binary/multiple files inside and provides the user a way to restore them.

foxidrive
  • 40,353
  • 10
  • 53
  • 68
0

If JScript is not an option, a "for" loop in a batch file can do the trick:

for /f "delims=] tokens=1" %%s in ('find /i /n "BASE64ENCODED" %~dpnx0') do set skip=%%s
for /f "skip=%skip:~1% tokens=*" %%l in (%~dpnx0) do echo %%l>>targetfile.exe
Goto :EOF

BASE64ENCODED
'put your encoded stuff here...

Unfortunately, this will not solve your performance issue... And to dynamically get the number of lines to skip, it reads the whole file twice.

Martin Binder
  • 1,066
  • 7
  • 5