diff options
-rw-r--r-- | .gitignore | 21 | ||||
-rw-r--r-- | Makefile.am | 3 | ||||
-rwxr-xr-x | bootstrap.sh | 4 | ||||
-rw-r--r-- | configure.ac | 42 | ||||
-rw-r--r-- | proone.code-workspace | 8 | ||||
-rwxr-xr-x | scripts/build-all.sh | 87 | ||||
-rwxr-xr-x | scripts/test_bin-archive.sh | 63 | ||||
-rwxr-xr-x | scripts/xcomp.sh | 8 | ||||
-rw-r--r-- | src/Makefile.am | 36 | ||||
-rw-r--r-- | src/proone-list-arch.c | 14 | ||||
-rw-r--r-- | src/proone-packer.c | 145 | ||||
-rw-r--r-- | src/proone-unpacker.c | 144 | ||||
-rw-r--r-- | src/proone.c | 7 | ||||
-rw-r--r-- | src/proone_pack.c | 277 | ||||
-rw-r--r-- | src/proone_pack.h | 44 | ||||
-rw-r--r-- | src/proone_protocol.c | 74 | ||||
-rw-r--r-- | src/proone_protocol.h | 27 | ||||
-rw-r--r-- | src/proone_util.h | 11 |
18 files changed, 1015 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..bda183d --- /dev/null +++ b/.gitignore @@ -0,0 +1,21 @@ + +Makefile +Makefile.in +.deps + +/configure +/config.guess +/config.sub +/config.status +/config.log +/aclocal.m4 +/autom4te.cache +/compile +/depcomp +/install-sh +/missing + +/src/*.o +/builds/* +/scripts/pack_test +/scripts/*.log diff --git a/Makefile.am b/Makefile.am new file mode 100644 index 0000000..655bc18 --- /dev/null +++ b/Makefile.am @@ -0,0 +1,3 @@ +AUTOMAKE_OPTIONS = foreign +SUBDIRS = src +ACLOCAL_AMFLAGS = -I m4 diff --git a/bootstrap.sh b/bootstrap.sh new file mode 100755 index 0000000..347d7d9 --- /dev/null +++ b/bootstrap.sh @@ -0,0 +1,4 @@ +#!/bin/sh +aclocal && + automake --add-missing --copy && + autoconf diff --git a/configure.ac b/configure.ac new file mode 100644 index 0000000..8779eec --- /dev/null +++ b/configure.ac @@ -0,0 +1,42 @@ +AC_INIT([proone], [0.0.0], []) + +: ${CFLAGS=""} +: ${CXXFLAGS=""} + +AM_INIT_AUTOMAKE([1.0 subdir-objects]) +AC_CANONICAL_HOST +AC_LANG([C]) +AC_PROG_CC +AC_PROG_RANLIB + +AC_ARG_ENABLE(debug, +AS_HELP_STRING([--enable-debug], + [build with debug flags, default: no]), +[case "${enableval}" in + yes) debug=true ;; + no) debug=false ;; + *) AC_MSG_ERROR([bad value ${enableval} for --enable-debug]) ;; +esac], +[debug=false]) +AM_CONDITIONAL(DEBUG, test x"$debug" = x"true") + +AC_ARG_ENABLE(tests, +AS_HELP_STRING([--enable-tests], + [build tests, default: no]), +[case "${enableval}" in + yes) tests=true ;; + no) tests=false ;; + *) AC_MSG_ERROR([bad value ${enableval} for --enable-tests]) ;; +esac], +[tests=false]) +AM_CONDITIONAL(TESTS, test x"$tests" = x"true") +AM_COND_IF([TESTS], [ + AC_CHECK_HEADERS([gtest/gtest.h], + [], + [AC_MSG_ERROR([gtest/gtest.h not found.])]) +]) + +PKG_CHECK_MODULES_STATIC([DEP], [zlib openssl]) + +AC_CONFIG_FILES([Makefile src/Makefile]) +AC_OUTPUT diff --git a/proone.code-workspace b/proone.code-workspace new file mode 100644 index 0000000..5709732 --- /dev/null +++ b/proone.code-workspace @@ -0,0 +1,8 @@ +{ + "folders": [ + { + "path": "." + } + ], + "settings": {} +} diff --git a/scripts/build-all.sh b/scripts/build-all.sh new file mode 100755 index 0000000..40f0b85 --- /dev/null +++ b/scripts/build-all.sh @@ -0,0 +1,87 @@ +#!/bin/bash +ARCH_ARR=( + "armv4t" + "armv7" + "i586" + "m68k" + "mips" + "mpsl" + "ppc" + "sh4" + "spc" + "x86_64" +) +TOOLCHAIN_ARR=( + "armv4t" + "armv7" + "i586" + "m68k" + "mips" + "mpsl" + "ppc" + "sh4" + "spc" + "x86_64" +) +HOST_ARR=( + "arm-buildroot-linux-uclibcgnueabi" + "arm-buildroot-linux-uclibcgnueabi" + "i586-buildroot-linux-uclibc" + "m68k-buildroot-linux-uclibc" + "mips-buildroot-linux-uclibc" + "mipsel-buildroot-linux-uclibc" + "powerpc-buildroot-linux-uclibc" + "sh4-buildroot-linux-uclibc" + "sparc-buildroot-linux-uclibc" + "x86_64-buildroot-linux-uclibc" +) +ARR_SIZE="${#ARCH_ARR[@]}" +if [ $ARR_SIZE -ne "${#TOOLCHAIN_ARR[@]}" ] || [ $ARR_SIZE -ne "${#HOST_ARR[@]}" ]; then + echo "Config error: arrays" >&2 + exit 2 +fi + +PROONE_PREFIX="builds" +PROONE_BIN="$PROONE_PREFIX/bin" +PROONE_TOOLS="$PROONE_PREFIX/tools" +export PROONE_BIN_PREFIX="$PROONE_BIN/proone" +PROONE_PACKER="$PROONE_TOOLS/proone-packer" +PROONE_UNPACKER="$PROONE_TOOLS/proone-unpacker" +PROONE_BIN_ARCHIVE="$PROONE_PREFIX/bin-archive.zz.base64" + +rm -rf "$PROONE_PREFIX" && mkdir "$PROONE_PREFIX" "$PROONE_BIN" "$PROONE_TOOLS" +if [ $? -ne 0 ] ; then + exit $? +fi + +make distclean + +# native build for tools +./configure && make -j$(nproc) && cp -a src/proone-packer "$PROONE_PACKER" && cp -a src/proone-unpacker "$PROONE_UNPACKER" && make distclean +if [ $? -ne 0 ]; then + exit $? +fi + +# cross-compile targets +for (( i = 0; i < ARR_SIZE; i += 1 )); do + PROONE_HOST="${HOST_ARR[$i]}" PROONE_BIN_ARCH="${ARCH_ARR[$i]}" bash-xcomp-uclibc "${TOOLCHAIN_ARR[$i]}" "scripts/xcomp.sh" + if [ $? -ne 0 ]; then + exit $? + fi +done + +# pack +"$PROONE_PACKER" "$PROONE_BIN_PREFIX."* | pigz -z - | base64 > "$PROONE_BIN_ARCHIVE" +if [ $? -ne 0 ]; then + exit $? +fi + +# archive test + + +# size report +total_bin_size=$(cat "$PROONE_BIN_PREFIX."* | wc -c) +bin_archive_size=$(wc -c "$PROONE_BIN_ARCHIVE" | awk '{print $1;}') +echo "print(\"archive/bin = $bin_archive_size / $total_bin_size (\" + str($bin_archive_size / $total_bin_size * 100) + \"%)\")" | python3 + +exit 0 diff --git a/scripts/test_bin-archive.sh b/scripts/test_bin-archive.sh new file mode 100755 index 0000000..c4e1d93 --- /dev/null +++ b/scripts/test_bin-archive.sh @@ -0,0 +1,63 @@ +#!/bin/bash +RND_BLOCK_SIZE=4096 +if [ -z "$RND_BIN_CNT_MIN" ]; then + RND_BIN_CNT_MIN=1 +fi +if [ -z "$RND_BIN_CNT_MAX" ]; then + RND_BIN_CNT_MAX=20 +fi +TEST_DIR="pack_test" +BIN_PACK_DIR="$TEST_DIR/pack" +BIN_UNPACK_DIR="$TEST_DIR/unpack" +BIN_PREFIX="bin" +BIN_ARCHIVE_PREFIX="bin_archive" +SIZE_LOG="pack_test-size.log" +if [ -z "$LISTARCH" ]; then + LISTARCH="../src/proone-list-arch" +fi +if [ -z "$PACKER" ]; then + PACKER="../src/proone-packer" +fi +if [ -z "$UNPACKER" ]; then + UNPACKER="../src/proone-unpacker" +fi +ARCH_ARR=(`"$LISTARCH"`) + +if [ -d "$TEST_DIR" ]; then + rm -rf "$TEST_DIR/"* +else + mkdir "$TEST_DIR" +fi +mkdir "$BIN_PACK_DIR" "$BIN_UNPACK_DIR" +if [ $? -ne 0 ]; then + exit 2 +fi + +for arch in ${ARCH_ARR[@]}; do + bin_block_cnt="$(shuf -n1 -i $RND_BIN_CNT_MIN-$RND_BIN_CNT_MAX)" &&\ + dd if=/dev/random of="$BIN_PACK_DIR/$BIN_PREFIX.$arch" iflag=fullblock bs=$RND_BLOCK_SIZE count=$bin_block_cnt + if [ $? -ne 0 ]; then + exit 2 + fi +done + +"$PACKER" "$BIN_PACK_DIR/$BIN_PREFIX."* | pigz -z - | base64 > "$TEST_DIR/$BIN_ARCHIVE_PREFIX.zz.b64" +if [ $? -ne 0 ]; then + exit 2; +fi + +"$UNPACKER" "$BIN_UNPACK_DIR/$BIN_PREFIX" < "$TEST_DIR/$BIN_ARCHIVE_PREFIX.zz.b64" +if [ $? -ne 0 ]; then + exit 2; +fi + +for arch in ${ARCH_ARR[@]}; do + diff -q "$BIN_PACK_DIR/$BIN_PREFIX.$arch" "$BIN_UNPACK_DIR/$BIN_PREFIX.$arch" + if [ $? -ne 0 ]; then + exit 2; + fi +done + +echo $(du -bs "$BIN_PACK_DIR" | awk '{print $1;}') $(wc -c "$TEST_DIR/$BIN_ARCHIVE_PREFIX.zz.b64" | awk '{print $1;}') >> "$SIZE_LOG" + +exit 0 diff --git a/scripts/xcomp.sh b/scripts/xcomp.sh new file mode 100755 index 0000000..2ff24a5 --- /dev/null +++ b/scripts/xcomp.sh @@ -0,0 +1,8 @@ +#!/bin/bash +OUT="$PROONE_BIN_PREFIX.$PROONE_BIN_ARCH" + +./configure --host="$PROONE_HOST" &&\ + make -j$(nproc) &&\ + cp -a src/proone "$OUT" &&\ + "$PROONE_HOST-strip" -S --strip-unneeded --remove-section=.note.gnu.gold-version --remove-section=.comment --remove-section=.note --remove-section=.note.gnu.build-id --remove-section=.note.ABI-tag --remove-section=.jcr --remove-section=.got.plt --remove-section=.eh_frame --remove-section=.eh_frame_ptr --remove-section=.eh_frame_hdr "$OUT" &&\ + make distclean diff --git a/src/Makefile.am b/src/Makefile.am new file mode 100644 index 0000000..c5acf4e --- /dev/null +++ b/src/Makefile.am @@ -0,0 +1,36 @@ +TARGET_FLAGS = +DEV_FLAGS = +if DEBUG +TARGET_FLAGS += -g -O0 +DEV_FLAGS += -g -O0 +else +TARGET_FLAGS += -Os +DEV_FLAGS += -Os +endif + +noinst_LIBRARIES = libproone.a +bin_PROGRAMS = proone proone-packer proone-unpacker proone-list-arch + +libproone_a_SOURCES =\ + proone_protocol.c\ + proone_pack.c + +proone_CFLAGS = -std=c11 -Wall -Wno-switch $(DEV_FLAGS) +proone_LDFLAGS = -static +proone_LDADD = libproone.a $(DEP_LIBS) +proone_SOURCES =\ + proone.c + +proone_packer_CFLAGS = -std=c11 -Wall -Wno-switch $(DEV_FLAGS) +proone_packer_LDADD = libproone.a +proone_packer_SOURCES = proone-packer.c +proone_unpacker_CFLAGS = -std=c11 -Wall -Wno-switch $(DEV_FLAGS) +proone_unpacker_LDADD = libproone.a +proone_unpacker_LDFLAGS = $(DEP_LIBS) +proone_unpacker_SOURCES = proone-unpacker.c +proone_list_arch_CFLAGS = -std=c11 -Wall -Wno-switch $(DEV_FLAGS) +proone_list_arch_LDADD = libproone.a +proone_list_arch_SOURCES = proone-list-arch.c + +if TESTS +endif diff --git a/src/proone-list-arch.c b/src/proone-list-arch.c new file mode 100644 index 0000000..792b9c2 --- /dev/null +++ b/src/proone-list-arch.c @@ -0,0 +1,14 @@ +#include <stdio.h> + +#include "proone_protocol.h" + + +int main (void) { + proone_arch_t i; + + for (i = PROONE_ARCH_NONE + 1; i < NB_PROONE_ARCH; i += 1) { + printf("%s\n", proone_arch2str(i)); + } + + return 0; +} diff --git a/src/proone-packer.c b/src/proone-packer.c new file mode 100644 index 0000000..3568bf8 --- /dev/null +++ b/src/proone-packer.c @@ -0,0 +1,145 @@ +#include <stdint.h> +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include <unistd.h> +#include <errno.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/sendfile.h> +#include <fcntl.h> + +#include "proone_protocol.h" + + +int main (const int args, const char **argc) { + typedef struct { + proone_arch_t arch; + const char *path; + } archive_tuple_t; + size_t i; + const archive_tuple_t *encounter_arr[NB_PROONE_ARCH]; + archive_tuple_t archive_arr[NB_PROONE_ARCH]; + archive_tuple_t *archive; + size_t archive_arr_cnt = 0; + const char *path, *ext; + bool proc_result = true; + proone_arch_t arch; + int bin_fd = -1; + struct stat st; + uint8_t head[4]; + + if (args <= 1) { + fprintf(stderr, "Usage: %s <path to binary 1> [path to binary 2 [path to binary ...]]\n", argc[0]); + return 1; + } + // refuse to run if stdout is terminal + if (isatty(STDOUT_FILENO)) { + fprintf(stderr, "** Refusing to print on terminal.\n"); + return 1; + } + // too many files + if (args - 1 > NB_PROONE_ARCH) { + fprintf(stderr, "** Too many files given (%d > %d).\n", args - 1, NB_PROONE_ARCH); + return 1; + } + + // init + memset(encounter_arr, 0, sizeof(archive_tuple_t*) * NB_PROONE_ARCH); + memset(archive_arr, 0, sizeof(archive_tuple_t) * NB_PROONE_ARCH); + + // Check the file names are valid + for (i = 1; i < (size_t)args; i += 1) { + path = argc[i]; + + ext = strrchr(path, '.'); + if (ext == NULL) { + fprintf(stderr, "** %s: file extension not found\n", path); + proc_result = false; + continue; + } + ext += 1; + + arch = proone_str2arch(ext); + if (arch == PROONE_ARCH_NONE) { + fprintf(stderr, "** %s: unknown arch \"%s\"\n", path, ext); + proc_result = false; + continue; + } + + if (encounter_arr[arch] != NULL) { + fprintf(stderr, "** Duplicate arch!\n%s\n%s\n", encounter_arr[arch]->path, path); + proc_result = false; + continue; + } + + archive_arr[archive_arr_cnt].arch = arch; + archive_arr[archive_arr_cnt].path = path; + encounter_arr[arch] = &archive_arr[archive_arr_cnt]; + archive_arr_cnt += 1; + } + if (!proc_result) { + return 1; + } + + // do packing + fprintf(stderr, archive_arr_cnt == NB_PROONE_ARCH ? "Packing %zu binaries.\n" : "* Warning: packing only %zu binaries\n", archive_arr_cnt); + for (i = 0; i < archive_arr_cnt; i += 1) { + archive = &archive_arr[i]; + fprintf(stderr, "Packing: %s ...\n", archive->path); + + bin_fd = open(archive->path, O_RDONLY); + if (bin_fd < 0) { + perror("** open()"); + proc_result = false; + break; + } + + // get size + if (fstat(bin_fd, &st) != 0) { + perror("** fstat()"); + proc_result = false; + break; + } + if (st.st_size == 0) { + fprintf(stderr, "** empty file!\n"); + proc_result = false; + break; + } + if (st.st_size > 0x00FFFFFE) { + fprintf(stderr, "** binary too large!\n"); + proc_result = false; + break; + } + + // write head + head[0] = (uint8_t)archive->arch; + // endian conversion as the file is big endian + head[1] = (uint8_t)(((uint32_t)st.st_size & 0x00FF0000) >> 16); + head[2] = (uint8_t)(((uint32_t)st.st_size & 0x0000FF00) >> 8); + head[3] = (uint8_t)((uint32_t)st.st_size & 0x000000FF); + if (write(STDOUT_FILENO, head, 4) != 4) { + perror("write()"); + proc_result = false; + break; + } + + // write binary + if (sendfile(STDOUT_FILENO, bin_fd, NULL, st.st_size) < 0) { + perror("** sendfile()"); + proc_result = false; + break; + } + + close(bin_fd); + bin_fd = -1; + } + + close(bin_fd); + bin_fd = -1; + errno = 0; + + return proc_result ? 0 : 2; +} diff --git a/src/proone-unpacker.c b/src/proone-unpacker.c new file mode 100644 index 0000000..2a98166 --- /dev/null +++ b/src/proone-unpacker.c @@ -0,0 +1,144 @@ +#include <stdio.h> +#include <stdint.h> +#include <stdbool.h> +#include <string.h> + +#include <unistd.h> +#include <fcntl.h> + +#include <openssl/err.h> +#include <zlib.h> + +#include "proone_pack.h" + + +static void report_unpack_bin_archive_err (const proone_unpack_bin_archive_result_t *r) { + const char *err_str, *err_msg = NULL; + + switch (r->result) { + case PROONE_UNPACK_BIN_ARCHIVE_OK: + err_str = "ok"; + break; + case PROONE_UNPACK_BIN_ARCHIVE_OPENSSL_ERR: + err_str = "openssl error"; + err_msg = ERR_error_string(r->err, NULL); + break; + case PROONE_UNPACK_BIN_ARCHIVE_Z_ERR: + err_str = "zlib error"; + err_msg = zError((int)r->err); + break; + case PROONE_UNPACK_BIN_ARCHIVE_ERRNO: + err_str = "errno"; + err_msg = strerror((int)r->err); + break; + case PROONE_UNPACK_BIN_ARCHIVE_MEM_ERR: + err_str = "memory error"; + err_msg = strerror((int)r->err); + break; + default: + err_str = "* unknown"; + } + + if (err_msg == NULL) { + fprintf(stderr, "%s.\n", err_str); + } + else { + fprintf(stderr, "%s: %s\n", err_str, err_msg); + } +} + +static void report_index_bin_archive_err (const proone_index_bin_archive_result_code_t c) { + const char *msg; + + switch (c) { + case PROONE_INDEX_BIN_ARCHIVE_OK: + msg = "ok"; break; + case PROONE_INDEX_BIN_ARCHIVE_FMT_ERR: + msg = "format error"; break; + case PROONE_INDEX_BIN_ARCHIVE_MEM_ERR: + msg = "memory error"; break; + default: + msg = "* unknown"; break; + } + + fprintf(stderr, "%s.\n", msg); +} + +int main (const int args, const char **argc) { + int exit_code = 0; + const char *path_prefix; + size_t path_prefix_len; + proone_unpack_bin_archive_result_t unpack_ret; + bin_archive_t bin_archive; + proone_index_bin_archive_result_code_t index_ret; + size_t i; + const char *arch_str; + char *path = NULL; + size_t path_size; + void *ny_buf; + int fd = -1; + + if (args <= 1) { + fprintf(stderr, "Usage: %s <prefix>\n", argc[0]); + return 1; + } + + path_prefix = argc[1]; + path_prefix_len = strlen(path_prefix); + proone_init_bin_archive(&bin_archive); + + do { // fake loop + unpack_ret = proone_unpack_bin_archive(STDIN_FILENO); + if (unpack_ret.result != PROONE_UNPACK_BIN_ARCHIVE_OK) { + report_unpack_bin_archive_err(&unpack_ret); + exit_code = 2; + break; + } + + index_ret = proone_index_bin_archive(&unpack_ret, &bin_archive); + if (index_ret != PROONE_INDEX_BIN_ARCHIVE_OK) { + report_index_bin_archive_err(index_ret); + exit_code = 2; + break; + } + + for (i = 0; i < bin_archive.nb_binaries; i += 1) { + arch_str = proone_arch2str(bin_archive.arch_arr[i]); + if (arch_str == NULL) { + fprintf(stderr, "** unrecognised arch!"); + exit_code = 2; + break; + } + + path_size = 2 + path_prefix_len + strlen(arch_str); + ny_buf = realloc(path, path_size); + if (ny_buf == NULL) { + perror("realloc()"); + exit_code = 2; + break; + } + path = (char*)ny_buf; + sprintf(path, "%s.%s", path_prefix, arch_str); + + fd = open(path, O_CREAT | O_WRONLY | O_TRUNC, 0666); + if (fd < 0) { + perror("open()"); + exit_code = 2; + break; + } + if (write(fd, bin_archive.data + bin_archive.offset_arr[i], bin_archive.size_arr[i]) != bin_archive.size_arr[i]) { + perror("write()"); + exit_code = 2; + break; + } + close(fd); + } + } while (false); + + free(path); + close(fd); + proone_free_unpack_bin_archive_result(&unpack_ret); + proone_free_bin_archive(&bin_archive); + + return exit_code; +} diff --git a/src/proone.c b/src/proone.c new file mode 100644 index 0000000..b99ea62 --- /dev/null +++ b/src/proone.c @@ -0,0 +1,7 @@ +#include <stdio.h> + + +int main (void) { + printf("it works!\n"); + return 0; +} diff --git a/src/proone_pack.c b/src/proone_pack.c new file mode 100644 index 0000000..c257195 --- /dev/null +++ b/src/proone_pack.c @@ -0,0 +1,277 @@ +#include "proone_pack.h" + +#include <stdint.h> +#include <stdbool.h> +#include <stdlib.h> +#include <string.h> +#include <ctype.h> + +#include <fcntl.h> +#include <unistd.h> +#include <errno.h> + +#include <openssl/bio.h> +#include <openssl/evp.h> +#include <openssl/err.h> +#include <zlib.h> + + +void proone_init_bin_archive (bin_archive_t *a) { + a->data_size = 0; + a->data = NULL; + a->nb_binaries = 0; + a->arch_arr = NULL; + a->offset_arr = NULL; + a->size_arr = NULL; +} + +void proone_init_unpack_bin_archive_result (proone_unpack_bin_archive_result_t *r) { + r->data_size = 0; + r->data = NULL; + r->raw_data_size = 0; + r->raw_data = NULL; + r->result = PROONE_UNPACK_BIN_ARCHIVE_OK; + r->err = 0; +} + +proone_unpack_bin_archive_result_t proone_unpack_bin_archive (const int fd) { + static const size_t fd_buf_size = 77, bio_buf_size = 58, z_buf_size = 4096; + + proone_unpack_bin_archive_result_t ret; + BIO *b64_bio = NULL, *mem_bio = NULL; + uint8_t fd_buf[fd_buf_size], bio_buf[bio_buf_size], z_buf[z_buf_size]; + int fd_read_size, fd_data_size, bio_write_size, bio_read_size; + int z_func_ret; + z_stream stream; + size_t z_out_size; + void *ny_buf; + bool stream_end; + size_t i; + + proone_init_unpack_bin_archive_result(&ret); + + stream.zalloc = NULL; + stream.zfree = NULL; + stream.opaque = NULL; + stream.avail_in = 0; + stream.next_in = Z_NULL; + z_func_ret = inflateInit(&stream); + if (z_func_ret != Z_OK) { + ret.result = PROONE_UNPACK_BIN_ARCHIVE_Z_ERR; + ret.err = z_func_ret; + return ret; + } + + if ((mem_bio = BIO_new(BIO_s_mem())) == NULL || (b64_bio = BIO_new(BIO_f_base64())) == NULL) { + ret.result = PROONE_UNPACK_BIN_ARCHIVE_OPENSSL_ERR; + ret.err = ERR_get_error(); + goto END; + } + BIO_set_flags(b64_bio, BIO_FLAGS_BASE64_NO_NL); + BIO_push(b64_bio, mem_bio); + + stream_end = false; + do { + fd_read_size = read(fd, fd_buf, fd_buf_size); + if (fd_read_size < 0) { + ret.result = PROONE_UNPACK_BIN_ARCHIVE_ERRNO; + ret.err = errno; + goto END; + } + if (fd_read_size == 0) { + break; + } + + ny_buf = realloc(ret.raw_data, ret.raw_data_size + fd_read_size); + if (ny_buf == NULL) { + ret.result = PROONE_UNPACK_BIN_ARCHIVE_MEM_ERR; + ret.err = errno; + goto END; + } + ret.raw_data = (uint8_t*)ny_buf; + memcpy(ret.raw_data + ret.raw_data_size, fd_buf, fd_read_size); + ret.raw_data_size += fd_read_size; + + // remove white spaces + fd_data_size = fd_read_size; + for (i = 0; i < fd_data_size; ) { + if (isspace(fd_buf[i])) { + if (i + 1 >= fd_data_size) { + // last trailing whitespace + fd_data_size -= 1; + break; + } + memmove(fd_buf + i, fd_buf + i + 1, fd_data_size - i - 1); + fd_data_size -= 1; + } + else { + i += 1; + } + } + + if (fd_data_size > 0) { + BIO_reset(mem_bio); + bio_write_size = BIO_write(mem_bio, fd_buf, fd_data_size); + if (bio_write_size != fd_data_size) { + ret.result = PROONE_UNPACK_BIN_ARCHIVE_MEM_ERR; + goto END; + } + + bio_read_size = BIO_read(b64_bio, bio_buf, (int)bio_buf_size); + if (bio_read_size < 0) { + ret.result = PROONE_UNPACK_BIN_ARCHIVE_OPENSSL_ERR; + ret.err = ERR_get_error(); + goto END; + } + + if (bio_read_size > 0) { + stream.avail_in = bio_read_size; + stream.next_in = bio_buf; + do { + stream.avail_out = z_buf_size; + stream.next_out = z_buf; + z_func_ret = inflate(&stream, Z_NO_FLUSH); + switch (z_func_ret) { + case Z_STREAM_END: + stream_end = true; + break; + case Z_OK: + case Z_BUF_ERROR: + break; + default: + ret.result = PROONE_UNPACK_BIN_ARCHIVE_Z_ERR; + ret.err = z_func_ret; + goto END; + } + + z_out_size = z_buf_size - stream.avail_out; + ny_buf = realloc(ret.data, ret.data_size + z_out_size); + if (ny_buf == NULL) { + ret.result = PROONE_UNPACK_BIN_ARCHIVE_MEM_ERR; + ret.err = errno; + break; + } + ret.data = (uint8_t*)ny_buf; + + memcpy(ret.data + ret.data_size, z_buf, z_out_size); + ret.data_size += z_out_size; + } while (stream.avail_out == 0); + } + } + } while (!stream_end); + +END: + inflateEnd(&stream); + BIO_free(b64_bio); + BIO_free(mem_bio); + + if (ret.result != PROONE_UNPACK_BIN_ARCHIVE_OK) { + free(ret.data); + free(ret.raw_data); + ret.data = NULL; + ret.data_size = 0; + ret.raw_data = NULL; + ret.raw_data_size = 0; + } + + return ret; +} + +proone_index_bin_archive_result_code_t proone_index_bin_archive (proone_unpack_bin_archive_result_t *in, bin_archive_t *out) { + proone_index_bin_archive_result_code_t ret = PROONE_INDEX_BIN_ARCHIVE_OK; + size_t buf_pos = 0, arr_cnt = 0, offset_arr[NB_PROONE_ARCH], size_arr[NB_PROONE_ARCH], i; + proone_arch_t arch; + uint32_t bin_size; + proone_arch_t arch_arr[NB_PROONE_ARCH]; + bin_archive_t archive; + uint8_t *out_buf; + void *ny_buf; + + memset(arch_arr, 0, sizeof(proone_arch_t) * NB_PROONE_ARCH); + memset(offset_arr, 0, sizeof(size_t) * NB_PROONE_ARCH); + memset(size_arr, 0, sizeof(size_t) * NB_PROONE_ARCH); + proone_init_bin_archive(&archive); + + do { + if (buf_pos + 4 >= in->data_size || arr_cnt >= NB_PROONE_ARCH) { + ret = PROONE_INDEX_BIN_ARCHIVE_FMT_ERR; + goto END; + } + + arch = (proone_arch_t)in->data[buf_pos]; + bin_size = + ((uint32_t)in->data[buf_pos + 1] << 16) | + ((uint32_t)in->data[buf_pos + 2] << 8) | + (uint32_t)in->data[buf_pos + 3]; + if (proone_arch2str(arch) == NULL || bin_size == 0 || buf_pos + 4 + bin_size > in->data_size) { + ret = PROONE_INDEX_BIN_ARCHIVE_FMT_ERR; + goto END; + } + + arch_arr[arr_cnt] = arch; + offset_arr[arr_cnt] = 4 + buf_pos; + size_arr[arr_cnt] = bin_size; + arr_cnt += 1; + + buf_pos += 4 + bin_size; + } while (buf_pos < in->data_size); + + out_buf = (uint8_t*)malloc(sizeof(proone_arch_t) * arr_cnt + sizeof(size_t*) * arr_cnt + sizeof(size_t*) * arr_cnt); + if (out_buf == NULL) { + ret = PROONE_INDEX_BIN_ARCHIVE_MEM_ERR; + goto END; + } + archive.arch_arr = (proone_arch_t*)out_buf; + archive.offset_arr = (size_t*)(out_buf + sizeof(proone_arch_t) * arr_cnt); + archive.size_arr = (size_t*)(out_buf + sizeof(proone_arch_t) * arr_cnt + sizeof(size_t*) * arr_cnt); + + archive.nb_binaries = arr_cnt; + buf_pos = 0; + for (i = 0; i < arr_cnt; i += 1) { + memmove(in->data + buf_pos, in->data + offset_arr[i], size_arr[i]); + archive.arch_arr[i] = arch_arr[i]; + archive.offset_arr[i] = buf_pos; + archive.size_arr[i] = size_arr[i]; + buf_pos += size_arr[i]; + } + + ny_buf = realloc(in->data, buf_pos); + if (ny_buf == NULL) { + ret = PROONE_INDEX_BIN_ARCHIVE_MEM_ERR; + goto END; + } + archive.data = (uint8_t*)ny_buf; + archive.data_size = buf_pos; + + *out = archive; + in->data = NULL; + in->data_size = 0; + +END: + if (ret != PROONE_INDEX_BIN_ARCHIVE_OK) { + proone_free_bin_archive(&archive); + } + + return ret; +} + +void proone_free_unpack_bin_archive_result (proone_unpack_bin_archive_result_t *r) { + free(r->data); + free(r->raw_data); + r->data = NULL; + r->data_size = 0; + r->raw_data = NULL; + r->raw_data_size = 0; + r->result = PROONE_INDEX_BIN_ARCHIVE_OK; + r->err = 0; +} + +void proone_free_bin_archive (bin_archive_t *a) { + free(a->data); + free(a->arch_arr); + a->nb_binaries = 0; + a->data_size = 0; + a->arch_arr = NULL; + a->offset_arr = NULL; + a->size_arr = NULL; +} diff --git a/src/proone_pack.h b/src/proone_pack.h new file mode 100644 index 0000000..59b38cc --- /dev/null +++ b/src/proone_pack.h @@ -0,0 +1,44 @@ +#pragma once +#include <stdint.h> +#include <stdbool.h> + +#include "proone_protocol.h" + +typedef struct { + size_t data_size; + uint8_t *data; + size_t nb_binaries; + proone_arch_t *arch_arr; + size_t *offset_arr; + size_t *size_arr; +} bin_archive_t; + +typedef enum { + PROONE_UNPACK_BIN_ARCHIVE_OK, + PROONE_UNPACK_BIN_ARCHIVE_OPENSSL_ERR, + PROONE_UNPACK_BIN_ARCHIVE_Z_ERR, + PROONE_UNPACK_BIN_ARCHIVE_ERRNO, + PROONE_UNPACK_BIN_ARCHIVE_MEM_ERR +} proone_unpack_bin_archive_result_code_t; + +typedef struct { + size_t data_size; + uint8_t *data; + size_t raw_data_size; + uint8_t *raw_data; + proone_unpack_bin_archive_result_code_t result; + long err; +} proone_unpack_bin_archive_result_t; + +typedef enum { + PROONE_INDEX_BIN_ARCHIVE_OK, + PROONE_INDEX_BIN_ARCHIVE_FMT_ERR, + PROONE_INDEX_BIN_ARCHIVE_MEM_ERR +} proone_index_bin_archive_result_code_t; + +void proone_init_bin_archive (bin_archive_t *a); +void proone_init_unpack_bin_archive_result (proone_unpack_bin_archive_result_t *r); +proone_unpack_bin_archive_result_t proone_unpack_bin_archive (const int fd); +proone_index_bin_archive_result_code_t proone_index_bin_archive (proone_unpack_bin_archive_result_t *in, bin_archive_t *out); +void proone_free_unpack_bin_archive_result (proone_unpack_bin_archive_result_t *r); +void proone_free_bin_archive (bin_archive_t *a); diff --git a/src/proone_protocol.c b/src/proone_protocol.c new file mode 100644 index 0000000..b56769c --- /dev/null +++ b/src/proone_protocol.c @@ -0,0 +1,74 @@ +#include "proone_protocol.h" +#include <string.h> + +const char *proone_arch2str (const proone_arch_t x) { + switch (x){ + case PROONE_ARCH_ARMV4T: + return "armv4t"; + case PROONE_ARCH_ARMV7: + return "armv7"; + case PROONE_ARCH_I586: + return "i586"; + case PROONE_ARCH_M68K: + return "m68k"; + case PROONE_ARCH_MIPS: + return "mips"; + case PROONE_ARCH_MPSL: + return "mpsl"; + case PROONE_ARCH_PPC: + return "ppc"; + case PROONE_ARCH_RV32: + return "rv32"; + case PROONE_ARCH_RV64: + return "rv64"; + case PROONE_ARCH_SH4: + return "sh4"; + case PROONE_ARCH_SPC: + return "spc"; + case PROONE_ARCH_X86_64: + return "x86_64"; + } + + return NULL; +} + +proone_arch_t proone_str2arch (const char *str) { + if (strcmp(str, "armv4t") == 0) { + return PROONE_ARCH_ARMV4T; + } + else if (strcmp(str, "armv7") == 0) { + return PROONE_ARCH_ARMV7; + } + else if (strcmp(str, "i586") == 0) { + return PROONE_ARCH_I586; + } + else if (strcmp(str, "m68k") == 0) { + return PROONE_ARCH_M68K; + } + else if (strcmp(str, "mips") == 0) { + return PROONE_ARCH_MIPS; + } + else if (strcmp(str, "mpsl") == 0) { + return PROONE_ARCH_MPSL; + } + else if (strcmp(str, "ppc") == 0) { + return PROONE_ARCH_PPC; + } + else if (strcmp(str, "rv32") == 0) { + return PROONE_ARCH_RV32; + } + else if (strcmp(str, "rv64") == 0) { + return PROONE_ARCH_RV64; + } + else if (strcmp(str, "sh4") == 0) { + return PROONE_ARCH_SH4; + } + else if (strcmp(str, "spc") == 0) { + return PROONE_ARCH_SPC; + } + else if (strcmp(str, "x86_64") == 0) { + return PROONE_ARCH_X86_64; + } + + return PROONE_ARCH_NONE; +} diff --git a/src/proone_protocol.h b/src/proone_protocol.h new file mode 100644 index 0000000..0d44acb --- /dev/null +++ b/src/proone_protocol.h @@ -0,0 +1,27 @@ +#pragma once +#include <stddef.h> + +enum proone_arch { + PROONE_ARCH_NONE = -1, + + PROONE_ARCH_ARMV4T, + PROONE_ARCH_ARMV7, + PROONE_ARCH_I586, + PROONE_ARCH_M68K, + PROONE_ARCH_MIPS, + PROONE_ARCH_MPSL, + PROONE_ARCH_PPC, + PROONE_ARCH_RV32, + PROONE_ARCH_RV64, + PROONE_ARCH_SH4, + PROONE_ARCH_SPC, + PROONE_ARCH_X86_64, + + NB_PROONE_ARCH +}; + +typedef enum proone_arch proone_arch_t; + + +const char *proone_arch2str (const proone_arch_t x); +proone_arch_t proone_str2arch (const char *str); diff --git a/src/proone_util.h b/src/proone_util.h new file mode 100644 index 0000000..5f9bcd9 --- /dev/null +++ b/src/proone_util.h @@ -0,0 +1,11 @@ +#if 0 +bool proone_strendsw (const char *str, const char *w) { + const size_t len_str = strlen(str); + const size_t len_w = strlen(w); + + if (len_str < len_w) { + return false; + } + return strcmp(str + (len_str - len_w), w) == 0; +} +#endif |