mirror of
https://github.com/dobin/SuperMega
synced 2026-06-02 17:27:10 +00:00
feature: in-place dll loader (support)
This commit is contained in:
@@ -11,6 +11,26 @@ logger = logging.getLogger("PEHelper")
|
||||
# Its mostly used for verification of what we were doing.
|
||||
|
||||
|
||||
# PRE-LOAD a dll file into memory
|
||||
# This will load the DLL file into a memory buffer, already
|
||||
# loaded at the correct RVA addresses (e.g. sections page aligned).
|
||||
def preload_dll(payload_path: str) -> bytes:
|
||||
dllPe = pefile.PE(payload_path)
|
||||
dllImageSize = dllPe.OPTIONAL_HEADER.SizeOfImage
|
||||
payload: bytearray = bytearray(dllImageSize)
|
||||
|
||||
# copy PE header sizeofheaders
|
||||
payload[:dllPe.OPTIONAL_HEADER.SizeOfHeaders] = dllPe.get_data()[:dllPe.OPTIONAL_HEADER.SizeOfHeaders]
|
||||
|
||||
# copy sections
|
||||
for section in dllPe.sections:
|
||||
if section.SizeOfRawData == 0:
|
||||
continue
|
||||
payload[section.VirtualAddress:section.VirtualAddress + section.SizeOfRawData] = section.get_data()
|
||||
|
||||
return bytes(payload)
|
||||
|
||||
|
||||
def extract_code_from_exe_file_ep(exe_file: FilePath, len: int) -> bytes:
|
||||
pe = pefile.PE(exe_file)
|
||||
section = get_code_section(pe)
|
||||
@@ -69,3 +89,11 @@ def remove_trailing_null_bytes(data: bytes) -> bytes:
|
||||
if data[i] != b'\x00'[0]: # Check for a non-null byte
|
||||
return data[:i + 1]
|
||||
return b'' # If the entire sequence is null bytes
|
||||
|
||||
|
||||
def align_to_page_size(rva, offset, page_size=4096):
|
||||
# Align to the nearest lower page boundary
|
||||
aligned_address = rva & ~(page_size - 1)
|
||||
real_address = aligned_address - offset
|
||||
logger.debug(" Aligning: 0x{:X} to 0x{:X}".format(aligned_address, real_address))
|
||||
return real_address
|
||||
+7
-1
@@ -17,7 +17,7 @@ from model.defs import *
|
||||
logger = logging.getLogger("Injector")
|
||||
|
||||
|
||||
def inject_exe(main_shc: bytes, settings: Settings, carrier: Carrier):
|
||||
def inject_exe(main_shc: bytes, settings: Settings, carrier: Carrier, project: Project):
|
||||
exe_in = settings.inject_exe_in
|
||||
exe_out = settings.inject_exe_out
|
||||
carrier_invoke_style: CarrierInvokeStyle = settings.carrier_invoke_style
|
||||
@@ -90,6 +90,12 @@ def inject_exe(main_shc: bytes, settings: Settings, carrier: Carrier):
|
||||
shellcode_offset += sect.PointerToRawData
|
||||
shellcode_rva = superpe.pe.get_rva_from_offset(shellcode_offset)
|
||||
|
||||
# Aligning the payload (not carrier!) to page size is important for dll_loader_change
|
||||
if settings.carrier_name == "dll_loader_change":
|
||||
# align shellcode_rva minus an offset to page size
|
||||
shellcode_rva = align_to_page_size(shellcode_rva, shellcode_len - project.payload.len)
|
||||
shellcode_offset = superpe.pe.get_offset_from_rva(shellcode_rva)
|
||||
|
||||
logger.info("---( Inject: Write Shellcode to offset:0x{:X} (rva:0x{:X})".format(
|
||||
shellcode_offset, shellcode_rva))
|
||||
|
||||
|
||||
+12
-12
@@ -12,13 +12,13 @@ import phases.compiler
|
||||
import phases.assembler
|
||||
import phases.injector
|
||||
from observer import observer
|
||||
from pe.pehelper import extract_code_from_exe_file_ep
|
||||
from pe.pehelper import preload_dll
|
||||
from sender import scannerDetectsBytes
|
||||
from model.project import Project, prepare_project
|
||||
from model.settings import Settings
|
||||
from model.defs import *
|
||||
from log import setup_logging
|
||||
from model.carrier import Carrier, DataReuseEntry, IatRequest
|
||||
from model.carrier import DataReuseEntry
|
||||
|
||||
|
||||
def main():
|
||||
@@ -151,6 +151,14 @@ def start_real(settings: Settings):
|
||||
project.settings.plugin_decoy)
|
||||
)
|
||||
|
||||
# FIXUP DLL Payload
|
||||
# Prepare DLL payload for usage in dll_loader_change
|
||||
# This needs to be done before rendering the C templates, as the need
|
||||
# the size of the payload
|
||||
if project.settings.carrier_name == "dll_loader_change":
|
||||
project.payload.payload_data = preload_dll(project.payload.payload_path)
|
||||
project.payload.len = len(project.payload.payload_data)
|
||||
|
||||
# CREATE: Carrier C source files from template (C->C)
|
||||
phases.templater.create_c_from_template(settings, project.payload.len)
|
||||
|
||||
@@ -198,19 +206,11 @@ def start_real(settings: Settings):
|
||||
#observer.add_code_file("full_shc", full_shellcode)
|
||||
else:
|
||||
# shellcode is in .rdata, so we dont need to merge
|
||||
# This is handle before, e.g. encoding.
|
||||
full_shellcode = carrier_shellcode
|
||||
|
||||
# RWX Injection (optional): obfuscate loader+payload
|
||||
#if project.exe_host.rwx_section != None:
|
||||
# logger.info("--[ RWX section {} found. Will obfuscate loader+payload and inject into it".format(
|
||||
# project.exe_host.rwx_section.Name.decode().rstrip('\x00')
|
||||
# ))
|
||||
# obfuscate_shc_loader(settings.main_shc_path, settings.main_shc_path + ".sgn")
|
||||
# observer.add_code_file("payload_sgn", file_readall_binary(settings.main_shc_path + ".sgn"))
|
||||
# shutil.move(settings.main_shc_path + ".sgn", settings.main_shc_path)
|
||||
|
||||
# inject (merged) loader into an exe. Big task.
|
||||
phases.injector.inject_exe(full_shellcode, settings, project.carrier)
|
||||
phases.injector.inject_exe(full_shellcode, settings, project.carrier, project)
|
||||
#observer.add_code_file("exe_final", extract_code_from_exe_file_ep(settings.inject_exe_out, 300))
|
||||
|
||||
# Check binary with avred
|
||||
|
||||
Reference in New Issue
Block a user