A Bash script executes within an interpreted environment, relying on the Bash shell to translate commands into actions at runtime. Converting it into a binary encapsulates the logic, reduces direct script exposure, and removes the strict dependency on the Bash interpreter. This approach can simplify distribution and produce a more self-contained artifact.

Tools like shc handle this conversion by wrapping the original script in obfuscated C code before compilation. The resulting output is not pure machine code, but it is notably harder to inspect or modify than a plain text script. This layer of complexity hinders casual attempts to access the script’s contents, providing a basic level of obfuscation.

While the compiled ELF binary still depends on the underlying Linux environment and its libraries, it serves as a practical deterrent against casual script examination. The process should not be considered a robust security measure, but it can effectively discourage quick reverse-engineering attempts. Balancing convenience, security, and maintainability remains essential when adopting such techniques.

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.