Skip to content

Instantly share code, notes, and snippets.

@v3l0c1r4pt0r
Last active September 2, 2019 19:01
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save v3l0c1r4pt0r/9acdbca0792cc1c8eece039b6246a537 to your computer and use it in GitHub Desktop.
Save v3l0c1r4pt0r/9acdbca0792cc1c8eece039b6246a537 to your computer and use it in GitHub Desktop.
SMAZ package decompressor (Work In Progress)
// compile with:
// $ gcc -o smaz smaz.c -Iucl-1.03/include -lucl -Lucl-1.03/build/src/.libs
// or if you have ucl in system:
// $ gcc -o smaz smaz.c -lucl
#include <stdlib.h>
#include <stdint.h>
#include <stdio.h>
#include <arpa/inet.h>
#include <ucl/ucl.h>
#define SMAZ 0x534d415a
#define OUTLEN 0x50000 * 20
typedef struct {
uint32_t magic;
uint32_t unknown;
uint32_t unknown1;
uint32_t size;
} smaz_hdr_t;
int main() {
/* read header */
smaz_hdr_t header;
if (fread(&header, 1, sizeof(header), stdin) != sizeof(header)) {
perror("fread(header)");
return 1;
}
/* check magic */
if (header.magic != htonl(SMAZ)) {
fprintf(stderr, "error: wrong magic: '%.4s'\n", header.magic);
return 1;
}
uint32_t flags = header.unknown1;
size_t compressed_size = ntohl(header.size);
do {
/* read rest of file to buffer */
void *buffer = malloc(header.size);
//compressed_size -= sizeof(header);
size_t to_read = compressed_size;
size_t done = 0;
fprintf(stderr, "info: I am about to read %u bytes\n", to_read);
while (to_read > 0) {
done = fread(buffer, 1, to_read, stdin);
fprintf(stderr, "info: done %u bytes\n", done);
if (done == 0) {
perror("fread(buffer)");
fprintf(stderr, "info: %u yet to be read, but got nothing\n", to_read);
break;
//return 1;
}
to_read -= done;
fprintf(stderr, "info: %u yet to be read\n", to_read);
}
/* decompress */
void *cursor = buffer;
unsigned int outlen = compressed_size + (compressed_size / 8) + 256;
uint8_t *output = (uint8_t*) calloc(outlen, 1);
int status = ucl_nrv2e_decompress_safe_8(buffer, compressed_size, output, &outlen, NULL);
if (status != 0) {
fprintf(stderr, "error: decompression failed with %x\n", status);
/* intentionally do not return, something was done either way */
}
fprintf(stderr, "info: I am about to write %u bytes\n", outlen);
if (fwrite(output, 1, outlen, stdout) != outlen) {
perror("fwrite");
return 1;
}
if (fread(&flags, 1, sizeof(flags), stdin) != sizeof(flags)) {
perror("fread(flags)");
return 1;
}
flags = ntohl(flags);
fprintf(stderr, "info: flags are %u\n", flags);
if (flags == 0) {
break;
}
if (fread(&compressed_size, 1, sizeof(uint32_t), stdin) != sizeof(uint32_t)) {
perror("fread(compressed_size)");
return 1;
}
compressed_size = ntohl(compressed_size);
fprintf(stderr, "info: next chunk compressed size is %u\n", compressed_size);
free(buffer);
} while (flags != 0);
/* clean up */
return 0;
}
@danielkucera
Copy link

How do you feed this?

@v3l0c1r4pt0r
Copy link
Author

How do you feed this?

You mean, where is input and output? You pipe complete SMAZ container on standard input and get decoded data on standard output.
In my case it was like:

./smaz < test.smaz > test.raw

where:

$ hexdump -C test.smaz | head -1
00000000  53 4d 41 5a 00 08 00 00  00 05 00 00 00 02 47 77  |SMAZ..........Gw|

@danielkucera
Copy link

but first you need to extract SMAZ from .PKG file. is there a programmatical way?

@danielkucera
Copy link

I skipped the header by this:

int main() {
  void* beg = malloc(0xb80);
  fread(beg, 1, 0xb80, stdin);
  /* read header */

but decoding is still failing for me...

# ./smaz < IPTV_TX_PKG_v4_0_0_0_20160427.PKG > out.raw
info: I am about to read 150295 bytes
info: done 150295 bytes
info: 0 yet to be read
error: decompression failed with ffffff36
info: I am about to write 169338 bytes
info: flags are 0

@danielkucera
Copy link

and this line is not very safe too:
https://gist.github.com/v3l0c1r4pt0r/9acdbca0792cc1c8eece039b6246a537#file-smaz-c-L30
I'm getting segfault:

# ./smaz < /dev/urandom > out.raw
Segmentation fault (core dumped)

@v3l0c1r4pt0r
Copy link
Author

but first you need to extract SMAZ from .PKG file. is there a programmatical way?

Unfortunately, dd only. I started writing Python library for that when hacking lkv for the first time, but never finished it. All that is done is as far as I remember ITEPKG itself, not SMEDIA, nor SMAZ. Should be helpful a little bit: https://github.com/v3l0c1r4pt0r/ittk.

Maybe one more thing. I have written a tool for coloring hexdumps few years ago. The last time I was extracting SMAZ containers, I used it together with ITEPKG, SMEDIA and SMAZ syntax definitions (the same ones that I used to make screenshots for wiki). Here are the links, if you want to give them a try:

@v3l0c1r4pt0r
Copy link
Author

v3l0c1r4pt0r commented Sep 2, 2019

I'm not sure if you did it right. In my case (LKV373A-fw/TX\ firmware/LKV373A_TX_20151028_PKG.PKG) it is 0xb70.

I know this is not the best code I've wrote :) I would like to rewrite it from scratch, when I find some time to do that. For now I want to see where the rabbit hole leads me :)

Edit: Ah, one more note. Ignore the errors and other junk printed to stderr. The juice is on stdout, regardless of any errors happening in the meantime.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment