aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Timber <david@lyset.snart.me>2019-12-27 18:22:18 +1100
committerDavid Timber <david@lyset.snart.me>2019-12-27 18:22:18 +1100
commit5f341e4c20767f08165776bdf559b096dc8996e9 (patch)
tree440052148fcda127898dad2ba3e6a6458482dba6
initial commit
-rw-r--r--.gitignore21
-rw-r--r--Makefile.am3
-rwxr-xr-xbootstrap.sh4
-rw-r--r--configure.ac42
-rw-r--r--proone.code-workspace8
-rwxr-xr-xscripts/build-all.sh87
-rwxr-xr-xscripts/test_bin-archive.sh63
-rwxr-xr-xscripts/xcomp.sh8
-rw-r--r--src/Makefile.am36
-rw-r--r--src/proone-list-arch.c14
-rw-r--r--src/proone-packer.c145
-rw-r--r--src/proone-unpacker.c144
-rw-r--r--src/proone.c7
-rw-r--r--src/proone_pack.c277
-rw-r--r--src/proone_pack.h44
-rw-r--r--src/proone_protocol.c74
-rw-r--r--src/proone_protocol.h27
-rw-r--r--src/proone_util.h11
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