Bash script containing binary executable

2020-02-11 03:59发布

问题:

Is it possible to write a bash script, which would contain a binary executable program inside?

I mean a script, which would contain a dump of an executable in a textual form, which will be dumped back to an executable by this script when it is executed?

I would love to know a solution, which will work out of the box without a need of installing additional packages. Is it possible?

Thanks!

回答1:

i never done something like this before ;) this will compile some c source, create a b.bash script containing the binary (and the original script for simple development)

(a.bash)

#!/bin/bash

if [ "$0" == "b.bash" ];then
  tail -n +$[ `grep -n '^BINARY' $0|cut -d ':' -f 1` + 1 ] $0 | base64 -d > a2.out
  chmod +x a2.out
  ./a2.out
  echo $?
  exit
fi

cat "$0" > b.bash
echo "BINARY" >> b.bash
cat > a.c << EOF
int     main(){
        return 12;
}
EOF
gcc a.c 
base64 a.out >> b.bash

invoke with (a.bash generates b.bash):

bash a.bash ;bash b.bash

i don't know how to evade writing out the binary into a temporary file before execution...



回答2:

I tried this out and it works. Hex was generated with xxd.

#!/bin/bash

xxd -r >foo <<'EndHere'
0000000: 7f45 4c46 0201 0100 0000 0000 0000 0000  .ELF............
0000010: 0200 3e00 0100 0000 e003 4000 0000 0000  ..>.......@.....
0000020: 4000 0000 0000 0000 000a 0000 0000 0000  @...............
0000030: 0000 0000 4000 3800 0800 4000 1e00 1b00  ....@.8...@.....
0000040: 0600 0000 0500 0000 4000 0000 0000 0000  ........@.......
0000050: 4000 4000 0000 0000 4000 4000 0000 0000  @.@.....@.@.....
...
0001960: 6400 5f65 6461 7461 006d 6169 6e00 5f69  d._edata.main._i
0001970: 6e69 7400                                nit.
EndHere
chmod +x foo
./foo


回答3:

Don't reinvent the wheel like several other answers are suggesting, just use the venerable shar command which is precisely doing this by design.

Assuming the file you want to embed in your script is binaryfile, simply run

$ shar binaryfile > binaryfile.shar

and you are set. You have a shell script named binaryfile.shar which when executed will extract binaryfile.



回答4:

You can convert your binary to text, and then back to binary using uuencode/uudecode.

http://linux.die.net/man/1/uuencode

So you can store your binary data as text in your script and output it to a binary file.

uuencode binaryFile > output.txt

And then put that data into your script and when creating the binary file use uudecode.



回答5:

So, if I got it right you want to include a binary in your script and execute it on script exit?

Here is a binarymaker script(This does not only create a script that extracts a binary, but merges any your script with any binary):

#!/bin/bash

lineCount=$(wc -l "$1" | cut -f 1 -d ' ') # just get the line count
((lineCount+=2)) # because we are going to append a line

head -n 1 "$1" > "$3" # this is done to ensure that shebang is preserved
echo "trap 'tail -n +$lineCount \$0 > binary; chmod +x binary; ./binary' EXIT" >> "$3"
tail -n +2 "$1" >> "$3"
cat "$2" >> "$3"

exit 0

You should run it like this

./binarymaker myscript mybinary resultscript

If you run resultscript then both myscript and mybinary are going to be executed. You can optionally add a command to rm the binary afterwards.

Also, do not forget to exit at the end of your script because otherwise it will continue and try to parse binary data.

If you're working with another script and not a binary, then it can be executed from pipe like this:

tail -n +$lineCount \$0 | source /dev/stdin

But it is not going to work on real binaries. Also, it doesn't work if your bash version is under 4



回答6:

I had to make a installer script to deploy it on a machine that did not even have tar, and I ended embedding busybox (for tar and gunzip) and the tarball to deploy on a shell script. I did it the dd way:

#!/usr/bin/env bash

get_length()
{
    ls -l "$1" | cut -f5 -d' '
}

# First parameter is the number of semicolons to add to second parameter
# NOTE: we do not use an "add_blanks" function directly because it seems bash
# removes duplicated blanks. The workaround is adding other character and
# replacing later using e.g. sed.
add_semicolons()
{
    scratch="$2"
    for n in $(seq 1 $1)
    do
        scratch+=";"
    done
    echo $scratch
}

# Default values
output="installer"
input="deployable.tar.gz"
shell="busybox"

shell_len=$(get_length "$shell")
payload_len=$(get_length "$input")

# START OF INSTALLATION SCRIPT GENERATION.
#
# Note: generated scripts reserves 9 digits for the skip (ibs) offsets.
# When the script is first written, these digits are written as semicolons.
# Later when the lengths are computed, these semicolons are replaced by the
# correct numbers, but the 9-digit length must be preserved by adding blanks
# until 9 digits are filled. Failure to do this will cause the script length
# to vary and offsets would need to be iteratively computed.

# Add shebang
echo "#!/usr/bin/env ash" > "$output"

echo "echo Extracting installer..." >> "$output"
# Add lines to extract binary data and extract payload
echo "mkdir -p /tmp/installer" >> "$output"
echo "dd if=\"$(basename $output)\" ibs=;;;;;;;;; skip=1 | dd ibs=$shell_len count=1 of=/tmp/installer/shell 2>/dev/null" >> "$output"
echo "chmod +x /tmp/installer/shell" >> "$output";
echo "dd if=\"$(basename $output)\" ibs=;;;;;;;;; skip=1 2>/dev/null of=/tmp/installer/payload.tar.gz 2>/dev/null" >> "$output"
# From here on, the binary extraction is completed, do something with extracted files...
# [...]
# Use exit command to avoid the shell script parsing to reach the binary part
echo "echo Done!" >> "$output"
echo "exit 0" >> "$output"

# We reserved 9 blanks for the ibs offsets. Thus fill offsets with blanks up to 9 chars total
script_len=$(get_length "$output")
skip_len=$((script_len + shell_len))

to_add=$((9 - ${#script_len}))
script_len_str=$(add_semicolons $to_add $script_len)
to_add=$((9 - ${#skip_len}))
skip_len_str=$(add_semicolons $to_add $skip_len)

# Add skip values
sed -i "4s/ibs=;;;;;;;;;/ibs=$script_len_str/" "$output"
sed -i "4s/;/ /g" "$output"
sed -i "6s/ibs=;;;;;;;;;/ibs=$skip_len_str/" "$output"
sed -i "6s/;/ /g" "$output"

cat "$shell" >> "$output"
cat "$input" >> "$output"
chmod +x "$output"


回答7:

Sure it is!

You can for example dump any binary into a file with:

echo $binary > file

There are many installation scripts which do things like that.