Skip to content
Browse files

initial checkin

  • Loading branch information...
0 parents commit 93073d683d6c1225a6aa521f517fc453f05f6ad3 @badeip committed Dec 27, 2011
Showing with 1,133 additions and 0 deletions.
  1. +71 −0 README
  2. +59 −0 include/kcache.h
  3. +50 −0 makefile
  4. +79 −0 src/crypto.c
  5. +471 −0 src/kcache.c
  6. +363 −0 src/lzss.c
  7. +40 −0 src/util.c
71 README
@@ -0,0 +1,71 @@
+// By: petter wahlman, http://www.twitter.com/badeip
+//
+// About:
+// Encrypt/decrypt iOS kernelcache
+//
+// Notes: the code is POC, and the syntax sucks.
+//
+// Example usage: (a $ prefix is used to indicate commands that must be executed in a terminal)
+
+$ mkdir -p ~/iphone/ipsw/
+$ cd ~/iphone/ipsw
+$ mv ~/Downloads/iPhone3,1_5.1_9B5117b_Restore.ipsw .
+$ 7z x iPhone3,1_5.0.1_9A405_Restore.ipsw
+$ kcache --in kernelcache.release.n90 --iv 5533d04f6c805307c2f2a573339a6850 --key 0ef7774fea99e988487f92f8765e4678aeefc8a14de40b95ba210955445eff22
+
+// kcache/kernelcache.bin will now contain the decrypted kernelcache image:
+
+$ file kcache/kernelcache.bin
+kcache/kernelcache.bin: Mach-O executable arm
+
+
+// Example output:
+
+iv: 5533d04f6c805307c2f2a573339a6850
+key: 0ef7774fea99e988487f92f8765e4678aeefc8a14de40b95ba210955445eff22
+in: kernelcache.release.n90
+wd: ./kcache
+
+opening: kernelcache.release.n90
+magic: Img3
+filesize: 6516484
+contentsize: 6516464
+certarea: 6514360
+filetype: krnl
+
+0x00000000 0x00000004: TYPE
+0x00000020 0x0063659b: DATA
+0x006365cc 0x00000004: SEPO
+0x006365e8 0x00000038: KBAG
+0x00636634 0x00000038: KBAG
+0x006366b8 0x00000080: SHSH
+0x00636744 0x00000794: CERT
+creating: ./kcache/kernelcache.data
+
+AES decrypt:(len: 6514075 pad: 11)
+
+plaintext (excerpt):
+ dc e5 5d 51 97 c1 04 0d e4 72 bb 64 36 13 25 2a | ..]Q.....r.d6.%*
+ b4 ab eb 67 a7 55 e6 81 7b 3c 9a 5b ac 99 55 40 | ...g.U..{<.[..U@
+ 65 97 f3 a8 c6 bf fc 7c 5b c8 03 56 2b 2c 88 6d | e......|[..V+,.m
+ b3 2b 35 5d 52 89 5d 1b d3 43 77 63 6c 62 a4 46 | .+5]R.]..Cwclb.F
+ b9 39 e4 82 64 e9 7f 49 35 b5 58 95 25 00 e1 1d | .9..d..I5.X.%...
+ f3 aa 31 16 78 65 2c b1 10 d0 b5 9a ed 65 f1 ad | ..1.xe,......e..
+ 9b e5 83 af b5 c0 a6 0e c2 79 bb 16 ff c9 f1 5a | .........y.....Z
+ ce 09 1e 16 3e 8f ce ab 95 df 5b 2a 9f 04 ad 87 | ....>.....[*....
+
+decrypted (excerpt):
+ 63 6f 6d 70 6c 7a 73 73 5b 4c f0 db 00 b1 f0 00 | complzss[L......
+ 00 63 64 1b 00 00 00 00 00 00 00 00 00 00 00 00 | .cd.............
+ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 | ................
+ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 | ................
+ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 | ................
+ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 | ................
+ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 | ................
+ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 | ................
+
+creating: ./kcache/kernelcache.data.pt
+creating: ./kcache/kernelcache.hdr
+creating: ./kcache/kernelcache.lzss
+creating: ./kcache/kernelcache.bin
+
59 include/kcache.h
@@ -0,0 +1,59 @@
+#ifndef KCACHE_H
+#define KCACHE_H
+
+//---[ macros: ]----------------------------------------------------------------
+#define TOI(a) (a[0]<<24|a[1]<<16|a[2]<<8|a[3])
+#define TOA(w) { \
+ char *c = (char *)&w; \
+ if (isprint(c[0]) && isprint(c[1]) && isprint(c[2]) && isprint(c[3])) \
+ printf("%c%c%c%c\n", c[3], c[2], c[1], c[0]); \
+}
+#define TOX(s, bufsize, buf) \
+{ \
+ int i; \
+ int slen = strlen(s); \
+ for (i = 0; (i < slen) && (i < (bufsize << 1)); i++) { \
+ s[i] |= 0x20; \
+ if (s[i] >= '0' && (s[i] <= '9')) \
+ s[i] -= '0'; \
+ else \
+ s[i] -= 87; \
+ if (i % 2) \
+ buf[i >> 1] |= s[i]; \
+ else \
+ buf[i >> 1] = s[i] << 4; \
+ } \
+}
+
+//---[ prototypes: ]------------------------------------------------------------
+void lzss_compress(unsigned char *in, unsigned int len, FILE *outfile);
+void lzss_uncompress(unsigned char *in, unsigned int len, FILE *outfile);
+int aes_decrypt(void *in, size_t len, unsigned char **out, unsigned char *iv, unsigned char *key);
+int aes_encrypt(void *in, size_t len, unsigned char **out, unsigned char *iv, unsigned char *key);
+void print_hex(void *data, size_t len, unsigned int flag);
+
+//---[ structs: ]---------------------------------------------------------------
+struct img3 {
+ unsigned int magic;
+ unsigned int filesize;
+ unsigned int contentsize;
+ unsigned int certarea;
+ unsigned int filetype;
+};
+
+struct tag {
+ unsigned int magic;
+ unsigned int blocksize;
+ unsigned int payloadsize;
+};
+
+//---[ flags: ]----------------------------------------------------------------
+// hex output flags:
+#define HEX_SKIP_ASCII 1
+#define HEX_SKIP_WS 2
+#define HEX_SKIP_TAB 4
+#define HEX_SKIP_NL 8
+
+
+
+#endif
50 makefile
@@ -0,0 +1,50 @@
+# (!c) petter wahlman
+#
+CC = gcc
+
+SRCDIR = ./src
+OBJDIR = ./obj
+BINDIR = ./bin
+INCLUDE = ./include
+
+BINARY = $(BINDIR)/kcache
+
+CFLAGS = -I $(INCLUDE) -g -Wall
+LDFLAGS = -lcrypto
+
+VPATH = $(SRCDIR)
+
+BINARY_OBJ = \
+ $(OBJDIR)/kcache.o \
+ $(OBJDIR)/crypto.o \
+ $(OBJDIR)/util.o \
+ $(OBJDIR)/lzss.o
+
+$(OBJDIR)/%.o: %.c
+ $(CC) -c $< $(CFLAGS) -o $@
+
+.PHONY:
+all: make_dirs $(BINARY) install
+
+$(BINARY): $(BINARY_OBJ)
+ $(CC) -o $@ $^ $(LDFLAGS)
+
+.PHONY:
+clean:
+ @rm -rvf \
+ $(BINARY) \
+ $(BINARY_OBJ)
+ @-ls ./kcache/*kernelcache.* |grep -v release | xargs rm -v
+
+.PHONY:
+make_dirs:
+ @mkdir -p $(OBJDIR) $(BINDIR)
+
+.PHONY:
+install:
+ @if [ -d ~/bin ]; then \
+ install $(BINARY) ~/bin; \
+ else \
+ sudo install $(BINARY) /usr/local/bin; \
+ fi
+
79 src/crypto.c
@@ -0,0 +1,79 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <openssl/aes.h>
+
+#include "kcache.h"
+
+// the last 4 bytes are not encrypted with decodeimg3.pl
+// define 'SKIP_LAST_WORD' to make this output identical
+#define SKIP_LAST_WORD
+
+int aes_decrypt(void *in, size_t len, unsigned char **out, unsigned char *iv, unsigned char *key)
+{
+ AES_KEY aeskey;
+ int ret;
+
+ if (!len)
+ return 0;
+
+ ret = AES_set_decrypt_key(key, 256, &aeskey);
+ assert(!ret);
+
+ printf("(len: %zd pad: %zd)\n", len, len % 16);
+ len += len % 16;
+
+ *out = calloc(1, len); // consider padding..
+ assert(*out);
+
+#ifdef SKIP_LAST_WORD
+ AES_cbc_encrypt(in, *out, len-4, &aeskey, iv, AES_DECRYPT);
+ memcpy(*out + (len - 4), in + (len - 4), 4);
+#else
+ AES_cbc_encrypt(in, *out, len, &aeskey, iv, AES_DECRYPT);
+#endif
+
+ printf("\nplaintext (excerpt):\n");
+ print_hex(in, 128, 0);
+
+ printf("decrypted (excerpt):\n");
+ print_hex(*out, 128, 0);
+
+ return 0;
+}
+
+int aes_encrypt(void *in, size_t len, unsigned char **out, unsigned char *iv, unsigned char *key)
+{
+ AES_KEY aeskey;
+ int ret;
+
+ if (!len)
+ return 0;
+
+ ret = AES_set_encrypt_key(key, 256, &aeskey);
+ assert(!ret);
+
+ printf("(len: %ld pad: %ld)\n", len, len % 16);
+ len += len % 16;
+
+ *out = calloc(1, len); // consider padding..
+ assert(*out);
+
+#ifdef SKIP_LAST_WORD
+ AES_cbc_encrypt(in, *out, len-4, &aeskey, iv, AES_ENCRYPT);
+ memcpy(*out + (len - 4), in + (len - 4), 4);
+#else
+ AES_cbc_encrypt(in, *out, len, &aeskey, iv, AES_ENCRYPT);
+#endif
+
+ printf("\nplaintext (excerpt):\n");
+ print_hex(in, 128, 0);
+
+ printf("ciphertext (excerpt):\n");
+ print_hex(*out, 128, 0);
+
+ return 0;
+}
+
+
471 src/kcache.c
@@ -0,0 +1,471 @@
+// by petter wahlman, petter@wahlman.no
+//
+// for compatibility with decodeimg3.pl, compile with -D SKIP_LAST_WORD
+// and supply --nostrip --nodecompress
+
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <string.h>
+#include <libgen.h>
+#include <unistd.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <ctype.h>
+#include <getopt.h>
+#include <sys/mman.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include "kcache.h"
+
+// the last 4 bytes are not encrypted with decodeimg3.pl
+// define 'SKIP_LAST_WORD' to make this output identical
+//#define SKIP_LAST_WORD
+
+#define FILE_RELEASE "kernelcache.release"
+#define FILE_HDR "kernelcache.hdr"
+#define FILE_LZSS "kernelcache.lzss"
+#define FILE_BIN "kernelcache.bin"
+
+//---[ cml switches: ]----------------------------------------------------------
+int opt_encrypt = 0;
+int opt_decrypt = 1;
+int opt_compress = 0;
+int opt_decomp = 1;
+int opt_strip = 1;
+
+
+void print_usage(void)
+{
+ printf("usage: img3 [option(s)]\n"
+ " -h, --help this information\n"
+ " -i, --in <filename> input file (default ./kcache/kernelcache.release.n90,\n"
+ " or ./kcache/kernelcache.bin if --encrypt is supplied)\n"
+ " -w, --wd <directory> work directory (default ./kcache)\n"
+ " -k, --key <key> AES key\n"
+ " -v, --iv <iv> AES init vector\n"
+ " -e, --encrypt encrypt data (inverse of default)\n"
+ // don't use these flags unless you know what you are doing:
+ //" -e, --encrypt encrypt data\n"
+ //" -c, --compress compress data\n"
+ //" -D, --nodecompess don't decompress lzss container\n"
+ //" -S, --nostrip don't strip lzss header\n"
+ );
+}
+
+struct tag *find_tag(unsigned char *data, unsigned int len, char *tagname)
+{
+ unsigned char *ptr;
+ struct tag *tag;
+
+ ptr = data;
+ do {
+ tag = (typeof(tag)) ptr;
+ if (!tagname) {
+ printf("0x%08lx 0x%08x: ", ptr - data, tag->payloadsize);
+ TOA(tag->magic);
+ } else {
+ if (tag->magic == TOI(tagname))
+ return tag;
+ else if (tag->magic == TOI("DATA"));// type of image:
+ else if (tag->magic == TOI("TYPE"));// type of image:
+ else if (tag->magic == TOI("SDOM"));// security domain:
+ else if (tag->magic == TOI("PROD"));// production mode:
+ else if (tag->magic == TOI("CHIP"));// chip to be used:
+ else if (tag->magic == TOI("BORD"));// board to be used:
+ else if (tag->magic == TOI("KBAG"));// key and iv required to decrypt encrypted data
+ else if (tag->magic == TOI("SHSH"));// encrypted sha1 hash of the file:
+ else if (tag->magic == TOI("CERT"));// certificate:
+ else if (tag->magic == TOI("ECID"));// exclusive chip id:
+ else if (tag->magic == TOI("SEPO"));// security epoch
+ else if (tag->magic == TOI("VERS"));// iBoot version of the image
+ else {
+ fprintf(stderr, "error, unknown magic\n");
+ break;
+ }
+ }
+ ptr += tag->blocksize;
+ } while(((char *)ptr - (char *)data) < len);
+
+ return NULL;
+}
+
+// todo: consider creating dest. directories
+int copy_file(char *src, char *dst, mode_t mode)
+{
+ char buf[4096];
+ int fd[2];
+ int nr, nw;
+
+ fd[0] = open(src, O_RDONLY);
+ if (-1 == fd[0]) {
+ fprintf(stderr, "error, could not open: %s: %s\n", src, strerror(errno));
+ return 1;
+ }
+
+ fd[1] = open(src, O_WRONLY | O_CREAT | O_TRUNC, mode);
+ if (-1 == fd[0]) {
+ fprintf(stderr, "error, could not open: %s: %s\n", dst, strerror(errno));
+ return 1;
+ }
+
+ for (;;) {
+ nw = read(fd[0], buf, sizeof(buf));
+ if (nw < 1) break;
+ nr = write(fd[1], buf, nw);
+ if (nw < 1) break;
+ }
+
+ close(fd[0]);
+ close(fd[1]);
+
+ return 0;
+}
+
+// encrypt and compress
+int kcache_encrypt(char *in, char *wd, unsigned char *iv, unsigned char *key)
+{
+ unsigned char *ciphertext;
+ unsigned char *data;
+ struct stat st;
+ struct img3 *img;
+ struct tag *tag;
+ FILE *fp;
+ int fd;
+
+ // compress data, and copy the result to output file
+ printf("opening: %s\n", in);
+ fd = open(in, O_RDONLY);
+ if (-1 == fd) {
+ fprintf(stderr, "error, unable to open %s: %s\n", in, strerror(errno));
+ return 1;
+ }
+
+ if (chdir(wd)) {
+ fprintf(stderr, "error, could not chdir to %s: %s\n", wd, strerror(errno));
+ return 1;
+ }
+
+ fstat(fd, &st);
+ data = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
+ if (MAP_FAILED == data) {
+ perror("mmap");
+ close(fd);
+ return 1;
+ }
+ close(fd);
+
+ printf("compressing: %s/mod.kernelcache.lzss\n", wd);
+ fp = fopen("./mod.kernelcache.lzss", "wb");
+ assert(fp);
+
+ lzss_compress(data, st.st_size, fp);
+ fclose(fp);
+ munmap(data, st.st_size);
+
+//-------------------------------------------------------------------------------------------------
+ unsigned char *buf;
+ size_t size;
+
+ printf("opening: %s/kernelcache.hdr", wd);
+ fd = open("./kernelcache.hdr", O_RDONLY);
+ if (-1 == fd) {
+ fprintf(stderr, "error, unable to open %s: %s\n", "kernelcache.hdr", strerror(errno));
+ return 1;
+ }
+
+ fstat(fd, &st);
+ size = st.st_size;
+
+ buf = malloc(size);
+ read(fd, buf, size);
+ close(fd);
+
+ printf("hdr:\n");
+ print_hex(buf, 64, 0);
+
+ printf("opening: %s/mod.kernelcache.lzss\n", wd);
+ fd = open("./mod.kernelcache.lzss", O_RDONLY);
+ if (-1 == fd) {
+ fprintf(stderr, "error, unable to open %s: %s\n", "mod.kernelcache.lzss", strerror(errno));
+ return 1;
+ }
+
+ fstat(fd, &st);
+ buf = realloc(buf, st.st_size + size);
+
+ read(fd, buf + size, st.st_size);
+ close(fd);
+
+ printf("creating: %s/mod.kernelcache.data.pt\n", wd);
+ fd = open("./mod.kernelcache.data.pt", O_WRONLY | O_CREAT | O_TRUNC, 0644);
+ if (-1 == fd) {
+ fprintf(stderr, "error, unable to open %s: %s\n", "mod.kernelcache.data.pt", strerror(errno));
+ return 1;
+ }
+
+ write(fd, buf, size + st.st_size);
+ close(fd);
+
+ tag = NULL;
+
+ printf("creating: %s/mod.kernelcache.data\n", wd);
+ printf("\nAES encrypt:");
+ aes_encrypt(buf, size + st.st_size, &ciphertext, iv, key);
+ free(buf); buf = NULL;
+
+ printf("locating data tag:\n");
+ printf("opening: %s/kernelcache.release.n90\n", wd);
+ fd = open("./kernelcache.release.n90", O_RDONLY);
+ if (-1 == fd) {
+ fprintf(stderr, "error, unable to open %s: %s\n", in, strerror(errno));
+ return 1;
+ }
+
+ fstat(fd, &st);
+ buf = malloc(st.st_size);
+ read(fd, buf, st.st_size);
+
+ // error:?
+ close(fd);
+ img = (typeof(img)) buf;
+
+ tag = find_tag(buf + sizeof(*img), img->contentsize, "DATA");
+ if (!tag) {
+ fprintf(stderr, "error, unable to locate \"DATA\" tag\n");
+ return 1;
+ }
+
+ printf("tag found at: 0x%08lx\n", (char *)tag - (char *)buf);
+ printf("creating: %s/mod.kernelcache.data\n", wd);
+ fd = open("./mod.kernelcache.data", O_WRONLY | O_CREAT | O_TRUNC, 0644);
+ if (-1 == fd) {
+ fprintf(stderr, "error, unable to open %s: %s\n", "mod.kernelcache.data", strerror(errno));
+ return 1;
+ }
+
+ write(fd, ciphertext, tag->payloadsize);
+ free(buf); buf = NULL;
+ free(ciphertext); ciphertext = NULL;
+
+ // copy kernelcache.release.n90 -> mod.kernelcache.release.n90
+ // inject data in tag offset
+
+ return 0;
+}
+
+// decrypt and uncompress
+// TODO: add contentsize, not img?
+int kcache_decrypt(char *in, char *wd, unsigned char *iv, unsigned char *key)
+{
+ unsigned char *plaintext;
+ unsigned char *data;
+ unsigned char *ptr;
+ struct stat st;
+ struct img3 *img;
+ struct tag *tag;
+ FILE *fp;
+ int fd;
+
+ // open input file:
+ printf("opening: %s\n", in);
+ fd = open(in, O_RDONLY);
+ if (-1 == fd) {
+ perror(in);
+ return 1;
+ }
+
+ if (chdir(wd)) {
+ fprintf(stderr, "error, could not chdir to %s: %s\n", wd, strerror(errno));
+ return 1;
+ }
+
+ fstat(fd, &st);
+ data = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
+ close(fd);
+
+ // check input file integrity:
+ img = (typeof(img)) data;
+ if (img->magic != TOI("Img3")) {
+ fprintf(stderr, "error, incorrect magic.\n");
+ goto end;
+ }
+
+ if (img->filesize != st.st_size) {
+ fprintf(stderr, "error, incorrect filesize\n");
+ goto end;
+ }
+
+ printf("magic: "); TOA(img->magic);
+ printf("filesize: %d\n", img->filesize);
+ printf("contentsize: %d\n", img->contentsize);
+ printf("certarea: %d\n", img->certarea);
+ printf("filetype: "); TOA(img->filetype);
+ printf("\n");
+
+ img = (typeof(img)) data;
+ ptr = data + sizeof(*img);
+
+ // print all tags:
+ find_tag(ptr, img->contentsize, NULL);
+
+ tag = find_tag(data + sizeof(*img), img->contentsize, "DATA");
+ if (!tag) {
+ fprintf(stderr, "error, unable to locate \"DATA\" tag\n");
+ return 1;
+ }
+
+// write tag:
+ printf("creating: %s/kernelcache.data\n", wd);
+ fd = open("./kernelcache.data", O_WRONLY | O_CREAT | O_TRUNC, 0644);
+ write(fd, tag + 1, tag->payloadsize);
+ close(fd);
+
+// write decrypted tag
+ printf("\nAES decrypt:");
+ aes_decrypt(tag + 1, tag->payloadsize, &plaintext, iv, key);
+ printf("creating: %s/kernelcache.data.pt\n", wd);
+ fd = open("./kernelcache.data.pt", O_WRONLY | O_CREAT | O_TRUNC, 0644);
+ write(fd, plaintext, tag->payloadsize);
+ close(fd);
+
+// write decrypted header:
+ printf("creating: %s/kernelcache.hdr\n", wd);
+ fd = open("./kernelcache.hdr", O_WRONLY | O_CREAT | O_TRUNC, 0644);
+ write(fd, plaintext, 0x180);
+ close(fd);
+
+// write decrypted lzss container:
+ printf("creating: %s/kernelcache.lzss\n", wd);
+ fd = open("./kernelcache.lzss", O_WRONLY | O_CREAT | O_TRUNC, 0644);
+ write(fd, plaintext + 0x180, tag->payloadsize - 0x180);
+ close(fd);
+
+// write extracted MACH-O kernelcache
+ printf("creating: %s/kernelcache.bin\n", wd);
+ fp = fopen("./kernelcache.bin", "wb");
+ assert(fp);
+ lzss_uncompress(plaintext + 0x180, tag->payloadsize - 0x180, fp);
+ fclose(fp);
+
+end:
+ free(plaintext); plaintext = NULL;
+ if (data)
+ munmap(data, st.st_size);
+
+ return 0;
+}
+
+int main(int argc, char **argv)
+{
+ char *in;
+ char *wd;
+ unsigned char iv[] = {
+ 0x30, 0x1c, 0x0d, 0xb0, 0xf6, 0xfc, 0x3a, 0x92,
+ 0xc3, 0x4f, 0x34, 0xb2, 0xdf, 0xf5, 0xd9, 0x2f};
+ unsigned char key[] = { // IOS 4.3.3, Durango 8J2:
+ 0x65, 0xc3, 0x51, 0x33, 0x0f, 0x82, 0x48, 0x89,
+ 0xfe, 0x25, 0xb1, 0x4e, 0x2d, 0x0c, 0xb5, 0xe2,
+ 0x91, 0x99, 0x1a, 0x74, 0x9f, 0x13, 0x76, 0x1b,
+ 0x82, 0x5a, 0x70, 0xf3, 0x17, 0xf0, 0x05, 0xaa};
+
+ in = wd = NULL;
+ while (1) {
+ unsigned int c;
+ int option_index = 0;
+ static struct option long_options[] = {
+ { "help", 0, 0, 'h' },
+ { "in", 1, 0, 'i' },
+ { "wd", 1, 0, 'w' },
+ { "key", 1, 0, 'k' },
+ { "iv", 1, 0, 'v' },
+ { "encrypt", 0, 0, 'e' },
+ // developer opts:
+ { "compress", 0, 0, 'c' },
+ { "nodecomp", 0, 0, 'D' },
+ { "nostrip", 0, 0, 'S' },
+ { NULL, 0, 0, 0 }
+ };
+
+ c = getopt_long(argc, argv, "hi:w:k:v:ecDS", long_options, &option_index);
+ if (-1 == c)
+ break;
+
+ switch (c) {
+ case 'h':
+ print_usage();
+ exit(0);
+ case 'i':
+ in = strdup(optarg);
+ break;
+ case 'w':
+ wd = optarg;
+ break;
+ case 'k':
+ TOX(optarg, sizeof(key), key);
+ break;
+ case 'v':
+ TOX(optarg, sizeof(iv), iv);
+ break;
+ case 'e':
+ opt_encrypt = 1;
+ break;
+ case 'D': // nodecomp
+ opt_decomp = 0;
+ break;
+ case 'S': // nostrip
+ opt_strip = 0;
+ break;
+ case 'c':
+ opt_compress = 1;
+ break;
+ default:
+ exit(1);
+ }
+ }
+
+ if (!in) {
+ fprintf(stderr, "error, no input file specified\n");
+ return 1;
+ }
+
+ if (opt_decomp && opt_compress) {
+ fprintf(stderr, "error, --decompress and --compress are mutually exclusive\n");
+ return 1;
+ }
+
+ printf("iv: ");
+ print_hex(iv, sizeof(iv), -1);
+
+ printf("key: ");
+ print_hex(key, sizeof(key), -1);
+
+ if (opt_encrypt) {
+ char *tmp = strdup(in);
+ //in = "./kcache/kernelcache.bin";
+ //wd = "./kcache";
+ asprintf(&wd, "%s", dirname(tmp));
+ free(tmp);
+
+ printf("in: %s\n", in);
+ printf("wd: %s\n", wd);
+ printf("\n");
+ kcache_encrypt(in, wd, iv, key);
+ } else {
+ char *tmp = strdup(in);
+ //in = "./kcache/kernelcache.release.n90";
+ //wd = "./kcache";
+ asprintf(&wd, "%s/kcache", dirname(tmp));
+ free(tmp);
+ mkdir(wd, 0755);
+
+ printf("in: %s\n", in);
+ printf("wd: %s\n", wd);
+ printf("\n");
+ kcache_decrypt(in, wd, iv, key);
+ }
+
+ return 0;
+}
363 src/lzss.c
@@ -0,0 +1,363 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <sys/stat.h>
+
+#define N 4096
+#define F 18
+#define THRESHOLD 2
+#define NIL N
+
+unsigned char text_buf[N + F - 1];
+int lson[N + 1];
+int rson[N + 257];
+int dad[N + 1];
+
+void init_tree(int *rson, int *dad)
+{
+ int i;
+
+ for (i = N + 1; i <= N + 256; i++)
+ rson[i] = NIL;
+
+ for (i = 0; i < N; i++)
+ dad[i] = NIL;
+}
+
+void insert_node(int r, int *match_pos, int *match_len)
+{
+ int i, p, cmp;
+ unsigned char *key;
+
+ cmp = 1;
+ key = &text_buf[r];
+ p = N + 1 + key[0];
+ rson[r] = lson[r] = NIL;
+ *match_len = 0;
+
+ for (;;) {
+ if (cmp >= 0) {
+ if (rson[p] != NIL) p = rson[p];
+ else {
+ rson[p] = r;
+ dad[r] = p;
+ return;
+ }
+ } else {
+ if (lson[p] != NIL)
+ p = lson[p];
+ else {
+ lson[p] = r;
+ dad[r] = p;
+ return;
+ }
+ }
+
+ for (i = 1; i < F; i++)
+ if ((cmp = key[i] - text_buf[p + i]) != 0)
+ break;
+
+ if (i > *match_len) {
+ *match_pos = p;
+
+ if ((*match_len = i) >= F)
+ break;
+ }
+ }
+
+ dad[r] = dad[p];
+ lson[r] = lson[p];
+ rson[r] = rson[p];
+ dad[lson[p]] = r;
+ dad[rson[p]] = r;
+
+ if (rson[dad[p]] == p)
+ rson[dad[p]] = r;
+ else
+ lson[dad[p]] = r;
+
+ dad[p] = NIL;
+}
+
+void delete_node(int p)
+{
+ int q;
+
+ if (dad[p] == NIL)
+ return;
+
+ if (rson[p] == NIL)
+ q = lson[p];
+ else if (lson[p] == NIL)
+ q = rson[p];
+ else {
+ q = lson[p];
+
+ if (rson[q] != NIL) {
+ do {
+ q = rson[q];
+ } while (rson[q] != NIL);
+
+ rson[dad[q]] = lson[q];
+ dad[lson[q]] = dad[q];
+ lson[q] = lson[p];
+ dad[lson[p]] = q;
+ }
+
+ rson[q] = rson[p];
+ dad[rson[p]] = q;
+ }
+
+ dad[q] = dad[p];
+
+ if (rson[dad[p]] == p)
+ rson[dad[p]] = q;
+ else
+ lson[dad[p]] = q;
+
+ dad[p] = NIL;
+}
+
+void lzss_compress(unsigned char *in, unsigned int len, FILE *outfile)
+{
+ int i, c, size, r, s, last_match_sizegth, code_buf_ptr;
+ unsigned char code_buf[17], mask;
+ unsigned int textsize;
+ unsigned int codesize;
+ int match_pos;
+ int match_size;
+ int idx;
+
+ textsize = 0;
+ codesize = 0;
+ match_pos = 0;
+ match_size = 0;
+ idx = 0;
+
+ init_tree(rson, dad);
+ code_buf[0] = 0;
+
+ code_buf_ptr = mask = 1;
+ s = 0;
+ r = N - F;
+
+ for (i = 0; i < r; i++)
+ text_buf[i] = ' ';
+
+ for (size = 0; size < F; size++) {
+ c = in[idx++];
+ if (idx > len)
+ break;
+ text_buf[r + size] = c;
+ }
+
+ if (!(textsize = size))
+ return;
+
+ for (i = 1; i <= F; i++)
+ insert_node(r - i, &match_pos, &match_size);
+
+ insert_node(r, &match_pos, &match_size);
+
+ do {
+ if (match_size > size)
+ match_size = size;
+
+ if (match_size <= THRESHOLD) {
+ match_size = 1;
+ code_buf[0] |= mask;
+ code_buf[code_buf_ptr++] = text_buf[r];
+ } else {
+ code_buf[code_buf_ptr++] = (unsigned char) match_pos;
+ code_buf[code_buf_ptr++] = (unsigned char) (((match_pos >> 4) & 0xf0) | (match_size - (THRESHOLD + 1)));
+ }
+
+ if ((mask <<= 1) == 0) {
+ for (i = 0; i < code_buf_ptr; i++)
+ putc(code_buf[i], outfile);
+
+ codesize += code_buf_ptr;
+ code_buf[0] = 0;
+ code_buf_ptr = mask = 1;
+ }
+
+ last_match_sizegth = match_size;
+
+ for (i = 0; i < last_match_sizegth; i++) {
+ c = in[idx++];
+ //if (idx > size)
+ if (idx > len)
+ break;
+
+ delete_node(s);
+ text_buf[s] = c;
+
+ if (s < F - 1)
+ text_buf[s + N] = c;
+
+ s = (s + 1) & (N - 1);
+ r = (r + 1) & (N - 1);
+ insert_node(r, &match_pos, &match_size);
+ }
+
+ while (i++ < last_match_sizegth) {
+ delete_node(s);
+ s = (s + 1) & (N - 1);
+ r = (r + 1) & (N - 1);
+
+ if (--size)
+ insert_node(r, &match_pos, &match_size);
+ }
+ } while (size > 0);
+
+ if (code_buf_ptr > 1) {
+ for (i = 0; i < code_buf_ptr; i++)
+ putc(code_buf[i], outfile);
+ codesize += code_buf_ptr;
+ }
+}
+
+void lzss_compress_org(FILE *infile, FILE *outfile)
+{
+ int i, c, len, r, s, last_match_length, code_buf_ptr;
+ unsigned char code_buf[17], mask;
+ unsigned int textsize;
+ unsigned int codesize;
+ int match_pos;
+ int match_len;
+
+ textsize = 0;
+ codesize = 0;
+ match_pos = 0;
+ match_len = 0;
+
+ init_tree(rson, dad);
+ code_buf[0] = 0;
+
+ code_buf_ptr = mask = 1;
+ s = 0;
+ r = N - F;
+
+ for (i = s; i < r; i++)
+ text_buf[i] = ' ';
+
+ for (len = 0; len < F && (c = getc(infile)) != EOF; len++)
+ text_buf[r + len] = c;
+
+ if ((textsize = len) == 0)
+ return;
+
+ for (i = 1; i <= F; i++)
+ insert_node(r - i, &match_pos, &match_len);
+
+ insert_node(r, &match_pos, &match_len);
+
+ do {
+ if (match_len > len)
+ match_len = len;
+
+ if (match_len <= THRESHOLD) {
+ match_len = 1;
+ code_buf[0] |= mask;
+ code_buf[code_buf_ptr++] = text_buf[r];
+ } else {
+ code_buf[code_buf_ptr++] = (unsigned char) match_pos;
+ code_buf[code_buf_ptr++] = (unsigned char) (((match_pos >> 4) & 0xf0) | (match_len - (THRESHOLD + 1)));
+ }
+
+ if ((mask <<= 1) == 0) {
+ for (i = 0; i < code_buf_ptr; i++)
+ putc(code_buf[i], outfile);
+
+ codesize += code_buf_ptr;
+ code_buf[0] = 0;
+ code_buf_ptr = mask = 1;
+ }
+
+ last_match_length = match_len;
+
+ for (i = 0; i < last_match_length &&
+ (c = getc(infile)) != EOF; i++) {
+ delete_node(s);
+ text_buf[s] = c;
+
+ if (s < F - 1)
+ text_buf[s + N] = c;
+
+ s = (s + 1) & (N - 1);
+ r = (r + 1) & (N - 1);
+ insert_node(r, &match_pos, &match_len);
+ }
+
+ while (i++ < last_match_length) {
+ delete_node(s);
+ s = (s + 1) & (N - 1);
+ r = (r + 1) & (N - 1);
+
+ if (--len)
+ insert_node(r, &match_pos, &match_len);
+ }
+ } while (len > 0);
+
+ if (code_buf_ptr > 1) {
+ for (i = 0; i < code_buf_ptr; i++)
+ putc(code_buf[i], outfile);
+
+ codesize += code_buf_ptr;
+ }
+
+#ifdef PROGRESS
+ printf("In : %ld bytes\n", textsize);
+ printf("Out: %ld bytes\n", codesize);
+ printf("Out/In: %.3f\n", (double)codesize / textsize);
+#endif
+}
+
+
+void lzss_uncompress(unsigned char *in, unsigned int len, FILE *outfile)
+{
+ int i, j, k, r, c;
+ unsigned int flags;
+ int idx;
+
+ for (i = 0; i < N - F; i++)
+ text_buf[i] = ' ';
+
+ r = N - F;
+ flags = 0;
+ idx = 0;
+ while (idx < len) {
+ if (!((flags >>= 1) & 256)) {
+ c = in[idx++];
+ if (idx >= len)
+ break;
+ flags = c | 0xff00;
+ }
+
+ if (flags & 1) {
+ c = in[idx++];
+ putc(c, outfile);
+ text_buf[r++] = c;
+ r &= (N - 1);
+ continue;
+ }
+
+ i = in[idx++];
+ if (idx >= len)
+ break;
+
+ j = in[idx++];
+
+ i |= ((j & 0xf0) << 4);
+ j = (j & 0x0f) + THRESHOLD;
+
+ for (k = 0; k <= j; k++) {
+ c = text_buf[(i + k) & (N - 1)];
+ putc(c, outfile);
+ text_buf[r++] = c;
+ r &= (N - 1);
+ }
+ }
+}
+
40 src/util.c
@@ -0,0 +1,40 @@
+#include <stdio.h>
+#include <ctype.h>
+#include "kcache.h"
+
+void print_hex(void *data, size_t len, unsigned int flag)
+{
+ unsigned char *in = (unsigned char *)data;
+ int i, j;
+
+ if (!(flag & HEX_SKIP_TAB))
+ printf("\t");
+
+ i = 0;
+ while (i < len) {
+ for (j = 0; j < 16 && i + j < len; j++) {
+ printf("%02x", in[i + j]);
+ if (!(flag & HEX_SKIP_WS))
+ printf(" ");
+ }
+
+ while (j++ < 16)
+ printf(" ");
+
+ if (!(flag & HEX_SKIP_ASCII)) {
+ printf("| ");
+ for (j = 0; j < 16 && i + j < len; j++)
+ printf("%c", isprint(in[i + j]) ? in[i + j] : '.');
+ }
+ i += 16;
+ if (!(flag & HEX_SKIP_NL))
+ printf("\n");
+
+ if (!(flag & HEX_SKIP_TAB))
+ printf("\t");
+ }
+
+ printf("\n");
+}
+
+

0 comments on commit 93073d6

Please sign in to comment.
Something went wrong with that request. Please try again.