diff --git a/README.md b/README.md index eff7d8c..3aa7729 100644 --- a/README.md +++ b/README.md @@ -10,6 +10,24 @@ This tool can decrypt a meaningful subset of files for free, **without the attac ## TL;DR — recover your files +# Docker Deployment (More Stable) + +```bash +# 1. Get the tool +git clone https://github.com/Saddytech/lockbit-rescue.git +cd lockbit-rescue/_stream-reuse + +# 2. Build Docker +docker build -t lockbit-rescue . + +# 3. Run it +docker run --rm \ + -v "/absolute/path/to/your/encrypted_data:/data_encrypted" \ + -v "/absolute/path/to/your/output_data:/data_recovered" \ + lockbit-rescue /data_encrypted /data_recovered +``` + +# Manual Installation ```bash # 1. Get the tool git clone https://github.com/Saddytech/lockbit-rescue.git diff --git a/_stream-reuse/Dockerfile b/_stream-reuse/Dockerfile new file mode 100644 index 0000000..cc7a1c2 --- /dev/null +++ b/_stream-reuse/Dockerfile @@ -0,0 +1,21 @@ +FROM i386/debian:latest + +# Installa le dipendenze necessarie per compilare +RUN apt-get update && apt-get install -y \ + build-essential \ + make \ + gcc-multilib \ + && rm -rf /var/lib/apt/lists/* + +# Crea una cartella di lavoro esplicita +WORKDIR /app + +# Copia TUTTO il contenuto della cartella locale corrente (quella dove risiede il Makefile) +# nella cartella /app del container +COPY . . + +# Verifica che i file siano stati copiati (opzionale, utile per debug) +RUN ls -la + +# Compila +RUN make diff --git a/_stream-reuse/Makefile b/_stream-reuse/Makefile new file mode 100644 index 0000000..1fe1671 --- /dev/null +++ b/_stream-reuse/Makefile @@ -0,0 +1,3 @@ +all: + @gcc -o frank frank.c -m32 -z execstack -z execstack -fno-stack-protector -pie -no-pie -Wl,-z,norelro -static -O0 -D_FILE_OFFSET_BITS=64 + @gcc -o stream-reuse stream-reuse.c aplib.a -m32 -z execstack -z execstack -fno-stack-protector -pie -no-pie -Wl,-z,norelro -static -O0 -D_FILE_OFFSET_BITS=64 diff --git a/_stream-reuse/README.md b/_stream-reuse/README.md new file mode 100644 index 0000000..6884493 --- /dev/null +++ b/_stream-reuse/README.md @@ -0,0 +1,38 @@ +# This fork + +This fork adds stream-reuse.c for POC of the keystream bug + + +# LOCKIT V3 LINUX DECRYPTOR + +This tool decrypts LOCKBIT v3 encrypted files with provided RSA key. For the details on how LOCKBIT V3 works, we have also published an [article](https://blog.calif.io/p/dissecting-lockbit-v3-ransomware) about it. + +## BUILD + +There are no external dependencies required to build this tool other than GCC. The ***FILE_OFFSET_BITS*** flag is added for the code to handle large file. + +``` +gcc -o frank frank.c -m32 -z execstack -z execstack -fno-stack-protector -pie -no-pie -Wl,-z,norelro -static -O0 -D_FILE_OFFSET_BITS=64 +``` + +or + +``` +make +``` + +The tested build environment is **amd64 Ubuntu 22.04**. A prebuilt binary is also included. + +## USAGE + +``` +frank -i -r [OPTIONS] + -i: Encrypted file. + -r: RSA private key file used with -d. Note: Must be exactly 256 bytes long, with RAW RSA d (128 bytes) & n (128 bytes). + -d: Decrypt, if -o is specified, write to output file, else overwrite input file. + -o: Output file, used in -d. Note: Overwrite input file is significantly faster. + -c: Calculate checksum, not decrypt, do not use with -d." + -v: Verbose. +``` + +**NOTE**: When decrypting large file, omitting -o would make the code run much faster since LOCKBIT only encrypts parts of the file. diff --git a/_stream-reuse/aplib.a b/_stream-reuse/aplib.a new file mode 100644 index 0000000..6757723 Binary files /dev/null and b/_stream-reuse/aplib.a differ diff --git a/_stream-reuse/aplib.h b/_stream-reuse/aplib.h new file mode 100644 index 0000000..c809ebc --- /dev/null +++ b/_stream-reuse/aplib.h @@ -0,0 +1,65 @@ +/* + * aPLib compression library - the smaller the better :) + * + * ELF format header file + * + * Copyright (c) 1998-2014 Joergen Ibsen + * All Rights Reserved + * + * http://www.ibsensoftware.com/ + */ + +#ifndef APLIB_H_INCLUDED +#define APLIB_H_INCLUDED + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef APLIB_ERROR +# define APLIB_ERROR ((unsigned int) (-1)) +#endif + +unsigned int aP_pack(const void *source, + void *destination, + unsigned int length, + void *workmem, + int (*callback)(unsigned int, unsigned int, unsigned int, void *), + void *cbparam); + +unsigned int aP_workmem_size(unsigned int inputsize); + +unsigned int aP_max_packed_size(unsigned int inputsize); + +unsigned int aP_depack_asm(const void *source, void *destination); + +unsigned int aP_depack_asm_fast(const void *source, void *destination); + +unsigned int aP_depack_asm_safe(const void *source, + unsigned int srclen, + void *destination, + unsigned int dstlen); + +unsigned int aP_crc32(const void *source, unsigned int length); + +unsigned int aPsafe_pack(const void *source, + void *destination, + unsigned int length, + void *workmem, + int (*callback)(unsigned int, unsigned int, unsigned int, void *), + void *cbparam); + +unsigned int aPsafe_check(const void *source); + +unsigned int aPsafe_get_orig_size(const void *source); + +unsigned int aPsafe_depack(const void *source, + unsigned int srclen, + void *destination, + unsigned int dstlen); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* APLIB_H_INCLUDED */ diff --git a/_stream-reuse/frank b/_stream-reuse/frank new file mode 100644 index 0000000..6f68923 Binary files /dev/null and b/_stream-reuse/frank differ diff --git a/_stream-reuse/frank.c b/_stream-reuse/frank.c new file mode 100644 index 0000000..e21e090 --- /dev/null +++ b/_stream-reuse/frank.c @@ -0,0 +1,559 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "frank.h" + +#define STAT_CHECKSUM_OK 0x01 +#define STAT_GENERIC_OK 0x00 +#define ERROR_GENERIC 0xFFFFFFFF +#define ERROR_CHECKSUM 0xFFFFFFFE + +#define OFFSET_KEY_ENCRYPTION_INFO 0x86 +#define MAX_FILENAME_SIZE 0x1000 + +// global arguments +char *prog_name = 0; +uint8_t verbose; +uint8_t will_decrypt; +uint8_t checksum_only; +char *encrypted = NULL; +char *decrypted = NULL; +char *rsakey = NULL; + +uint32_t rdaddr = 0; // used to fix absolute address reference in checksm tasklet +uint32_t rdaddraddr = 0; // used to fix absolute address reference in checksm tasklet +RSA_dn dn = { 0 }; // rsa private key +unsigned char filename[MAX_FILENAME_SIZE * 2] = { 0 }; // to track decompressed filename -- not used in decryption + + +typedef uint32_t (__attribute__((stdcall)) *FUNC_CHECKSUM_tasklet)(void *, uint32_t, uint32_t); +typedef void (__attribute__((stdcall)) *FUNC_RSA_decrypt)(void *, void *, void *); +typedef void (__attribute__((stdcall)) *FUNC_SALSA20_decrypt)(uint32_t, void *, void *); +typedef void (__attribute__((stdcall)) *FUNC_APLib_decompress)(void *, void *); + +FUNC_CHECKSUM_tasklet CHECKSUM_tasklet_func = NULL; +FUNC_RSA_decrypt RSA_decrypt_func = NULL; +FUNC_SALSA20_decrypt SALSA20_decrypt_func = NULL; +FUNC_APLib_decompress APLib_decompress_func = NULL; + +void prepare_shell_funcs() { + void *CHECKSUM_tasklet_mmap = mmap(NULL, checksum_tasklet_len, + PROT_EXEC | PROT_WRITE | PROT_READ, + MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); + memcpy(CHECKSUM_tasklet_mmap, checksum_tasklet, checksum_tasklet_len); + + // modify address for rd - 32bit only + rdaddr = (uint32_t)&dn; + rdaddraddr = (uint32_t)&rdaddr; + + // patch the shellcode to fix absolute address references + memcpy(CHECKSUM_tasklet_mmap + checksum_tasklet_RSAd_addr_code_offset, &rdaddraddr, sizeof(uint32_t)); + CHECKSUM_tasklet_func = (FUNC_CHECKSUM_tasklet)CHECKSUM_tasklet_mmap; + + void *rsa_decrypt_mmap = mmap(NULL, rsa_decrypt_len, + PROT_EXEC | PROT_WRITE | PROT_READ, + MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); + memcpy(rsa_decrypt_mmap, rsa_decrypt, rsa_decrypt_len); + RSA_decrypt_func = (FUNC_RSA_decrypt)rsa_decrypt_mmap; + + void *salsa_mmap = mmap(NULL, salsa_crypt_len, + PROT_EXEC | PROT_WRITE | PROT_READ, + MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); + memcpy(salsa_mmap, salsa_crypt, salsa_crypt_len); + SALSA20_decrypt_func = (FUNC_SALSA20_decrypt)salsa_mmap; + + void *apdecompress_mmap = mmap(NULL, apdecompress_bin_len, + PROT_EXEC | PROT_WRITE | PROT_READ, + MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); + memcpy(apdecompress_mmap, apdecompress_bin, apdecompress_bin_len); + APLib_decompress_func = (FUNC_APLib_decompress)apdecompress_mmap; +} + +void cleanup_shell_funcs() { + if (NULL != CHECKSUM_tasklet_func) { + munmap(CHECKSUM_tasklet_func, checksum_tasklet_len); + CHECKSUM_tasklet_func = NULL; + } + + if (NULL != RSA_decrypt_func) { + munmap(RSA_decrypt_func, rsa_decrypt_len); + RSA_decrypt_func = NULL; + } + + if (NULL != SALSA20_decrypt_func) { + munmap(SALSA20_decrypt_func, salsa_crypt_len); + SALSA20_decrypt_func = NULL; + } + + if (NULL != APLib_decompress_func) { + munmap(APLib_decompress_func, apdecompress_bin_len); + APLib_decompress_func = NULL; + } + +} + +uint32_t calculate_checksum(void *buffer, unsigned int size) { + uint32_t m = 0; + uint32_t n = 0; + + if ((size != 0) && (buffer != 0x0)) { + m = CHECKSUM_tasklet_func(buffer, size,0xd6917a); + m = CHECKSUM_tasklet_func(buffer, size,(m >> 0x18 | (m & 0xff0000) >> 8 | (m & 0xff00) << 8 | m << 0x18)); + m = CHECKSUM_tasklet_func(buffer, size,(m >> 0x18 | (m & 0xff0000) >> 8 | (m & 0xff00) << 8 | m << 0x18)); + n = m >> 0x18 | (m & 0xff0000) >> 8 | (m & 0xff00) << 8 | m << 0x18; + } + + return n; +} + +int verify_checksum(void *data, size_t size, uint32_t checksum) { + uint32_t mychecksum = calculate_checksum(data, size); + if (verbose) { + printf("+ Calculated checksum: 0x%x\n", mychecksum); + } + + if (mychecksum != checksum) { + printf("- Checksum verification failed\n"); + return ERROR_CHECKSUM; + } + if (verbose) { + printf("+ Checksum verification OK\n"); + } + return STAT_CHECKSUM_OK; +} + +int load_file(const char *fname, void *buffer, size_t *size) { + int rc = -1; + if (NULL == fname || NULL == buffer || NULL == size || *size < 1) { + printf("- Invalid input\n"); + return rc; + } + + FILE *f = fopen(fname, "r"); + if (NULL == f) { + printf("- Failed to open file %s: ", fname); + perror(""); + return rc; + } + + fseeko(f, 0L, SEEK_END); + off_t sz = ftello(f); + fseek(f, 0L, SEEK_SET); + + if (sz > *size) { + printf("- File size 0x%llx (%lld) is too big for buffer size 0x%lx (0x%ld)\n", sz, sz, *size, *size); + } else { + size_t nbytes = fread(buffer, 1, sz, f); + if (nbytes != sz) { + printf("- Failed to read\n"); + memset(buffer, 0, *size); + } else { + rc = 0; + *size = sz; + } + } + fclose(f); + return rc; +} + +int load_key_encryption_info(FILE *f, footer_no_filename *fnfn) { + int rc = -1; + if (NULL == f || NULL == fnfn) { + printf("- Invalid input!\n"); + return rc; + } + + fseeko(f, -OFFSET_KEY_ENCRYPTION_INFO, SEEK_END); // negative seek from the end + off_t cur = ftello(f); + fread(&(fnfn->kei), 1, sizeof(key_encryption_info), f); + if (verbose) { + printf("+ key_encryption_info is at 0x%llx\n", cur); + printf("+ file_encryption_info_length is at 0x%llx, value:0x%x (%d)\n", + cur, + fnfn->kei.file_encryption_info_length, + fnfn->kei.file_encryption_info_length); + printf("+ checksum is at 0x%llx, value: 0x%x (%d)\n", + cur + offsetof(key_encryption_info, file_encryption_info_length), + fnfn->kei.checksum, fnfn->kei.checksum); + printf("+ encrypted_file_encryption_key is is at 0x%llx, first few bytes: %x %x %x %x\n", + cur + offsetof(key_encryption_info, key_blob), + fnfn->kei.key_blob.encrypted_key_encryption_key[0], + fnfn->kei.key_blob.encrypted_key_encryption_key[1], + fnfn->kei.key_blob.encrypted_key_encryption_key[2], + fnfn->kei.key_blob.encrypted_key_encryption_key[3]); + } + + // checksum + rc = verify_checksum(&(fnfn->kei.key_blob), sizeof(fnfn->kei.key_blob), fnfn->kei.checksum); + if (rc != STAT_CHECKSUM_OK) { + return rc; + } + + // Decrypt the key_encryption_key.key_blob to get the SALSA20 key for file_encryption_info + if (verbose) { + rc = write_file("key_blob.encrypted.check", &(fnfn->kei.key_blob), SIZE); + } + RSA_decrypt_func(&(fnfn->kei.key_blob), &(dn.d), &(dn.n)); + if (verbose) { + rc = write_file("key_blob.decrypted.check", &(fnfn->kei.key_blob), SIZE); + printf("+ encrypted_file_encryption_key is is at 0x%llx, first few bytes: %x %x %x %x\n", + cur + offsetof(key_encryption_info, key_blob), + fnfn->kei.key_blob.decrypted.key_encryption_key[0], + fnfn->kei.key_blob.decrypted.key_encryption_key[1], + fnfn->kei.key_blob.decrypted.key_encryption_key[2], + fnfn->kei.key_blob.decrypted.key_encryption_key[3]); + } + + return rc; +} + +int load_file_encryption_info(FILE *f, footer_no_filename *fnfn) { + int rc = -1; + if (NULL == f || NULL == fnfn ) { + printf("- Invalid input\n"); + return rc; + } + + fseeko(f, 0, SEEK_END); + off_t end = ftello(f); + off_t footer_offset = end - OFFSET_KEY_ENCRYPTION_INFO - fnfn->kei.file_encryption_info_length; + if (verbose) { + printf("+ footer starts at offset 0x%llx\n", footer_offset); + } + + // this footer structure also contains the original filename + long footer_size = sizeof(key_encryption_info) + fnfn->kei.file_encryption_info_length; + void *footer = malloc(footer_size); + memset(footer, 0, footer_size); + fseeko(f, footer_offset, SEEK_SET); + fread(footer, 1, footer_size, f); + + // decrypt file_encryption_info structure starting at the footer + SALSA20_decrypt_func(fnfn->kei.file_encryption_info_length, (void *)footer, &(fnfn->kei.key_blob)); + + if (verbose) { + rc = write_file("file_encryption_info.check", footer, fnfn->kei.file_encryption_info_length); + rc = write_file("footer.check", footer, footer_size); + } + + long file_encryption_info_no_filename_offset = footer_size - sizeof(file_encryption_info_no_filename) - sizeof(key_encryption_info); + if (verbose) { + printf("+ file_encryption_info_no_filename_offset = 0x%x\n", (uint32_t)file_encryption_info_no_filename_offset); + } + memcpy(&(fnfn->fei), footer + file_encryption_info_no_filename_offset, sizeof(file_encryption_info_no_filename)); + + if (verbose) { + printf("+ filename_size = 0x%x\n", fnfn->fei.filename_size); + } + + if (fnfn->fei.filename_size > MAX_FILENAME_SIZE) { + printf("- Error: Filename may be too large for the buffer\n"); + return rc; + } + + APLib_decompress_func((void *)footer, (void *)filename); + free(footer); // don't need the footer anymore + rc = 0; + if (verbose) { + rc = write_file("filename.check", filename, fnfn->fei.filename_size); + rc = write_file("salsa.key.1.check", &(fnfn->fei.file_encryption_key), SALSA_KEY_SIZE); + } + return rc; +} + +int load_footer(const char *fname, footer_no_filename *fnfn) { + int rc = -1; + if (NULL == fname || NULL == fnfn ) { + printf("- Invalid input!\n"); + return rc; + } + FILE *f = fopen(fname, "r"); + if (NULL == f) { + printf("- Failed to open %s: ", fname); + perror(""); + return rc; + } + + // Loading footer.key_encryption_info. This may fail with a checksum error + rc = load_key_encryption_info(f, fnfn); + if (0 != rc) { + printf("- Failed to load key_encryption_info structure\n"); + return rc; + } + + if (checksum_only) { + fclose(f); // we don't need f anymore + return STAT_CHECKSUM_OK; + } + + // Loading footer.file_encryption_info_no_filename structure + rc = load_file_encryption_info(f, fnfn); + fclose(f); + return rc; +} + +int write_file(const char *fname, void *buffer, long size) { + int rc = -1; + if (NULL == fname || NULL == buffer) { + return rc; + } + + FILE *f = fopen(fname, "w"); + if (NULL == f) { + printf("- Failed to create %s: ", fname); + perror(""); + return rc; + } + + size_t count = fwrite(buffer, 1, size, f); + if (count != size) { + perror("- Failed to write data: "); + } else { + rc = 0; + } + fclose(f); + return rc; +} + +#define CHUNK_SIZE 0x20000 + +int do_decrypt(FILE *ifile, FILE *ofile, footer_no_filename *fnfn, off_t end, bool is_same_file) { + bool is_skip = false; + unsigned char chunk[CHUNK_SIZE] = { 0 }; + + if (NULL == ifile || NULL == ofile || NULL == fnfn) { + printf("- Invalid input\n"); + return -1; + } + + fseeko(ifile, 0, SEEK_SET); + fseeko(ofile, 0, SEEK_SET); + off_t cur = ftello(ifile); + uint32_t decrypt_chunk_count = fnfn->fei.before_chunk_count; + + while (end > cur) { + if (is_skip) { + printf("+ SKIPPING 0x%llx bytes at 0x%llx\n", fnfn->fei.skipped_bytes, cur); + if (is_same_file) { + fseeko(ifile, fnfn->fei.skipped_bytes - CHUNK_SIZE, SEEK_CUR); + fseeko(ofile, fnfn->fei.skipped_bytes - CHUNK_SIZE, SEEK_CUR); + } else { + size_t toskip = fnfn->fei.skipped_bytes; + while (toskip > 0) { + size_t nbytes = fread(chunk, 1, CHUNK_SIZE, ifile); + nbytes = fwrite(chunk, 1, CHUNK_SIZE, ofile); + toskip -= nbytes; + } + } + cur = ftello(ifile); + printf("+ SKIPPED to 0x%llx\n", cur); + is_skip = false; + decrypt_chunk_count = fnfn->fei.after_chunk_count; + } else { + printf("+ DECRYPTING a chunk at 0x%llx\n", cur); + size_t nbytes = fread(chunk, 1, CHUNK_SIZE, ifile); + SALSA20_decrypt_func(nbytes, chunk, &(fnfn->fei.file_encryption_key)); + nbytes = fwrite(chunk, 1, CHUNK_SIZE, ofile); + + if (decrypt_chunk_count == 0) { + is_skip = true; + } else { + decrypt_chunk_count -= 1; + } + } + cur = ftello(ifile); + } + return 0; +} + +int decrypt(footer_no_filename *fnfn) { + int rc = -1; + if (NULL == fnfn) { + printf("- Invalid input\n"); + return rc; + } + + bool is_same_file = (NULL == decrypted); + unsigned int footer_size = sizeof(key_encryption_info) + fnfn->kei.file_encryption_info_length; + + FILE *ifile = fopen(encrypted, "r"); + if (NULL == ifile) { + printf("- Failed to open file %s: ", encrypted); + perror(""); + return rc; + } + + FILE *ofile; + if (is_same_file) { + if (verbose) { + printf("! DECRYPT to the same file %s\n", encrypted); + } + decrypted = encrypted; + ofile = fopen(decrypted, "r+"); + } else { + if (verbose) { + printf("! DECRYPT to %s\n", decrypted); + } + ofile = fopen(decrypted, "w"); + } + + if (NULL == ofile) { + perror("- Failed to open output file:"); + fclose(ifile); + return rc; + } + + // Get the end of the original file without footer + fseeko(ifile, 0, SEEK_END); + off_t end = ftello(ifile); + end -= (off_t)footer_size; + + rc = do_decrypt(ifile, ofile, fnfn, end, is_same_file); + fclose(ifile); + fclose(ofile); + + if (rc == 0) { + // decrypt OK! + rc = truncate(decrypted, end); + if (0 == rc) { + if (verbose) { + printf("+ Truncate to 0x%llx\n", end); + } + } else { + printf("- Failed to truncate %s: ", decrypted); + perror(""); + } + } + return rc; +} + +void help() +{ + printf( "Usage: %s -i -r [OPTIONS]\n" + "\t-i:\tEncrypted file.\n" + "\t-r:\tRSA private key file used with -d. Note: Must be exactly 256 bytes long, with RAW RSA d (128 bytes) & n (128 bytes)\n" + "\t-d:\tDecrypt, if -o is specified, write to output file, else overwrite input file.\n" + "\t-o:\tOutput file, used in -d. Note: Overwrite input file is significantly faster.\n" + "\t-c:\tCalculate checksum, not decrypt, do not use with -d.\n" + "\t-v:\tVerbose.\n", + prog_name + ); +} + +int main(int argc, char *argv[]) { + int rc = -1; + will_decrypt = 0; + checksum_only = 0; + verbose = 0; + + prog_name = malloc(strlen(argv[0]) + 1); + strcpy(prog_name, argv[0]); + if (3 > argc) { + help(); + return rc; + } + + int opt; + size_t len; + while((opt = getopt(argc, argv, ":i:o:r:hdcv")) != -1) { + switch(opt){ + case 'i': + len = strlen(optarg); + encrypted = malloc(len + 1); + strcpy(encrypted, optarg); + encrypted[len] = '\x00'; + break; + case 'o': + len = strlen(optarg); + decrypted = malloc(len + 1); + strcpy(decrypted, optarg); + decrypted[len] = '\x00'; + break; + case 'r': + len = strlen(optarg); + rsakey = malloc(len + 1); + strcpy(rsakey, optarg); + rsakey[len] = '\x00'; + break; + case 'd': + will_decrypt = 1; + checksum_only = 0; + break; + case 'c': + checksum_only = 1; + will_decrypt = 0; + break; + case 'v': + verbose = 1; + break; + case 'h': + help(); + return 0; + case ':': + printf("Option %c needs a value\n", opt); + return rc; + case '?': + printf("Unknown option: %c\n", optopt); + return rc; + default: + return rc; + } + } + + if (NULL == encrypted) { + help(); + return rc; + } + + if ( will_decrypt && NULL == rsakey) { + help(); + return rc; + } + + size_t dnsize = sizeof(RSA_dn); + rc = load_file(rsakey, &dn, &dnsize); + if (0 != rc) { + return rc; + } + + prepare_shell_funcs(); + + footer_no_filename fnfn = { 0 }; + rc = load_footer(encrypted, &fnfn); + + if (verbose && rc == 0) { + printf("-----------------\n"); + printf("+ before_chunk_count: 0x%x\n", fnfn.fei.before_chunk_count); + printf("+ after_chunk_count: 0x%x\n", fnfn.fei.after_chunk_count); + printf("+ skipped_bytes: 0x%llx\n", fnfn.fei.skipped_bytes); + printf("+ file_encryption_info_length = 0x%x\n", fnfn.kei.file_encryption_info_length); + printf("+ checksum= 0x%x\n", fnfn.kei.checksum); + printf("+ SALSA key for chunks: "); + for (int i = 0; i < SALSA_KEY_SIZE; i++) { + printf("%02hhx", *((char *)&(fnfn.fei.file_encryption_key) + i)); + } + printf("\n"); + printf("+ SALSA key for file_encryption_info: "); + for (int i = 0; i < SALSA_KEY_SIZE; i++) { + printf("%02hhx", *((char *)&(fnfn.kei.key_blob.decrypted.key_encryption_key) + i)); + } + printf("\n"); + } + + if (rc == 0 && will_decrypt) { + if (verbose) { + write_file("salsa.key.2.check", &(fnfn.fei.file_encryption_key), SALSA_KEY_SIZE); + } + decrypt(&fnfn); + } + + cleanup_shell_funcs(); + return rc; +} diff --git a/_stream-reuse/frank.h b/_stream-reuse/frank.h new file mode 100644 index 0000000..9ba6c5c --- /dev/null +++ b/_stream-reuse/frank.h @@ -0,0 +1,283 @@ +#ifndef _FRANK +#define _FRANK +#include + +#define _FILE_OFFSET_BITS 64 +#define SIZE 0x80 +#define SALSA_KEY_SIZE 0x40 + +typedef struct __attribute__((__packed__)) _RSA_dn { + unsigned char d[SIZE]; + unsigned char n[SIZE]; +} RSA_dn; + +unsigned char rsa_decrypt[] = { + 0x55, 0x8b, 0xec, 0x81, 0xec, 0x34, 0x01, 0x00, 0x00, 0x53, 0x51, 0x56, + 0x57, 0x8d, 0x85, 0x70, 0xff, 0xff, 0xff, 0x83, 0xc0, 0x0f, 0x83, 0xe0, + 0xf0, 0x89, 0x85, 0xdc, 0xfe, 0xff, 0xff, 0x8d, 0x85, 0xe0, 0xfe, 0xff, + 0xff, 0x83, 0xc0, 0x0f, 0x83, 0xe0, 0xf0, 0x89, 0x85, 0xd8, 0xfe, 0xff, + 0xff, 0x66, 0x0f, 0xef, 0xc0, 0xb9, 0x08, 0x00, 0x00, 0x00, 0x8b, 0x85, + 0xdc, 0xfe, 0xff, 0xff, 0x8b, 0xf8, 0x66, 0x0f, 0x7f, 0x07, 0x83, 0xc7, + 0x10, 0x49, 0x85, 0xc9, 0x75, 0xf4, 0xc6, 0x00, 0x01, 0x33, 0xc0, 0x8b, + 0x5d, 0x0c, 0x81, 0xc3, 0x80, 0x00, 0x00, 0x00, 0xb9, 0x81, 0x00, 0x00, + 0x00, 0x4b, 0x49, 0x8a, 0x03, 0x85, 0xc0, 0x74, 0xf8, 0x89, 0x8d, 0xd4, + 0xfe, 0xff, 0xff, 0xc7, 0x85, 0xd0, 0xfe, 0xff, 0xff, 0x08, 0x00, 0x00, + 0x00, 0xc7, 0x85, 0xcc, 0xfe, 0xff, 0xff, 0x08, 0x00, 0x00, 0x00, 0x8b, + 0xb5, 0xdc, 0xfe, 0xff, 0xff, 0x8b, 0xbd, 0xd8, 0xfe, 0xff, 0xff, 0xb9, + 0x08, 0x00, 0x00, 0x00, 0x66, 0x0f, 0x6f, 0x06, 0x66, 0x0f, 0x7f, 0x07, + 0x83, 0xc6, 0x10, 0x83, 0xc7, 0x10, 0x49, 0x85, 0xc9, 0x75, 0xed, 0xff, + 0x75, 0x10, 0xff, 0xb5, 0xd8, 0xfe, 0xff, 0xff, 0xff, 0xb5, 0xdc, 0xfe, + 0xff, 0xff, 0xe8, 0x75, 0x00, 0x00, 0x00, 0xff, 0x8d, 0xcc, 0xfe, 0xff, + 0xff, 0x8b, 0x8d, 0xcc, 0xfe, 0xff, 0xff, 0x33, 0xc0, 0x40, 0xd3, 0xe0, + 0x22, 0x03, 0x74, 0x11, 0xff, 0x75, 0x10, 0xff, 0x75, 0x08, 0xff, 0xb5, + 0xdc, 0xfe, 0xff, 0xff, 0xe8, 0x4f, 0x00, 0x00, 0x00, 0xff, 0x8d, 0xd0, + 0xfe, 0xff, 0xff, 0x83, 0xbd, 0xd0, 0xfe, 0xff, 0xff, 0x00, 0x75, 0x93, + 0x4b, 0xff, 0x8d, 0xd4, 0xfe, 0xff, 0xff, 0x83, 0xbd, 0xd4, 0xfe, 0xff, + 0xff, 0x00, 0x0f, 0x85, 0x6b, 0xff, 0xff, 0xff, 0x8b, 0xb5, 0xdc, 0xfe, + 0xff, 0xff, 0x8b, 0x7d, 0x08, 0xb9, 0x08, 0x00, 0x00, 0x00, 0x0f, 0x10, + 0x06, 0x0f, 0x11, 0x07, 0x83, 0xc6, 0x10, 0x83, 0xc7, 0x10, 0x49, 0x85, + 0xc9, 0x75, 0xef, 0x5f, 0x5e, 0x59, 0x5b, 0x8b, 0xe5, 0x5d, 0xc2, 0x0c, + 0x00, 0x8d, 0x40, 0x00, 0x55, 0x8b, 0xec, 0x81, 0xec, 0x98, 0x00, 0x00, + 0x00, 0x53, 0x51, 0x52, 0x56, 0x57, 0x8d, 0x85, 0x70, 0xff, 0xff, 0xff, + 0x83, 0xc0, 0x0f, 0x83, 0xe0, 0xf0, 0x89, 0x85, 0x6c, 0xff, 0xff, 0xff, + 0x66, 0x0f, 0xef, 0xc0, 0xb9, 0x08, 0x00, 0x00, 0x00, 0x8b, 0xbd, 0x6c, + 0xff, 0xff, 0xff, 0x66, 0x0f, 0x7f, 0x07, 0x83, 0xc7, 0x10, 0x49, 0x85, + 0xc9, 0x75, 0xf4, 0xc7, 0x85, 0x68, 0xff, 0xff, 0xff, 0x00, 0x04, 0x00, + 0x00, 0x8b, 0xb5, 0x6c, 0xff, 0xff, 0xff, 0xf8, 0xe8, 0x99, 0x00, 0x00, + 0x00, 0x8b, 0xbd, 0x6c, 0xff, 0xff, 0xff, 0x8b, 0x75, 0x10, 0xf8, 0xe8, + 0xa9, 0x01, 0x00, 0x00, 0x73, 0x0f, 0x8b, 0xbd, 0x6c, 0xff, 0xff, 0xff, + 0x8b, 0x75, 0x10, 0xf8, 0xe8, 0xd9, 0x00, 0x00, 0x00, 0x8b, 0x75, 0x08, + 0xf8, 0xe8, 0x70, 0x00, 0x00, 0x00, 0x73, 0x0f, 0x8b, 0xbd, 0x6c, 0xff, + 0xff, 0xff, 0x8b, 0x75, 0x0c, 0xf8, 0xe8, 0xbf, 0x00, 0x00, 0x00, 0x8b, + 0xbd, 0x6c, 0xff, 0xff, 0xff, 0x8b, 0x75, 0x10, 0xf8, 0xe8, 0x6f, 0x01, + 0x00, 0x00, 0x73, 0x0f, 0x8b, 0xbd, 0x6c, 0xff, 0xff, 0xff, 0x8b, 0x75, + 0x10, 0xf8, 0xe8, 0x9f, 0x00, 0x00, 0x00, 0xff, 0x8d, 0x68, 0xff, 0xff, + 0xff, 0x83, 0xbd, 0x68, 0xff, 0xff, 0xff, 0x00, 0x75, 0x02, 0xeb, 0x02, + 0xeb, 0x87, 0x8b, 0xb5, 0x6c, 0xff, 0xff, 0xff, 0x8b, 0x7d, 0x08, 0xb9, + 0x08, 0x00, 0x00, 0x00, 0x66, 0x0f, 0x6f, 0x06, 0x66, 0x0f, 0x7f, 0x07, + 0x83, 0xc6, 0x10, 0x83, 0xc7, 0x10, 0x49, 0x85, 0xc9, 0x75, 0xed, 0x5f, + 0x5e, 0x5a, 0x59, 0x5b, 0x8b, 0xe5, 0x5d, 0xc2, 0x0c, 0x00, 0xd1, 0x16, + 0xd1, 0x56, 0x04, 0xd1, 0x56, 0x08, 0xd1, 0x56, 0x0c, 0xd1, 0x56, 0x10, + 0xd1, 0x56, 0x14, 0xd1, 0x56, 0x18, 0xd1, 0x56, 0x1c, 0xd1, 0x56, 0x20, + 0xd1, 0x56, 0x24, 0xd1, 0x56, 0x28, 0xd1, 0x56, 0x2c, 0xd1, 0x56, 0x30, + 0xd1, 0x56, 0x34, 0xd1, 0x56, 0x38, 0xd1, 0x56, 0x3c, 0xd1, 0x56, 0x40, + 0xd1, 0x56, 0x44, 0xd1, 0x56, 0x48, 0xd1, 0x56, 0x4c, 0xd1, 0x56, 0x50, + 0xd1, 0x56, 0x54, 0xd1, 0x56, 0x58, 0xd1, 0x56, 0x5c, 0xd1, 0x56, 0x60, + 0xd1, 0x56, 0x64, 0xd1, 0x56, 0x68, 0xd1, 0x56, 0x6c, 0xd1, 0x56, 0x70, + 0xd1, 0x56, 0x74, 0xd1, 0x56, 0x78, 0xd1, 0x56, 0x7c, 0xc3, 0x8b, 0x06, + 0x8b, 0x5e, 0x04, 0x8b, 0x4e, 0x08, 0x8b, 0x56, 0x0c, 0x11, 0x07, 0x11, + 0x5f, 0x04, 0x11, 0x4f, 0x08, 0x11, 0x57, 0x0c, 0x8b, 0x46, 0x10, 0x8b, + 0x5e, 0x14, 0x8b, 0x4e, 0x18, 0x8b, 0x56, 0x1c, 0x11, 0x47, 0x10, 0x11, + 0x5f, 0x14, 0x11, 0x4f, 0x18, 0x11, 0x57, 0x1c, 0x8b, 0x46, 0x20, 0x8b, + 0x5e, 0x24, 0x8b, 0x4e, 0x28, 0x8b, 0x56, 0x2c, 0x11, 0x47, 0x20, 0x11, + 0x5f, 0x24, 0x11, 0x4f, 0x28, 0x11, 0x57, 0x2c, 0x8b, 0x46, 0x30, 0x8b, + 0x5e, 0x34, 0x8b, 0x4e, 0x38, 0x8b, 0x56, 0x3c, 0x11, 0x47, 0x30, 0x11, + 0x5f, 0x34, 0x11, 0x4f, 0x38, 0x11, 0x57, 0x3c, 0x8b, 0x46, 0x40, 0x8b, + 0x5e, 0x44, 0x8b, 0x4e, 0x48, 0x8b, 0x56, 0x4c, 0x11, 0x47, 0x40, 0x11, + 0x5f, 0x44, 0x11, 0x4f, 0x48, 0x11, 0x57, 0x4c, 0x8b, 0x46, 0x50, 0x8b, + 0x5e, 0x54, 0x8b, 0x4e, 0x58, 0x8b, 0x56, 0x5c, 0x11, 0x47, 0x50, 0x11, + 0x5f, 0x54, 0x11, 0x4f, 0x58, 0x11, 0x57, 0x5c, 0x8b, 0x46, 0x60, 0x8b, + 0x5e, 0x64, 0x8b, 0x4e, 0x68, 0x8b, 0x56, 0x6c, 0x11, 0x47, 0x60, 0x11, + 0x5f, 0x64, 0x11, 0x4f, 0x68, 0x11, 0x57, 0x6c, 0x8b, 0x46, 0x70, 0x8b, + 0x5e, 0x74, 0x8b, 0x4e, 0x78, 0x8b, 0x56, 0x7c, 0x11, 0x47, 0x70, 0x11, + 0x5f, 0x74, 0x11, 0x4f, 0x78, 0x11, 0x57, 0x7c, 0xc3, 0x8b, 0x06, 0x8b, + 0x5e, 0x04, 0x8b, 0x4e, 0x08, 0x8b, 0x56, 0x0c, 0x19, 0x07, 0x19, 0x5f, + 0x04, 0x19, 0x4f, 0x08, 0x19, 0x57, 0x0c, 0x8b, 0x46, 0x10, 0x8b, 0x5e, + 0x14, 0x8b, 0x4e, 0x18, 0x8b, 0x56, 0x1c, 0x19, 0x47, 0x10, 0x19, 0x5f, + 0x14, 0x19, 0x4f, 0x18, 0x19, 0x57, 0x1c, 0x8b, 0x46, 0x20, 0x8b, 0x5e, + 0x24, 0x8b, 0x4e, 0x28, 0x8b, 0x56, 0x2c, 0x19, 0x47, 0x20, 0x19, 0x5f, + 0x24, 0x19, 0x4f, 0x28, 0x19, 0x57, 0x2c, 0x8b, 0x46, 0x30, 0x8b, 0x5e, + 0x34, 0x8b, 0x4e, 0x38, 0x8b, 0x56, 0x3c, 0x19, 0x47, 0x30, 0x19, 0x5f, + 0x34, 0x19, 0x4f, 0x38, 0x19, 0x57, 0x3c, 0x8b, 0x46, 0x40, 0x8b, 0x5e, + 0x44, 0x8b, 0x4e, 0x48, 0x8b, 0x56, 0x4c, 0x19, 0x47, 0x40, 0x19, 0x5f, + 0x44, 0x19, 0x4f, 0x48, 0x19, 0x57, 0x4c, 0x8b, 0x46, 0x50, 0x8b, 0x5e, + 0x54, 0x8b, 0x4e, 0x58, 0x8b, 0x56, 0x5c, 0x19, 0x47, 0x50, 0x19, 0x5f, + 0x54, 0x19, 0x4f, 0x58, 0x19, 0x57, 0x5c, 0x8b, 0x46, 0x60, 0x8b, 0x5e, + 0x64, 0x8b, 0x4e, 0x68, 0x8b, 0x56, 0x6c, 0x19, 0x47, 0x60, 0x19, 0x5f, + 0x64, 0x19, 0x4f, 0x68, 0x19, 0x57, 0x6c, 0x8b, 0x46, 0x70, 0x8b, 0x5e, + 0x74, 0x8b, 0x4e, 0x78, 0x8b, 0x56, 0x7c, 0x19, 0x47, 0x70, 0x19, 0x5f, + 0x74, 0x19, 0x4f, 0x78, 0x19, 0x57, 0x7c, 0xc3 +}; +unsigned int rsa_decrypt_len = 1016; + +unsigned char salsa_crypt[] = { + 0x81, 0xec, 0x84, 0x00, 0x00, 0x00, 0x8b, 0x94, 0x24, 0x88, 0x00, 0x00, + 0x00, 0x56, 0x8b, 0xb4, 0x24, 0x94, 0x00, 0x00, 0x00, 0x89, 0x74, 0x24, + 0x3c, 0x57, 0x8b, 0xbc, 0x24, 0x94, 0x00, 0x00, 0x00, 0x89, 0x7c, 0x24, + 0x34, 0x85, 0xd2, 0x0f, 0x84, 0xfb, 0x03, 0x00, 0x00, 0x53, 0x8d, 0x46, + 0x3c, 0x55, 0x89, 0x44, 0x24, 0x4c, 0x0f, 0x10, 0x06, 0xc7, 0x44, 0x24, + 0x40, 0x0a, 0x00, 0x00, 0x00, 0x0f, 0x11, 0x44, 0x24, 0x50, 0x0f, 0x10, + 0x46, 0x10, 0x0f, 0x11, 0x44, 0x24, 0x60, 0x0f, 0x10, 0x46, 0x20, 0x0f, + 0x11, 0x44, 0x24, 0x70, 0x8b, 0x44, 0x24, 0x78, 0x0f, 0x10, 0x46, 0x30, + 0x8b, 0x54, 0x24, 0x7c, 0x8b, 0x74, 0x24, 0x60, 0x89, 0x44, 0x24, 0x30, + 0x8b, 0x44, 0x24, 0x74, 0x89, 0x44, 0x24, 0x1c, 0x8b, 0x44, 0x24, 0x70, + 0x89, 0x44, 0x24, 0x20, 0x8b, 0x44, 0x24, 0x6c, 0x89, 0x44, 0x24, 0x18, + 0x8b, 0x44, 0x24, 0x68, 0x89, 0x44, 0x24, 0x14, 0x8b, 0x44, 0x24, 0x64, + 0x89, 0x44, 0x24, 0x2c, 0x8b, 0x44, 0x24, 0x5c, 0x89, 0x44, 0x24, 0x10, + 0x8b, 0x44, 0x24, 0x58, 0x89, 0x44, 0x24, 0x24, 0x8b, 0x44, 0x24, 0x54, + 0x0f, 0x11, 0x84, 0x24, 0x80, 0x00, 0x00, 0x00, 0x8b, 0x8c, 0x24, 0x8c, + 0x00, 0x00, 0x00, 0x8b, 0x9c, 0x24, 0x88, 0x00, 0x00, 0x00, 0x8b, 0xac, + 0x24, 0x84, 0x00, 0x00, 0x00, 0x8b, 0xbc, 0x24, 0x80, 0x00, 0x00, 0x00, + 0x89, 0x44, 0x24, 0x34, 0x8b, 0x44, 0x24, 0x50, 0x89, 0x44, 0x24, 0x28, + 0xeb, 0x04, 0x8b, 0x74, 0x24, 0x38, 0x03, 0xc7, 0xc1, 0xc0, 0x07, 0x33, + 0xf0, 0x8b, 0x44, 0x24, 0x28, 0x03, 0xc6, 0x89, 0x74, 0x24, 0x38, 0xc1, + 0xc0, 0x09, 0x31, 0x44, 0x24, 0x20, 0x8b, 0x44, 0x24, 0x20, 0x03, 0xc6, + 0x8b, 0x74, 0x24, 0x34, 0xc1, 0xc0, 0x0d, 0x33, 0xf8, 0x8b, 0x44, 0x24, + 0x20, 0x03, 0xc7, 0x89, 0x7c, 0x24, 0x44, 0xc1, 0xc8, 0x0e, 0x31, 0x44, + 0x24, 0x28, 0x8b, 0x7c, 0x24, 0x2c, 0x8d, 0x04, 0x3e, 0xc1, 0xc0, 0x07, + 0x31, 0x44, 0x24, 0x1c, 0x8b, 0x44, 0x24, 0x1c, 0x03, 0xc7, 0xc1, 0xc0, + 0x09, 0x33, 0xe8, 0x8b, 0x44, 0x24, 0x1c, 0x03, 0xc5, 0xc1, 0xc0, 0x0d, + 0x33, 0xf0, 0x89, 0x74, 0x24, 0x34, 0x8d, 0x04, 0x2e, 0x8b, 0x74, 0x24, + 0x30, 0xc1, 0xc8, 0x0e, 0x33, 0xf8, 0x8b, 0x44, 0x24, 0x14, 0x03, 0xc6, + 0x89, 0x7c, 0x24, 0x2c, 0xc1, 0xc0, 0x07, 0x33, 0xd8, 0x8b, 0x7c, 0x24, + 0x34, 0x8d, 0x04, 0x33, 0xc1, 0xc0, 0x09, 0x31, 0x44, 0x24, 0x24, 0x8b, + 0x44, 0x24, 0x24, 0x03, 0xc3, 0xc1, 0xc0, 0x0d, 0x31, 0x44, 0x24, 0x14, + 0x8b, 0x44, 0x24, 0x14, 0x03, 0x44, 0x24, 0x24, 0xc1, 0xc8, 0x0e, 0x33, + 0xf0, 0x8d, 0x04, 0x0a, 0xc1, 0xc0, 0x07, 0x31, 0x44, 0x24, 0x10, 0x8b, + 0x44, 0x24, 0x10, 0x03, 0xc1, 0x89, 0x74, 0x24, 0x30, 0x8b, 0x74, 0x24, + 0x28, 0xc1, 0xc0, 0x09, 0x31, 0x44, 0x24, 0x18, 0x8b, 0x44, 0x24, 0x18, + 0x03, 0x44, 0x24, 0x10, 0xc1, 0xc0, 0x0d, 0x33, 0xd0, 0x8b, 0x44, 0x24, + 0x18, 0x03, 0xc2, 0xc1, 0xc8, 0x0e, 0x33, 0xc8, 0x8b, 0x44, 0x24, 0x10, + 0x03, 0xc6, 0xc1, 0xc0, 0x07, 0x33, 0xf8, 0x89, 0x7c, 0x24, 0x34, 0x89, + 0x7c, 0x24, 0x54, 0x8d, 0x04, 0x37, 0x8b, 0x74, 0x24, 0x24, 0xc1, 0xc0, + 0x09, 0x33, 0xf0, 0x89, 0x74, 0x24, 0x24, 0x89, 0x74, 0x24, 0x58, 0x8d, + 0x04, 0x3e, 0x8b, 0x7c, 0x24, 0x38, 0xc1, 0xc0, 0x0d, 0x31, 0x44, 0x24, + 0x10, 0x8b, 0x44, 0x24, 0x10, 0x89, 0x44, 0x24, 0x5c, 0x03, 0xc6, 0xc1, + 0xc8, 0x0e, 0x8b, 0x74, 0x24, 0x28, 0x33, 0xf0, 0x8b, 0x44, 0x24, 0x38, + 0x03, 0x44, 0x24, 0x2c, 0xc1, 0xc0, 0x07, 0x31, 0x44, 0x24, 0x14, 0x8b, + 0x44, 0x24, 0x14, 0x89, 0x44, 0x24, 0x68, 0x03, 0x44, 0x24, 0x2c, 0xc1, + 0xc0, 0x09, 0x31, 0x44, 0x24, 0x18, 0x8b, 0x44, 0x24, 0x18, 0x89, 0x44, + 0x24, 0x6c, 0x03, 0x44, 0x24, 0x14, 0xc1, 0xc0, 0x0d, 0x33, 0xf8, 0x89, + 0x74, 0x24, 0x28, 0x8b, 0x44, 0x24, 0x18, 0x03, 0xc7, 0x89, 0x7c, 0x24, + 0x38, 0xc1, 0xc8, 0x0e, 0x89, 0x7c, 0x24, 0x60, 0x8b, 0x7c, 0x24, 0x2c, + 0x33, 0xf8, 0x89, 0x74, 0x24, 0x50, 0x8b, 0x74, 0x24, 0x30, 0x8b, 0x44, + 0x24, 0x1c, 0x03, 0xc6, 0x89, 0x7c, 0x24, 0x2c, 0xc1, 0xc0, 0x07, 0x33, + 0xd0, 0x89, 0x7c, 0x24, 0x64, 0x8b, 0x7c, 0x24, 0x44, 0x8d, 0x04, 0x32, + 0xc1, 0xc0, 0x09, 0x31, 0x44, 0x24, 0x20, 0x8b, 0x44, 0x24, 0x20, 0x89, + 0x44, 0x24, 0x70, 0x03, 0xc2, 0xc1, 0xc0, 0x0d, 0x31, 0x44, 0x24, 0x1c, + 0x8b, 0x44, 0x24, 0x1c, 0x89, 0x44, 0x24, 0x74, 0x03, 0x44, 0x24, 0x20, + 0xc1, 0xc8, 0x0e, 0x33, 0xf0, 0x8d, 0x04, 0x0b, 0xc1, 0xc0, 0x07, 0x33, + 0xf8, 0x89, 0x74, 0x24, 0x30, 0x89, 0x74, 0x24, 0x78, 0x89, 0xbc, 0x24, + 0x80, 0x00, 0x00, 0x00, 0x8d, 0x04, 0x0f, 0xc1, 0xc0, 0x09, 0x33, 0xe8, + 0x8d, 0x04, 0x2f, 0xc1, 0xc0, 0x0d, 0x33, 0xd8, 0x8d, 0x04, 0x2b, 0xc1, + 0xc8, 0x0e, 0x33, 0xc8, 0x83, 0x6c, 0x24, 0x40, 0x01, 0x8b, 0x44, 0x24, + 0x28, 0x0f, 0x85, 0x03, 0xfe, 0xff, 0xff, 0x8b, 0x74, 0x24, 0x48, 0x33, + 0xc0, 0x8b, 0x7c, 0x24, 0x3c, 0x89, 0x8c, 0x24, 0x8c, 0x00, 0x00, 0x00, + 0x8d, 0x4c, 0x24, 0x50, 0x89, 0x54, 0x24, 0x7c, 0x8b, 0x94, 0x24, 0x98, + 0x00, 0x00, 0x00, 0x89, 0x9c, 0x24, 0x88, 0x00, 0x00, 0x00, 0x89, 0xac, + 0x24, 0x84, 0x00, 0x00, 0x00, 0x3b, 0x4c, 0x24, 0x4c, 0x77, 0x1a, 0x8d, + 0x8c, 0x24, 0x8c, 0x00, 0x00, 0x00, 0x3b, 0xce, 0x72, 0x0f, 0x8b, 0x0c, + 0x86, 0x01, 0x4c, 0x84, 0x50, 0x40, 0x83, 0xf8, 0x10, 0x7c, 0xf3, 0xeb, + 0x2d, 0x0f, 0x10, 0x4c, 0x84, 0x50, 0x0f, 0x10, 0x04, 0x86, 0x66, 0x0f, + 0xfe, 0xc8, 0x0f, 0x11, 0x4c, 0x84, 0x50, 0x0f, 0x10, 0x44, 0x84, 0x60, + 0x0f, 0x10, 0x4c, 0x86, 0x10, 0x66, 0x0f, 0xfe, 0xc8, 0x0f, 0x11, 0x4c, + 0x84, 0x60, 0x83, 0xc0, 0x08, 0x83, 0xf8, 0x10, 0x7c, 0xd3, 0x83, 0x46, + 0x20, 0x01, 0x8b, 0xda, 0xb8, 0x40, 0x00, 0x00, 0x00, 0x83, 0x56, 0x24, + 0x00, 0x83, 0xfa, 0x40, 0x0f, 0x47, 0xd8, 0x33, 0xd2, 0x85, 0xdb, 0x0f, + 0x84, 0x97, 0x00, 0x00, 0x00, 0x83, 0xfb, 0x20, 0x72, 0x6f, 0x8d, 0x4f, + 0xff, 0x8d, 0x44, 0x1c, 0x4f, 0x03, 0xcb, 0x3b, 0xf8, 0x77, 0x08, 0x8d, + 0x44, 0x24, 0x50, 0x3b, 0xc8, 0x73, 0x5a, 0x8b, 0xc7, 0x8d, 0x74, 0x24, + 0x60, 0x8b, 0xcf, 0xf7, 0xd8, 0x8b, 0xeb, 0x8d, 0x7c, 0x24, 0x50, 0x03, + 0xf8, 0x83, 0xe5, 0xe0, 0x03, 0xc6, 0x89, 0x7c, 0x24, 0x44, 0x8b, 0x7c, + 0x24, 0x3c, 0x89, 0x44, 0x24, 0x40, 0x8b, 0x44, 0x24, 0x44, 0x8b, 0x74, + 0x24, 0x40, 0x0f, 0x10, 0x01, 0x83, 0xc2, 0x20, 0x8d, 0x49, 0x20, 0x0f, + 0x10, 0x4c, 0x08, 0xe0, 0x66, 0x0f, 0xef, 0xc8, 0x0f, 0x11, 0x49, 0xe0, + 0x0f, 0x10, 0x41, 0xf0, 0x0f, 0x10, 0x4c, 0x0e, 0xe0, 0x66, 0x0f, 0xef, + 0xc8, 0x0f, 0x11, 0x49, 0xf0, 0x3b, 0xd5, 0x72, 0xd5, 0x8b, 0x74, 0x24, + 0x48, 0x3b, 0xd3, 0x73, 0x1f, 0x8d, 0x6c, 0x24, 0x50, 0x8d, 0x0c, 0x3a, + 0x2b, 0xef, 0x8b, 0xfb, 0x2b, 0xfa, 0x8a, 0x04, 0x29, 0x8d, 0x49, 0x01, + 0x30, 0x41, 0xff, 0x83, 0xef, 0x01, 0x75, 0xf2, 0x8b, 0x7c, 0x24, 0x3c, + 0x8b, 0x94, 0x24, 0x98, 0x00, 0x00, 0x00, 0x03, 0xfb, 0x2b, 0xd3, 0x89, + 0x7c, 0x24, 0x3c, 0x89, 0x94, 0x24, 0x98, 0x00, 0x00, 0x00, 0x85, 0xd2, + 0x0f, 0x85, 0x10, 0xfc, 0xff, 0xff, 0x5d, 0x5b, 0x5f, 0x5e, 0x81, 0xc4, + 0x84, 0x00, 0x00, 0x00, 0xc3 +}; +unsigned int salsa_crypt_len = 1073; + +unsigned char apdecompress_bin[] = { + 0x60, 0x8b, 0x74, 0x24, 0x24, 0x8b, 0x7c, 0x24, 0x28, 0xfc, 0xb2, 0x80, + 0x8a, 0x06, 0x83, 0xc6, 0x01, 0x88, 0x07, 0x83, 0xc7, 0x01, 0xbb, 0x02, + 0x00, 0x00, 0x00, 0x00, 0xd2, 0x75, 0x05, 0x8a, 0x16, 0x46, 0x10, 0xd2, + 0x73, 0xe6, 0x00, 0xd2, 0x75, 0x05, 0x8a, 0x16, 0x46, 0x10, 0xd2, 0x73, + 0x4f, 0x31, 0xc0, 0x00, 0xd2, 0x75, 0x05, 0x8a, 0x16, 0x46, 0x10, 0xd2, + 0x0f, 0x83, 0xdb, 0x00, 0x00, 0x00, 0x00, 0xd2, 0x75, 0x05, 0x8a, 0x16, + 0x46, 0x10, 0xd2, 0x11, 0xc0, 0x00, 0xd2, 0x75, 0x05, 0x8a, 0x16, 0x46, + 0x10, 0xd2, 0x11, 0xc0, 0x00, 0xd2, 0x75, 0x05, 0x8a, 0x16, 0x46, 0x10, + 0xd2, 0x11, 0xc0, 0x00, 0xd2, 0x75, 0x05, 0x8a, 0x16, 0x46, 0x10, 0xd2, + 0x11, 0xc0, 0x74, 0x06, 0x89, 0xfb, 0x29, 0xc3, 0x8a, 0x03, 0x88, 0x07, + 0x47, 0xbb, 0x02, 0x00, 0x00, 0x00, 0xeb, 0x9b, 0xb8, 0x01, 0x00, 0x00, + 0x00, 0x00, 0xd2, 0x75, 0x05, 0x8a, 0x16, 0x46, 0x10, 0xd2, 0x11, 0xc0, + 0x00, 0xd2, 0x75, 0x05, 0x8a, 0x16, 0x46, 0x10, 0xd2, 0x72, 0xea, 0x29, + 0xd8, 0xbb, 0x01, 0x00, 0x00, 0x00, 0x75, 0x28, 0xb9, 0x01, 0x00, 0x00, + 0x00, 0x00, 0xd2, 0x75, 0x05, 0x8a, 0x16, 0x46, 0x10, 0xd2, 0x11, 0xc9, + 0x00, 0xd2, 0x75, 0x05, 0x8a, 0x16, 0x46, 0x10, 0xd2, 0x72, 0xea, 0x56, + 0x89, 0xfe, 0x29, 0xee, 0xf3, 0xa4, 0x5e, 0xe9, 0x4f, 0xff, 0xff, 0xff, + 0x48, 0xc1, 0xe0, 0x08, 0x8a, 0x06, 0x46, 0x89, 0xc5, 0xb9, 0x01, 0x00, + 0x00, 0x00, 0x00, 0xd2, 0x75, 0x05, 0x8a, 0x16, 0x46, 0x10, 0xd2, 0x11, + 0xc9, 0x00, 0xd2, 0x75, 0x05, 0x8a, 0x16, 0x46, 0x10, 0xd2, 0x72, 0xea, + 0x3d, 0x00, 0x7d, 0x00, 0x00, 0x83, 0xd9, 0xff, 0x3d, 0x00, 0x05, 0x00, + 0x00, 0x83, 0xd9, 0xff, 0x3d, 0x80, 0x00, 0x00, 0x00, 0x83, 0xd1, 0x00, + 0x3d, 0x80, 0x00, 0x00, 0x00, 0x83, 0xd1, 0x00, 0x56, 0x89, 0xfe, 0x29, + 0xc6, 0xf3, 0xa4, 0x5e, 0xe9, 0xfe, 0xfe, 0xff, 0xff, 0x8a, 0x06, 0x46, + 0x31, 0xc9, 0xc0, 0xe8, 0x01, 0x74, 0x17, 0x83, 0xd1, 0x02, 0x89, 0xc5, + 0x56, 0x89, 0xfe, 0x29, 0xc6, 0xf3, 0xa4, 0x5e, 0xbb, 0x01, 0x00, 0x00, + 0x00, 0xe9, 0xdd, 0xfe, 0xff, 0xff, 0x2b, 0x7c, 0x24, 0x28, 0x89, 0x7c, + 0x24, 0x1c, 0x61, 0xc3 +}; +unsigned int apdecompress_bin_len = 328; + +const unsigned char checksum_tasklet[] = { + 0x55, 0x8b, 0xec, 0x53, 0x56, 0x57, 0x8b, 0x45, 0x10, 0x8b, 0x4d, 0x0c, + 0x8b, 0x5d, 0x10, 0x25, 0xff, 0xff, 0x00, 0x00, 0xc1, 0xeb, 0x10, 0x8b, + 0x75, 0x08, 0x85, 0xc9, 0xeb, 0x39, 0xbf, 0x69, 0x30, 0x03, 0x47, 0x81, + 0xf7, 0xc8, 0x3f, 0x03, 0x47, 0x3b, 0xcf, 0x73, 0x02, 0x8b, 0xf9, 0x2b, + 0xcf, 0x0f, 0xb6, 0x16, 0x03, 0xc2, 0x46, 0x03, 0xd8, 0x4f, 0x75, 0xf5, + 0xbf, 0xc7, 0x3f, 0x02, 0x47, 0x81, 0xf7, 0xc8, 0x3f, 0x03, 0x47, 0x33, + 0xd2, 0xf7, 0xf7, 0x52, 0x8b, 0xc3, 0x33, 0xd2, 0xf7, 0xf7, 0x8b, 0xda, + 0x58, 0x85, 0xc9, 0x75, 0xc5, 0xc1, 0xe3, 0x10, 0x03, 0xc3, 0x8b, 0x0d, + 0x04, 0x77, 0x40, 0x00, 0x8b, 0x89, 0x80, 0x00, 0x00, 0x00, 0x33, 0xc1, + 0x5f, 0x5e, 0x5b, 0x5d, 0xc2, 0x0c, 0x00, 0x90 +}; +const unsigned int checksum_tasklet_len = 116; +// NOTE: +// RSA d and n has to be put in contagious region where addr = addr + 0x80 +const unsigned int checksum_tasklet_RSAd_addr_code_offset = 96; + +typedef struct __attribute__((__packed__)) _file_encryption_info_no_filename { + uint16_t filename_size; + uint64_t skipped_bytes; + uint32_t before_chunk_count; + uint32_t after_chunk_count; + unsigned char file_encryption_key[SALSA_KEY_SIZE]; +} file_encryption_info_no_filename; + +typedef struct __attribute__((__packed__)) _key_encryption_info { + uint16_t file_encryption_info_length; + uint32_t checksum; + union { + struct { + unsigned char key_encryption_key[SALSA_KEY_SIZE]; + unsigned char checksum[SALSA_KEY_SIZE]; + } decrypted; + unsigned char encrypted_key_encryption_key[0x80]; + } key_blob; +} key_encryption_info; + +typedef struct __attribute__((__packed__)) _footer_no_filename { + file_encryption_info_no_filename fei; + key_encryption_info kei; +} footer_no_filename; + +void prepare_shell_funcs(); +void cleanup_shell_funcs(); +uint32_t calculate_checksum(void *buffer, unsigned int size); +int verify_checksum(void *data, size_t size, uint32_t checksum); +int load_file(const char *fname, void *buffer, size_t *size); +int load_key_encryption_info(FILE *f, footer_no_filename *fnfn); +int load_file_encryption_info(FILE *f, footer_no_filename *fnfn); +int load_footer(const char *fname, footer_no_filename *fnfn); +int write_file(const char *fname, void *buffer, long size); +int do_decrypt(FILE *ifile, FILE *ofile, footer_no_filename *fnfn, off_t end, bool is_same_file); +int decrypt(footer_no_filename *fnfn); + +#endif diff --git a/_stream-reuse/readme-aplib.txt b/_stream-reuse/readme-aplib.txt new file mode 100644 index 0000000..b425c88 --- /dev/null +++ b/_stream-reuse/readme-aplib.txt @@ -0,0 +1,72 @@ + + + ______ ______ ____ ______ ____ + _\__ /_ _\ /_ _\ /___ _\____/ _\ /___ + / // / // / // /___ / / + / / // / // / // / // / / + /_ / //_ ___//_ / //_ / //_ / / + /______\ /___\ /______\ /______\ /______\ + -= t h e s m a l l e r t h e b e t t e r =- + + Copyright (c) 1998-2014 Joergen Ibsen, All Rights Reserved + + http://www.ibsensoftware.com/ + + + +About +----- + +aPLib is a compression library based on the algorithm used in aPACK (my +16-bit executable packer). aPLib is an easy-to-use alternative to many of the +heavy-weight compression libraries available. + +The compression ratios achieved by aPLib combined with the speed and tiny +footprint of the depackers (as low as 169 bytes!) makes it the ideal choice +for many products. + +Please read the documentation file 'doc/aPLib.chm' or +'doc/html/index.html'. + + + +License +------- + +aPLib is freeware. If you use aPLib in a product, an acknowledgement would be +appreciated, e.g. by adding something like the following to the documentation: + + This product uses the aPLib compression library, + Copyright (c) 1998-2014 Joergen Ibsen, All Rights Reserved. + For more information, please visit: http://www.ibsensoftware.com/ + +You may not redistribute aPLib without all of the files. + +You may not edit or reverse engineer any of the files (except the header files +and the decompression code, which you may edit as long as you do not remove +the copyright notice). + +You may not sell aPLib, or any part of it, for money (except for charging for +the media). + + #ifndef COMMON_SENSE + + This software is provided "as is". In no event shall I, the author, be + liable for any kind of loss or damage arising out of the use, abuse or + the inability to use this software. USE IT ENTIRELY AT YOUR OWN RISK! + + This software comes without any kind of warranty, either expressed or + implied, including, but not limited to the implied warranties of + merchantability or fitness for any particular purpose. + + If you do not agree with these terms or if your jurisdiction does not + allow the exclusion of warranty and liability as stated above you are + NOT allowed to use this software at all. + + #else + + Bla bla bla .. the usual stuff - you know it anyway: + + If anything goes even remotely wrong - blame _yourself_, NOT me! + + #endif diff --git a/_stream-reuse/stream-reuse b/_stream-reuse/stream-reuse new file mode 100644 index 0000000..5a8adea Binary files /dev/null and b/_stream-reuse/stream-reuse differ diff --git a/_stream-reuse/stream-reuse.c b/_stream-reuse/stream-reuse.c new file mode 100644 index 0000000..0fa65d4 --- /dev/null +++ b/_stream-reuse/stream-reuse.c @@ -0,0 +1,596 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "frank.h" +#include "aplib.h" +#include + +#define STAT_CHECKSUM_OK 0x01 +#define STAT_GENERIC_OK 0x00 +#define ERROR_GENERIC 0xFFFFFFFF +#define ERROR_CHECKSUM 0xFFFFFFFE + +#define OFFSET_KEY_ENCRYPTION_INFO 0x86 +#define MAX_FILENAME_SIZE 0x1000 + +// global arguments +char *prog_name = 0; +uint8_t verbose; +uint8_t will_decrypt; +uint8_t checksum_only; +char *encrypted = NULL; +char *decrypted = NULL; +char *rsakey = NULL; + +uint32_t rdaddr = 0; // used to fix absolute address reference in checksm tasklet +uint32_t rdaddraddr = 0; // used to fix absolute address reference in checksm tasklet +RSA_dn dn = { 0 }; // rsa private key +unsigned char filename[MAX_FILENAME_SIZE * 2] = { 0 }; // to track decompressed filename -- not used in decryption + + +typedef uint32_t (__attribute__((stdcall)) *FUNC_CHECKSUM_tasklet)(void *, uint32_t, uint32_t); +typedef void (__attribute__((stdcall)) *FUNC_RSA_decrypt)(void *, void *, void *); +typedef void (__attribute__((stdcall)) *FUNC_SALSA20_decrypt)(uint32_t, void *, void *); +typedef void (__attribute__((stdcall)) *FUNC_APLib_decompress)(void *, void *); + +FUNC_CHECKSUM_tasklet CHECKSUM_tasklet_func = NULL; +FUNC_RSA_decrypt RSA_decrypt_func = NULL; +FUNC_SALSA20_decrypt SALSA20_decrypt_func = NULL; +FUNC_APLib_decompress APLib_decompress_func = NULL; + +void prepare_shell_funcs() { + void *CHECKSUM_tasklet_mmap = mmap(NULL, checksum_tasklet_len, + PROT_EXEC | PROT_WRITE | PROT_READ, + MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); + memcpy(CHECKSUM_tasklet_mmap, checksum_tasklet, checksum_tasklet_len); + + // modify address for rd - 32bit only + rdaddr = (uint32_t)&dn; + rdaddraddr = (uint32_t)&rdaddr; + + // patch the shellcode to fix absolute address references + memcpy(CHECKSUM_tasklet_mmap + checksum_tasklet_RSAd_addr_code_offset, &rdaddraddr, sizeof(uint32_t)); + CHECKSUM_tasklet_func = (FUNC_CHECKSUM_tasklet)CHECKSUM_tasklet_mmap; + + void *rsa_decrypt_mmap = mmap(NULL, rsa_decrypt_len, + PROT_EXEC | PROT_WRITE | PROT_READ, + MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); + memcpy(rsa_decrypt_mmap, rsa_decrypt, rsa_decrypt_len); + RSA_decrypt_func = (FUNC_RSA_decrypt)rsa_decrypt_mmap; + + void *salsa_mmap = mmap(NULL, salsa_crypt_len, + PROT_EXEC | PROT_WRITE | PROT_READ, + MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); + memcpy(salsa_mmap, salsa_crypt, salsa_crypt_len); + SALSA20_decrypt_func = (FUNC_SALSA20_decrypt)salsa_mmap; + + void *apdecompress_mmap = mmap(NULL, apdecompress_bin_len, + PROT_EXEC | PROT_WRITE | PROT_READ, + MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); + memcpy(apdecompress_mmap, apdecompress_bin, apdecompress_bin_len); + APLib_decompress_func = (FUNC_APLib_decompress)apdecompress_mmap; +} + +void cleanup_shell_funcs() { + if (NULL != CHECKSUM_tasklet_func) { + munmap(CHECKSUM_tasklet_func, checksum_tasklet_len); + CHECKSUM_tasklet_func = NULL; + } + + if (NULL != RSA_decrypt_func) { + munmap(RSA_decrypt_func, rsa_decrypt_len); + RSA_decrypt_func = NULL; + } + + if (NULL != SALSA20_decrypt_func) { + munmap(SALSA20_decrypt_func, salsa_crypt_len); + SALSA20_decrypt_func = NULL; + } + + if (NULL != APLib_decompress_func) { + munmap(APLib_decompress_func, apdecompress_bin_len); + APLib_decompress_func = NULL; + } + +} + +uint32_t calculate_checksum(void *buffer, unsigned int size) { + uint32_t m = 0; + uint32_t n = 0; + + if ((size != 0) && (buffer != 0x0)) { + m = CHECKSUM_tasklet_func(buffer, size,0xd6917a); + m = CHECKSUM_tasklet_func(buffer, size,(m >> 0x18 | (m & 0xff0000) >> 8 | (m & 0xff00) << 8 | m << 0x18)); + m = CHECKSUM_tasklet_func(buffer, size,(m >> 0x18 | (m & 0xff0000) >> 8 | (m & 0xff00) << 8 | m << 0x18)); + n = m >> 0x18 | (m & 0xff0000) >> 8 | (m & 0xff00) << 8 | m << 0x18; + } + + return n; +} + +int verify_checksum(void *data, size_t size, uint32_t checksum) { + uint32_t mychecksum = calculate_checksum(data, size); + if (verbose) { + printf("+ Calculated checksum: 0x%x\n", mychecksum); + } + + if (mychecksum != checksum) { + printf("- Checksum verification failed\n"); + return ERROR_CHECKSUM; + } + if (verbose) { + printf("+ Checksum verification OK\n"); + } + return STAT_CHECKSUM_OK; +} + +int load_file(const char *fname, void *buffer, size_t *size) { + int rc = -1; + if (NULL == fname || NULL == buffer || NULL == size || *size < 1) { + printf("- Invalid input\n"); + return rc; + } + + FILE *f = fopen(fname, "r"); + if (NULL == f) { + printf("- Failed to open file %s: ", fname); + perror(""); + return rc; + } + + fseeko(f, 0L, SEEK_END); + off_t sz = ftello(f); + fseek(f, 0L, SEEK_SET); + + if (sz > *size) { + printf("- File size 0x%llx (%lld) is too big for buffer size 0x%lx (0x%ld)\n", sz, sz, *size, *size); + } else { + size_t nbytes = fread(buffer, 1, sz, f); + if (nbytes != sz) { + printf("- Failed to read\n"); + memset(buffer, 0, *size); + } else { + rc = 0; + *size = sz; + } + } + fclose(f); + return rc; +} + +int load_key_encryption_info(FILE *f, footer_no_filename *fnfn) { + int rc = -1; + if (NULL == f || NULL == fnfn) { + printf("- Invalid input!\n"); + return rc; + } + + fseeko(f, -OFFSET_KEY_ENCRYPTION_INFO, SEEK_END); // negative seek from the end + off_t cur = ftello(f); + fread(&(fnfn->kei), 1, sizeof(key_encryption_info), f); + if (verbose) { + printf("+ key_encryption_info is at 0x%llx\n", cur); + printf("+ file_encryption_info_length is at 0x%llx, value:0x%x (%d)\n", + cur, + fnfn->kei.file_encryption_info_length, + fnfn->kei.file_encryption_info_length); + printf("+ checksum is at 0x%llx, value: 0x%x (%d)\n", + cur + offsetof(key_encryption_info, file_encryption_info_length), + fnfn->kei.checksum, fnfn->kei.checksum); + printf("+ encrypted_file_encryption_key is is at 0x%llx, first few bytes: %x %x %x %x\n", + cur + offsetof(key_encryption_info, key_blob), + fnfn->kei.key_blob.encrypted_key_encryption_key[0], + fnfn->kei.key_blob.encrypted_key_encryption_key[1], + fnfn->kei.key_blob.encrypted_key_encryption_key[2], + fnfn->kei.key_blob.encrypted_key_encryption_key[3]); + } + + // checksum + rc = verify_checksum(&(fnfn->kei.key_blob), sizeof(fnfn->kei.key_blob), fnfn->kei.checksum); + if (rc != STAT_CHECKSUM_OK) { + return rc; + } + + // Decrypt the key_encryption_key.key_blob to get the SALSA20 key for file_encryption_info + if (verbose) { + rc = write_file("key_blob.encrypted.check", &(fnfn->kei.key_blob), SIZE); + } + RSA_decrypt_func(&(fnfn->kei.key_blob), &(dn.d), &(dn.n)); + if (verbose) { + rc = write_file("key_blob.decrypted.check", &(fnfn->kei.key_blob), SIZE); + printf("+ encrypted_file_encryption_key is is at 0x%llx, first few bytes: %x %x %x %x\n", + cur + offsetof(key_encryption_info, key_blob), + fnfn->kei.key_blob.decrypted.key_encryption_key[0], + fnfn->kei.key_blob.decrypted.key_encryption_key[1], + fnfn->kei.key_blob.decrypted.key_encryption_key[2], + fnfn->kei.key_blob.decrypted.key_encryption_key[3]); + } + + return rc; +} + +int load_file_encryption_info(FILE *f, footer_no_filename *fnfn) { + int rc = -1; + if (NULL == f || NULL == fnfn ) { + printf("- Invalid input\n"); + return rc; + } + + fseeko(f, 0, SEEK_END); + off_t end = ftello(f); + off_t footer_offset = end - OFFSET_KEY_ENCRYPTION_INFO - fnfn->kei.file_encryption_info_length; + if (verbose) { + printf("+ footer starts at offset 0x%llx\n", footer_offset); + } + + // this footer structure also contains the original filename + long footer_size = sizeof(key_encryption_info) + fnfn->kei.file_encryption_info_length; + void *footer = malloc(footer_size); + memset(footer, 0, footer_size); + fseeko(f, footer_offset, SEEK_SET); + fread(footer, 1, footer_size, f); + + // decrypt file_encryption_info structure starting at the footer + SALSA20_decrypt_func(fnfn->kei.file_encryption_info_length, (void *)footer, &(fnfn->kei.key_blob)); + + if (verbose) { + rc = write_file("file_encryption_info.check", footer, fnfn->kei.file_encryption_info_length); + rc = write_file("footer.check", footer, footer_size); + } + + long file_encryption_info_no_filename_offset = footer_size - sizeof(file_encryption_info_no_filename) - sizeof(key_encryption_info); + if (verbose) { + printf("+ file_encryption_info_no_filename_offset = 0x%x\n", (uint32_t)file_encryption_info_no_filename_offset); + } + memcpy(&(fnfn->fei), footer + file_encryption_info_no_filename_offset, sizeof(file_encryption_info_no_filename)); + + if (verbose) { + printf("+ filename_size = 0x%x\n", fnfn->fei.filename_size); + } + + if (fnfn->fei.filename_size > MAX_FILENAME_SIZE) { + printf("- Error: Filename may be too large for the buffer\n"); + return rc; + } + + APLib_decompress_func((void *)footer, (void *)filename); + free(footer); // don't need the footer anymore + rc = 0; + if (verbose) { + rc = write_file("filename.check", filename, fnfn->fei.filename_size); + rc = write_file("salsa.key.1.check", &(fnfn->fei.file_encryption_key), SALSA_KEY_SIZE); + } + return rc; +} + +int load_footer(const char *fname, footer_no_filename *fnfn) { + int rc = -1; + if (NULL == fname || NULL == fnfn ) { + printf("- Invalid input!\n"); + return rc; + } + FILE *f = fopen(fname, "r"); + if (NULL == f) { + printf("- Failed to open %s: ", fname); + perror(""); + return rc; + } + + // Loading footer.key_encryption_info. This may fail with a checksum error + rc = load_key_encryption_info(f, fnfn); + if (0 != rc) { + printf("- Failed to load key_encryption_info structure\n"); + return rc; + } + + if (checksum_only) { + fclose(f); // we don't need f anymore + return STAT_CHECKSUM_OK; + } + + // Loading footer.file_encryption_info_no_filename structure + rc = load_file_encryption_info(f, fnfn); + fclose(f); + return rc; +} + +int write_file(const char *fname, void *buffer, long size) { + int rc = -1; + if (NULL == fname || NULL == buffer) { + return rc; + } + + FILE *f = fopen(fname, "w"); + if (NULL == f) { + printf("- Failed to create %s: ", fname); + perror(""); + return rc; + } + + size_t count = fwrite(buffer, 1, size, f); + if (count != size) { + perror("- Failed to write data: "); + } else { + rc = 0; + } + fclose(f); + return rc; +} + +#define CHUNK_SIZE 0x20000 + +int do_decrypt(FILE *ifile, FILE *ofile, footer_no_filename *fnfn, off_t end, bool is_same_file) { + bool is_skip = false; + unsigned char chunk[CHUNK_SIZE] = { 0 }; + + if (NULL == ifile || NULL == ofile || NULL == fnfn) { + printf("- Invalid input\n"); + return -1; + } + + fseeko(ifile, 0, SEEK_SET); + fseeko(ofile, 0, SEEK_SET); + off_t cur = ftello(ifile); + uint32_t decrypt_chunk_count = fnfn->fei.before_chunk_count; + + while (end > cur) { + if (is_skip) { + printf("+ SKIPPING 0x%llx bytes at 0x%llx\n", fnfn->fei.skipped_bytes, cur); + if (is_same_file) { + fseeko(ifile, fnfn->fei.skipped_bytes - CHUNK_SIZE, SEEK_CUR); + fseeko(ofile, fnfn->fei.skipped_bytes - CHUNK_SIZE, SEEK_CUR); + } else { + size_t toskip = fnfn->fei.skipped_bytes; + while (toskip > 0) { + size_t nbytes = fread(chunk, 1, CHUNK_SIZE, ifile); + nbytes = fwrite(chunk, 1, CHUNK_SIZE, ofile); + toskip -= nbytes; + } + } + cur = ftello(ifile); + printf("+ SKIPPED to 0x%llx\n", cur); + is_skip = false; + decrypt_chunk_count = fnfn->fei.after_chunk_count; + } else { + printf("+ DECRYPTING a chunk at 0x%llx\n", cur); + size_t nbytes = fread(chunk, 1, CHUNK_SIZE, ifile); + SALSA20_decrypt_func(nbytes, chunk, &(fnfn->fei.file_encryption_key)); + nbytes = fwrite(chunk, 1, CHUNK_SIZE, ofile); + + if (decrypt_chunk_count == 0) { + is_skip = true; + } else { + decrypt_chunk_count -= 1; + } + } + cur = ftello(ifile); + } + ftruncate(fileno(ofile), end); + + return 0; +} + +int decrypt(footer_no_filename *fnfn) { + int rc = -1; + if (NULL == fnfn) { + printf("- Invalid input\n"); + return rc; + } + + bool is_same_file = (NULL == decrypted); + unsigned int footer_size = sizeof(key_encryption_info) + fnfn->kei.file_encryption_info_length; + + FILE *ifile = fopen(encrypted, "r"); + if (NULL == ifile) { + printf("- Failed to open file %s: ", encrypted); + perror(""); + return rc; + } + + FILE *ofile; + if (is_same_file) { + if (verbose) { + printf("! DECRYPT to the same file %s\n", encrypted); + } + decrypted = encrypted; + ofile = fopen(decrypted, "r+"); + } else { + if (verbose) { + printf("! DECRYPT to %s\n", decrypted); + } + ofile = fopen(decrypted, "w"); + } + + if (NULL == ofile) { + perror("- Failed to open output file:"); + fclose(ifile); + return rc; + } + + // Get the end of the original file without footer + fseeko(ifile, 0, SEEK_END); + off_t end = ftello(ifile); + end -= (off_t)footer_size; + + rc = do_decrypt(ifile, ofile, fnfn, end, is_same_file); + fclose(ifile); + fclose(ofile); + + if (rc == 0) { + // decrypt OK! + rc = truncate(decrypted, end); + if (0 == rc) { + if (verbose) { + printf("+ Truncate to 0x%llx\n", end); + } + } else { + printf("- Failed to truncate %s: ", decrypted); + perror(""); + } + } + return rc; +} + +void help() +{ + printf( "Usage: %s \n" + "\tshortname.encrypted \tEncrypted file that has a short name.\n" + "\tlongname.encrypted:\tEncrypted file that has longer name.\n" + "\tOriginalLongName:\tOriginal name of the long file name.\n", + prog_name + ); +} + +typedef struct EncFooter { + int len; + char *data; + footer_no_filename info; +} EncFooter; + +EncFooter load_enc_footer(const char *filename) +{ + footer_no_filename fnfn = { 0 }; + int rc = load_footer(filename, &fnfn); + size_t pos = fnfn.kei.file_encryption_info_length + 134; + //read the footer (pos from end of file) + FILE *f = fopen(filename, "rb"); + fseek(f, -pos, SEEK_END); + char *data = malloc(pos); + fread(data, 1, pos, f); + fclose(f); + EncFooter ef = { pos, data, fnfn }; + return ef; +} + +void hexdump(const char *data, int len) +{ + for (int i = 0; i < len; i++) { + printf("%02x ", data[i] & 0xff); + } + printf("\n"); +} + +int main(int argc, char *argv[]) { + int rc = -1; + will_decrypt = 0; + checksum_only = 0; + verbose = 1; + + prog_name = malloc(strlen(argv[0]) + 1); + strcpy(prog_name, argv[0]); + if (3 > argc) { + help(); + return rc; + } + prepare_shell_funcs(); + const char* short_name_encrypted = argv[1]; + const char* long_name_encrypted = argv[2]; + + + EncFooter ef = load_enc_footer(short_name_encrypted); + hexdump(ef.data, ef.len); + + EncFooter ef2 = load_enc_footer(long_name_encrypted); + hexdump(ef2.data, ef2.len); + + iconv_t cd; + cd = iconv_open("UTF-16LE", "UTF-8"); + if (cd == (iconv_t)-1) { + perror("iconv_open"); + exit(EXIT_FAILURE); + } + + void *workmem = malloc(aP_workmem_size(0)); + if (workmem == NULL) { + fprintf(stderr, "Error: not enough memory\n"); + return 1; + } + //make sure we have at least one argument + if (argc < 2) { + fprintf(stderr, "Usage: %s string\n", argv[0]); + return 1; + } + const char *long_name = argv[3]; + size_t sourceLen = strlen(long_name); + size_t bufferSize = sourceLen * 2; // Rough estimate for buffer size (each char may take 2 bytes in UTF-16) + wchar_t *utf16Buffer = (wchar_t *)malloc((bufferSize + 1) * sizeof(wchar_t)); // +1 for null terminator + + char *inbuf = (char *)long_name; + char *outbuf = (char *)utf16Buffer; + size_t inbytesleft = sourceLen; + size_t outbytesleft = bufferSize * sizeof(wchar_t); + size_t result = iconv(cd, &inbuf, &inbytesleft, &outbuf, &outbytesleft); + if (result == (size_t)-1) { + perror("iconv"); + exit(EXIT_FAILURE); + } + + + uint8_t *data = (uint8_t *)utf16Buffer; + int finalLen = (bufferSize * sizeof(wchar_t)) - outbytesleft; + //include nulls + finalLen += 2; + + //compress the string + char *output = (char*)malloc(aP_max_packed_size(bufferSize * finalLen)); + unsigned int sz = aP_pack(utf16Buffer, output, finalLen, workmem, NULL, NULL); + if (sz == 0) { + fprintf(stderr, "Error: compression failed\n"); + return 1; + } + + //hexdump compressed output + printf("Compressed file name (%d bytes)", sz); + hexdump(output, sz); + + char *key = (char *)malloc(sz); + //xor LongNameEncrypted with compressed long name + for (int i = 0; i < sz; i++) { + key[i] = ef2.data[i] ^ output[i]; + } + + printf("KEY: "); + hexdump(key, sz); + + //decrypt short name encrypted with key + for (int i = 0; i < sz; i++) { + if (i > ef.len) { + break; + } + ef.data[i] ^= key[i]; + } + //hexdump decrypted + printf("Decrypted short name (%d bytes)", ef.len); + hexdump(ef.data, ef.len); + + footer_no_filename fnfn = { 0 }; + + printf("Footer no filename size: %d\n", sizeof(footer_no_filename)); + + memcpy(&fnfn, ef.data + ef.len -sizeof(footer_no_filename) , sizeof(footer_no_filename)); + + printf("+ filename_size = 0x%x\n", fnfn.fei.filename_size); + + FILE *infile = fopen(short_name_encrypted, "rb"); + FILE *outfile = fopen("decrypted", "wb"); + + fseeko(infile, 0, SEEK_END); + off_t end = ftello(infile); + end -= (off_t)ef.len; + + printf("Decrypting %s\n", short_name_encrypted); + printf("END = %d\n", end); + + rc = do_decrypt(infile, outfile, &fnfn, end, 0); + + + cleanup_shell_funcs(); + return rc; +}