diff --git a/CryptoUnLocker.py b/CryptoUnLocker.py index 20a1215..ecd2e2c 100755 --- a/CryptoUnLocker.py +++ b/CryptoUnLocker.py @@ -1,48 +1,21 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 import struct import os import argparse import shutil import sys -from collections import namedtuple -from datetime import datetime import csv import re +from collections import namedtuple +from datetime import datetime -from Crypto.Cipher import AES +from Crypto.Cipher import AES, PKCS1_v1_5 from Crypto.PublicKey import RSA -from Crypto.Cipher import PKCS1_v1_5 -from Crypto.Hash import SHA +from Crypto.Hash import SHA1 from Crypto.Util.number import bytes_to_long -""" -CryptoLocker file structure: - -0x14 bytes : SHA1 hash of '\x00'*4 + next 0x100 bytes of file. -0x100 bytes : AES key encrypted with RSA PKCS#1 v1.5: - 0x2c bytes : AES key blob - -remainder : file data encrypted with AES256-CBC with IV of 0x00 - -Key blob is a Microsoft PUBLICKEYSTRUC: -typedef struct _PUBLICKEYSTRUC { - BYTE bType; - BYTE bVersion; - WORD reserved; - ALG_ID aiKeyAlg; -} BLOBHEADER, PUBLICKEYSTRUC; - -where: -bType = 0x08 -bVersion = 0x02 -reserved = 0 -aiKeyAlg = 0x6610 (AES-256) - -followed by a DWORD length of 0x20, and finally the 32 byte AES key. -""" - PUBLICKEYSTRUC = namedtuple('PUBLICKEYSTRUC', 'bType bVersion reserved aiKeyAlg') RSAPUBKEY = namedtuple('RSAPUBKEY', 'magic bitlen pubexp') PRIVATEKEYBLOB = namedtuple('PRIVATEKEYBLOB', 'modulus prime1 prime2 exponent1 exponent2 coefficient privateExponent') @@ -50,248 +23,155 @@ PUBLICKEYSTRUC_s = struct.Struct('= 0x2c and blob[:4] == b'\x08\x02\x00\x00': + return blob[0x0c:0x0c+32] + return None - # retrieve key from file_header - (bType, bVersion, reserved, aiKeyAlg, keyLen) = struct.unpack(' OutputLevel.InfoLevel: - icon = '[-]' - - if fn: - sys.stderr.write('%s %s: %s\n' % (icon, msg, fn)) - else: - sys.stderr.write('%s %s\n' % (icon, msg)) - sys.stderr.flush() def main(): parser = argparse.ArgumentParser(description='Decrypt CryptoLocker encrypted files.') - group = parser.add_mutually_exclusive_group(required=True) - - group.add_argument('--keyfile', action='store', dest='keyfile', - help='File containing the private key, or the EXE file provided for decryption') - group.add_argument('--keydir', action='store', dest='keydir', - help='Directory containing any number of private keys; the appropriate private key will be used during the decryption process') - group.add_argument('--detect', action='store_true', dest='detect', help="Don't try to decrypt; just find files that may be CryptoLockered") - - parser.add_argument('-r', action='store_true', dest='recursive', help="Recursively search subdirectories") - parser.add_argument('-v', action='store_true', dest='verbose', help="Verbose output") - parser.add_argument('--dry-run', action='store_true', dest='dry_run', help="Don't actually write decrypted files") - parser.add_argument('-o', action='store', dest='destdir', help='Copy all decrypted files to an output directory, mirroring the source path') - parser.add_argument('--csv', action='store', dest='csvfile', help='Output to a CSV file') + parser.add_argument('--detect', action='store_true', help='Detect CryptoLocker files without decrypting') + parser.add_argument('-r', '--recursive', action='store_true', help='Recursive search') # Add this line + parser.add_argument('-v', action='store_true', help='Verbose output') + parser.add_argument('--dry-run', action='store_true', help='Dry run mode') + parser.add_argument('-o', dest='destdir', help='Output directory') + parser.add_argument('--csv', dest='csvfile', help='CSV output file') + parser.add_argument('encrypted_filenames', nargs='+') + return CryptoUnLockerProcess(parser.parse_args(), CryptoUnLocker()).doit() - parser.add_argument('encrypted_filenames', nargs="+") - - results = parser.parse_args() - unlocker = CryptoUnLocker() - processor = CryptoUnLockerProcess(results, unlocker) - - return processor.doit() if __name__ == '__main__': sys.exit(main()) - diff --git a/README.md b/README.md index fcd6f28..31bcc59 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# CryptoLocker Encrypted File Format +# CryptoLocker Encrypted File Format - Updated with Python3 Each file encrypted by CryptoLocker is encrypted with a unique AES-256 key. The unique symmetric key is then encrypted with the public RSA-2048 diff --git a/setup.py b/setup.py deleted file mode 100644 index cd50b8c..0000000 --- a/setup.py +++ /dev/null @@ -1,11 +0,0 @@ -#!/usr/bin/env python - -import sys -from cx_Freeze import setup, Executable - -setup( - name="CryptoUnLocker", - version="1.0", - Description="Detection and Decryption tool for CryptoLocker files", - executables= [Executable("CryptoUnLocker.py")] -)