-
Notifications
You must be signed in to change notification settings - Fork 6
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit 1971d59
Showing
6 changed files
with
486 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
build/ | ||
releases/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
# | ||
# Makefile | ||
# Andres J. Diaz, 2016-10-18 08:57 | ||
# | ||
|
||
all: | ||
@./scripts/build.sh && rm -f ./releases/bash | ||
|
||
clean: | ||
rm -rf build/* releases/* | ||
# vim:ft=make | ||
# |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,74 @@ | ||
▄▄▄▄▄▄▄▄▄▄ ▄▄▄▄▄▄▄▄▄▄▄ ▄▄▄▄▄▄▄▄▄▄▄ ▄ ▄ ▄▄▄▄▄▄▄▄▄▄▄ | ||
▐░░░░░░░░░░▌ ▐░░░░░░░░░░░▌▐░░░░░░░░░░░▌▐░▌ ▐░▌▐░░░░░░░░░░░▌ | ||
▐░█▀▀▀▀▀▀▀█░▌▐░█▀▀▀▀▀▀▀█░▌▐░█▀▀▀▀▀▀▀▀▀ ▐░▌ ▐░▌▐░█▀▀▀▀▀▀▀▀▀ | ||
▐░▌ ▐░▌▐░▌ ▐░▌▐░▌ ▐░▌ ▐░▌▐░▌ | ||
▐░█▄▄▄▄▄▄▄█░▌▐░█▄▄▄▄▄▄▄█░▌▐░█▄▄▄▄▄▄▄▄▄ ▐░█▄▄▄▄▄▄▄█░▌▐░▌ | ||
▐░░░░░░░░░░▌ ▐░░░░░░░░░░░▌▐░░░░░░░░░░░▌▐░░░░░░░░░░░▌▐░▌ | ||
▐░█▀▀▀▀▀▀▀█░▌▐░█▀▀▀▀▀▀▀█░▌ ▀▀▀▀▀▀▀▀▀█░▌▐░█▀▀▀▀▀▀▀█░▌▐░▌ | ||
▐░▌ ▐░▌▐░▌ ▐░▌ ▐░▌▐░▌ ▐░▌▐░▌ | ||
▐░█▄▄▄▄▄▄▄█░▌▐░▌ ▐░▌ ▄▄▄▄▄▄▄▄▄█░▌▐░▌ ▐░▌▐░█▄▄▄▄▄▄▄▄▄ | ||
▐░░░░░░░░░░▌ ▐░▌ ▐░▌▐░░░░░░░░░░░▌▐░▌ ▐░▌▐░░░░░░░░░░░▌ | ||
▀▀▀▀▀▀▀▀▀▀ ▀ ▀ ▀▀▀▀▀▀▀▀▀▀▀ ▀ ▀ ▀▀▀▀▀▀▀▀▀▀▀ | ||
|
||
|
||
BashC is a tool which get your bash script and produces an static linked | ||
binary for Linux x86 and x86_64 machines (also support ARM and many other | ||
OS, but I cannot test them yet) which runs your script. | ||
|
||
For example: | ||
|
||
$ cat > myscript.sh << EOF | ||
#!/bin/bash | ||
echo "This is a test | ||
EOF | ||
|
||
$ bashc myscript.sh myscript.bin | ||
$ file myscript.bin | ||
bashc: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), statically | ||
linked, stripped | ||
$ ./myscript.bin | ||
This is a test | ||
|
||
Nice eh! | ||
|
||
|
||
---- Installation -------------------------------------------------------- | ||
|
||
From source code just run: | ||
|
||
make | ||
|
||
Easy :) | ||
|
||
---- Internals ---------------------------------------------------------- | ||
|
||
This application is based on previous work from Robert Xu¹, which uses musl | ||
instead of glibc avoiding calls to dlopen(3) to produce a static binary. | ||
|
||
I added some patches (in patch/ directory) to convert the bash binary in | ||
a compiler tool. The patch does the following: | ||
|
||
1. Read he filesize of itself and jump (lseek) to the last byte of the | ||
binary. | ||
2. There read -20 chars as decimal number which represents the length of the | ||
script to be executed | ||
3. Jump again (lseek) to END - length readed in (2) | ||
4. Bash interpret the code in current fd position. | ||
|
||
That is how bashc runs a script. To create the binary just concatenate to the | ||
static patched bash, the script to run. Because of ELF header (and in theory | ||
also Match) ensure us that execution will never reads after lenght scecified | ||
in ELF header, then our script still safe after that position. During the | ||
execution the algorithm explained above is running and the script is | ||
interpreted. | ||
|
||
|
||
¹ https://github.com/robxu9/bash-static | ||
|
||
---- Limitations -------------------------------------------------------- | ||
|
||
* Not tested in any other platform than Linux X86 and X86_64. | ||
* The bash script code is concatenated in plain text, so no security here. | ||
* We cannot use any external dependency for the script unless it was | ||
previously compiled as builtin. | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,302 @@ | ||
--- shell.orig.c 2016-06-08 19:42:37.010736398 +0200 | ||
+++ shell.c 2016-06-08 21:12:42.051558743 +0200 | ||
@@ -366,6 +366,7 @@ | ||
#endif | ||
volatile int locally_skip_execution; | ||
volatile int arg_index, top_level_arg_index; | ||
+ char buf[21]; | ||
#ifdef __OPENNT | ||
char **env; | ||
|
||
@@ -456,59 +457,11 @@ | ||
set_shell_name (argv[0]); | ||
shell_start_time = NOW; /* NOW now defined in general.h */ | ||
|
||
- /* Parse argument flags from the input line. */ | ||
- | ||
- /* Find full word arguments first. */ | ||
- arg_index = parse_long_options (argv, arg_index, argc); | ||
- | ||
- if (want_initial_help) | ||
- { | ||
- show_shell_usage (stdout, 1); | ||
- exit (EXECUTION_SUCCESS); | ||
- } | ||
- | ||
- if (do_version) | ||
- { | ||
- show_shell_version (1); | ||
- exit (EXECUTION_SUCCESS); | ||
- } | ||
- | ||
- /* All done with full word options; do standard shell option parsing.*/ | ||
- this_command_name = shell_name; /* for error reporting */ | ||
- arg_index = parse_shell_options (argv, arg_index, argc); | ||
- | ||
- /* If user supplied the "--login" (or -l) flag, then set and invert | ||
- LOGIN_SHELL. */ | ||
- if (make_login_shell) | ||
- { | ||
- login_shell++; | ||
- login_shell = -login_shell; | ||
- } | ||
- | ||
set_login_shell ("login_shell", login_shell != 0); | ||
|
||
- if (dump_po_strings) | ||
- dump_translatable_strings = 1; | ||
- | ||
- if (dump_translatable_strings) | ||
- read_but_dont_execute = 1; | ||
- | ||
if (running_setuid && privileged_mode == 0) | ||
disable_priv_mode (); | ||
|
||
- /* Need to get the argument to a -c option processed in the | ||
- above loop. The next arg is a command to execute, and the | ||
- following args are $0...$n respectively. */ | ||
- if (want_pending_command) | ||
- { | ||
- command_execution_string = argv[arg_index]; | ||
- if (command_execution_string == 0) | ||
- { | ||
- report_error (_("%s: option requires an argument"), "-c"); | ||
- exit (EX_BADUSAGE); | ||
- } | ||
- arg_index++; | ||
- } | ||
this_command_name = (char *)NULL; | ||
|
||
cmd_init(); /* initialize the command object caches */ | ||
@@ -521,7 +474,7 @@ | ||
standard input is a terminal | ||
standard error is a terminal | ||
Refer to Posix.2, the description of the `sh' utility. */ | ||
- | ||
+#if 0 | ||
if (forced_interactive || /* -i flag */ | ||
(!command_execution_string && /* No -c command and ... */ | ||
wordexp_only == 0 && /* No --wordexp and ... */ | ||
@@ -532,33 +485,8 @@ | ||
init_interactive (); | ||
else | ||
init_noninteractive (); | ||
- | ||
- /* | ||
- * Some systems have the bad habit of starting login shells with lots of open | ||
- * file descriptors. For instance, most systems that have picked up the | ||
- * pre-4.0 Sun YP code leave a file descriptor open each time you call one | ||
- * of the getpw* functions, and it's set to be open across execs. That | ||
- * means one for login, one for xterm, one for shelltool, etc. There are | ||
- * also systems that open persistent FDs to other agents or files as part | ||
- * of process startup; these need to be set to be close-on-exec. | ||
- */ | ||
- if (login_shell && interactive_shell) | ||
- { | ||
- for (i = 3; i < 20; i++) | ||
- SET_CLOSE_ON_EXEC (i); | ||
- } | ||
- | ||
- /* If we're in a strict Posix.2 mode, turn on interactive comments, | ||
- alias expansion in non-interactive shells, and other Posix.2 things. */ | ||
- if (posixly_correct) | ||
- { | ||
- bind_variable ("POSIXLY_CORRECT", "y", 0); | ||
- sv_strict_posix ("POSIXLY_CORRECT"); | ||
- } | ||
- | ||
- /* Now we run the shopt_alist and process the options. */ | ||
- if (shopt_alist) | ||
- run_shopt_alist (); | ||
+#endif | ||
+ init_noninteractive(); | ||
|
||
/* From here on in, the shell must be a normal functioning shell. | ||
Variables from the environment are expected to be set, etc. */ | ||
@@ -567,30 +495,6 @@ | ||
set_default_lang (); | ||
set_default_locale_vars (); | ||
|
||
- /* | ||
- * M-x term -> TERM=eterm EMACS=22.1 (term:0.96) (eterm) | ||
- * M-x shell -> TERM=dumb EMACS=t (no line editing) | ||
- * M-x terminal -> TERM=emacs-em7955 EMACS= (line editing) | ||
- */ | ||
- if (interactive_shell) | ||
- { | ||
- char *term, *emacs; | ||
- | ||
- term = get_string_value ("TERM"); | ||
- emacs = get_string_value ("EMACS"); | ||
- | ||
- /* Not sure any emacs terminal emulator sets TERM=emacs any more */ | ||
- no_line_editing |= term && (STREQ (term, "emacs")); | ||
- no_line_editing |= emacs && emacs[0] == 't' && emacs[1] == '\0' && STREQ (term, "dumb"); | ||
- | ||
- /* running_under_emacs == 2 for `eterm' */ | ||
- running_under_emacs = (emacs != 0) || (term && STREQN (term, "emacs", 5)); | ||
- running_under_emacs += term && STREQN (term, "eterm", 5) && emacs && strstr (emacs, "term"); | ||
- | ||
- if (running_under_emacs) | ||
- gnu_error_format = 1; | ||
- } | ||
- | ||
top_level_arg_index = arg_index; | ||
old_errexit_flag = exit_immediately_on_error; | ||
|
||
@@ -648,21 +552,15 @@ | ||
#endif | ||
|
||
/* The startup files are run with `set -e' temporarily disabled. */ | ||
- if (locally_skip_execution == 0 && running_setuid == 0) | ||
+ /*if (locally_skip_execution == 0 && running_setuid == 0) | ||
{ | ||
old_errexit_flag = exit_immediately_on_error; | ||
exit_immediately_on_error = 0; | ||
|
||
run_startup_files (); | ||
exit_immediately_on_error += old_errexit_flag; | ||
- } | ||
+ }*/ | ||
|
||
- /* If we are invoked as `sh', turn on Posix mode. */ | ||
- if (act_like_sh) | ||
- { | ||
- bind_variable ("POSIXLY_CORRECT", "y", 0); | ||
- sv_strict_posix ("POSIXLY_CORRECT"); | ||
- } | ||
|
||
#if defined (RESTRICTED_SHELL) | ||
/* Turn on the restrictions after executing the startup files. This | ||
@@ -682,69 +580,13 @@ | ||
} | ||
#endif | ||
|
||
- if (command_execution_string) | ||
- { | ||
- arg_index = bind_args (argv, arg_index, argc, 0); | ||
- startup_state = 2; | ||
- | ||
- if (debugging_mode) | ||
- start_debugger (); | ||
- | ||
-#if defined (ONESHOT) | ||
- executing = 1; | ||
- run_one_command (command_execution_string); | ||
- exit_shell (last_command_exit_value); | ||
-#else /* ONESHOT */ | ||
- with_input_from_string (command_execution_string, "-c"); | ||
- goto read_and_execute; | ||
-#endif /* !ONESHOT */ | ||
- } | ||
- | ||
/* Get possible input filename and set up default_buffered_input or | ||
default_input as appropriate. */ | ||
- if (arg_index != argc && read_from_stdin == 0) | ||
- { | ||
- open_shell_script (argv[arg_index]); | ||
- arg_index++; | ||
- } | ||
- else if (interactive == 0) | ||
- /* In this mode, bash is reading a script from stdin, which is a | ||
- pipe or redirected file. */ | ||
-#if defined (BUFFERED_INPUT) | ||
- default_buffered_input = fileno (stdin); /* == 0 */ | ||
-#else | ||
- setbuf (default_input, (char *)NULL); | ||
-#endif /* !BUFFERED_INPUT */ | ||
- | ||
+ open_shell_script (argv[0]); | ||
set_bash_input (); | ||
|
||
/* Bind remaining args to $1 ... $n */ | ||
- arg_index = bind_args (argv, arg_index, argc, 1); | ||
- | ||
- if (debugging_mode && locally_skip_execution == 0 && running_setuid == 0 && dollar_vars[1]) | ||
- start_debugger (); | ||
- | ||
- /* Do the things that should be done only for interactive shells. */ | ||
- if (interactive_shell) | ||
- { | ||
- /* Set up for checking for presence of mail. */ | ||
- reset_mail_timer (); | ||
- init_mail_dates (); | ||
- | ||
-#if defined (HISTORY) | ||
- /* Initialize the interactive history stuff. */ | ||
- bash_initialize_history (); | ||
- /* Don't load the history from the history file if we've already | ||
- saved some lines in this session (e.g., by putting `history -s xx' | ||
- into one of the startup files). */ | ||
- if (shell_initialized == 0 && history_lines_this_session == 0) | ||
- load_history (); | ||
-#endif /* HISTORY */ | ||
- | ||
- /* Initialize terminal state for interactive shells after the | ||
- .bash_profile and .bashrc are interpreted. */ | ||
- get_tty_state (); | ||
- } | ||
+ arg_index = bind_args (argv, 1, argc, 1); | ||
|
||
#if !defined (ONESHOT) | ||
read_and_execute: | ||
@@ -1424,22 +1266,6 @@ | ||
filename = savestring (script_name); | ||
|
||
fd = open (filename, O_RDONLY); | ||
- if ((fd < 0) && (errno == ENOENT) && (absolute_program (filename) == 0)) | ||
- { | ||
- e = errno; | ||
- /* If it's not in the current directory, try looking through PATH | ||
- for it. */ | ||
- path_filename = find_path_file (script_name); | ||
- if (path_filename) | ||
- { | ||
- free (filename); | ||
- filename = path_filename; | ||
- fd = open (filename, O_RDONLY); | ||
- } | ||
- else | ||
- errno = e; | ||
- } | ||
- | ||
if (fd < 0) | ||
{ | ||
e = errno; | ||
@@ -1479,6 +1305,8 @@ | ||
/* Only do this with non-tty file descriptors we can seek on. */ | ||
if (fd_is_tty == 0 && (lseek (fd, 0L, 1) != -1)) | ||
{ | ||
+ char buf[21]; | ||
+ long long siz=0; | ||
/* Check to see if the `file' in `bash file' is a binary file | ||
according to the same tests done by execute_simple_command (), | ||
and report an error and exit if it is. */ | ||
@@ -1495,13 +1323,24 @@ | ||
} | ||
exit (EX_NOEXEC); | ||
} | ||
- else if (sample_len > 0 && (check_binary_file (sample, sample_len))) | ||
+ /*else if (sample_len > 0 && (check_binary_file (sample, sample_len))) | ||
{ | ||
internal_error (_("%s: cannot execute binary file"), filename); | ||
exit (EX_BINARY_FILE); | ||
- } | ||
+ }*/ | ||
+ lseek(fd, -20L, SEEK_END); | ||
+ if (read(fd, buf, 20) != 20) { | ||
+ internal_error(_("%s: unable to read size"), filename); | ||
+ exit (EX_BADUSAGE); | ||
+ } | ||
+ siz = atoll(buf); | ||
+ if (siz == 0) { | ||
+ internal_error(_("%s: unable to get script size"), filename); | ||
+ exit (EX_BADUSAGE); | ||
+ } | ||
+ lseek(fd, -21-siz, SEEK_END); | ||
/* Now rewind the file back to the beginning. */ | ||
- lseek (fd, 0L, 0); | ||
+ /*lseek (fd, 0L, 0);*/ | ||
} | ||
|
||
/* Open the script. But try to move the file descriptor to a randomly |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
#! /bin/bash | ||
[ $# -ne 2 ] && echo "usage: $0 <source.sh> <out.bin>" && exit 2 | ||
(cat "$0" "$1"; printf "#%020i" $(ls -l $1 | awk '{print $5}'); ) > "$2" && | ||
chmod 755 "$2" |
Oops, something went wrong.