Compiling a bash script into a binary can simplify deployment and reduce external dependencies. It helps ensure consistent runtime behavior while protecting the source code from casual inspection, which can be important for proprietary or sensitive scripts. Converting a script to a standalone executable allows direct execution on GNU/Linux systems without the need for an interpreter at runtime.

Many distributions include tools for script compilation, with shc being a common choice. This utility leverages the system’s GCC compiler to generate native ELF files. It embeds the script into a C source file, then compiles it just like any other application, providing portability and ease of distribution.

Careful testing is necessary to ensure that environment variables and references to external files remain intact after compilation. The compiled file typically runs on the same GNU or compatible ecosystem as the original script. Although converting a script into a binary complicates reverse engineering, it should not be viewed as a foolproof security measure.

Steps to compile bash script to binary:

  1. Install shc and a C compiler on Ubuntu or Debian.
    $ sudo apt update && sudo apt --assume-yes install gcc shc
    Reading package lists... Done
    Building dependency tree       
    Reading state information... Done
    The following NEW packages will be installed:
      gcc shc
    Need to get 27.8 MB of archives.
    ...

    For other Linux distributions, install shc and a suitable compiler from https://github.com/neurobin/shc, ensuring that gcc or another C compiler is available.

  2. Compile the Bash script into a binary using shc and specify the input file with --filename via -f.
    $ shc -f hello.sh
    $ ls -l hello*
    -rw-rw-r-- 1 user user    29 Mar 14 07:37 hello.sh
    -rwxrwxr-x 1 user user 14960 Mar 14 07:39 hello.sh.x
    -rw-rw-r-- 1 user user 10047 Mar 14 07:39 hello.sh.x.c

    The .sh.x file is the compiled executable and the .sh.x.c file is the obfuscated C source code produced by shc.

  3. Verify that the original script, compiled binary, and obfuscated source file are present.
    $ ls -l hello*
    -rw-rw-r-- 1 user user    29 Mar 14 07:37 hello.sh
    -rwxrwxr-x 1 user user 14960 Mar 14 07:39 hello.sh.x
    -rw-rw-r-- 1 user user 10047 Mar 14 07:39 hello.sh.x.c

    Distribute only the .sh.x binary to limit direct access to the original script.

  4. Determine the file type to confirm that it is a compiled executable.
    $ file hello.sh.x
    hello.sh.x: ELF 64-bit LSB shared object, x86-64, ...

    The output shows an ELF 64-bit file suitable for the Linux architecture used during compilation.

  5. Rename the compiled binary for convenience.
    $ mv hello.sh.x hello
    $ ls -l hello
    -rwxrwxr-x 1 user user 14960 Mar 14 07:39 hello

    Renaming is optional but can simplify usage or distribution.

  6. Ensure the binary is executable.
    $ chmod +x hello
    $ ./hello Bob
    Hello, Bob!

    If execute permissions are not set, use chmod to add them before running the binary.

  7. Check the binary’s runtime dependencies.
    $ ldd hello
        linux-vdso.so.1 (0x00007ffe2feef000)
        libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f3a6784f000)
        /lib64/ld-linux-x86-64.so.2 (0x00007f3a67a89000)

    ldd reveals the libraries required by the compiled binary.

Discuss the article:

Comment anonymously. Login not required.