10

是否可以编写一个 bash 脚本,其中包含一个二进制可执行程序?

我的意思是一个脚本,它将包含一个文本形式的可执行文件的转储,当它被执行时,它将被这个脚本转储回一个可执行文件?

我很想知道一个解决方案,它可以开箱即用,无需安装额外的软件包。可能吗?

谢谢!

4

7 回答 7

9

我以前从未做过这样的事情;)这将编译一些c源代码,创建一个b.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

调用(a.bash 生成 b.bash):

bash a.bash ;bash b.bash

我不知道如何避免在执行之前将二进制文件写入临时文件...

于 2013-08-23T20:02:22.250 回答
5

不要像其他几个答案所暗示的那样重新发明轮子,只需使用古老的shar命令,它正是通过设计来做到这一点的。

假设您要嵌入脚本的文件是binaryfile,只需运行

$ shar binaryfile > binaryfile.shar

你已经准备好了。您有一个名为的 shell 脚本binaryfile.shar,执行时将提取binaryfile.

于 2013-08-24T00:09:53.880 回答
4

我试过了,它有效。使用 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
于 2013-08-23T20:34:35.727 回答
1

您可以将二进制文件转换为文本,然后使用 uuencode/uudecode 转换回二进制文件。

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

因此,您可以将二进制数据作为文本存储在脚本中并将其输出到二进制文件。

uuencode binaryFile > output.txt

然后将该数据放入您的脚本中,并在创建二进制文件时使用 uudecode。

于 2013-08-23T19:57:55.380 回答
1

所以,如果我做对了,你想在脚本中包含一个二进制文件并在脚本退出时执行它?

这是一个binarymaker脚本(这不仅会创建一个提取二进制文件的脚本,还会将您的任何脚本与任何二进制文件合并):

#!/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

你应该像这样运行它

./binarymaker myscript mybinary resultscript

如果你运行,resultscript那么两者myscriptmybinary将被执行。之后,您可以选择将命令添加到rm二进制文件中。

另外,不要忘记在脚本结束时退出,否则它将继续并尝试解析二进制数据。

如果您正在使用另一个脚本而不是二进制文件,则可以像这样从管道执行它:

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

但它不适用于真正的二进制文件。此外,如果您的 bash 版本低于 4,它也不起作用

于 2013-08-23T20:49:23.883 回答
1

我不得不制作一个安装程序脚本来将它部署在一台甚至没有 tar 的机器上,并且我结束了嵌入busybox(用于 tar 和 gunzip)和 tarball 以部署在一个 shell 脚本上。我以 dd 方式做到了

#!/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"
于 2019-01-21T07:38:31.103 回答
-2

是的!

例如,您可以将任何二进制文件转储到文件中:

echo $binary > file

有许多安装脚本可以做这样的事情。

于 2013-08-23T19:53:21.487 回答