├── Makefile ├── README.md ├── aplib.a ├── aplib.h ├── frank ├── frank.c ├── frank.h ├── readme-aplib.txt └── stream-reuse.c /Makefile: -------------------------------------------------------------------------------- 1 | all: 2 | @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 3 | @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 4 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # This fork 2 | 3 | This fork adds stream-reuse.c for POC of the keystream bug 4 | 5 | 6 | # LOCKIT V3 LINUX DECRYPTOR 7 | 8 | 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. 9 | 10 | ## BUILD 11 | 12 | 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. 13 | 14 | ``` 15 | 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 16 | ``` 17 | 18 | or 19 | 20 | ``` 21 | make 22 | ``` 23 | 24 | The tested build environment is **amd64 Ubuntu 22.04**. A prebuilt binary is also included. 25 | 26 | ## USAGE 27 | 28 | ``` 29 | frank -i -r [OPTIONS] 30 | -i: Encrypted file. 31 | -r: RSA private key file used with -d. Note: Must be exactly 256 bytes long, with RAW RSA d (128 bytes) & n (128 bytes). 32 | -d: Decrypt, if -o is specified, write to output file, else overwrite input file. 33 | -o: Output file, used in -d. Note: Overwrite input file is significantly faster. 34 | -c: Calculate checksum, not decrypt, do not use with -d." 35 | -v: Verbose. 36 | ``` 37 | 38 | **NOTE**: When decrypting large file, omitting -o would make the code run much faster since LOCKBIT only encrypts parts of the file. 39 | -------------------------------------------------------------------------------- /aplib.a: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yohanes/lockbit-v3-linux-decryptor/062421d89c048fc2493002e03fa0cb7fba4d6c3f/aplib.a -------------------------------------------------------------------------------- /aplib.h: -------------------------------------------------------------------------------- 1 | /* 2 | * aPLib compression library - the smaller the better :) 3 | * 4 | * ELF format header file 5 | * 6 | * Copyright (c) 1998-2014 Joergen Ibsen 7 | * All Rights Reserved 8 | * 9 | * http://www.ibsensoftware.com/ 10 | */ 11 | 12 | #ifndef APLIB_H_INCLUDED 13 | #define APLIB_H_INCLUDED 14 | 15 | #ifdef __cplusplus 16 | extern "C" { 17 | #endif 18 | 19 | #ifndef APLIB_ERROR 20 | # define APLIB_ERROR ((unsigned int) (-1)) 21 | #endif 22 | 23 | unsigned int aP_pack(const void *source, 24 | void *destination, 25 | unsigned int length, 26 | void *workmem, 27 | int (*callback)(unsigned int, unsigned int, unsigned int, void *), 28 | void *cbparam); 29 | 30 | unsigned int aP_workmem_size(unsigned int inputsize); 31 | 32 | unsigned int aP_max_packed_size(unsigned int inputsize); 33 | 34 | unsigned int aP_depack_asm(const void *source, void *destination); 35 | 36 | unsigned int aP_depack_asm_fast(const void *source, void *destination); 37 | 38 | unsigned int aP_depack_asm_safe(const void *source, 39 | unsigned int srclen, 40 | void *destination, 41 | unsigned int dstlen); 42 | 43 | unsigned int aP_crc32(const void *source, unsigned int length); 44 | 45 | unsigned int aPsafe_pack(const void *source, 46 | void *destination, 47 | unsigned int length, 48 | void *workmem, 49 | int (*callback)(unsigned int, unsigned int, unsigned int, void *), 50 | void *cbparam); 51 | 52 | unsigned int aPsafe_check(const void *source); 53 | 54 | unsigned int aPsafe_get_orig_size(const void *source); 55 | 56 | unsigned int aPsafe_depack(const void *source, 57 | unsigned int srclen, 58 | void *destination, 59 | unsigned int dstlen); 60 | 61 | #ifdef __cplusplus 62 | } /* extern "C" */ 63 | #endif 64 | 65 | #endif /* APLIB_H_INCLUDED */ 66 | -------------------------------------------------------------------------------- /frank: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yohanes/lockbit-v3-linux-decryptor/062421d89c048fc2493002e03fa0cb7fba4d6c3f/frank -------------------------------------------------------------------------------- /frank.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include "frank.h" 12 | 13 | #define STAT_CHECKSUM_OK 0x01 14 | #define STAT_GENERIC_OK 0x00 15 | #define ERROR_GENERIC 0xFFFFFFFF 16 | #define ERROR_CHECKSUM 0xFFFFFFFE 17 | 18 | #define OFFSET_KEY_ENCRYPTION_INFO 0x86 19 | #define MAX_FILENAME_SIZE 0x1000 20 | 21 | // global arguments 22 | char *prog_name = 0; 23 | uint8_t verbose; 24 | uint8_t will_decrypt; 25 | uint8_t checksum_only; 26 | char *encrypted = NULL; 27 | char *decrypted = NULL; 28 | char *rsakey = NULL; 29 | 30 | uint32_t rdaddr = 0; // used to fix absolute address reference in checksm tasklet 31 | uint32_t rdaddraddr = 0; // used to fix absolute address reference in checksm tasklet 32 | RSA_dn dn = { 0 }; // rsa private key 33 | unsigned char filename[MAX_FILENAME_SIZE * 2] = { 0 }; // to track decompressed filename -- not used in decryption 34 | 35 | 36 | typedef uint32_t (__attribute__((stdcall)) *FUNC_CHECKSUM_tasklet)(void *, uint32_t, uint32_t); 37 | typedef void (__attribute__((stdcall)) *FUNC_RSA_decrypt)(void *, void *, void *); 38 | typedef void (__attribute__((stdcall)) *FUNC_SALSA20_decrypt)(uint32_t, void *, void *); 39 | typedef void (__attribute__((stdcall)) *FUNC_APLib_decompress)(void *, void *); 40 | 41 | FUNC_CHECKSUM_tasklet CHECKSUM_tasklet_func = NULL; 42 | FUNC_RSA_decrypt RSA_decrypt_func = NULL; 43 | FUNC_SALSA20_decrypt SALSA20_decrypt_func = NULL; 44 | FUNC_APLib_decompress APLib_decompress_func = NULL; 45 | 46 | void prepare_shell_funcs() { 47 | void *CHECKSUM_tasklet_mmap = mmap(NULL, checksum_tasklet_len, 48 | PROT_EXEC | PROT_WRITE | PROT_READ, 49 | MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); 50 | memcpy(CHECKSUM_tasklet_mmap, checksum_tasklet, checksum_tasklet_len); 51 | 52 | // modify address for rd - 32bit only 53 | rdaddr = (uint32_t)&dn; 54 | rdaddraddr = (uint32_t)&rdaddr; 55 | 56 | // patch the shellcode to fix absolute address references 57 | memcpy(CHECKSUM_tasklet_mmap + checksum_tasklet_RSAd_addr_code_offset, &rdaddraddr, sizeof(uint32_t)); 58 | CHECKSUM_tasklet_func = (FUNC_CHECKSUM_tasklet)CHECKSUM_tasklet_mmap; 59 | 60 | void *rsa_decrypt_mmap = mmap(NULL, rsa_decrypt_len, 61 | PROT_EXEC | PROT_WRITE | PROT_READ, 62 | MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); 63 | memcpy(rsa_decrypt_mmap, rsa_decrypt, rsa_decrypt_len); 64 | RSA_decrypt_func = (FUNC_RSA_decrypt)rsa_decrypt_mmap; 65 | 66 | void *salsa_mmap = mmap(NULL, salsa_crypt_len, 67 | PROT_EXEC | PROT_WRITE | PROT_READ, 68 | MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); 69 | memcpy(salsa_mmap, salsa_crypt, salsa_crypt_len); 70 | SALSA20_decrypt_func = (FUNC_SALSA20_decrypt)salsa_mmap; 71 | 72 | void *apdecompress_mmap = mmap(NULL, apdecompress_bin_len, 73 | PROT_EXEC | PROT_WRITE | PROT_READ, 74 | MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); 75 | memcpy(apdecompress_mmap, apdecompress_bin, apdecompress_bin_len); 76 | APLib_decompress_func = (FUNC_APLib_decompress)apdecompress_mmap; 77 | } 78 | 79 | void cleanup_shell_funcs() { 80 | if (NULL != CHECKSUM_tasklet_func) { 81 | munmap(CHECKSUM_tasklet_func, checksum_tasklet_len); 82 | CHECKSUM_tasklet_func = NULL; 83 | } 84 | 85 | if (NULL != RSA_decrypt_func) { 86 | munmap(RSA_decrypt_func, rsa_decrypt_len); 87 | RSA_decrypt_func = NULL; 88 | } 89 | 90 | if (NULL != SALSA20_decrypt_func) { 91 | munmap(SALSA20_decrypt_func, salsa_crypt_len); 92 | SALSA20_decrypt_func = NULL; 93 | } 94 | 95 | if (NULL != APLib_decompress_func) { 96 | munmap(APLib_decompress_func, apdecompress_bin_len); 97 | APLib_decompress_func = NULL; 98 | } 99 | 100 | } 101 | 102 | uint32_t calculate_checksum(void *buffer, unsigned int size) { 103 | uint32_t m = 0; 104 | uint32_t n = 0; 105 | 106 | if ((size != 0) && (buffer != 0x0)) { 107 | m = CHECKSUM_tasklet_func(buffer, size,0xd6917a); 108 | m = CHECKSUM_tasklet_func(buffer, size,(m >> 0x18 | (m & 0xff0000) >> 8 | (m & 0xff00) << 8 | m << 0x18)); 109 | m = CHECKSUM_tasklet_func(buffer, size,(m >> 0x18 | (m & 0xff0000) >> 8 | (m & 0xff00) << 8 | m << 0x18)); 110 | n = m >> 0x18 | (m & 0xff0000) >> 8 | (m & 0xff00) << 8 | m << 0x18; 111 | } 112 | 113 | return n; 114 | } 115 | 116 | int verify_checksum(void *data, size_t size, uint32_t checksum) { 117 | uint32_t mychecksum = calculate_checksum(data, size); 118 | if (verbose) { 119 | printf("+ Calculated checksum: 0x%x\n", mychecksum); 120 | } 121 | 122 | if (mychecksum != checksum) { 123 | printf("- Checksum verification failed\n"); 124 | return ERROR_CHECKSUM; 125 | } 126 | if (verbose) { 127 | printf("+ Checksum verification OK\n"); 128 | } 129 | return STAT_CHECKSUM_OK; 130 | } 131 | 132 | int load_file(const char *fname, void *buffer, size_t *size) { 133 | int rc = -1; 134 | if (NULL == fname || NULL == buffer || NULL == size || *size < 1) { 135 | printf("- Invalid input\n"); 136 | return rc; 137 | } 138 | 139 | FILE *f = fopen(fname, "r"); 140 | if (NULL == f) { 141 | printf("- Failed to open file %s: ", fname); 142 | perror(""); 143 | return rc; 144 | } 145 | 146 | fseeko(f, 0L, SEEK_END); 147 | off_t sz = ftello(f); 148 | fseek(f, 0L, SEEK_SET); 149 | 150 | if (sz > *size) { 151 | printf("- File size 0x%llx (%lld) is too big for buffer size 0x%lx (0x%ld)\n", sz, sz, *size, *size); 152 | } else { 153 | size_t nbytes = fread(buffer, 1, sz, f); 154 | if (nbytes != sz) { 155 | printf("- Failed to read\n"); 156 | memset(buffer, 0, *size); 157 | } else { 158 | rc = 0; 159 | *size = sz; 160 | } 161 | } 162 | fclose(f); 163 | return rc; 164 | } 165 | 166 | int load_key_encryption_info(FILE *f, footer_no_filename *fnfn) { 167 | int rc = -1; 168 | if (NULL == f || NULL == fnfn) { 169 | printf("- Invalid input!\n"); 170 | return rc; 171 | } 172 | 173 | fseeko(f, -OFFSET_KEY_ENCRYPTION_INFO, SEEK_END); // negative seek from the end 174 | off_t cur = ftello(f); 175 | fread(&(fnfn->kei), 1, sizeof(key_encryption_info), f); 176 | if (verbose) { 177 | printf("+ key_encryption_info is at 0x%llx\n", cur); 178 | printf("+ file_encryption_info_length is at 0x%llx, value:0x%x (%d)\n", 179 | cur, 180 | fnfn->kei.file_encryption_info_length, 181 | fnfn->kei.file_encryption_info_length); 182 | printf("+ checksum is at 0x%llx, value: 0x%x (%d)\n", 183 | cur + offsetof(key_encryption_info, file_encryption_info_length), 184 | fnfn->kei.checksum, fnfn->kei.checksum); 185 | printf("+ encrypted_file_encryption_key is is at 0x%llx, first few bytes: %x %x %x %x\n", 186 | cur + offsetof(key_encryption_info, key_blob), 187 | fnfn->kei.key_blob.encrypted_key_encryption_key[0], 188 | fnfn->kei.key_blob.encrypted_key_encryption_key[1], 189 | fnfn->kei.key_blob.encrypted_key_encryption_key[2], 190 | fnfn->kei.key_blob.encrypted_key_encryption_key[3]); 191 | } 192 | 193 | // checksum 194 | rc = verify_checksum(&(fnfn->kei.key_blob), sizeof(fnfn->kei.key_blob), fnfn->kei.checksum); 195 | if (rc != STAT_CHECKSUM_OK) { 196 | return rc; 197 | } 198 | 199 | // Decrypt the key_encryption_key.key_blob to get the SALSA20 key for file_encryption_info 200 | if (verbose) { 201 | rc = write_file("key_blob.encrypted.check", &(fnfn->kei.key_blob), SIZE); 202 | } 203 | RSA_decrypt_func(&(fnfn->kei.key_blob), &(dn.d), &(dn.n)); 204 | if (verbose) { 205 | rc = write_file("key_blob.decrypted.check", &(fnfn->kei.key_blob), SIZE); 206 | printf("+ encrypted_file_encryption_key is is at 0x%llx, first few bytes: %x %x %x %x\n", 207 | cur + offsetof(key_encryption_info, key_blob), 208 | fnfn->kei.key_blob.decrypted.key_encryption_key[0], 209 | fnfn->kei.key_blob.decrypted.key_encryption_key[1], 210 | fnfn->kei.key_blob.decrypted.key_encryption_key[2], 211 | fnfn->kei.key_blob.decrypted.key_encryption_key[3]); 212 | } 213 | 214 | return rc; 215 | } 216 | 217 | int load_file_encryption_info(FILE *f, footer_no_filename *fnfn) { 218 | int rc = -1; 219 | if (NULL == f || NULL == fnfn ) { 220 | printf("- Invalid input\n"); 221 | return rc; 222 | } 223 | 224 | fseeko(f, 0, SEEK_END); 225 | off_t end = ftello(f); 226 | off_t footer_offset = end - OFFSET_KEY_ENCRYPTION_INFO - fnfn->kei.file_encryption_info_length; 227 | if (verbose) { 228 | printf("+ footer starts at offset 0x%llx\n", footer_offset); 229 | } 230 | 231 | // this footer structure also contains the original filename 232 | long footer_size = sizeof(key_encryption_info) + fnfn->kei.file_encryption_info_length; 233 | void *footer = malloc(footer_size); 234 | memset(footer, 0, footer_size); 235 | fseeko(f, footer_offset, SEEK_SET); 236 | fread(footer, 1, footer_size, f); 237 | 238 | // decrypt file_encryption_info structure starting at the footer 239 | SALSA20_decrypt_func(fnfn->kei.file_encryption_info_length, (void *)footer, &(fnfn->kei.key_blob)); 240 | 241 | if (verbose) { 242 | rc = write_file("file_encryption_info.check", footer, fnfn->kei.file_encryption_info_length); 243 | rc = write_file("footer.check", footer, footer_size); 244 | } 245 | 246 | long file_encryption_info_no_filename_offset = footer_size - sizeof(file_encryption_info_no_filename) - sizeof(key_encryption_info); 247 | if (verbose) { 248 | printf("+ file_encryption_info_no_filename_offset = 0x%x\n", (uint32_t)file_encryption_info_no_filename_offset); 249 | } 250 | memcpy(&(fnfn->fei), footer + file_encryption_info_no_filename_offset, sizeof(file_encryption_info_no_filename)); 251 | 252 | if (verbose) { 253 | printf("+ filename_size = 0x%x\n", fnfn->fei.filename_size); 254 | } 255 | 256 | if (fnfn->fei.filename_size > MAX_FILENAME_SIZE) { 257 | printf("- Error: Filename may be too large for the buffer\n"); 258 | return rc; 259 | } 260 | 261 | APLib_decompress_func((void *)footer, (void *)filename); 262 | free(footer); // don't need the footer anymore 263 | rc = 0; 264 | if (verbose) { 265 | rc = write_file("filename.check", filename, fnfn->fei.filename_size); 266 | rc = write_file("salsa.key.1.check", &(fnfn->fei.file_encryption_key), SALSA_KEY_SIZE); 267 | } 268 | return rc; 269 | } 270 | 271 | int load_footer(const char *fname, footer_no_filename *fnfn) { 272 | int rc = -1; 273 | if (NULL == fname || NULL == fnfn ) { 274 | printf("- Invalid input!\n"); 275 | return rc; 276 | } 277 | FILE *f = fopen(fname, "r"); 278 | if (NULL == f) { 279 | printf("- Failed to open %s: ", fname); 280 | perror(""); 281 | return rc; 282 | } 283 | 284 | // Loading footer.key_encryption_info. This may fail with a checksum error 285 | rc = load_key_encryption_info(f, fnfn); 286 | if (0 != rc) { 287 | printf("- Failed to load key_encryption_info structure\n"); 288 | return rc; 289 | } 290 | 291 | if (checksum_only) { 292 | fclose(f); // we don't need f anymore 293 | return STAT_CHECKSUM_OK; 294 | } 295 | 296 | // Loading footer.file_encryption_info_no_filename structure 297 | rc = load_file_encryption_info(f, fnfn); 298 | fclose(f); 299 | return rc; 300 | } 301 | 302 | int write_file(const char *fname, void *buffer, long size) { 303 | int rc = -1; 304 | if (NULL == fname || NULL == buffer) { 305 | return rc; 306 | } 307 | 308 | FILE *f = fopen(fname, "w"); 309 | if (NULL == f) { 310 | printf("- Failed to create %s: ", fname); 311 | perror(""); 312 | return rc; 313 | } 314 | 315 | size_t count = fwrite(buffer, 1, size, f); 316 | if (count != size) { 317 | perror("- Failed to write data: "); 318 | } else { 319 | rc = 0; 320 | } 321 | fclose(f); 322 | return rc; 323 | } 324 | 325 | #define CHUNK_SIZE 0x20000 326 | 327 | int do_decrypt(FILE *ifile, FILE *ofile, footer_no_filename *fnfn, off_t end, bool is_same_file) { 328 | bool is_skip = false; 329 | unsigned char chunk[CHUNK_SIZE] = { 0 }; 330 | 331 | if (NULL == ifile || NULL == ofile || NULL == fnfn) { 332 | printf("- Invalid input\n"); 333 | return -1; 334 | } 335 | 336 | fseeko(ifile, 0, SEEK_SET); 337 | fseeko(ofile, 0, SEEK_SET); 338 | off_t cur = ftello(ifile); 339 | uint32_t decrypt_chunk_count = fnfn->fei.before_chunk_count; 340 | 341 | while (end > cur) { 342 | if (is_skip) { 343 | printf("+ SKIPPING 0x%llx bytes at 0x%llx\n", fnfn->fei.skipped_bytes, cur); 344 | if (is_same_file) { 345 | fseeko(ifile, fnfn->fei.skipped_bytes - CHUNK_SIZE, SEEK_CUR); 346 | fseeko(ofile, fnfn->fei.skipped_bytes - CHUNK_SIZE, SEEK_CUR); 347 | } else { 348 | size_t toskip = fnfn->fei.skipped_bytes; 349 | while (toskip > 0) { 350 | size_t nbytes = fread(chunk, 1, CHUNK_SIZE, ifile); 351 | nbytes = fwrite(chunk, 1, CHUNK_SIZE, ofile); 352 | toskip -= nbytes; 353 | } 354 | } 355 | cur = ftello(ifile); 356 | printf("+ SKIPPED to 0x%llx\n", cur); 357 | is_skip = false; 358 | decrypt_chunk_count = fnfn->fei.after_chunk_count; 359 | } else { 360 | printf("+ DECRYPTING a chunk at 0x%llx\n", cur); 361 | size_t nbytes = fread(chunk, 1, CHUNK_SIZE, ifile); 362 | SALSA20_decrypt_func(nbytes, chunk, &(fnfn->fei.file_encryption_key)); 363 | nbytes = fwrite(chunk, 1, CHUNK_SIZE, ofile); 364 | 365 | if (decrypt_chunk_count == 0) { 366 | is_skip = true; 367 | } else { 368 | decrypt_chunk_count -= 1; 369 | } 370 | } 371 | cur = ftello(ifile); 372 | } 373 | return 0; 374 | } 375 | 376 | int decrypt(footer_no_filename *fnfn) { 377 | int rc = -1; 378 | if (NULL == fnfn) { 379 | printf("- Invalid input\n"); 380 | return rc; 381 | } 382 | 383 | bool is_same_file = (NULL == decrypted); 384 | unsigned int footer_size = sizeof(key_encryption_info) + fnfn->kei.file_encryption_info_length; 385 | 386 | FILE *ifile = fopen(encrypted, "r"); 387 | if (NULL == ifile) { 388 | printf("- Failed to open file %s: ", encrypted); 389 | perror(""); 390 | return rc; 391 | } 392 | 393 | FILE *ofile; 394 | if (is_same_file) { 395 | if (verbose) { 396 | printf("! DECRYPT to the same file %s\n", encrypted); 397 | } 398 | decrypted = encrypted; 399 | ofile = fopen(decrypted, "r+"); 400 | } else { 401 | if (verbose) { 402 | printf("! DECRYPT to %s\n", decrypted); 403 | } 404 | ofile = fopen(decrypted, "w"); 405 | } 406 | 407 | if (NULL == ofile) { 408 | perror("- Failed to open output file:"); 409 | fclose(ifile); 410 | return rc; 411 | } 412 | 413 | // Get the end of the original file without footer 414 | fseeko(ifile, 0, SEEK_END); 415 | off_t end = ftello(ifile); 416 | end -= (off_t)footer_size; 417 | 418 | rc = do_decrypt(ifile, ofile, fnfn, end, is_same_file); 419 | fclose(ifile); 420 | fclose(ofile); 421 | 422 | if (rc == 0) { 423 | // decrypt OK! 424 | rc = truncate(decrypted, end); 425 | if (0 == rc) { 426 | if (verbose) { 427 | printf("+ Truncate to 0x%llx\n", end); 428 | } 429 | } else { 430 | printf("- Failed to truncate %s: ", decrypted); 431 | perror(""); 432 | } 433 | } 434 | return rc; 435 | } 436 | 437 | void help() 438 | { 439 | printf( "Usage: %s -i -r [OPTIONS]\n" 440 | "\t-i:\tEncrypted file.\n" 441 | "\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" 442 | "\t-d:\tDecrypt, if -o is specified, write to output file, else overwrite input file.\n" 443 | "\t-o:\tOutput file, used in -d. Note: Overwrite input file is significantly faster.\n" 444 | "\t-c:\tCalculate checksum, not decrypt, do not use with -d.\n" 445 | "\t-v:\tVerbose.\n", 446 | prog_name 447 | ); 448 | } 449 | 450 | int main(int argc, char *argv[]) { 451 | int rc = -1; 452 | will_decrypt = 0; 453 | checksum_only = 0; 454 | verbose = 0; 455 | 456 | prog_name = malloc(strlen(argv[0]) + 1); 457 | strcpy(prog_name, argv[0]); 458 | if (3 > argc) { 459 | help(); 460 | return rc; 461 | } 462 | 463 | int opt; 464 | size_t len; 465 | while((opt = getopt(argc, argv, ":i:o:r:hdcv")) != -1) { 466 | switch(opt){ 467 | case 'i': 468 | len = strlen(optarg); 469 | encrypted = malloc(len + 1); 470 | strcpy(encrypted, optarg); 471 | encrypted[len] = '\x00'; 472 | break; 473 | case 'o': 474 | len = strlen(optarg); 475 | decrypted = malloc(len + 1); 476 | strcpy(decrypted, optarg); 477 | decrypted[len] = '\x00'; 478 | break; 479 | case 'r': 480 | len = strlen(optarg); 481 | rsakey = malloc(len + 1); 482 | strcpy(rsakey, optarg); 483 | rsakey[len] = '\x00'; 484 | break; 485 | case 'd': 486 | will_decrypt = 1; 487 | checksum_only = 0; 488 | break; 489 | case 'c': 490 | checksum_only = 1; 491 | will_decrypt = 0; 492 | break; 493 | case 'v': 494 | verbose = 1; 495 | break; 496 | case 'h': 497 | help(); 498 | return 0; 499 | case ':': 500 | printf("Option %c needs a value\n", opt); 501 | return rc; 502 | case '?': 503 | printf("Unknown option: %c\n", optopt); 504 | return rc; 505 | default: 506 | return rc; 507 | } 508 | } 509 | 510 | if (NULL == encrypted) { 511 | help(); 512 | return rc; 513 | } 514 | 515 | if ( will_decrypt && NULL == rsakey) { 516 | help(); 517 | return rc; 518 | } 519 | 520 | size_t dnsize = sizeof(RSA_dn); 521 | rc = load_file(rsakey, &dn, &dnsize); 522 | if (0 != rc) { 523 | return rc; 524 | } 525 | 526 | prepare_shell_funcs(); 527 | 528 | footer_no_filename fnfn = { 0 }; 529 | rc = load_footer(encrypted, &fnfn); 530 | 531 | if (verbose && rc == 0) { 532 | printf("-----------------\n"); 533 | printf("+ before_chunk_count: 0x%x\n", fnfn.fei.before_chunk_count); 534 | printf("+ after_chunk_count: 0x%x\n", fnfn.fei.after_chunk_count); 535 | printf("+ skipped_bytes: 0x%llx\n", fnfn.fei.skipped_bytes); 536 | printf("+ file_encryption_info_length = 0x%x\n", fnfn.kei.file_encryption_info_length); 537 | printf("+ checksum= 0x%x\n", fnfn.kei.checksum); 538 | printf("+ SALSA key for chunks: "); 539 | for (int i = 0; i < SALSA_KEY_SIZE; i++) { 540 | printf("%02hhx", *((char *)&(fnfn.fei.file_encryption_key) + i)); 541 | } 542 | printf("\n"); 543 | printf("+ SALSA key for file_encryption_info: "); 544 | for (int i = 0; i < SALSA_KEY_SIZE; i++) { 545 | printf("%02hhx", *((char *)&(fnfn.kei.key_blob.decrypted.key_encryption_key) + i)); 546 | } 547 | printf("\n"); 548 | } 549 | 550 | if (rc == 0 && will_decrypt) { 551 | if (verbose) { 552 | write_file("salsa.key.2.check", &(fnfn.fei.file_encryption_key), SALSA_KEY_SIZE); 553 | } 554 | decrypt(&fnfn); 555 | } 556 | 557 | cleanup_shell_funcs(); 558 | return rc; 559 | } 560 | -------------------------------------------------------------------------------- /frank.h: -------------------------------------------------------------------------------- 1 | #ifndef _FRANK 2 | #define _FRANK 3 | #include 4 | 5 | #define _FILE_OFFSET_BITS 64 6 | #define SIZE 0x80 7 | #define SALSA_KEY_SIZE 0x40 8 | 9 | typedef struct __attribute__((__packed__)) _RSA_dn { 10 | unsigned char d[SIZE]; 11 | unsigned char n[SIZE]; 12 | } RSA_dn; 13 | 14 | unsigned char rsa_decrypt[] = { 15 | 0x55, 0x8b, 0xec, 0x81, 0xec, 0x34, 0x01, 0x00, 0x00, 0x53, 0x51, 0x56, 16 | 0x57, 0x8d, 0x85, 0x70, 0xff, 0xff, 0xff, 0x83, 0xc0, 0x0f, 0x83, 0xe0, 17 | 0xf0, 0x89, 0x85, 0xdc, 0xfe, 0xff, 0xff, 0x8d, 0x85, 0xe0, 0xfe, 0xff, 18 | 0xff, 0x83, 0xc0, 0x0f, 0x83, 0xe0, 0xf0, 0x89, 0x85, 0xd8, 0xfe, 0xff, 19 | 0xff, 0x66, 0x0f, 0xef, 0xc0, 0xb9, 0x08, 0x00, 0x00, 0x00, 0x8b, 0x85, 20 | 0xdc, 0xfe, 0xff, 0xff, 0x8b, 0xf8, 0x66, 0x0f, 0x7f, 0x07, 0x83, 0xc7, 21 | 0x10, 0x49, 0x85, 0xc9, 0x75, 0xf4, 0xc6, 0x00, 0x01, 0x33, 0xc0, 0x8b, 22 | 0x5d, 0x0c, 0x81, 0xc3, 0x80, 0x00, 0x00, 0x00, 0xb9, 0x81, 0x00, 0x00, 23 | 0x00, 0x4b, 0x49, 0x8a, 0x03, 0x85, 0xc0, 0x74, 0xf8, 0x89, 0x8d, 0xd4, 24 | 0xfe, 0xff, 0xff, 0xc7, 0x85, 0xd0, 0xfe, 0xff, 0xff, 0x08, 0x00, 0x00, 25 | 0x00, 0xc7, 0x85, 0xcc, 0xfe, 0xff, 0xff, 0x08, 0x00, 0x00, 0x00, 0x8b, 26 | 0xb5, 0xdc, 0xfe, 0xff, 0xff, 0x8b, 0xbd, 0xd8, 0xfe, 0xff, 0xff, 0xb9, 27 | 0x08, 0x00, 0x00, 0x00, 0x66, 0x0f, 0x6f, 0x06, 0x66, 0x0f, 0x7f, 0x07, 28 | 0x83, 0xc6, 0x10, 0x83, 0xc7, 0x10, 0x49, 0x85, 0xc9, 0x75, 0xed, 0xff, 29 | 0x75, 0x10, 0xff, 0xb5, 0xd8, 0xfe, 0xff, 0xff, 0xff, 0xb5, 0xdc, 0xfe, 30 | 0xff, 0xff, 0xe8, 0x75, 0x00, 0x00, 0x00, 0xff, 0x8d, 0xcc, 0xfe, 0xff, 31 | 0xff, 0x8b, 0x8d, 0xcc, 0xfe, 0xff, 0xff, 0x33, 0xc0, 0x40, 0xd3, 0xe0, 32 | 0x22, 0x03, 0x74, 0x11, 0xff, 0x75, 0x10, 0xff, 0x75, 0x08, 0xff, 0xb5, 33 | 0xdc, 0xfe, 0xff, 0xff, 0xe8, 0x4f, 0x00, 0x00, 0x00, 0xff, 0x8d, 0xd0, 34 | 0xfe, 0xff, 0xff, 0x83, 0xbd, 0xd0, 0xfe, 0xff, 0xff, 0x00, 0x75, 0x93, 35 | 0x4b, 0xff, 0x8d, 0xd4, 0xfe, 0xff, 0xff, 0x83, 0xbd, 0xd4, 0xfe, 0xff, 36 | 0xff, 0x00, 0x0f, 0x85, 0x6b, 0xff, 0xff, 0xff, 0x8b, 0xb5, 0xdc, 0xfe, 37 | 0xff, 0xff, 0x8b, 0x7d, 0x08, 0xb9, 0x08, 0x00, 0x00, 0x00, 0x0f, 0x10, 38 | 0x06, 0x0f, 0x11, 0x07, 0x83, 0xc6, 0x10, 0x83, 0xc7, 0x10, 0x49, 0x85, 39 | 0xc9, 0x75, 0xef, 0x5f, 0x5e, 0x59, 0x5b, 0x8b, 0xe5, 0x5d, 0xc2, 0x0c, 40 | 0x00, 0x8d, 0x40, 0x00, 0x55, 0x8b, 0xec, 0x81, 0xec, 0x98, 0x00, 0x00, 41 | 0x00, 0x53, 0x51, 0x52, 0x56, 0x57, 0x8d, 0x85, 0x70, 0xff, 0xff, 0xff, 42 | 0x83, 0xc0, 0x0f, 0x83, 0xe0, 0xf0, 0x89, 0x85, 0x6c, 0xff, 0xff, 0xff, 43 | 0x66, 0x0f, 0xef, 0xc0, 0xb9, 0x08, 0x00, 0x00, 0x00, 0x8b, 0xbd, 0x6c, 44 | 0xff, 0xff, 0xff, 0x66, 0x0f, 0x7f, 0x07, 0x83, 0xc7, 0x10, 0x49, 0x85, 45 | 0xc9, 0x75, 0xf4, 0xc7, 0x85, 0x68, 0xff, 0xff, 0xff, 0x00, 0x04, 0x00, 46 | 0x00, 0x8b, 0xb5, 0x6c, 0xff, 0xff, 0xff, 0xf8, 0xe8, 0x99, 0x00, 0x00, 47 | 0x00, 0x8b, 0xbd, 0x6c, 0xff, 0xff, 0xff, 0x8b, 0x75, 0x10, 0xf8, 0xe8, 48 | 0xa9, 0x01, 0x00, 0x00, 0x73, 0x0f, 0x8b, 0xbd, 0x6c, 0xff, 0xff, 0xff, 49 | 0x8b, 0x75, 0x10, 0xf8, 0xe8, 0xd9, 0x00, 0x00, 0x00, 0x8b, 0x75, 0x08, 50 | 0xf8, 0xe8, 0x70, 0x00, 0x00, 0x00, 0x73, 0x0f, 0x8b, 0xbd, 0x6c, 0xff, 51 | 0xff, 0xff, 0x8b, 0x75, 0x0c, 0xf8, 0xe8, 0xbf, 0x00, 0x00, 0x00, 0x8b, 52 | 0xbd, 0x6c, 0xff, 0xff, 0xff, 0x8b, 0x75, 0x10, 0xf8, 0xe8, 0x6f, 0x01, 53 | 0x00, 0x00, 0x73, 0x0f, 0x8b, 0xbd, 0x6c, 0xff, 0xff, 0xff, 0x8b, 0x75, 54 | 0x10, 0xf8, 0xe8, 0x9f, 0x00, 0x00, 0x00, 0xff, 0x8d, 0x68, 0xff, 0xff, 55 | 0xff, 0x83, 0xbd, 0x68, 0xff, 0xff, 0xff, 0x00, 0x75, 0x02, 0xeb, 0x02, 56 | 0xeb, 0x87, 0x8b, 0xb5, 0x6c, 0xff, 0xff, 0xff, 0x8b, 0x7d, 0x08, 0xb9, 57 | 0x08, 0x00, 0x00, 0x00, 0x66, 0x0f, 0x6f, 0x06, 0x66, 0x0f, 0x7f, 0x07, 58 | 0x83, 0xc6, 0x10, 0x83, 0xc7, 0x10, 0x49, 0x85, 0xc9, 0x75, 0xed, 0x5f, 59 | 0x5e, 0x5a, 0x59, 0x5b, 0x8b, 0xe5, 0x5d, 0xc2, 0x0c, 0x00, 0xd1, 0x16, 60 | 0xd1, 0x56, 0x04, 0xd1, 0x56, 0x08, 0xd1, 0x56, 0x0c, 0xd1, 0x56, 0x10, 61 | 0xd1, 0x56, 0x14, 0xd1, 0x56, 0x18, 0xd1, 0x56, 0x1c, 0xd1, 0x56, 0x20, 62 | 0xd1, 0x56, 0x24, 0xd1, 0x56, 0x28, 0xd1, 0x56, 0x2c, 0xd1, 0x56, 0x30, 63 | 0xd1, 0x56, 0x34, 0xd1, 0x56, 0x38, 0xd1, 0x56, 0x3c, 0xd1, 0x56, 0x40, 64 | 0xd1, 0x56, 0x44, 0xd1, 0x56, 0x48, 0xd1, 0x56, 0x4c, 0xd1, 0x56, 0x50, 65 | 0xd1, 0x56, 0x54, 0xd1, 0x56, 0x58, 0xd1, 0x56, 0x5c, 0xd1, 0x56, 0x60, 66 | 0xd1, 0x56, 0x64, 0xd1, 0x56, 0x68, 0xd1, 0x56, 0x6c, 0xd1, 0x56, 0x70, 67 | 0xd1, 0x56, 0x74, 0xd1, 0x56, 0x78, 0xd1, 0x56, 0x7c, 0xc3, 0x8b, 0x06, 68 | 0x8b, 0x5e, 0x04, 0x8b, 0x4e, 0x08, 0x8b, 0x56, 0x0c, 0x11, 0x07, 0x11, 69 | 0x5f, 0x04, 0x11, 0x4f, 0x08, 0x11, 0x57, 0x0c, 0x8b, 0x46, 0x10, 0x8b, 70 | 0x5e, 0x14, 0x8b, 0x4e, 0x18, 0x8b, 0x56, 0x1c, 0x11, 0x47, 0x10, 0x11, 71 | 0x5f, 0x14, 0x11, 0x4f, 0x18, 0x11, 0x57, 0x1c, 0x8b, 0x46, 0x20, 0x8b, 72 | 0x5e, 0x24, 0x8b, 0x4e, 0x28, 0x8b, 0x56, 0x2c, 0x11, 0x47, 0x20, 0x11, 73 | 0x5f, 0x24, 0x11, 0x4f, 0x28, 0x11, 0x57, 0x2c, 0x8b, 0x46, 0x30, 0x8b, 74 | 0x5e, 0x34, 0x8b, 0x4e, 0x38, 0x8b, 0x56, 0x3c, 0x11, 0x47, 0x30, 0x11, 75 | 0x5f, 0x34, 0x11, 0x4f, 0x38, 0x11, 0x57, 0x3c, 0x8b, 0x46, 0x40, 0x8b, 76 | 0x5e, 0x44, 0x8b, 0x4e, 0x48, 0x8b, 0x56, 0x4c, 0x11, 0x47, 0x40, 0x11, 77 | 0x5f, 0x44, 0x11, 0x4f, 0x48, 0x11, 0x57, 0x4c, 0x8b, 0x46, 0x50, 0x8b, 78 | 0x5e, 0x54, 0x8b, 0x4e, 0x58, 0x8b, 0x56, 0x5c, 0x11, 0x47, 0x50, 0x11, 79 | 0x5f, 0x54, 0x11, 0x4f, 0x58, 0x11, 0x57, 0x5c, 0x8b, 0x46, 0x60, 0x8b, 80 | 0x5e, 0x64, 0x8b, 0x4e, 0x68, 0x8b, 0x56, 0x6c, 0x11, 0x47, 0x60, 0x11, 81 | 0x5f, 0x64, 0x11, 0x4f, 0x68, 0x11, 0x57, 0x6c, 0x8b, 0x46, 0x70, 0x8b, 82 | 0x5e, 0x74, 0x8b, 0x4e, 0x78, 0x8b, 0x56, 0x7c, 0x11, 0x47, 0x70, 0x11, 83 | 0x5f, 0x74, 0x11, 0x4f, 0x78, 0x11, 0x57, 0x7c, 0xc3, 0x8b, 0x06, 0x8b, 84 | 0x5e, 0x04, 0x8b, 0x4e, 0x08, 0x8b, 0x56, 0x0c, 0x19, 0x07, 0x19, 0x5f, 85 | 0x04, 0x19, 0x4f, 0x08, 0x19, 0x57, 0x0c, 0x8b, 0x46, 0x10, 0x8b, 0x5e, 86 | 0x14, 0x8b, 0x4e, 0x18, 0x8b, 0x56, 0x1c, 0x19, 0x47, 0x10, 0x19, 0x5f, 87 | 0x14, 0x19, 0x4f, 0x18, 0x19, 0x57, 0x1c, 0x8b, 0x46, 0x20, 0x8b, 0x5e, 88 | 0x24, 0x8b, 0x4e, 0x28, 0x8b, 0x56, 0x2c, 0x19, 0x47, 0x20, 0x19, 0x5f, 89 | 0x24, 0x19, 0x4f, 0x28, 0x19, 0x57, 0x2c, 0x8b, 0x46, 0x30, 0x8b, 0x5e, 90 | 0x34, 0x8b, 0x4e, 0x38, 0x8b, 0x56, 0x3c, 0x19, 0x47, 0x30, 0x19, 0x5f, 91 | 0x34, 0x19, 0x4f, 0x38, 0x19, 0x57, 0x3c, 0x8b, 0x46, 0x40, 0x8b, 0x5e, 92 | 0x44, 0x8b, 0x4e, 0x48, 0x8b, 0x56, 0x4c, 0x19, 0x47, 0x40, 0x19, 0x5f, 93 | 0x44, 0x19, 0x4f, 0x48, 0x19, 0x57, 0x4c, 0x8b, 0x46, 0x50, 0x8b, 0x5e, 94 | 0x54, 0x8b, 0x4e, 0x58, 0x8b, 0x56, 0x5c, 0x19, 0x47, 0x50, 0x19, 0x5f, 95 | 0x54, 0x19, 0x4f, 0x58, 0x19, 0x57, 0x5c, 0x8b, 0x46, 0x60, 0x8b, 0x5e, 96 | 0x64, 0x8b, 0x4e, 0x68, 0x8b, 0x56, 0x6c, 0x19, 0x47, 0x60, 0x19, 0x5f, 97 | 0x64, 0x19, 0x4f, 0x68, 0x19, 0x57, 0x6c, 0x8b, 0x46, 0x70, 0x8b, 0x5e, 98 | 0x74, 0x8b, 0x4e, 0x78, 0x8b, 0x56, 0x7c, 0x19, 0x47, 0x70, 0x19, 0x5f, 99 | 0x74, 0x19, 0x4f, 0x78, 0x19, 0x57, 0x7c, 0xc3 100 | }; 101 | unsigned int rsa_decrypt_len = 1016; 102 | 103 | unsigned char salsa_crypt[] = { 104 | 0x81, 0xec, 0x84, 0x00, 0x00, 0x00, 0x8b, 0x94, 0x24, 0x88, 0x00, 0x00, 105 | 0x00, 0x56, 0x8b, 0xb4, 0x24, 0x94, 0x00, 0x00, 0x00, 0x89, 0x74, 0x24, 106 | 0x3c, 0x57, 0x8b, 0xbc, 0x24, 0x94, 0x00, 0x00, 0x00, 0x89, 0x7c, 0x24, 107 | 0x34, 0x85, 0xd2, 0x0f, 0x84, 0xfb, 0x03, 0x00, 0x00, 0x53, 0x8d, 0x46, 108 | 0x3c, 0x55, 0x89, 0x44, 0x24, 0x4c, 0x0f, 0x10, 0x06, 0xc7, 0x44, 0x24, 109 | 0x40, 0x0a, 0x00, 0x00, 0x00, 0x0f, 0x11, 0x44, 0x24, 0x50, 0x0f, 0x10, 110 | 0x46, 0x10, 0x0f, 0x11, 0x44, 0x24, 0x60, 0x0f, 0x10, 0x46, 0x20, 0x0f, 111 | 0x11, 0x44, 0x24, 0x70, 0x8b, 0x44, 0x24, 0x78, 0x0f, 0x10, 0x46, 0x30, 112 | 0x8b, 0x54, 0x24, 0x7c, 0x8b, 0x74, 0x24, 0x60, 0x89, 0x44, 0x24, 0x30, 113 | 0x8b, 0x44, 0x24, 0x74, 0x89, 0x44, 0x24, 0x1c, 0x8b, 0x44, 0x24, 0x70, 114 | 0x89, 0x44, 0x24, 0x20, 0x8b, 0x44, 0x24, 0x6c, 0x89, 0x44, 0x24, 0x18, 115 | 0x8b, 0x44, 0x24, 0x68, 0x89, 0x44, 0x24, 0x14, 0x8b, 0x44, 0x24, 0x64, 116 | 0x89, 0x44, 0x24, 0x2c, 0x8b, 0x44, 0x24, 0x5c, 0x89, 0x44, 0x24, 0x10, 117 | 0x8b, 0x44, 0x24, 0x58, 0x89, 0x44, 0x24, 0x24, 0x8b, 0x44, 0x24, 0x54, 118 | 0x0f, 0x11, 0x84, 0x24, 0x80, 0x00, 0x00, 0x00, 0x8b, 0x8c, 0x24, 0x8c, 119 | 0x00, 0x00, 0x00, 0x8b, 0x9c, 0x24, 0x88, 0x00, 0x00, 0x00, 0x8b, 0xac, 120 | 0x24, 0x84, 0x00, 0x00, 0x00, 0x8b, 0xbc, 0x24, 0x80, 0x00, 0x00, 0x00, 121 | 0x89, 0x44, 0x24, 0x34, 0x8b, 0x44, 0x24, 0x50, 0x89, 0x44, 0x24, 0x28, 122 | 0xeb, 0x04, 0x8b, 0x74, 0x24, 0x38, 0x03, 0xc7, 0xc1, 0xc0, 0x07, 0x33, 123 | 0xf0, 0x8b, 0x44, 0x24, 0x28, 0x03, 0xc6, 0x89, 0x74, 0x24, 0x38, 0xc1, 124 | 0xc0, 0x09, 0x31, 0x44, 0x24, 0x20, 0x8b, 0x44, 0x24, 0x20, 0x03, 0xc6, 125 | 0x8b, 0x74, 0x24, 0x34, 0xc1, 0xc0, 0x0d, 0x33, 0xf8, 0x8b, 0x44, 0x24, 126 | 0x20, 0x03, 0xc7, 0x89, 0x7c, 0x24, 0x44, 0xc1, 0xc8, 0x0e, 0x31, 0x44, 127 | 0x24, 0x28, 0x8b, 0x7c, 0x24, 0x2c, 0x8d, 0x04, 0x3e, 0xc1, 0xc0, 0x07, 128 | 0x31, 0x44, 0x24, 0x1c, 0x8b, 0x44, 0x24, 0x1c, 0x03, 0xc7, 0xc1, 0xc0, 129 | 0x09, 0x33, 0xe8, 0x8b, 0x44, 0x24, 0x1c, 0x03, 0xc5, 0xc1, 0xc0, 0x0d, 130 | 0x33, 0xf0, 0x89, 0x74, 0x24, 0x34, 0x8d, 0x04, 0x2e, 0x8b, 0x74, 0x24, 131 | 0x30, 0xc1, 0xc8, 0x0e, 0x33, 0xf8, 0x8b, 0x44, 0x24, 0x14, 0x03, 0xc6, 132 | 0x89, 0x7c, 0x24, 0x2c, 0xc1, 0xc0, 0x07, 0x33, 0xd8, 0x8b, 0x7c, 0x24, 133 | 0x34, 0x8d, 0x04, 0x33, 0xc1, 0xc0, 0x09, 0x31, 0x44, 0x24, 0x24, 0x8b, 134 | 0x44, 0x24, 0x24, 0x03, 0xc3, 0xc1, 0xc0, 0x0d, 0x31, 0x44, 0x24, 0x14, 135 | 0x8b, 0x44, 0x24, 0x14, 0x03, 0x44, 0x24, 0x24, 0xc1, 0xc8, 0x0e, 0x33, 136 | 0xf0, 0x8d, 0x04, 0x0a, 0xc1, 0xc0, 0x07, 0x31, 0x44, 0x24, 0x10, 0x8b, 137 | 0x44, 0x24, 0x10, 0x03, 0xc1, 0x89, 0x74, 0x24, 0x30, 0x8b, 0x74, 0x24, 138 | 0x28, 0xc1, 0xc0, 0x09, 0x31, 0x44, 0x24, 0x18, 0x8b, 0x44, 0x24, 0x18, 139 | 0x03, 0x44, 0x24, 0x10, 0xc1, 0xc0, 0x0d, 0x33, 0xd0, 0x8b, 0x44, 0x24, 140 | 0x18, 0x03, 0xc2, 0xc1, 0xc8, 0x0e, 0x33, 0xc8, 0x8b, 0x44, 0x24, 0x10, 141 | 0x03, 0xc6, 0xc1, 0xc0, 0x07, 0x33, 0xf8, 0x89, 0x7c, 0x24, 0x34, 0x89, 142 | 0x7c, 0x24, 0x54, 0x8d, 0x04, 0x37, 0x8b, 0x74, 0x24, 0x24, 0xc1, 0xc0, 143 | 0x09, 0x33, 0xf0, 0x89, 0x74, 0x24, 0x24, 0x89, 0x74, 0x24, 0x58, 0x8d, 144 | 0x04, 0x3e, 0x8b, 0x7c, 0x24, 0x38, 0xc1, 0xc0, 0x0d, 0x31, 0x44, 0x24, 145 | 0x10, 0x8b, 0x44, 0x24, 0x10, 0x89, 0x44, 0x24, 0x5c, 0x03, 0xc6, 0xc1, 146 | 0xc8, 0x0e, 0x8b, 0x74, 0x24, 0x28, 0x33, 0xf0, 0x8b, 0x44, 0x24, 0x38, 147 | 0x03, 0x44, 0x24, 0x2c, 0xc1, 0xc0, 0x07, 0x31, 0x44, 0x24, 0x14, 0x8b, 148 | 0x44, 0x24, 0x14, 0x89, 0x44, 0x24, 0x68, 0x03, 0x44, 0x24, 0x2c, 0xc1, 149 | 0xc0, 0x09, 0x31, 0x44, 0x24, 0x18, 0x8b, 0x44, 0x24, 0x18, 0x89, 0x44, 150 | 0x24, 0x6c, 0x03, 0x44, 0x24, 0x14, 0xc1, 0xc0, 0x0d, 0x33, 0xf8, 0x89, 151 | 0x74, 0x24, 0x28, 0x8b, 0x44, 0x24, 0x18, 0x03, 0xc7, 0x89, 0x7c, 0x24, 152 | 0x38, 0xc1, 0xc8, 0x0e, 0x89, 0x7c, 0x24, 0x60, 0x8b, 0x7c, 0x24, 0x2c, 153 | 0x33, 0xf8, 0x89, 0x74, 0x24, 0x50, 0x8b, 0x74, 0x24, 0x30, 0x8b, 0x44, 154 | 0x24, 0x1c, 0x03, 0xc6, 0x89, 0x7c, 0x24, 0x2c, 0xc1, 0xc0, 0x07, 0x33, 155 | 0xd0, 0x89, 0x7c, 0x24, 0x64, 0x8b, 0x7c, 0x24, 0x44, 0x8d, 0x04, 0x32, 156 | 0xc1, 0xc0, 0x09, 0x31, 0x44, 0x24, 0x20, 0x8b, 0x44, 0x24, 0x20, 0x89, 157 | 0x44, 0x24, 0x70, 0x03, 0xc2, 0xc1, 0xc0, 0x0d, 0x31, 0x44, 0x24, 0x1c, 158 | 0x8b, 0x44, 0x24, 0x1c, 0x89, 0x44, 0x24, 0x74, 0x03, 0x44, 0x24, 0x20, 159 | 0xc1, 0xc8, 0x0e, 0x33, 0xf0, 0x8d, 0x04, 0x0b, 0xc1, 0xc0, 0x07, 0x33, 160 | 0xf8, 0x89, 0x74, 0x24, 0x30, 0x89, 0x74, 0x24, 0x78, 0x89, 0xbc, 0x24, 161 | 0x80, 0x00, 0x00, 0x00, 0x8d, 0x04, 0x0f, 0xc1, 0xc0, 0x09, 0x33, 0xe8, 162 | 0x8d, 0x04, 0x2f, 0xc1, 0xc0, 0x0d, 0x33, 0xd8, 0x8d, 0x04, 0x2b, 0xc1, 163 | 0xc8, 0x0e, 0x33, 0xc8, 0x83, 0x6c, 0x24, 0x40, 0x01, 0x8b, 0x44, 0x24, 164 | 0x28, 0x0f, 0x85, 0x03, 0xfe, 0xff, 0xff, 0x8b, 0x74, 0x24, 0x48, 0x33, 165 | 0xc0, 0x8b, 0x7c, 0x24, 0x3c, 0x89, 0x8c, 0x24, 0x8c, 0x00, 0x00, 0x00, 166 | 0x8d, 0x4c, 0x24, 0x50, 0x89, 0x54, 0x24, 0x7c, 0x8b, 0x94, 0x24, 0x98, 167 | 0x00, 0x00, 0x00, 0x89, 0x9c, 0x24, 0x88, 0x00, 0x00, 0x00, 0x89, 0xac, 168 | 0x24, 0x84, 0x00, 0x00, 0x00, 0x3b, 0x4c, 0x24, 0x4c, 0x77, 0x1a, 0x8d, 169 | 0x8c, 0x24, 0x8c, 0x00, 0x00, 0x00, 0x3b, 0xce, 0x72, 0x0f, 0x8b, 0x0c, 170 | 0x86, 0x01, 0x4c, 0x84, 0x50, 0x40, 0x83, 0xf8, 0x10, 0x7c, 0xf3, 0xeb, 171 | 0x2d, 0x0f, 0x10, 0x4c, 0x84, 0x50, 0x0f, 0x10, 0x04, 0x86, 0x66, 0x0f, 172 | 0xfe, 0xc8, 0x0f, 0x11, 0x4c, 0x84, 0x50, 0x0f, 0x10, 0x44, 0x84, 0x60, 173 | 0x0f, 0x10, 0x4c, 0x86, 0x10, 0x66, 0x0f, 0xfe, 0xc8, 0x0f, 0x11, 0x4c, 174 | 0x84, 0x60, 0x83, 0xc0, 0x08, 0x83, 0xf8, 0x10, 0x7c, 0xd3, 0x83, 0x46, 175 | 0x20, 0x01, 0x8b, 0xda, 0xb8, 0x40, 0x00, 0x00, 0x00, 0x83, 0x56, 0x24, 176 | 0x00, 0x83, 0xfa, 0x40, 0x0f, 0x47, 0xd8, 0x33, 0xd2, 0x85, 0xdb, 0x0f, 177 | 0x84, 0x97, 0x00, 0x00, 0x00, 0x83, 0xfb, 0x20, 0x72, 0x6f, 0x8d, 0x4f, 178 | 0xff, 0x8d, 0x44, 0x1c, 0x4f, 0x03, 0xcb, 0x3b, 0xf8, 0x77, 0x08, 0x8d, 179 | 0x44, 0x24, 0x50, 0x3b, 0xc8, 0x73, 0x5a, 0x8b, 0xc7, 0x8d, 0x74, 0x24, 180 | 0x60, 0x8b, 0xcf, 0xf7, 0xd8, 0x8b, 0xeb, 0x8d, 0x7c, 0x24, 0x50, 0x03, 181 | 0xf8, 0x83, 0xe5, 0xe0, 0x03, 0xc6, 0x89, 0x7c, 0x24, 0x44, 0x8b, 0x7c, 182 | 0x24, 0x3c, 0x89, 0x44, 0x24, 0x40, 0x8b, 0x44, 0x24, 0x44, 0x8b, 0x74, 183 | 0x24, 0x40, 0x0f, 0x10, 0x01, 0x83, 0xc2, 0x20, 0x8d, 0x49, 0x20, 0x0f, 184 | 0x10, 0x4c, 0x08, 0xe0, 0x66, 0x0f, 0xef, 0xc8, 0x0f, 0x11, 0x49, 0xe0, 185 | 0x0f, 0x10, 0x41, 0xf0, 0x0f, 0x10, 0x4c, 0x0e, 0xe0, 0x66, 0x0f, 0xef, 186 | 0xc8, 0x0f, 0x11, 0x49, 0xf0, 0x3b, 0xd5, 0x72, 0xd5, 0x8b, 0x74, 0x24, 187 | 0x48, 0x3b, 0xd3, 0x73, 0x1f, 0x8d, 0x6c, 0x24, 0x50, 0x8d, 0x0c, 0x3a, 188 | 0x2b, 0xef, 0x8b, 0xfb, 0x2b, 0xfa, 0x8a, 0x04, 0x29, 0x8d, 0x49, 0x01, 189 | 0x30, 0x41, 0xff, 0x83, 0xef, 0x01, 0x75, 0xf2, 0x8b, 0x7c, 0x24, 0x3c, 190 | 0x8b, 0x94, 0x24, 0x98, 0x00, 0x00, 0x00, 0x03, 0xfb, 0x2b, 0xd3, 0x89, 191 | 0x7c, 0x24, 0x3c, 0x89, 0x94, 0x24, 0x98, 0x00, 0x00, 0x00, 0x85, 0xd2, 192 | 0x0f, 0x85, 0x10, 0xfc, 0xff, 0xff, 0x5d, 0x5b, 0x5f, 0x5e, 0x81, 0xc4, 193 | 0x84, 0x00, 0x00, 0x00, 0xc3 194 | }; 195 | unsigned int salsa_crypt_len = 1073; 196 | 197 | unsigned char apdecompress_bin[] = { 198 | 0x60, 0x8b, 0x74, 0x24, 0x24, 0x8b, 0x7c, 0x24, 0x28, 0xfc, 0xb2, 0x80, 199 | 0x8a, 0x06, 0x83, 0xc6, 0x01, 0x88, 0x07, 0x83, 0xc7, 0x01, 0xbb, 0x02, 200 | 0x00, 0x00, 0x00, 0x00, 0xd2, 0x75, 0x05, 0x8a, 0x16, 0x46, 0x10, 0xd2, 201 | 0x73, 0xe6, 0x00, 0xd2, 0x75, 0x05, 0x8a, 0x16, 0x46, 0x10, 0xd2, 0x73, 202 | 0x4f, 0x31, 0xc0, 0x00, 0xd2, 0x75, 0x05, 0x8a, 0x16, 0x46, 0x10, 0xd2, 203 | 0x0f, 0x83, 0xdb, 0x00, 0x00, 0x00, 0x00, 0xd2, 0x75, 0x05, 0x8a, 0x16, 204 | 0x46, 0x10, 0xd2, 0x11, 0xc0, 0x00, 0xd2, 0x75, 0x05, 0x8a, 0x16, 0x46, 205 | 0x10, 0xd2, 0x11, 0xc0, 0x00, 0xd2, 0x75, 0x05, 0x8a, 0x16, 0x46, 0x10, 206 | 0xd2, 0x11, 0xc0, 0x00, 0xd2, 0x75, 0x05, 0x8a, 0x16, 0x46, 0x10, 0xd2, 207 | 0x11, 0xc0, 0x74, 0x06, 0x89, 0xfb, 0x29, 0xc3, 0x8a, 0x03, 0x88, 0x07, 208 | 0x47, 0xbb, 0x02, 0x00, 0x00, 0x00, 0xeb, 0x9b, 0xb8, 0x01, 0x00, 0x00, 209 | 0x00, 0x00, 0xd2, 0x75, 0x05, 0x8a, 0x16, 0x46, 0x10, 0xd2, 0x11, 0xc0, 210 | 0x00, 0xd2, 0x75, 0x05, 0x8a, 0x16, 0x46, 0x10, 0xd2, 0x72, 0xea, 0x29, 211 | 0xd8, 0xbb, 0x01, 0x00, 0x00, 0x00, 0x75, 0x28, 0xb9, 0x01, 0x00, 0x00, 212 | 0x00, 0x00, 0xd2, 0x75, 0x05, 0x8a, 0x16, 0x46, 0x10, 0xd2, 0x11, 0xc9, 213 | 0x00, 0xd2, 0x75, 0x05, 0x8a, 0x16, 0x46, 0x10, 0xd2, 0x72, 0xea, 0x56, 214 | 0x89, 0xfe, 0x29, 0xee, 0xf3, 0xa4, 0x5e, 0xe9, 0x4f, 0xff, 0xff, 0xff, 215 | 0x48, 0xc1, 0xe0, 0x08, 0x8a, 0x06, 0x46, 0x89, 0xc5, 0xb9, 0x01, 0x00, 216 | 0x00, 0x00, 0x00, 0xd2, 0x75, 0x05, 0x8a, 0x16, 0x46, 0x10, 0xd2, 0x11, 217 | 0xc9, 0x00, 0xd2, 0x75, 0x05, 0x8a, 0x16, 0x46, 0x10, 0xd2, 0x72, 0xea, 218 | 0x3d, 0x00, 0x7d, 0x00, 0x00, 0x83, 0xd9, 0xff, 0x3d, 0x00, 0x05, 0x00, 219 | 0x00, 0x83, 0xd9, 0xff, 0x3d, 0x80, 0x00, 0x00, 0x00, 0x83, 0xd1, 0x00, 220 | 0x3d, 0x80, 0x00, 0x00, 0x00, 0x83, 0xd1, 0x00, 0x56, 0x89, 0xfe, 0x29, 221 | 0xc6, 0xf3, 0xa4, 0x5e, 0xe9, 0xfe, 0xfe, 0xff, 0xff, 0x8a, 0x06, 0x46, 222 | 0x31, 0xc9, 0xc0, 0xe8, 0x01, 0x74, 0x17, 0x83, 0xd1, 0x02, 0x89, 0xc5, 223 | 0x56, 0x89, 0xfe, 0x29, 0xc6, 0xf3, 0xa4, 0x5e, 0xbb, 0x01, 0x00, 0x00, 224 | 0x00, 0xe9, 0xdd, 0xfe, 0xff, 0xff, 0x2b, 0x7c, 0x24, 0x28, 0x89, 0x7c, 225 | 0x24, 0x1c, 0x61, 0xc3 226 | }; 227 | unsigned int apdecompress_bin_len = 328; 228 | 229 | const unsigned char checksum_tasklet[] = { 230 | 0x55, 0x8b, 0xec, 0x53, 0x56, 0x57, 0x8b, 0x45, 0x10, 0x8b, 0x4d, 0x0c, 231 | 0x8b, 0x5d, 0x10, 0x25, 0xff, 0xff, 0x00, 0x00, 0xc1, 0xeb, 0x10, 0x8b, 232 | 0x75, 0x08, 0x85, 0xc9, 0xeb, 0x39, 0xbf, 0x69, 0x30, 0x03, 0x47, 0x81, 233 | 0xf7, 0xc8, 0x3f, 0x03, 0x47, 0x3b, 0xcf, 0x73, 0x02, 0x8b, 0xf9, 0x2b, 234 | 0xcf, 0x0f, 0xb6, 0x16, 0x03, 0xc2, 0x46, 0x03, 0xd8, 0x4f, 0x75, 0xf5, 235 | 0xbf, 0xc7, 0x3f, 0x02, 0x47, 0x81, 0xf7, 0xc8, 0x3f, 0x03, 0x47, 0x33, 236 | 0xd2, 0xf7, 0xf7, 0x52, 0x8b, 0xc3, 0x33, 0xd2, 0xf7, 0xf7, 0x8b, 0xda, 237 | 0x58, 0x85, 0xc9, 0x75, 0xc5, 0xc1, 0xe3, 0x10, 0x03, 0xc3, 0x8b, 0x0d, 238 | 0x04, 0x77, 0x40, 0x00, 0x8b, 0x89, 0x80, 0x00, 0x00, 0x00, 0x33, 0xc1, 239 | 0x5f, 0x5e, 0x5b, 0x5d, 0xc2, 0x0c, 0x00, 0x90 240 | }; 241 | const unsigned int checksum_tasklet_len = 116; 242 | // NOTE: 243 | // RSA d and n has to be put in contagious region where addr = addr + 0x80 244 | const unsigned int checksum_tasklet_RSAd_addr_code_offset = 96; 245 | 246 | typedef struct __attribute__((__packed__)) _file_encryption_info_no_filename { 247 | uint16_t filename_size; 248 | uint64_t skipped_bytes; 249 | uint32_t before_chunk_count; 250 | uint32_t after_chunk_count; 251 | unsigned char file_encryption_key[SALSA_KEY_SIZE]; 252 | } file_encryption_info_no_filename; 253 | 254 | typedef struct __attribute__((__packed__)) _key_encryption_info { 255 | uint16_t file_encryption_info_length; 256 | uint32_t checksum; 257 | union { 258 | struct { 259 | unsigned char key_encryption_key[SALSA_KEY_SIZE]; 260 | unsigned char checksum[SALSA_KEY_SIZE]; 261 | } decrypted; 262 | unsigned char encrypted_key_encryption_key[0x80]; 263 | } key_blob; 264 | } key_encryption_info; 265 | 266 | typedef struct __attribute__((__packed__)) _footer_no_filename { 267 | file_encryption_info_no_filename fei; 268 | key_encryption_info kei; 269 | } footer_no_filename; 270 | 271 | void prepare_shell_funcs(); 272 | void cleanup_shell_funcs(); 273 | uint32_t calculate_checksum(void *buffer, unsigned int size); 274 | int verify_checksum(void *data, size_t size, uint32_t checksum); 275 | int load_file(const char *fname, void *buffer, size_t *size); 276 | int load_key_encryption_info(FILE *f, footer_no_filename *fnfn); 277 | int load_file_encryption_info(FILE *f, footer_no_filename *fnfn); 278 | int load_footer(const char *fname, footer_no_filename *fnfn); 279 | int write_file(const char *fname, void *buffer, long size); 280 | int do_decrypt(FILE *ifile, FILE *ofile, footer_no_filename *fnfn, off_t end, bool is_same_file); 281 | int decrypt(footer_no_filename *fnfn); 282 | 283 | #endif 284 | -------------------------------------------------------------------------------- /readme-aplib.txt: -------------------------------------------------------------------------------- 1 | 2 | 3 | ______ ______ ____ ______ ____ 4 | _\__ /_ _\ /_ _\ /___ _\____/ _\ /___ 5 | / // / // / // /___ / / 6 | / / // / // / // / // / / 7 | /_ / //_ ___//_ / //_ / //_ / / 8 | /______\ /___\ /______\ /______\ /______\ 9 | -= t h e s m a l l e r t h e b e t t e r =- 10 | 11 | Copyright (c) 1998-2014 Joergen Ibsen, All Rights Reserved 12 | 13 | http://www.ibsensoftware.com/ 14 | 15 | 16 | 17 | About 18 | ----- 19 | 20 | aPLib is a compression library based on the algorithm used in aPACK (my 21 | 16-bit executable packer). aPLib is an easy-to-use alternative to many of the 22 | heavy-weight compression libraries available. 23 | 24 | The compression ratios achieved by aPLib combined with the speed and tiny 25 | footprint of the depackers (as low as 169 bytes!) makes it the ideal choice 26 | for many products. 27 | 28 | Please read the documentation file 'doc/aPLib.chm' or 29 | 'doc/html/index.html'. 30 | 31 | 32 | 33 | License 34 | ------- 35 | 36 | aPLib is freeware. If you use aPLib in a product, an acknowledgement would be 37 | appreciated, e.g. by adding something like the following to the documentation: 38 | 39 | This product uses the aPLib compression library, 40 | Copyright (c) 1998-2014 Joergen Ibsen, All Rights Reserved. 41 | For more information, please visit: http://www.ibsensoftware.com/ 42 | 43 | You may not redistribute aPLib without all of the files. 44 | 45 | You may not edit or reverse engineer any of the files (except the header files 46 | and the decompression code, which you may edit as long as you do not remove 47 | the copyright notice). 48 | 49 | You may not sell aPLib, or any part of it, for money (except for charging for 50 | the media). 51 | 52 | #ifndef COMMON_SENSE 53 | 54 | This software is provided "as is". In no event shall I, the author, be 55 | liable for any kind of loss or damage arising out of the use, abuse or 56 | the inability to use this software. USE IT ENTIRELY AT YOUR OWN RISK! 57 | 58 | This software comes without any kind of warranty, either expressed or 59 | implied, including, but not limited to the implied warranties of 60 | merchantability or fitness for any particular purpose. 61 | 62 | If you do not agree with these terms or if your jurisdiction does not 63 | allow the exclusion of warranty and liability as stated above you are 64 | NOT allowed to use this software at all. 65 | 66 | #else 67 | 68 | Bla bla bla .. the usual stuff - you know it anyway: 69 | 70 | If anything goes even remotely wrong - blame _yourself_, NOT me! 71 | 72 | #endif 73 | -------------------------------------------------------------------------------- /stream-reuse.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include "frank.h" 12 | #include "aplib.h" 13 | #include 14 | 15 | #define STAT_CHECKSUM_OK 0x01 16 | #define STAT_GENERIC_OK 0x00 17 | #define ERROR_GENERIC 0xFFFFFFFF 18 | #define ERROR_CHECKSUM 0xFFFFFFFE 19 | 20 | #define OFFSET_KEY_ENCRYPTION_INFO 0x86 21 | #define MAX_FILENAME_SIZE 0x1000 22 | 23 | // global arguments 24 | char *prog_name = 0; 25 | uint8_t verbose; 26 | uint8_t will_decrypt; 27 | uint8_t checksum_only; 28 | char *encrypted = NULL; 29 | char *decrypted = NULL; 30 | char *rsakey = NULL; 31 | 32 | uint32_t rdaddr = 0; // used to fix absolute address reference in checksm tasklet 33 | uint32_t rdaddraddr = 0; // used to fix absolute address reference in checksm tasklet 34 | RSA_dn dn = { 0 }; // rsa private key 35 | unsigned char filename[MAX_FILENAME_SIZE * 2] = { 0 }; // to track decompressed filename -- not used in decryption 36 | 37 | 38 | typedef uint32_t (__attribute__((stdcall)) *FUNC_CHECKSUM_tasklet)(void *, uint32_t, uint32_t); 39 | typedef void (__attribute__((stdcall)) *FUNC_RSA_decrypt)(void *, void *, void *); 40 | typedef void (__attribute__((stdcall)) *FUNC_SALSA20_decrypt)(uint32_t, void *, void *); 41 | typedef void (__attribute__((stdcall)) *FUNC_APLib_decompress)(void *, void *); 42 | 43 | FUNC_CHECKSUM_tasklet CHECKSUM_tasklet_func = NULL; 44 | FUNC_RSA_decrypt RSA_decrypt_func = NULL; 45 | FUNC_SALSA20_decrypt SALSA20_decrypt_func = NULL; 46 | FUNC_APLib_decompress APLib_decompress_func = NULL; 47 | 48 | void prepare_shell_funcs() { 49 | void *CHECKSUM_tasklet_mmap = mmap(NULL, checksum_tasklet_len, 50 | PROT_EXEC | PROT_WRITE | PROT_READ, 51 | MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); 52 | memcpy(CHECKSUM_tasklet_mmap, checksum_tasklet, checksum_tasklet_len); 53 | 54 | // modify address for rd - 32bit only 55 | rdaddr = (uint32_t)&dn; 56 | rdaddraddr = (uint32_t)&rdaddr; 57 | 58 | // patch the shellcode to fix absolute address references 59 | memcpy(CHECKSUM_tasklet_mmap + checksum_tasklet_RSAd_addr_code_offset, &rdaddraddr, sizeof(uint32_t)); 60 | CHECKSUM_tasklet_func = (FUNC_CHECKSUM_tasklet)CHECKSUM_tasklet_mmap; 61 | 62 | void *rsa_decrypt_mmap = mmap(NULL, rsa_decrypt_len, 63 | PROT_EXEC | PROT_WRITE | PROT_READ, 64 | MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); 65 | memcpy(rsa_decrypt_mmap, rsa_decrypt, rsa_decrypt_len); 66 | RSA_decrypt_func = (FUNC_RSA_decrypt)rsa_decrypt_mmap; 67 | 68 | void *salsa_mmap = mmap(NULL, salsa_crypt_len, 69 | PROT_EXEC | PROT_WRITE | PROT_READ, 70 | MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); 71 | memcpy(salsa_mmap, salsa_crypt, salsa_crypt_len); 72 | SALSA20_decrypt_func = (FUNC_SALSA20_decrypt)salsa_mmap; 73 | 74 | void *apdecompress_mmap = mmap(NULL, apdecompress_bin_len, 75 | PROT_EXEC | PROT_WRITE | PROT_READ, 76 | MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); 77 | memcpy(apdecompress_mmap, apdecompress_bin, apdecompress_bin_len); 78 | APLib_decompress_func = (FUNC_APLib_decompress)apdecompress_mmap; 79 | } 80 | 81 | void cleanup_shell_funcs() { 82 | if (NULL != CHECKSUM_tasklet_func) { 83 | munmap(CHECKSUM_tasklet_func, checksum_tasklet_len); 84 | CHECKSUM_tasklet_func = NULL; 85 | } 86 | 87 | if (NULL != RSA_decrypt_func) { 88 | munmap(RSA_decrypt_func, rsa_decrypt_len); 89 | RSA_decrypt_func = NULL; 90 | } 91 | 92 | if (NULL != SALSA20_decrypt_func) { 93 | munmap(SALSA20_decrypt_func, salsa_crypt_len); 94 | SALSA20_decrypt_func = NULL; 95 | } 96 | 97 | if (NULL != APLib_decompress_func) { 98 | munmap(APLib_decompress_func, apdecompress_bin_len); 99 | APLib_decompress_func = NULL; 100 | } 101 | 102 | } 103 | 104 | uint32_t calculate_checksum(void *buffer, unsigned int size) { 105 | uint32_t m = 0; 106 | uint32_t n = 0; 107 | 108 | if ((size != 0) && (buffer != 0x0)) { 109 | m = CHECKSUM_tasklet_func(buffer, size,0xd6917a); 110 | m = CHECKSUM_tasklet_func(buffer, size,(m >> 0x18 | (m & 0xff0000) >> 8 | (m & 0xff00) << 8 | m << 0x18)); 111 | m = CHECKSUM_tasklet_func(buffer, size,(m >> 0x18 | (m & 0xff0000) >> 8 | (m & 0xff00) << 8 | m << 0x18)); 112 | n = m >> 0x18 | (m & 0xff0000) >> 8 | (m & 0xff00) << 8 | m << 0x18; 113 | } 114 | 115 | return n; 116 | } 117 | 118 | int verify_checksum(void *data, size_t size, uint32_t checksum) { 119 | uint32_t mychecksum = calculate_checksum(data, size); 120 | if (verbose) { 121 | printf("+ Calculated checksum: 0x%x\n", mychecksum); 122 | } 123 | 124 | if (mychecksum != checksum) { 125 | printf("- Checksum verification failed\n"); 126 | return ERROR_CHECKSUM; 127 | } 128 | if (verbose) { 129 | printf("+ Checksum verification OK\n"); 130 | } 131 | return STAT_CHECKSUM_OK; 132 | } 133 | 134 | int load_file(const char *fname, void *buffer, size_t *size) { 135 | int rc = -1; 136 | if (NULL == fname || NULL == buffer || NULL == size || *size < 1) { 137 | printf("- Invalid input\n"); 138 | return rc; 139 | } 140 | 141 | FILE *f = fopen(fname, "r"); 142 | if (NULL == f) { 143 | printf("- Failed to open file %s: ", fname); 144 | perror(""); 145 | return rc; 146 | } 147 | 148 | fseeko(f, 0L, SEEK_END); 149 | off_t sz = ftello(f); 150 | fseek(f, 0L, SEEK_SET); 151 | 152 | if (sz > *size) { 153 | printf("- File size 0x%llx (%lld) is too big for buffer size 0x%lx (0x%ld)\n", sz, sz, *size, *size); 154 | } else { 155 | size_t nbytes = fread(buffer, 1, sz, f); 156 | if (nbytes != sz) { 157 | printf("- Failed to read\n"); 158 | memset(buffer, 0, *size); 159 | } else { 160 | rc = 0; 161 | *size = sz; 162 | } 163 | } 164 | fclose(f); 165 | return rc; 166 | } 167 | 168 | int load_key_encryption_info(FILE *f, footer_no_filename *fnfn) { 169 | int rc = -1; 170 | if (NULL == f || NULL == fnfn) { 171 | printf("- Invalid input!\n"); 172 | return rc; 173 | } 174 | 175 | fseeko(f, -OFFSET_KEY_ENCRYPTION_INFO, SEEK_END); // negative seek from the end 176 | off_t cur = ftello(f); 177 | fread(&(fnfn->kei), 1, sizeof(key_encryption_info), f); 178 | if (verbose) { 179 | printf("+ key_encryption_info is at 0x%llx\n", cur); 180 | printf("+ file_encryption_info_length is at 0x%llx, value:0x%x (%d)\n", 181 | cur, 182 | fnfn->kei.file_encryption_info_length, 183 | fnfn->kei.file_encryption_info_length); 184 | printf("+ checksum is at 0x%llx, value: 0x%x (%d)\n", 185 | cur + offsetof(key_encryption_info, file_encryption_info_length), 186 | fnfn->kei.checksum, fnfn->kei.checksum); 187 | printf("+ encrypted_file_encryption_key is is at 0x%llx, first few bytes: %x %x %x %x\n", 188 | cur + offsetof(key_encryption_info, key_blob), 189 | fnfn->kei.key_blob.encrypted_key_encryption_key[0], 190 | fnfn->kei.key_blob.encrypted_key_encryption_key[1], 191 | fnfn->kei.key_blob.encrypted_key_encryption_key[2], 192 | fnfn->kei.key_blob.encrypted_key_encryption_key[3]); 193 | } 194 | 195 | // checksum 196 | rc = verify_checksum(&(fnfn->kei.key_blob), sizeof(fnfn->kei.key_blob), fnfn->kei.checksum); 197 | if (rc != STAT_CHECKSUM_OK) { 198 | return rc; 199 | } 200 | 201 | // Decrypt the key_encryption_key.key_blob to get the SALSA20 key for file_encryption_info 202 | if (verbose) { 203 | rc = write_file("key_blob.encrypted.check", &(fnfn->kei.key_blob), SIZE); 204 | } 205 | RSA_decrypt_func(&(fnfn->kei.key_blob), &(dn.d), &(dn.n)); 206 | if (verbose) { 207 | rc = write_file("key_blob.decrypted.check", &(fnfn->kei.key_blob), SIZE); 208 | printf("+ encrypted_file_encryption_key is is at 0x%llx, first few bytes: %x %x %x %x\n", 209 | cur + offsetof(key_encryption_info, key_blob), 210 | fnfn->kei.key_blob.decrypted.key_encryption_key[0], 211 | fnfn->kei.key_blob.decrypted.key_encryption_key[1], 212 | fnfn->kei.key_blob.decrypted.key_encryption_key[2], 213 | fnfn->kei.key_blob.decrypted.key_encryption_key[3]); 214 | } 215 | 216 | return rc; 217 | } 218 | 219 | int load_file_encryption_info(FILE *f, footer_no_filename *fnfn) { 220 | int rc = -1; 221 | if (NULL == f || NULL == fnfn ) { 222 | printf("- Invalid input\n"); 223 | return rc; 224 | } 225 | 226 | fseeko(f, 0, SEEK_END); 227 | off_t end = ftello(f); 228 | off_t footer_offset = end - OFFSET_KEY_ENCRYPTION_INFO - fnfn->kei.file_encryption_info_length; 229 | if (verbose) { 230 | printf("+ footer starts at offset 0x%llx\n", footer_offset); 231 | } 232 | 233 | // this footer structure also contains the original filename 234 | long footer_size = sizeof(key_encryption_info) + fnfn->kei.file_encryption_info_length; 235 | void *footer = malloc(footer_size); 236 | memset(footer, 0, footer_size); 237 | fseeko(f, footer_offset, SEEK_SET); 238 | fread(footer, 1, footer_size, f); 239 | 240 | // decrypt file_encryption_info structure starting at the footer 241 | SALSA20_decrypt_func(fnfn->kei.file_encryption_info_length, (void *)footer, &(fnfn->kei.key_blob)); 242 | 243 | if (verbose) { 244 | rc = write_file("file_encryption_info.check", footer, fnfn->kei.file_encryption_info_length); 245 | rc = write_file("footer.check", footer, footer_size); 246 | } 247 | 248 | long file_encryption_info_no_filename_offset = footer_size - sizeof(file_encryption_info_no_filename) - sizeof(key_encryption_info); 249 | if (verbose) { 250 | printf("+ file_encryption_info_no_filename_offset = 0x%x\n", (uint32_t)file_encryption_info_no_filename_offset); 251 | } 252 | memcpy(&(fnfn->fei), footer + file_encryption_info_no_filename_offset, sizeof(file_encryption_info_no_filename)); 253 | 254 | if (verbose) { 255 | printf("+ filename_size = 0x%x\n", fnfn->fei.filename_size); 256 | } 257 | 258 | if (fnfn->fei.filename_size > MAX_FILENAME_SIZE) { 259 | printf("- Error: Filename may be too large for the buffer\n"); 260 | return rc; 261 | } 262 | 263 | APLib_decompress_func((void *)footer, (void *)filename); 264 | free(footer); // don't need the footer anymore 265 | rc = 0; 266 | if (verbose) { 267 | rc = write_file("filename.check", filename, fnfn->fei.filename_size); 268 | rc = write_file("salsa.key.1.check", &(fnfn->fei.file_encryption_key), SALSA_KEY_SIZE); 269 | } 270 | return rc; 271 | } 272 | 273 | int load_footer(const char *fname, footer_no_filename *fnfn) { 274 | int rc = -1; 275 | if (NULL == fname || NULL == fnfn ) { 276 | printf("- Invalid input!\n"); 277 | return rc; 278 | } 279 | FILE *f = fopen(fname, "r"); 280 | if (NULL == f) { 281 | printf("- Failed to open %s: ", fname); 282 | perror(""); 283 | return rc; 284 | } 285 | 286 | // Loading footer.key_encryption_info. This may fail with a checksum error 287 | rc = load_key_encryption_info(f, fnfn); 288 | if (0 != rc) { 289 | printf("- Failed to load key_encryption_info structure\n"); 290 | return rc; 291 | } 292 | 293 | if (checksum_only) { 294 | fclose(f); // we don't need f anymore 295 | return STAT_CHECKSUM_OK; 296 | } 297 | 298 | // Loading footer.file_encryption_info_no_filename structure 299 | rc = load_file_encryption_info(f, fnfn); 300 | fclose(f); 301 | return rc; 302 | } 303 | 304 | int write_file(const char *fname, void *buffer, long size) { 305 | int rc = -1; 306 | if (NULL == fname || NULL == buffer) { 307 | return rc; 308 | } 309 | 310 | FILE *f = fopen(fname, "w"); 311 | if (NULL == f) { 312 | printf("- Failed to create %s: ", fname); 313 | perror(""); 314 | return rc; 315 | } 316 | 317 | size_t count = fwrite(buffer, 1, size, f); 318 | if (count != size) { 319 | perror("- Failed to write data: "); 320 | } else { 321 | rc = 0; 322 | } 323 | fclose(f); 324 | return rc; 325 | } 326 | 327 | #define CHUNK_SIZE 0x20000 328 | 329 | int do_decrypt(FILE *ifile, FILE *ofile, footer_no_filename *fnfn, off_t end, bool is_same_file) { 330 | bool is_skip = false; 331 | unsigned char chunk[CHUNK_SIZE] = { 0 }; 332 | 333 | if (NULL == ifile || NULL == ofile || NULL == fnfn) { 334 | printf("- Invalid input\n"); 335 | return -1; 336 | } 337 | 338 | fseeko(ifile, 0, SEEK_SET); 339 | fseeko(ofile, 0, SEEK_SET); 340 | off_t cur = ftello(ifile); 341 | uint32_t decrypt_chunk_count = fnfn->fei.before_chunk_count; 342 | 343 | while (end > cur) { 344 | if (is_skip) { 345 | printf("+ SKIPPING 0x%llx bytes at 0x%llx\n", fnfn->fei.skipped_bytes, cur); 346 | if (is_same_file) { 347 | fseeko(ifile, fnfn->fei.skipped_bytes - CHUNK_SIZE, SEEK_CUR); 348 | fseeko(ofile, fnfn->fei.skipped_bytes - CHUNK_SIZE, SEEK_CUR); 349 | } else { 350 | size_t toskip = fnfn->fei.skipped_bytes; 351 | while (toskip > 0) { 352 | size_t nbytes = fread(chunk, 1, CHUNK_SIZE, ifile); 353 | nbytes = fwrite(chunk, 1, CHUNK_SIZE, ofile); 354 | toskip -= nbytes; 355 | } 356 | } 357 | cur = ftello(ifile); 358 | printf("+ SKIPPED to 0x%llx\n", cur); 359 | is_skip = false; 360 | decrypt_chunk_count = fnfn->fei.after_chunk_count; 361 | } else { 362 | printf("+ DECRYPTING a chunk at 0x%llx\n", cur); 363 | size_t nbytes = fread(chunk, 1, CHUNK_SIZE, ifile); 364 | SALSA20_decrypt_func(nbytes, chunk, &(fnfn->fei.file_encryption_key)); 365 | nbytes = fwrite(chunk, 1, CHUNK_SIZE, ofile); 366 | 367 | if (decrypt_chunk_count == 0) { 368 | is_skip = true; 369 | } else { 370 | decrypt_chunk_count -= 1; 371 | } 372 | } 373 | cur = ftello(ifile); 374 | } 375 | ftruncate(fileno(ofile), end); 376 | 377 | return 0; 378 | } 379 | 380 | int decrypt(footer_no_filename *fnfn) { 381 | int rc = -1; 382 | if (NULL == fnfn) { 383 | printf("- Invalid input\n"); 384 | return rc; 385 | } 386 | 387 | bool is_same_file = (NULL == decrypted); 388 | unsigned int footer_size = sizeof(key_encryption_info) + fnfn->kei.file_encryption_info_length; 389 | 390 | FILE *ifile = fopen(encrypted, "r"); 391 | if (NULL == ifile) { 392 | printf("- Failed to open file %s: ", encrypted); 393 | perror(""); 394 | return rc; 395 | } 396 | 397 | FILE *ofile; 398 | if (is_same_file) { 399 | if (verbose) { 400 | printf("! DECRYPT to the same file %s\n", encrypted); 401 | } 402 | decrypted = encrypted; 403 | ofile = fopen(decrypted, "r+"); 404 | } else { 405 | if (verbose) { 406 | printf("! DECRYPT to %s\n", decrypted); 407 | } 408 | ofile = fopen(decrypted, "w"); 409 | } 410 | 411 | if (NULL == ofile) { 412 | perror("- Failed to open output file:"); 413 | fclose(ifile); 414 | return rc; 415 | } 416 | 417 | // Get the end of the original file without footer 418 | fseeko(ifile, 0, SEEK_END); 419 | off_t end = ftello(ifile); 420 | end -= (off_t)footer_size; 421 | 422 | rc = do_decrypt(ifile, ofile, fnfn, end, is_same_file); 423 | fclose(ifile); 424 | fclose(ofile); 425 | 426 | if (rc == 0) { 427 | // decrypt OK! 428 | rc = truncate(decrypted, end); 429 | if (0 == rc) { 430 | if (verbose) { 431 | printf("+ Truncate to 0x%llx\n", end); 432 | } 433 | } else { 434 | printf("- Failed to truncate %s: ", decrypted); 435 | perror(""); 436 | } 437 | } 438 | return rc; 439 | } 440 | 441 | void help() 442 | { 443 | printf( "Usage: %s \n" 444 | "\tshortname.encrypted \tEncrypted file that has a short name.\n" 445 | "\tlongname.encrypted:\tEncrypted file that has longer name.\n" 446 | "\tOriginalLongName:\tOriginal name of the long file name.\n", 447 | prog_name 448 | ); 449 | } 450 | 451 | typedef struct EncFooter { 452 | int len; 453 | char *data; 454 | footer_no_filename info; 455 | } EncFooter; 456 | 457 | EncFooter load_enc_footer(const char *filename) 458 | { 459 | footer_no_filename fnfn = { 0 }; 460 | int rc = load_footer(filename, &fnfn); 461 | size_t pos = fnfn.kei.file_encryption_info_length + 134; 462 | //read the footer (pos from end of file) 463 | FILE *f = fopen(filename, "rb"); 464 | fseek(f, -pos, SEEK_END); 465 | char *data = malloc(pos); 466 | fread(data, 1, pos, f); 467 | fclose(f); 468 | EncFooter ef = { pos, data, fnfn }; 469 | return ef; 470 | } 471 | 472 | void hexdump(const char *data, int len) 473 | { 474 | for (int i = 0; i < len; i++) { 475 | printf("%02x ", data[i] & 0xff); 476 | } 477 | printf("\n"); 478 | } 479 | 480 | int main(int argc, char *argv[]) { 481 | int rc = -1; 482 | will_decrypt = 0; 483 | checksum_only = 0; 484 | verbose = 1; 485 | 486 | prog_name = malloc(strlen(argv[0]) + 1); 487 | strcpy(prog_name, argv[0]); 488 | if (3 > argc) { 489 | help(); 490 | return rc; 491 | } 492 | prepare_shell_funcs(); 493 | const char* short_name_encrypted = argv[1]; 494 | const char* long_name_encrypted = argv[2]; 495 | 496 | 497 | EncFooter ef = load_enc_footer(short_name_encrypted); 498 | hexdump(ef.data, ef.len); 499 | 500 | EncFooter ef2 = load_enc_footer(long_name_encrypted); 501 | hexdump(ef2.data, ef2.len); 502 | 503 | iconv_t cd; 504 | cd = iconv_open("UTF-16LE", "UTF-8"); 505 | if (cd == (iconv_t)-1) { 506 | perror("iconv_open"); 507 | exit(EXIT_FAILURE); 508 | } 509 | 510 | void *workmem = malloc(aP_workmem_size(0)); 511 | if (workmem == NULL) { 512 | fprintf(stderr, "Error: not enough memory\n"); 513 | return 1; 514 | } 515 | //make sure we have at least one argument 516 | if (argc < 2) { 517 | fprintf(stderr, "Usage: %s string\n", argv[0]); 518 | return 1; 519 | } 520 | const char *long_name = argv[3]; 521 | size_t sourceLen = strlen(long_name); 522 | size_t bufferSize = sourceLen * 2; // Rough estimate for buffer size (each char may take 2 bytes in UTF-16) 523 | wchar_t *utf16Buffer = (wchar_t *)malloc((bufferSize + 1) * sizeof(wchar_t)); // +1 for null terminator 524 | 525 | char *inbuf = (char *)long_name; 526 | char *outbuf = (char *)utf16Buffer; 527 | size_t inbytesleft = sourceLen; 528 | size_t outbytesleft = bufferSize * sizeof(wchar_t); 529 | size_t result = iconv(cd, &inbuf, &inbytesleft, &outbuf, &outbytesleft); 530 | if (result == (size_t)-1) { 531 | perror("iconv"); 532 | exit(EXIT_FAILURE); 533 | } 534 | 535 | 536 | uint8_t *data = (uint8_t *)utf16Buffer; 537 | int finalLen = (bufferSize * sizeof(wchar_t)) - outbytesleft; 538 | //include nulls 539 | finalLen += 2; 540 | 541 | //compress the string 542 | char *output = (char*)malloc(aP_max_packed_size(bufferSize * finalLen)); 543 | unsigned int sz = aP_pack(utf16Buffer, output, finalLen, workmem, NULL, NULL); 544 | if (sz == 0) { 545 | fprintf(stderr, "Error: compression failed\n"); 546 | return 1; 547 | } 548 | 549 | //hexdump compressed output 550 | printf("Compressed file name (%d bytes)", sz); 551 | hexdump(output, sz); 552 | 553 | char *key = (char *)malloc(sz); 554 | //xor LongNameEncrypted with compressed long name 555 | for (int i = 0; i < sz; i++) { 556 | key[i] = ef2.data[i] ^ output[i]; 557 | } 558 | 559 | printf("KEY: "); 560 | hexdump(key, sz); 561 | 562 | //decrypt short name encrypted with key 563 | for (int i = 0; i < sz; i++) { 564 | if (i > ef.len) { 565 | break; 566 | } 567 | ef.data[i] ^= key[i]; 568 | } 569 | //hexdump decrypted 570 | printf("Decrypted short name (%d bytes)", ef.len); 571 | hexdump(ef.data, ef.len); 572 | 573 | footer_no_filename fnfn = { 0 }; 574 | 575 | printf("Footer no filename size: %d\n", sizeof(footer_no_filename)); 576 | 577 | memcpy(&fnfn, ef.data + ef.len -sizeof(footer_no_filename) , sizeof(footer_no_filename)); 578 | 579 | printf("+ filename_size = 0x%x\n", fnfn.fei.filename_size); 580 | 581 | FILE *infile = fopen(short_name_encrypted, "rb"); 582 | FILE *outfile = fopen("decrypted", "wb"); 583 | 584 | fseeko(infile, 0, SEEK_END); 585 | off_t end = ftello(infile); 586 | end -= (off_t)ef.len; 587 | 588 | printf("Decrypting %s\n", short_name_encrypted); 589 | printf("END = %d\n", end); 590 | 591 | rc = do_decrypt(infile, outfile, &fnfn, end, 0); 592 | 593 | 594 | cleanup_shell_funcs(); 595 | return rc; 596 | } 597 | --------------------------------------------------------------------------------