Compiling programs makes sense for several good reasons. For example, you gain speed when running them. Additionally, compilers ideally generate small, portable programs that largely run independently of the computer on which they're created. Furthermore, this method protects the inherent algorithms from unintended changes.
The first two reasons – the gain in speed and portability – are not a focus of the Shell Script Compiler SHC [1]. The programs translated by SHC still require Bash as interpreter, so no great speed is gained. However, this point should not play a major role, because shell scripts aren't used for time-critical applications anyway.
Nevertheless, translating the source into binary code protects it from the ambitions of those users who want to make something good even better – while completely wrecking it. Currently, SHC is the most popular free tool for translating (Bash) shell scripts into fully functioning programs.
The operation of SHC provides some special features based on these reasons. Compilation occurs in two steps. SHC first generates from the script a fairly extensive, highly specialized C source code, then translates it into a binary program with help from the C compiler (see Figure 1).
In the first step, SHC generates a file with the .x.c extension, which it then translates into a file with the .x ending using the $CC C compiler environmental variable.
Converting the script source into C code done by using an array to capture all the script content. During compilation, SHC makes stepwise access to the (encrypted) elements of the array and integrates these entries into the executable program.
Details of the array and conversion to the binary program are comprehensively described in a blog [2]. The blog also covers the topic of password security in scripts. The author also describes ways to re-decrypt the programs created by SHC later on.
Installing SHC is easy in Ubuntu and its variants because there are PPAs with more or less recent versions.
With Arch Linux, you have two obstacles to overcome. The current versions are in the Arch User Repository (AUR), but with the wrong checksum in the PKGBUILD file (Listing 1).
Listing 1
Calculate Correct Checksum
source=("http://www.datsi.fi.upm.es/~frosal/sources/${pkgname}-${pkgver}.tgz") sha256sums=(,\textbf{ef7bbf1252c9c791f711782870d00d6f19c42c08e0ee57e9a04d0e2b3d114d40}')
You can calculate the correct checksum by using the sha256sums tool and adding the corresponding query (Listing 2). The script opens an editor so that you can make the required change.
Listing 2
Add Corresponding Entry
... ( Unsupported package: Potentially dangerous ! ) ==> Edit PKGBUILD ? [Y/n] ("A" to abort) ==> ------------------------------------ \textbf{Y}...
The SHC package also includes a series of test scripts (pru.sh , test.bash ) that the package manager with Arch Linux doesn't include by default, even though the original archive does. These test scripts check that SHC functions properly, so you should generally use them to check the results.
Alternatively, you can generate SHC directly from the sources and install it. After unpacking the archive, a simple make is enough; make install installs the program in /usr/local/ . The target make test no longer works in version 3.8.9, so use shc -f test.bash instead.
For a first test, use the classic "Hello World," although echo "Hello SHC " returns an alternative text. If the first script line doesn't contain #! /bin/sh , using the
shc -f hello.sh
command returns the message shc: invalid first line in script:… . Translation works with the shebang, and the -v option adds commenting (Listing 3).
Listing 3
Test with "Hello World"
# shc -v -f hello.sh shc shll=bash shc [-i]=-c shc [-x]=exec ,%s' "$@" shc [-l]= shc opts= shc: cc hello.sh.x.c -o hello.sh.x shc: strip hello.sh.x shc: chmod go-r hello.sh.x
The hello.sh.x.c source code thus generated is comparatively large at 9KB and largely incomprehensible at first, but it deals in large part with encrypting the script.
The executable program is not exactly small at 11KB and creates some problems on various platforms. Programs generated in Arch Linux and Ubuntu run on Arch Linux only when created with the -T option. This option actually allows observation of the program with external diagnostic tools such as Strace. Both systems run with no problem on Ubuntu.
Shell scripts have a few special properties that the compiler needs to understand and implement. This allows Bash to pass the script arguments that are position parameters inside the script. SHC can clearly understand them, even if you use set to reassign them.
The next important items that the compiler needs to check in shell scripts include return values ("exit codes") derived from internal and external commands.
With Bash, the $? variable contains this value for the last executed command in the foreground, and you read it with the echo $? prompt. SHC also supports this.
Particularly in shell scripts, return values occur in the context of linked commands. Bash provides some comfort with short-circuit tests: The double ampersand (&& ) connects two commands, where the shell executes the second one only if the first one terminates without an error (exit code 0 ).
Alternatively, you can use the double pipe (|| ). In this case, the shell executes the second command only if the first one terminates with an error (exit code not equal to 0 ). Short-circuit tests are easily combined with SHC (Listing 4).
Listing 4
Short-Circuit Test
$ true && echo "OK" # OK $ false && echo "OK" # no output $ true || echo "OK" # no output $ false || echo "OK" # OK $ true || echo "no" && echo "yes" # yes $ true && echo "yes" || echo "no" # yes
Another, sometimes touchy, subject involves inputs and outputs. Without additional software, the shell provides very limited options; however, these options always work. If you ask for input using Zenity or its new variant YAD, SHC does not get out of step:
INPUT=$(yad --entry "input" --editable); yad --entry $INPUT
Here, the INPUT environment variable first gets its value through a YAD query. The input dialog is preset with the string input , which you can change because of the --editable option. The second call to YAD then shows the current content of the $INPUT variable.
When using external programs, most important to note is that SHC binds them into the binary program but calls them as in the script. This step assumes that the external programs are in the same path. The same goes for the calling Bash. Alternatively, SHC accepts absolute paths when running the compiled script.
You control SHC mainly with options, the most important of which are shown in Table 1. Moreover, SHC evaluates two environment variables. $CC contains the C compiler used – default cc . The second variable in this context is $CFLAGS , which contains the compiler options.
Table 1
SHC Options
-e <date>
|
@#:Limits the time the program can be executed up to the given date, after which a warning appears. The compiler expects the date in the form <DD>/<MM>/<YYYY> . |
-m <message>
|
Message that appears after the -e time limit expires. |
-f <script>
|
Absolutely necessary, indicates the script name. |
-i <shell-options>
|
Special Bash options. |
-x <command>
|
The binary program starts the script with exec , by default followed by $@ (all command options and arguments). |
-l <option>
|
Defines the last command line option, normally – (the default). |
-r
|
Loosens the security settings during compilation, so that binaries can run on other computers with the same operating system. Currently mandatory for Arch Linux. |
-D
|
Enables debug mode of the binary program, which can generate a lot of additional information. |
-T
|
Creates a program traceable by Strace or similar tool. |
-A
|
Shows a short info and quits SHC without compiling the script. |
Several programs can help conceal the content of shell scripts. A search on Duckduckgo for shell script encrypt or shell script obfuscate returns some alternatives – often partly implemented as shell scripts – that convert code in one way or another. Among them are Obfsh [4] and Shellcrypt [5].
Although the former renders the source code unreadable by inserting or removing spaces and rows and other trash, Shellcrypt goes one step further. The program creates an truly encrypted program with the .bin extension that runs again only after re-decryption. The program used for it also acts as an interpreter (Figure 2).
The disadvantage of this approach is that the program also needs an installed Shellcrypt on the target system. In a similar way, you could use GPG encrypted scripts that you encrypt symmetrically with the -c option and re-decrypt with -d .
SHC is ranked somewhere between a toy and a useful tool. In no way can you count on the binaries created by the compiler to be truly encrypted. For one thing, they work only as long as the external programs required by the script are available. For another, they can read the original sources only with some difficulty.
On the positive side are the ease of use and the ability to prevent scripts from being modified. The alternatives to SHC have their own specific requirements or offer less portability. l
Infos