From c2094e02116f9f4d8c94b5c4142c52c738b908a0 Mon Sep 17 00:00:00 2001 From: Max Wash Date: Sat, 15 Feb 2025 12:36:57 +0000 Subject: [PATCH] implement unwrap command to retrieve binary files from containers --- src/unwrap.c | 168 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 168 insertions(+) create mode 100644 src/unwrap.c diff --git a/src/unwrap.c b/src/unwrap.c new file mode 100644 index 0000000..6bc2ce9 --- /dev/null +++ b/src/unwrap.c @@ -0,0 +1,168 @@ +#include "commands.h" +#include "misc.h" +#include "read.h" + +#include +#include +#include +#include + +enum { + ARG_CONTAINER, + OPT_TAG, + OPT_TAG_IDENT, +}; + +static int unwrap( + const b_command *self, + const b_arglist *opt, + const b_array *args) +{ + const char *in_path = NULL; + b_arglist_get_string( + opt, + B_COMMAND_INVALID_ID, + ARG_CONTAINER, + 0, + &in_path); + + FILE *inp = fopen(in_path, "rb"); + if (!inp) { + b_err("cannot open '%s'", in_path); + b_i("reason: %s", strerror(errno)); + return -1; + } + + struct ec3_reader *reader = NULL; + enum ec3_status status = ec3_reader_create(inp, &reader); + + if (status != EC3_SUCCESS) { + fclose(inp); + + b_err("cannot open '%s'", in_path); + b_i("reason: corrupted/unknown file format"); + return -1; + } + + const struct ec3_container_info *c_info + = ec3_reader_get_container_info(reader); + if (c_info->c_nr_tags == 0) { + ec3_reader_finish(reader); + fclose(inp); + + b_i("container '%s' has no tags", in_path); + return -1; + } + + uint64_t target_tag_ident = 0; + const char *target_tag_ident_str = NULL; + b_arglist_get_string( + opt, + OPT_TAG, + OPT_TAG_IDENT, + 0, + &target_tag_ident_str); + + if (target_tag_ident_str) { + ec3_identifier_from_string( + target_tag_ident_str, + &target_tag_ident); + } else { + const struct ec3_tag_info *tags = ec3_reader_get_tags(reader); + target_tag_ident = tags[0].tag_ident; + } + + char ident_str[32]; + ec3_identifier_to_string(target_tag_ident, ident_str, sizeof ident_str); + + struct ec3_tag_reader *tag_reader = NULL; + status = ec3_reader_open_tag(reader, target_tag_ident, &tag_reader); + if (status != EC3_SUCCESS) { + b_i("container '%s' has no %s tag", in_path, ident_str); + + ec3_reader_finish(reader); + fclose(inp); + return -1; + } + + const struct ec3_tag_info *target_tag_info + = ec3_reader_get_tag_info(reader, target_tag_ident); + size_t tag_length = target_tag_info->tag_total_length; + + printf("reading %zu bytes from tag %s...\n", tag_length, ident_str); + + char *buf = malloc(c_info->c_cluster_size); + + int ret = 0; + FILE *outp = fopen("data.bin", "wb"); + for (size_t i = 0;; i++) { + size_t nr_read = 0; + enum ec3_status status + = ec3_tag_reader_read(tag_reader, i, 1, buf, &nr_read); + + if (status != EC3_SUCCESS) { + b_err("I/O failure while reading from container", + in_path); + ret = -1; + break; + } + + printf("read %zu bytes from cluster %zu\n", nr_read, i); + fwrite(buf, 1, nr_read, outp); + + if (nr_read < c_info->c_cluster_size) { + break; + } + } + + free(buf); + + fclose(inp); + fclose(outp); + return ret; +} + +B_COMMAND(CMD_UNWRAP, CMD_ROOT) +{ + B_COMMAND_NAME("unwrap"); + B_COMMAND_SHORT_NAME('U'); + B_COMMAND_DESC( + "retrieve a binary or executable blob from an ec3 " + "container."); + B_COMMAND_FLAGS(B_COMMAND_SHOW_HELP_BY_DEFAULT); + B_COMMAND_FUNCTION(unwrap); + + B_COMMAND_HELP_OPTION(); + + B_COMMAND_ARG(ARG_CONTAINER) + { + B_ARG_NAME("container"); + B_ARG_DESC("the container to retrieve the blob from"); + B_ARG_NR_VALUES(1); + } + + B_COMMAND_OPTION(OPT_TAG) + { + B_OPTION_SHORT_NAME('T'); + B_OPTION_LONG_NAME("tag"); + B_OPTION_DESC("the identifier of the blob tag to retrieve"); + + B_OPTION_ARG(OPT_TAG_IDENT) + { + B_ARG_NAME("identifier"); + B_ARG_DESC("the identifier"); + B_ARG_NR_VALUES(1); + } + } + + B_COMMAND_USAGE() + { + B_COMMAND_USAGE_ARG(ARG_CONTAINER); + } + + B_COMMAND_USAGE() + { + B_COMMAND_USAGE_OPT(OPT_TAG); + B_COMMAND_USAGE_ARG(ARG_CONTAINER); + } +}