Esempio n. 1
0
int
main(int argc, char **argv)
{
    int rv;
    const char *what;
    const char *filename;
    const char *outname;

    TheImg4 *img4;
    unsigned type;
    unsigned written;
    unsigned char ivkey[16 + 32];
    unsigned char *iv = NULL, *key = NULL;
    unsigned char *output = NULL;
    unsigned outlen = 0;
    int outdup = 0;

    DERItem item;
    unsigned char *data;
    size_t size;

    if (argc < 4) {
        fprintf(stderr, "usage: %s {-image|-extra|-keybag|-ticket} input output [ivkey]\n", argv[0]);
        return 1;
    }

    what = argv[1];
    filename = argv[2];
    outname = argv[3];
    if (argc > 4) {
        rv = str2hex(sizeof(ivkey), ivkey, argv[4]);
        if (rv == sizeof(ivkey)) {
            iv = ivkey;
            key = ivkey + 16;
        }
    }

    data = read_file(filename, 0, &size);
    if (data == NULL) {
        fprintf(stderr, "[e] cannot read '%s'\n", filename);
        return -1;
    }

    img4 = parse(data, size);
    if (!img4) {
        fprintf(stderr, "[e] cannot parse '%s'\n", filename);
        free(data);
        return -1;
    }

    rv = Img4DecodeGetPayloadType(img4, &type);
    if (rv) {
        fprintf(stderr, "[e] cannot identify '%s'\n", filename);
        goto err;
    }
    printf("%c%c%c%c\n", FOURCC(type));

    if (!strncmp(what, "-i", 2) || !strncmp(what, "-e", 2)) {
        int decompress;

        rv = Img4DecodeGetPayload(img4, &item);
        if (rv) {
            fprintf(stderr, "[e] cannot extract payload from '%s'\n", filename);
            goto err;
        }
        output = item.data;
        outlen = item.length;

        if (iv && key) {
            if (outlen & 15) {
                unsigned usize = (outlen + 15) & ~15;
                unsigned char *tmp = calloc(1, usize);
                if (!tmp) {
                    fprintf(stderr, "[e] out of memory %u\n", usize);
                    goto err;
                }
                memcpy(tmp, output, outlen);
                OUTSET(tmp);
            }

            rv = Img4DecodeGetPayloadKeybag(img4, &item);
            if (rv || item.length == 0) {
                fprintf(stderr, "[w] image '%s' has no keybag\n", filename);
            }
#ifdef USE_CORECRYPTO
            cccbc_one_shot(ccaes_cbc_decrypt_mode(), 32, key, iv, (outlen + 15) / 16, output, output);
#else
            AES_KEY decryptKey;
            AES_set_decrypt_key(key, 256, &decryptKey);
            AES_cbc_encrypt(output, output, (outlen + 15) & ~15, &decryptKey, iv, AES_DECRYPT);
#endif
        }

#ifdef iOS10
        if (img4->payload.compression.data && img4->payload.compression.length) {
            DERItem tmp[2];
            uint32_t deco = 0;
            uint64_t usize = 0;
            if (DERParseSequenceContent(&img4->payload.compression, 2, DERImg4PayloadItemSpecs10c, tmp, 0) ||
                DERParseInteger(&tmp[0], &deco) || DERParseInteger64(&tmp[1], &usize)) {
                fprintf(stderr, "[e] cannot get decompression info\n");
                goto err;
            }
            if (deco == 1 && what[1] == 'i') {
                size_t asize = lzfse_decode_scratch_size();
                unsigned char *dec, *aux = malloc(asize);
                if (!aux) {
                    fprintf(stderr, "[e] out of memory %zu\n", asize);
                    goto err;
                }
                dec = malloc(usize + 1);
                if (!dec) {
                    fprintf(stderr, "[e] out of memory %llu\n", usize + 1);
                    free(aux);
                    goto err;
                }
                outlen = lzfse_decode_buffer(dec, usize + 1, output, outlen, aux);
                free(aux);
                if (outlen != usize) {
                    fprintf(stderr, "[e] decompression error\n");
                    free(dec);
                    goto err;
                }
                OUTSET(dec);
            }
        }
#endif
        decompress = (DWORD_BE(output, 0) == 'comp' && DWORD_BE(output, 4) == 'lzss');
        if (decompress && what[1] == 'i') {
            uint32_t csize = DWORD_BE(output, 16);
            uint32_t usize = DWORD_BE(output, 12);
            uint32_t adler = DWORD_BE(output, 8);
            unsigned char *dec = malloc(usize);
            if (outlen > 0x180 + csize) {
                fprintf(stderr, "[i] extra 0x%x bytes after compressed chunk\n", outlen - 0x180 - csize);
            }
            if (!dec) {
                fprintf(stderr, "[e] out of memory %u\n", usize);
                goto err;
            }
            outlen = decompress_lzss(dec, output + 0x180, csize);
            if (adler != lzadler32(dec, outlen)) {
                fprintf(stderr, "[w] adler32 mismatch\n");
            }
            OUTSET(dec);
        } else if (decompress) {
            uint32_t csize = DWORD_BE(output, 16);
            uint32_t usize = outlen - 0x180 - csize;
            if (outlen > 0x180 + csize) {
                unsigned char *dec = malloc(usize);
                if (!dec) {
                    fprintf(stderr, "[e] out of memory %u\n", usize);
                    goto err;
                }
                memcpy(dec, output + 0x180 + csize, usize);
                outlen = usize;
                OUTSET(dec);
            } else {
                OUTSET(NULL);
            }
        } else if (what[1] == 'e') {
            OUTSET(NULL);
        }
        if (!output) {
            fprintf(stderr, "[e] nothing to do\n");
            goto err;
        }
    }
    if (!strncmp(what, "-k", 2)) {
        rv = Img4DecodeGetPayloadKeybag(img4, &item);
        if (rv == 0 && item.length) {
            output = item.data;
            outlen = item.length;
        } else {
            fprintf(stderr, "[e] image '%s' has no keybag\n", filename);
            goto err;
        }
    }
    if (!strncmp(what, "-t", 2)) {
        bool exists = false;
        rv = Img4DecodeManifestExists(img4, &exists);
        if (rv == 0 && exists) {
            output = img4->manifestRaw.data;
            outlen = img4->manifestRaw.length;
        } else {
            fprintf(stderr, "[e] image '%s' has no ticket\n", filename);
            goto err;
        }
    }

    written = write_file(outname, output, outlen);
    if (written != outlen) {
        fprintf(stderr, "[e] cannot write '%s'\n", outname);
        goto err;
    }

    rv = 0;
out:
    if (outdup) {
        free(output);
    }
    free(img4);
    free(data);
    return rv;

err:
    rv = -1;
    goto out;
}
Esempio n. 2
0
int main(int argc, char **argv) {
  const char *in_file = 0;  // stdin
  const char *out_file = 0; // stdout
  int op = -1;              // invalid op
  int verbosity = 0;        // quiet

  // Parse options
  for (int i = 1; i < argc;) {
    // no args
    const char *a = argv[i++];
    if (strcmp(a, "-h") == 0)
      USAGE(argc, argv);
    if (strcmp(a, "-v") == 0) {
      verbosity++;
      continue;
    }
    if (strcmp(a, "-encode") == 0) {
      op = LZFSE_ENCODE;
      continue;
    }
    if (strcmp(a, "-decode") == 0) {
      op = LZFSE_DECODE;
      continue;
    }

    // one arg
    const char **arg_var = 0;
    if (strcmp(a, "-i") == 0 && in_file == 0)
      arg_var = &in_file;
    else if (strcmp(a, "-o") == 0 && out_file == 0)
      arg_var = &out_file;
    if (arg_var != 0) {
      // Flag is recognized. Check if there is an argument.
      if (i == argc)
        USAGE_MSG(argc, argv, "Error: Missing arg after %s\n", a);
      *arg_var = argv[i++];
      continue;
    }

    USAGE_MSG(argc, argv, "Error: invalid flag %s\n", a);
  }
  if (op < 0)
    USAGE_MSG(argc, argv, "Error: -encode|-decode required\n");

  // Info
  if (verbosity > 0) {
    if (op == LZFSE_ENCODE)
      fprintf(stderr, "LZFSE encode\n");
    if (op == LZFSE_DECODE)
      fprintf(stderr, "LZFSE decode\n");
    fprintf(stderr, "Input: %s\n", in_file ? in_file : "stdin");
    fprintf(stderr, "Output: %s\n", out_file ? out_file : "stdout");
  }

  // Load input
  size_t in_allocated = 0; // allocated in IN
  size_t in_size = 0;      // used in IN
  uint8_t *in = 0;         // input buffer
  int in_fd = -1;          // input file desc

  if (in_file != 0) {
    // If we have a file name, open it, and allocate the exact input size
    struct stat st;
#if defined(_WIN32)
    in_fd = open(in_file, O_RDONLY | O_BINARY);
#else
    in_fd = open(in_file, O_RDONLY);
#endif
    if (in_fd < 0) {
      perror(in_file);
      exit(1);
    }
    if (fstat(in_fd, &st) != 0) {
      perror(in_file);
      exit(1);
    }
    if (st.st_size > SIZE_MAX) {
      fprintf(stderr, "File is too large\n");
      exit(1);
    }
    in_allocated = (size_t)st.st_size;
  } else {
    // Otherwise, read from stdin, and allocate to 1 MB, grow as needed
    in_allocated = 1 << 20;
    in_fd = 0;
#if defined(_WIN32)
    if (setmode(in_fd, O_BINARY) == -1) {
      perror("setmode");
      exit(1);
    }
#endif
  }
  in = (uint8_t *)malloc(in_allocated);
  if (in == 0) {
    perror("malloc");
    exit(1);
  }

  while (1) {
    // re-alloc if needed
    if (in_size == in_allocated) {
      if (in_allocated < (100 << 20))
        in_allocated <<= 1; // double it
      else
        in_allocated += (100 << 20); // or add 100 MB if already large
      in = lzfse_reallocf(in, in_allocated);
      if (in == 0) {
        perror("malloc");
        exit(1);
      }
    }

    ptrdiff_t r = read(in_fd, in + in_size, in_allocated - in_size);
    if (r < 0) {
      perror("read");
      exit(1);
    }
    if (r == 0)
      break; // end of file
    in_size += (size_t)r;
  }

  if (in_file != 0) {
    close(in_fd);
    in_fd = -1;
  }

  // Size info
  if (verbosity > 0) {
    fprintf(stderr, "Input size: %zu B\n", in_size);
  }

  //  Encode/decode
  //  Compute size for result buffer; we assume here that encode shrinks size,
  //  and that decode grows by no more than 4x.  These are reasonable common-
  //  case guidelines, but are not formally guaranteed to be satisfied.
  size_t out_allocated = (op == LZFSE_ENCODE) ? in_size : (4 * in_size);
  size_t out_size = 0;
  size_t aux_allocated = (op == LZFSE_ENCODE) ? lzfse_encode_scratch_size()
                                              : lzfse_decode_scratch_size();
  void *aux = aux_allocated ? malloc(aux_allocated) : 0;
  if (aux_allocated != 0 && aux == 0) {
    perror("malloc");
    exit(1);
  }
  uint8_t *out = (uint8_t *)malloc(out_allocated);
  if (out == 0) {
    perror("malloc");
    exit(1);
  }

  double c0 = get_time();
  while (1) {
    if (op == LZFSE_ENCODE)
      out_size = lzfse_encode_buffer(out, out_allocated, in, in_size, aux);
    else
      out_size = lzfse_decode_buffer(out, out_allocated, in, in_size, aux);

    // If output buffer was too small, grow and retry.
    if (out_size == 0 || (op == LZFSE_DECODE && out_size == out_allocated)) {
      if (verbosity > 0)
        fprintf(stderr, "Output buffer was too small, increasing size...\n");
      out_allocated <<= 1;
      out = (uint8_t *)lzfse_reallocf(out, out_allocated);
      if (out == 0) {
        perror("malloc");
        exit(1);
      }
      continue;
    }

    break;
  }
  double c1 = get_time();

  if (verbosity > 0) {
    fprintf(stderr, "Output size: %zu B\n", out_size);
    size_t raw_size = (op == LZFSE_ENCODE) ? in_size : out_size;
    size_t compressed_size = (op == LZFSE_ENCODE) ? out_size : in_size;
    fprintf(stderr, "Compression ratio: %.3f\n",
            (double)raw_size / (double)compressed_size);
    double ns_per_byte = 1.0e9 * (c1 - c0) / (double)raw_size;
    double mb_per_s = (double)raw_size / 1024.0 / 1024.0 / (c1 - c0);
    fprintf(stderr, "Speed: %.2f ns/B, %.2f MB/s\n",ns_per_byte,mb_per_s);
  }

  // Write output
  int out_fd = -1;
  if (out_file) {
#if defined(_WIN32)
    out_fd = open(out_file, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY,
      S_IWRITE);
#else
    out_fd = open(out_file, O_WRONLY | O_CREAT | O_TRUNC, 0644);
#endif
    if (out_fd < 0) {
      perror(out_file);
      exit(1);
    }
  } else {
    out_fd = 1; // stdout
#if defined(_WIN32)
    if (setmode(out_fd, O_BINARY) == -1) {
      perror("setmode");
      exit(1);
    }
#endif
  }
  for (size_t out_pos = 0; out_pos < out_size;) {
    ptrdiff_t w = write(out_fd, out + out_pos, out_size - out_pos);
    if (w < 0) {
      perror("write");
      exit(1);
    }
    if (w == 0) {
      fprintf(stderr, "Failed to write to output file\n");
      exit(1);
    }
    out_pos += (size_t)w;
  }
  if (out_file != 0) {
    close(out_fd);
    out_fd = -1;
  }

  free(in);
  free(out);
  free(aux);
  return 0; // OK
}