From 1b738c55b310b33e4f29e0d50285ef6b6398c22e Mon Sep 17 00:00:00 2001 From: Dobin Date: Sat, 17 Feb 2024 19:56:05 +0000 Subject: [PATCH] feature: short call patching --- phases/compiler.py | 14 ++++++++------ project.py | 1 + supermega.py | 7 ++++++- 3 files changed, 15 insertions(+), 7 deletions(-) diff --git a/phases/compiler.py b/phases/compiler.py index 6b75d6b..f371bf5 100644 --- a/phases/compiler.py +++ b/phases/compiler.py @@ -15,7 +15,8 @@ use_templates = True def compile( c_in: FilePath, asm_out: FilePath, - payload_len: int + payload_len: int, + short_call_patching: bool = False ): logger.info("--[ Compile C to ASM: {} -> {} ".format(c_in, asm_out)) @@ -35,7 +36,7 @@ def compile( # Assembly text fixup (SuperMega) logger.info("---[ Fixup : {} ".format(asm_out)) - if not fixup_asm_file(asm_out, payload_len): + if not fixup_asm_file(asm_out, payload_len, short_call_patching=short_call_patching): raise Exception("Error: Fixup failed") observer.add_text("carrier_asm_fixup", file_readall_text(asm_out)) @@ -63,14 +64,15 @@ def bytes_to_asm_db(byte_data: bytes) -> bytes: return "\tDB " + formatted_string -def fixup_asm_file(filename: FilePath, payload_len: int): +def fixup_asm_file(filename: FilePath, payload_len: int, short_call_patching: bool = False): with open(filename, 'r', encoding='utf-8') as asmfile: lines = asmfile.readlines() # When it breaks, enable this - #for idx, line in enumerate(lines): - # if "jmp\tSHORT" in lines[idx]: - # lines[idx] = lines[idx].replace("SHORT", "") + if short_call_patching: + for idx, line in enumerate(lines): + if "jmp\tSHORT" in lines[idx]: + lines[idx] = lines[idx].replace("SHORT", "") for idx, line in enumerate(lines): # Remove EXTRN, we dont need it diff --git a/project.py b/project.py index 1445124..a092c31 100644 --- a/project.py +++ b/project.py @@ -13,6 +13,7 @@ class Project(): self.exec_style: ExecStyle = ExecStyle.CALL self.decoder_style: DecoderStyle = DecoderStyle.PLAIN_1 self.dataref_style: DataRefStyle = DataRefStyle.APPEND + self.short_call_patching: bool = False # Injectable self.inject: bool = False diff --git a/supermega.py b/supermega.py index a86f9ca..bc3b18d 100644 --- a/supermega.py +++ b/supermega.py @@ -32,6 +32,7 @@ def main(): parser.add_argument('--start-injected', action='store_true', help='Dev: Start the generated infected executable at the end') parser.add_argument('--start-loader-shellcode', action='store_true', help='Dev: Start the loader shellcode (without payload)') parser.add_argument('--start-final-shellcode', action='store_true', help='Debug: Start the final shellcode (loader + payload)') + parser.add_argument('--short-call-patching', action='store_true', help='Make short calls long. You will know when you need it.') parser.add_argument('--no-clean-at-start', action='store_true', help='Debug: Dont remove any temporary files at start') parser.add_argument('--no-clean-at-exit', action='store_true', help='Debug: Dont remove any temporary files at exit') parser.add_argument('--verify', type=str, help='Debug: Perform verification: std/iat') @@ -75,6 +76,9 @@ def main(): project.cleanup_files_on_start = not args.no_clean_at_start project.cleanup_files_on_exit =not args.no_clean_at_exit + if args.short_call_patching: + project.short_call_patching = True + if args.rbrunmode: if args.rbrunmode == "1" or args.rbrunmode == "2" or args.rbrunmode == "3": project.inject_mode = "1," + args.rbrunmode @@ -127,7 +131,8 @@ def start(): phases.compiler.compile( c_in = main_c_file, asm_out = main_asm_file, - payload_len = len(project.payload_data)) + payload_len = len(project.payload_data), + short_call_patching = project.short_call_patching) # Decide if we can use IAT_REUSE (all function calls available as import) required_functions = phases.compiler.get_function_stubs(main_asm_file)