Skip to content

Instantly share code, notes, and snippets.

@goofwear
Forked from SciresM/nx_bootloader_uncompress.c
Created January 15, 2019 07:01
Show Gist options
  • Save goofwear/6374db40c3fd982755cffc78d7a622a3 to your computer and use it in GitHub Desktop.
Save goofwear/6374db40c3fd982755cffc78d7a622a3 to your computer and use it in GitHub Desktop.
Quick and dirty NX bootloader uncompression code for 6.2.0+
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <stdbool.h>
typedef uint32_t u32;
typedef uint8_t u8;
typedef struct {
u8 *dst;
size_t dst_size;
size_t dst_off;
u8 *src;
size_t src_size;
size_t src_off;
} ctx_t;
u8 get_src_byte(ctx_t *ctx) {
return ctx->src[ctx->src_off++];
}
size_t get_copy_size(ctx_t *ctx, u8 ctrl) {
if (ctrl < 0xF) {
return ctrl;
}
size_t sz = ctrl;
do {
ctrl = get_src_byte(ctx);
sz += ctrl;
} while (ctrl >= 0xFF);
return sz;
}
size_t uncompress_impl(ctx_t *ctx) {
while (true) {
u8 ctrl_byte = get_src_byte(ctx);
size_t copy_size = get_copy_size(ctx, ctrl_byte >> 4);
memcpy(ctx->dst + ctx->dst_off, ctx->src + ctx->src_off, copy_size);
ctx->dst_off += copy_size;
ctx->src_off += copy_size;
if (ctx->src_off >= ctx->src_size) {
break;
}
int wide_ctrl = get_src_byte(ctx);
wide_ctrl |= (get_src_byte(ctx) << 8);
size_t wide_copy_size = get_copy_size(ctx, ctrl_byte & 0xF);
size_t end_off = ctx->dst_off + wide_copy_size + 4;
for (size_t cur_off = ctx->dst_off; cur_off < end_off; ctx->dst_off = cur_off) {
if (wide_ctrl >= cur_off) {
printf("OOB ACCESS!\n");
while (true) {
}
}
ctx->dst[cur_off] = ctx->dst[cur_off - wide_ctrl];
cur_off++;
}
}
}
size_t uncompress(void *input, size_t input_size, void *output, size_t output_size) {
ctx_t ctx;
ctx.src = (u8 *)input;
ctx.src_size = input_size;
ctx.src_off = 0;
ctx.dst = (u8 *)output;
ctx.dst_size = output_size;
ctx.dst_off = 0;
return uncompress_impl(&ctx);
}
int main(int argc, char **argv) {
if (argc != 2) {
fprintf(stderr, "Usage: %s input\n", argv[0]);
return EXIT_FAILURE;
}
size_t inp_size = 0;
size_t out_size = 0x1C000;
void *output = calloc(1, out_size);
FILE *fp = fopen(argv[1], "rb");
fseek(fp, 0L, SEEK_END);
inp_size = ftell(fp);
fseek(fp, 0L, SEEK_SET);
void *input = calloc(1, inp_size);
fread(input, inp_size, 1, fp);
fclose(fp);
printf("Decompressing...\n");
printf("Out: %08x\n", uncompress(input, inp_size, output, out_size));
fp = fopen("output.bin", "wb");
fwrite(output, out_size, 1, fp);
fclose(fp);
return EXIT_SUCCESS;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment