Refactored textarea from console, eventlog and buildlog into a separate widget to reduce code duplication.
This commit is contained in:
@@ -130,21 +130,21 @@ proc main(ip: string = "localhost", port: int = 37573) =
|
|||||||
|
|
||||||
of CLIENT_CONSOLE_ITEM:
|
of CLIENT_CONSOLE_ITEM:
|
||||||
let agentId = event.data["agentId"].getStr()
|
let agentId = event.data["agentId"].getStr()
|
||||||
consoles[agentId].addItem(
|
consoles[agentId].console.addItem(
|
||||||
cast[LogType](event.data["logType"].getInt()),
|
cast[LogType](event.data["logType"].getInt()),
|
||||||
event.data["message"].getStr(),
|
event.data["message"].getStr(),
|
||||||
event.timestamp.fromUnix().local().format("dd-MM-yyyy HH:mm:ss")
|
event.timestamp.fromUnix().local().format("dd-MM-yyyy HH:mm:ss")
|
||||||
)
|
)
|
||||||
|
|
||||||
of CLIENT_EVENTLOG_ITEM:
|
of CLIENT_EVENTLOG_ITEM:
|
||||||
eventlog.addItem(
|
eventlog.textarea.addItem(
|
||||||
cast[LogType](event.data["logType"].getInt()),
|
cast[LogType](event.data["logType"].getInt()),
|
||||||
event.data["message"].getStr(),
|
event.data["message"].getStr(),
|
||||||
event.timestamp.fromUnix().local().format("dd-MM-yyyy HH:mm:ss")
|
event.timestamp.fromUnix().local().format("dd-MM-yyyy HH:mm:ss")
|
||||||
)
|
)
|
||||||
|
|
||||||
of CLIENT_BUILDLOG_ITEM:
|
of CLIENT_BUILDLOG_ITEM:
|
||||||
listenersTable.generatePayloadModal.addBuildlogItem(
|
listenersTable.generatePayloadModal.buildLog.addItem(
|
||||||
cast[LogType](event.data["logType"].getInt()),
|
cast[LogType](event.data["logType"].getInt()),
|
||||||
event.data["message"].getStr(),
|
event.data["message"].getStr(),
|
||||||
event.timestamp.fromUnix().local().format("dd-MM-yyyy HH:mm:ss")
|
event.timestamp.fromUnix().local().format("dd-MM-yyyy HH:mm:ss")
|
||||||
@@ -193,7 +193,7 @@ proc main(ip: string = "localhost", port: int = 37573) =
|
|||||||
# This is done to ensure that closed console windows can be opened again
|
# This is done to ensure that closed console windows can be opened again
|
||||||
consoles = newConsoleTable
|
consoles = newConsoleTable
|
||||||
|
|
||||||
# igShowDemoWindow(nil)
|
igShowDemoWindow(nil)
|
||||||
|
|
||||||
# render
|
# render
|
||||||
app.render()
|
app.render()
|
||||||
|
|||||||
@@ -5,6 +5,8 @@ import ../utils/[appImGui, colors]
|
|||||||
import ../../common/[types, utils]
|
import ../../common/[types, utils]
|
||||||
import ../../modules/manager
|
import ../../modules/manager
|
||||||
import ../core/[task, websocket]
|
import ../core/[task, websocket]
|
||||||
|
import ./widgets/textarea
|
||||||
|
export addItem
|
||||||
|
|
||||||
const MAX_INPUT_LENGTH = 512
|
const MAX_INPUT_LENGTH = 512
|
||||||
type
|
type
|
||||||
@@ -12,53 +14,21 @@ type
|
|||||||
agent*: UIAgent
|
agent*: UIAgent
|
||||||
showConsole*: bool
|
showConsole*: bool
|
||||||
inputBuffer: array[MAX_INPUT_LENGTH, char]
|
inputBuffer: array[MAX_INPUT_LENGTH, char]
|
||||||
console*: ConsoleItems # Stores all console items
|
console*: TextareaWidget
|
||||||
consoleFiltered*: ConsoleItems # Temporarily stores console items that are displayed to the user
|
|
||||||
history: seq[string]
|
history: seq[string]
|
||||||
historyPosition: int
|
historyPosition: int
|
||||||
currentInput: string
|
currentInput: string
|
||||||
textSelect: ptr TextSelect
|
|
||||||
filter: ptr ImGuiTextFilter
|
filter: ptr ImGuiTextFilter
|
||||||
|
|
||||||
#[
|
|
||||||
Helper functions for text selection
|
|
||||||
]#
|
|
||||||
proc getText(item: ConsoleItem): cstring =
|
|
||||||
if item.itemType != LOG_OUTPUT:
|
|
||||||
# let timestamp = item.timestamp.fromUnix().format("dd-MM-yyyy HH:mm:ss")
|
|
||||||
return "[" & item.timestamp & "]" & $item.itemType & item.text
|
|
||||||
else:
|
|
||||||
return $item.itemType & item.text
|
|
||||||
|
|
||||||
proc getNumLines(data: pointer): csize_t {.cdecl.} =
|
|
||||||
if data.isNil:
|
|
||||||
return 0
|
|
||||||
let console = cast[ConsoleItems](data)
|
|
||||||
return console.items.len().csize_t
|
|
||||||
|
|
||||||
proc getLineAtIndex(i: csize_t, data: pointer, outLen: ptr csize_t): cstring {.cdecl.} =
|
|
||||||
if data.isNil:
|
|
||||||
return nil
|
|
||||||
let console = cast[ConsoleItems](data)
|
|
||||||
let line = console.items[i].getText()
|
|
||||||
if not outLen.isNil:
|
|
||||||
outLen[] = line.len.csize_t
|
|
||||||
return line
|
|
||||||
|
|
||||||
proc Console*(agent: UIAgent): ConsoleComponent =
|
proc Console*(agent: UIAgent): ConsoleComponent =
|
||||||
result = new ConsoleComponent
|
result = new ConsoleComponent
|
||||||
result.agent = agent
|
result.agent = agent
|
||||||
result.showConsole = true
|
result.showConsole = true
|
||||||
zeroMem(addr result.inputBuffer[0], MAX_INPUT_LENGTH)
|
zeroMem(addr result.inputBuffer[0], MAX_INPUT_LENGTH)
|
||||||
result.console = new ConsoleItems
|
result.console = Textarea()
|
||||||
result.console.items = @[]
|
|
||||||
result.consoleFiltered = new ConsoleItems
|
|
||||||
result.consoleFiltered.items = @[]
|
|
||||||
result.history = @[]
|
result.history = @[]
|
||||||
result.historyPosition = -1
|
result.historyPosition = -1
|
||||||
result.currentInput = ""
|
result.currentInput = ""
|
||||||
# Text selection covers only console items that are shown to the user even after using text filters
|
|
||||||
result.textSelect = textselect_create(getLineAtIndex, getNumLines, cast[pointer](result.consoleFiltered), 0)
|
|
||||||
result.filter = ImGuiTextFilter_ImGuiTextFilter("")
|
result.filter = ImGuiTextFilter_ImGuiTextFilter("")
|
||||||
|
|
||||||
#[
|
#[
|
||||||
@@ -173,47 +143,36 @@ proc callback(data: ptr ImGuiInputTextCallbackData): cint {.cdecl.} =
|
|||||||
|
|
||||||
else: discard
|
else: discard
|
||||||
|
|
||||||
#[
|
|
||||||
API to add new console item
|
|
||||||
]#
|
|
||||||
proc addItem*(component: ConsoleComponent, itemType: LogType, data: string, timestamp: string = now().format("dd-MM-yyyy HH:mm:ss")) =
|
|
||||||
for line in data.split("\n"):
|
|
||||||
component.console.items.add(ConsoleItem(
|
|
||||||
timestamp: timestamp,
|
|
||||||
itemType: itemType,
|
|
||||||
text: line
|
|
||||||
))
|
|
||||||
|
|
||||||
#[
|
#[
|
||||||
Handling console commands
|
Handling console commands
|
||||||
]#
|
]#
|
||||||
proc displayHelp(component: ConsoleComponent) =
|
proc displayHelp(component: ConsoleComponent) =
|
||||||
for module in getModules(component.agent.modules):
|
for module in getModules(component.agent.modules):
|
||||||
for cmd in module.commands:
|
for cmd in module.commands:
|
||||||
component.addItem(LOG_OUTPUT, " * " & cmd.name.alignLeft(15) & cmd.description)
|
component.console.addItem(LOG_OUTPUT, " * " & cmd.name.alignLeft(15) & cmd.description)
|
||||||
component.addItem(LOG_OUTPUT, "")
|
component.console.addItem(LOG_OUTPUT, "")
|
||||||
|
|
||||||
proc displayCommandHelp(component: ConsoleComponent, command: Command) =
|
proc displayCommandHelp(component: ConsoleComponent, command: Command) =
|
||||||
var usage = command.name & " " & command.arguments.mapIt(
|
var usage = command.name & " " & command.arguments.mapIt(
|
||||||
if it.isRequired: "<" & it.name & ">" else: "[" & it.name & "]"
|
if it.isRequired: "<" & it.name & ">" else: "[" & it.name & "]"
|
||||||
).join(" ")
|
).join(" ")
|
||||||
|
|
||||||
component.addItem(LOG_OUTPUT, command.description)
|
component.console.addItem(LOG_OUTPUT, command.description)
|
||||||
component.addItem(LOG_OUTPUT, "Usage : " & usage)
|
component.console.addItem(LOG_OUTPUT, "Usage : " & usage)
|
||||||
component.addItem(LOG_OUTPUT, "Example : " & command.example)
|
component.console.addItem(LOG_OUTPUT, "Example : " & command.example)
|
||||||
component.addItem(LOG_OUTPUT, "")
|
component.console.addItem(LOG_OUTPUT, "")
|
||||||
|
|
||||||
if command.arguments.len > 0:
|
if command.arguments.len > 0:
|
||||||
component.addItem(LOG_OUTPUT, "Arguments:")
|
component.console.addItem(LOG_OUTPUT, "Arguments:")
|
||||||
|
|
||||||
let header = @["Name", "Type", "Required", "Description"]
|
let header = @["Name", "Type", "Required", "Description"]
|
||||||
component.addItem(LOG_OUTPUT, " " & header[0].alignLeft(15) & " " & header[1].alignLeft(6) & " " & header[2].alignLeft(8) & " " & header[3])
|
component.console.addItem(LOG_OUTPUT, " " & header[0].alignLeft(15) & " " & header[1].alignLeft(6) & " " & header[2].alignLeft(8) & " " & header[3])
|
||||||
component.addItem(LOG_OUTPUT, " " & '-'.repeat(15) & " " & '-'.repeat(6) & " " & '-'.repeat(8) & " " & '-'.repeat(20))
|
component.console.addItem(LOG_OUTPUT, " " & '-'.repeat(15) & " " & '-'.repeat(6) & " " & '-'.repeat(8) & " " & '-'.repeat(20))
|
||||||
|
|
||||||
for arg in command.arguments:
|
for arg in command.arguments:
|
||||||
let isRequired = if arg.isRequired: "YES" else: "NO"
|
let isRequired = if arg.isRequired: "YES" else: "NO"
|
||||||
component.addItem(LOG_OUTPUT, " * " & arg.name.alignLeft(15) & " " & ($arg.argumentType).toUpperAscii().alignLeft(6) & " " & isRequired.align(8) & " " & arg.description)
|
component.console.addItem(LOG_OUTPUT, " * " & arg.name.alignLeft(15) & " " & ($arg.argumentType).toUpperAscii().alignLeft(6) & " " & isRequired.align(8) & " " & arg.description)
|
||||||
component.addItem(LOG_OUTPUT, "")
|
component.console.addItem(LOG_OUTPUT, "")
|
||||||
|
|
||||||
proc handleHelp(component: ConsoleComponent, parsed: seq[string]) =
|
proc handleHelp(component: ConsoleComponent, parsed: seq[string]) =
|
||||||
try:
|
try:
|
||||||
@@ -224,7 +183,7 @@ proc handleHelp(component: ConsoleComponent, parsed: seq[string]) =
|
|||||||
component.displayHelp()
|
component.displayHelp()
|
||||||
except ValueError:
|
except ValueError:
|
||||||
# Command was not found
|
# Command was not found
|
||||||
component.addItem(LOG_ERROR, "The command '" & parsed[1] & "' does not exist.")
|
component.console.addItem(LOG_ERROR, "The command '" & parsed[1] & "' does not exist.")
|
||||||
|
|
||||||
proc handleAgentCommand*(component: ConsoleComponent, connection: WsConnection, input: string) =
|
proc handleAgentCommand*(component: ConsoleComponent, connection: WsConnection, input: string) =
|
||||||
# Convert user input into sequence of string arguments
|
# Convert user input into sequence of string arguments
|
||||||
@@ -242,37 +201,10 @@ proc handleAgentCommand*(component: ConsoleComponent, connection: WsConnection,
|
|||||||
task = createTask(component.agent.agentId, component.agent.listenerId, command, parsedArgs[1..^1])
|
task = createTask(component.agent.agentId, component.agent.listenerId, command, parsedArgs[1..^1])
|
||||||
|
|
||||||
connection.sendAgentTask(component.agent.agentId, input, task)
|
connection.sendAgentTask(component.agent.agentId, input, task)
|
||||||
component.addItem(LOG_INFO, "Tasked agent to " & command.description.toLowerAscii() & " (" & Uuid.toString(task.taskId) & ")")
|
component.console.addItem(LOG_INFO, "Tasked agent to " & command.description.toLowerAscii() & " (" & Uuid.toString(task.taskId) & ")")
|
||||||
|
|
||||||
except CatchableError:
|
except CatchableError:
|
||||||
component.addItem(LOG_ERROR, getCurrentExceptionMsg())
|
component.console.addItem(LOG_ERROR, getCurrentExceptionMsg())
|
||||||
|
|
||||||
#[
|
|
||||||
Drawing
|
|
||||||
]#
|
|
||||||
proc print(item: ConsoleItem) =
|
|
||||||
|
|
||||||
if item.itemType != LOG_OUTPUT:
|
|
||||||
# let timestamp = item.timestamp.fromUnix().format("dd-MM-yyyy HH:mm:ss")
|
|
||||||
igTextColored(GRAY, "[" & item.timestamp & "]", nil)
|
|
||||||
igSameLine(0.0f, 0.0f)
|
|
||||||
|
|
||||||
case item.itemType:
|
|
||||||
of LOG_INFO, LOG_INFO_SHORT:
|
|
||||||
igTextColored(CONSOLE_INFO, $item.itemType)
|
|
||||||
of LOG_ERROR, LOG_ERROR_SHORT:
|
|
||||||
igTextColored(CONSOLE_ERROR, $item.itemType)
|
|
||||||
of LOG_SUCCESS, LOG_SUCCESS_SHORT:
|
|
||||||
igTextColored(CONSOLE_SUCCESS, $item.itemType)
|
|
||||||
of LOG_WARNING, LOG_WARNING_SHORT:
|
|
||||||
igTextColored(CONSOLE_WARNING, $item.itemType)
|
|
||||||
of LOG_COMMAND:
|
|
||||||
igTextColored(CONSOLE_COMMAND, $item.itemType)
|
|
||||||
of LOG_OUTPUT:
|
|
||||||
igTextColored(vec4(0.0f, 0.0f, 0.0f, 0.0f), $item.itemType)
|
|
||||||
|
|
||||||
igSameLine(0.0f, 0.0f)
|
|
||||||
igTextUnformatted(item.text.cstring, nil)
|
|
||||||
|
|
||||||
proc draw*(component: ConsoleComponent, connection: WsConnection) =
|
proc draw*(component: ConsoleComponent, connection: WsConnection) =
|
||||||
igBegin(fmt"[{component.agent.agentId}] {component.agent.username}@{component.agent.hostname}".cstring, addr component.showConsole, 0)
|
igBegin(fmt"[{component.agent.agentId}] {component.agent.username}@{component.agent.hostname}".cstring, addr component.showConsole, 0)
|
||||||
@@ -338,45 +270,10 @@ proc draw*(component: ConsoleComponent, connection: WsConnection) =
|
|||||||
igSameLine(0.0f, textSpacing)
|
igSameLine(0.0f, textSpacing)
|
||||||
component.filter.ImGuiTextFilter_Draw("##ConsoleSearch", searchBoxWidth)
|
component.filter.ImGuiTextFilter_Draw("##ConsoleSearch", searchBoxWidth)
|
||||||
|
|
||||||
try:
|
#[
|
||||||
# Set styles of the console window
|
Console textarea
|
||||||
igPushStyleColor_Vec4(ImGui_Col_FrameBg.int32, vec4(0.1f, 0.1f, 0.1f, 1.0f))
|
]#
|
||||||
igPushStyleColor_Vec4(ImGui_Col_ScrollbarBg.int32, vec4(0.1f, 0.1f, 0.1f, 1.0f))
|
component.console.draw(vec2(-1.0f, -footerHeight), component.filter)
|
||||||
igPushStyleColor_Vec4(ImGui_Col_Border.int32, vec4(0.2f, 0.2f, 0.2f, 1.0f))
|
|
||||||
igPushStyleVar_Float(ImGui_StyleVar_FrameBorderSize .int32, 1.0f)
|
|
||||||
|
|
||||||
let childWindowFlags = ImGuiChildFlags_NavFlattened.int32 or ImGui_ChildFlags_Borders.int32 or ImGui_ChildFlags_AlwaysUseWindowPadding.int32 or ImGuiChildFlags_FrameStyle.int32
|
|
||||||
if igBeginChild_Str("##Console", vec2(-1.0f, -footerHeight), childWindowFlags, ImGuiWindowFlags_HorizontalScrollbar.int32):
|
|
||||||
|
|
||||||
# Reset console items shown in the UI
|
|
||||||
component.consoleFiltered.items = @[]
|
|
||||||
|
|
||||||
# Display console items
|
|
||||||
for item in component.console.items:
|
|
||||||
|
|
||||||
# Apply filter
|
|
||||||
if component.filter.ImGuiTextFilter_IsActive():
|
|
||||||
if not component.filter.ImGuiTextFilter_PassFilter(item.getText(), nil):
|
|
||||||
continue
|
|
||||||
|
|
||||||
component.consoleFiltered.items.add(item)
|
|
||||||
item.print()
|
|
||||||
|
|
||||||
# Auto-scroll to bottom
|
|
||||||
if igGetScrollY() >= igGetScrollMaxY():
|
|
||||||
igSetScrollHereY(1.0f)
|
|
||||||
|
|
||||||
# Update selection
|
|
||||||
component.textSelect.textselect_update()
|
|
||||||
|
|
||||||
except IndexDefect:
|
|
||||||
# CTRL+A crashes when no items are in the console
|
|
||||||
discard
|
|
||||||
|
|
||||||
finally:
|
|
||||||
igPopStyleColor(3)
|
|
||||||
igPopStyleVar(1)
|
|
||||||
igEndChild()
|
|
||||||
|
|
||||||
# Padding
|
# Padding
|
||||||
igDummy(vec2(0.0f, consolePadding))
|
igDummy(vec2(0.0f, consolePadding))
|
||||||
@@ -397,7 +294,7 @@ proc draw*(component: ConsoleComponent, connection: WsConnection) =
|
|||||||
let command = ($(addr component.inputBuffer[0])).strip()
|
let command = ($(addr component.inputBuffer[0])).strip()
|
||||||
if not command.isEmptyOrWhitespace():
|
if not command.isEmptyOrWhitespace():
|
||||||
|
|
||||||
component.addItem(LOG_COMMAND, command)
|
component.console.addItem(LOG_COMMAND, command)
|
||||||
|
|
||||||
# Send command to team server
|
# Send command to team server
|
||||||
component.handleAgentCommand(connection, command)
|
component.handleAgentCommand(connection, command)
|
||||||
|
|||||||
@@ -1,115 +1,22 @@
|
|||||||
import strformat, strutils, times
|
import strformat, strutils, times
|
||||||
import imguin/[cimgui, glfw_opengl, simple]
|
import imguin/[cimgui, glfw_opengl, simple]
|
||||||
import ../utils/[appImGui, colors]
|
import ../utils/[appImGui, colors]
|
||||||
|
import ./widgets/textarea
|
||||||
import ../../common/types
|
import ../../common/types
|
||||||
|
export addItem
|
||||||
|
|
||||||
type
|
type
|
||||||
EventlogComponent* = ref object of RootObj
|
EventlogComponent* = ref object of RootObj
|
||||||
title: string
|
title: string
|
||||||
log*: ConsoleItems
|
textarea*: TextareaWidget
|
||||||
textSelect: ptr TextSelect
|
|
||||||
showTimestamps: bool
|
|
||||||
|
|
||||||
proc getText(item: ConsoleItem): cstring =
|
|
||||||
if item.itemType != LOG_OUTPUT:
|
|
||||||
return fmt"[{item.timestamp}]{$item.itemType}{item.text}".string
|
|
||||||
else:
|
|
||||||
return fmt"{$item.itemType}{item.text}".string
|
|
||||||
|
|
||||||
proc getNumLines(data: pointer): csize_t {.cdecl.} =
|
|
||||||
if data.isNil:
|
|
||||||
return 0
|
|
||||||
let log = cast[ConsoleItems](data)
|
|
||||||
return log.items.len().csize_t
|
|
||||||
|
|
||||||
proc getLineAtIndex(i: csize_t, data: pointer, outLen: ptr csize_t): cstring {.cdecl.} =
|
|
||||||
if data.isNil:
|
|
||||||
return nil
|
|
||||||
let log = cast[ConsoleItems](data)
|
|
||||||
let line = log.items[i].getText()
|
|
||||||
if not outLen.isNil:
|
|
||||||
outLen[] = line.len.csize_t
|
|
||||||
return line
|
|
||||||
|
|
||||||
proc Eventlog*(title: string): EventlogComponent =
|
proc Eventlog*(title: string): EventlogComponent =
|
||||||
result = new EventlogComponent
|
result = new EventlogComponent
|
||||||
result.title = title
|
result.title = title
|
||||||
result.log = new ConsoleItems
|
result.textarea = Textarea(showTimestamps = false)
|
||||||
result.log.items = @[]
|
|
||||||
result.textSelect = textselect_create(getLineAtIndex, getNumLines, cast[pointer](result.log), 0)
|
|
||||||
result.showTimestamps = false
|
|
||||||
|
|
||||||
#[
|
|
||||||
API to add new log entry
|
|
||||||
]#
|
|
||||||
proc addItem*(component: EventlogComponent, itemType: LogType, data: string, timestamp: string = now().format("dd-MM-yyyy HH:mm:ss")) =
|
|
||||||
|
|
||||||
for line in data.split("\n"):
|
|
||||||
component.log.items.add(ConsoleItem(
|
|
||||||
timestamp: timestamp,
|
|
||||||
itemType: itemType,
|
|
||||||
text: line
|
|
||||||
))
|
|
||||||
|
|
||||||
#[
|
|
||||||
Drawing
|
|
||||||
]#
|
|
||||||
proc print(component: EventlogComponent, item: ConsoleItem) =
|
|
||||||
if (item.itemType != LOG_OUTPUT) and component.showTimestamps:
|
|
||||||
igTextColored(vec4(0.6f, 0.6f, 0.6f, 1.0f), fmt"[{item.timestamp}]".cstring)
|
|
||||||
igSameLine(0.0f, 0.0f)
|
|
||||||
|
|
||||||
case item.itemType:
|
|
||||||
of LOG_INFO, LOG_INFO_SHORT:
|
|
||||||
igTextColored(CONSOLE_INFO, $item.itemType)
|
|
||||||
of LOG_ERROR, LOG_ERROR_SHORT:
|
|
||||||
igTextColored(CONSOLE_ERROR, $item.itemType)
|
|
||||||
of LOG_SUCCESS, LOG_SUCCESS_SHORT:
|
|
||||||
igTextColored(CONSOLE_SUCCESS, $item.itemType)
|
|
||||||
of LOG_WARNING, LOG_WARNING_SHORT:
|
|
||||||
igTextColored(CONSOLE_WARNING, $item.itemType)
|
|
||||||
of LOG_COMMAND:
|
|
||||||
igTextColored(CONSOLE_COMMAND, $item.itemType)
|
|
||||||
of LOG_OUTPUT:
|
|
||||||
igTextColored(vec4(0.0f, 0.0f, 0.0f, 0.0f), $item.itemType)
|
|
||||||
|
|
||||||
igSameLine(0.0f, 0.0f)
|
|
||||||
igTextUnformatted(item.text.cstring, nil)
|
|
||||||
|
|
||||||
proc draw*(component: EventlogComponent, showComponent: ptr bool) =
|
proc draw*(component: EventlogComponent, showComponent: ptr bool) =
|
||||||
igBegin(component.title, showComponent, 0)
|
igBegin(component.title, showComponent, 0)
|
||||||
defer: igEnd()
|
defer: igEnd()
|
||||||
|
|
||||||
try:
|
component.textarea.draw(vec2(-1.0f, -1.0f))
|
||||||
# Set styles of the eventlog window
|
|
||||||
igPushStyleColor_Vec4(ImGui_Col_FrameBg.int32, vec4(0.1f, 0.1f, 0.1f, 1.0f))
|
|
||||||
igPushStyleColor_Vec4(ImGui_Col_ScrollbarBg.int32, vec4(0.1f, 0.1f, 0.1f, 1.0f))
|
|
||||||
igPushStyleColor_Vec4(ImGui_Col_Border.int32, vec4(0.2f, 0.2f, 0.2f, 1.0f))
|
|
||||||
igPushStyleVar_Float(ImGui_StyleVar_FrameBorderSize .int32, 1.0f)
|
|
||||||
|
|
||||||
let childWindowFlags = ImGuiChildFlags_NavFlattened.int32 or ImGui_ChildFlags_Borders.int32 or ImGui_ChildFlags_AlwaysUseWindowPadding.int32 or ImGuiChildFlags_FrameStyle.int32
|
|
||||||
if igBeginChild_Str("##Log", vec2(-1.0f, -1.0f), childWindowFlags, ImGuiWindowFlags_HorizontalScrollbar.int32):
|
|
||||||
# Display eventlog items
|
|
||||||
for item in component.log.items:
|
|
||||||
component.print(item)
|
|
||||||
|
|
||||||
# Right click context menu to toggle timestamps in eventlog
|
|
||||||
if igBeginPopupContextWindow("EventlogSettings", ImGui_PopupFlags_MouseButtonRight.int32):
|
|
||||||
if igCheckbox("Show timestamps", addr component.showTimestamps):
|
|
||||||
igCloseCurrentPopup()
|
|
||||||
igEndPopup()
|
|
||||||
|
|
||||||
component.textSelect.textselect_update()
|
|
||||||
|
|
||||||
# Auto-scroll to bottom
|
|
||||||
if igGetScrollY() >= igGetScrollMaxY():
|
|
||||||
igSetScrollHereY(1.0f)
|
|
||||||
|
|
||||||
except IndexDefect:
|
|
||||||
# CTRL+A crashes when no items are in the eventlog
|
|
||||||
discard
|
|
||||||
|
|
||||||
finally:
|
|
||||||
igPopStyleColor(3)
|
|
||||||
igPopStyleVar(1)
|
|
||||||
igEndChild()
|
|
||||||
@@ -3,7 +3,8 @@ import imguin/[cimgui, glfw_opengl, simple]
|
|||||||
import ../../utils/[appImGui, colors]
|
import ../../utils/[appImGui, colors]
|
||||||
import ../../../common/[types, profile, utils]
|
import ../../../common/[types, profile, utils]
|
||||||
import ../../../modules/manager
|
import ../../../modules/manager
|
||||||
import ../widgets/dualListSelection
|
import ../widgets/[dualListSelection, textarea]
|
||||||
|
export addItem
|
||||||
|
|
||||||
type
|
type
|
||||||
AgentModalComponent* = ref object of RootObj
|
AgentModalComponent* = ref object of RootObj
|
||||||
@@ -12,8 +13,8 @@ type
|
|||||||
sleepMask: int32
|
sleepMask: int32
|
||||||
spoofStack: bool
|
spoofStack: bool
|
||||||
sleepMaskTechniques: seq[string]
|
sleepMaskTechniques: seq[string]
|
||||||
moduleSelection: DualListSelectionComponent[Module]
|
moduleSelection: DualListSelectionWidget[Module]
|
||||||
buildLog: ConsoleItems
|
buildLog*: TextareaWidget
|
||||||
|
|
||||||
|
|
||||||
proc AgentModal*(): AgentModalComponent =
|
proc AgentModal*(): AgentModalComponent =
|
||||||
@@ -37,9 +38,7 @@ proc AgentModal*(): AgentModalComponent =
|
|||||||
return cmp(x.moduleType, y.moduleType)
|
return cmp(x.moduleType, y.moduleType)
|
||||||
|
|
||||||
result.moduleSelection = DualListSelection(modules, moduleName, compareModules, moduleDesc)
|
result.moduleSelection = DualListSelection(modules, moduleName, compareModules, moduleDesc)
|
||||||
|
result.buildLog = Textarea(showTimestamps = false)
|
||||||
result.buildlog = new ConsoleItems
|
|
||||||
result.buildLog.items = @[]
|
|
||||||
|
|
||||||
proc resetModalValues*(component: AgentModalComponent) =
|
proc resetModalValues*(component: AgentModalComponent) =
|
||||||
component.listener = 0
|
component.listener = 0
|
||||||
@@ -47,33 +46,7 @@ proc resetModalValues*(component: AgentModalComponent) =
|
|||||||
component.sleepMask = 0
|
component.sleepMask = 0
|
||||||
component.spoofStack = false
|
component.spoofStack = false
|
||||||
component.moduleSelection.reset()
|
component.moduleSelection.reset()
|
||||||
component.buildLog.items = @[]
|
component.buildLog.clear()
|
||||||
|
|
||||||
proc addBuildlogItem*(component: AgentModalComponent, itemType: LogType, data: string, timestamp: string = now().format("dd-MM-yyyy HH:mm:ss")) =
|
|
||||||
for line in data.split("\n"):
|
|
||||||
component.buildLog.items.add(ConsoleItem(
|
|
||||||
timestamp: timestamp,
|
|
||||||
itemType: itemType,
|
|
||||||
text: line
|
|
||||||
))
|
|
||||||
|
|
||||||
proc print(component: AgentModalComponent, item: ConsoleItem) =
|
|
||||||
case item.itemType:
|
|
||||||
of LOG_INFO, LOG_INFO_SHORT:
|
|
||||||
igTextColored(CONSOLE_INFO, $item.itemType)
|
|
||||||
of LOG_ERROR, LOG_ERROR_SHORT:
|
|
||||||
igTextColored(CONSOLE_ERROR, $item.itemType)
|
|
||||||
of LOG_SUCCESS, LOG_SUCCESS_SHORT:
|
|
||||||
igTextColored(CONSOLE_SUCCESS, $item.itemType)
|
|
||||||
of LOG_WARNING, LOG_WARNING_SHORT:
|
|
||||||
igTextColored(CONSOLE_WARNING, $item.itemType)
|
|
||||||
of LOG_COMMAND:
|
|
||||||
igTextColored(CONSOLE_COMMAND, $item.itemType)
|
|
||||||
of LOG_OUTPUT:
|
|
||||||
igTextColored(vec4(0.0f, 0.0f, 0.0f, 0.0f), $item.itemType)
|
|
||||||
|
|
||||||
igSameLine(0.0f, 0.0f)
|
|
||||||
igTextUnformatted(item.text.cstring, nil)
|
|
||||||
|
|
||||||
proc draw*(component: AgentModalComponent, listeners: seq[UIListener]): AgentBuildInformation =
|
proc draw*(component: AgentModalComponent, listeners: seq[UIListener]): AgentBuildInformation =
|
||||||
|
|
||||||
@@ -142,32 +115,8 @@ proc draw*(component: AgentModalComponent, listeners: seq[UIListener]): AgentBui
|
|||||||
igDummy(vec2(0.0f, 10.0f))
|
igDummy(vec2(0.0f, 10.0f))
|
||||||
|
|
||||||
igText("Build log: ")
|
igText("Build log: ")
|
||||||
try:
|
let buildLogHeight = 250.0f
|
||||||
# Set styles of the log window
|
component.buildLog.draw(vec2(-1.0f, buildLogHeight))
|
||||||
igPushStyleColor_Vec4(ImGui_Col_FrameBg.int32, vec4(0.1f, 0.1f, 0.1f, 1.0f))
|
|
||||||
igPushStyleColor_Vec4(ImGui_Col_ScrollbarBg.int32, vec4(0.1f, 0.1f, 0.1f, 1.0f))
|
|
||||||
igPushStyleColor_Vec4(ImGui_Col_Border.int32, vec4(0.2f, 0.2f, 0.2f, 1.0f))
|
|
||||||
igPushStyleVar_Float(ImGui_StyleVar_FrameBorderSize .int32, 1.0f)
|
|
||||||
|
|
||||||
let buildLogHeight = 250.0f
|
|
||||||
let childWindowFlags = ImGuiChildFlags_NavFlattened.int32 or ImGui_ChildFlags_Borders.int32 or ImGui_ChildFlags_AlwaysUseWindowPadding.int32 or ImGuiChildFlags_FrameStyle.int32
|
|
||||||
if igBeginChild_Str("##Log", vec2(-1.0f, buildLogHeight), childWindowFlags, ImGuiWindowFlags_HorizontalScrollbar.int32):
|
|
||||||
# Display eventlog items
|
|
||||||
for item in component.buildLog.items:
|
|
||||||
component.print(item)
|
|
||||||
|
|
||||||
# Auto-scroll to bottom
|
|
||||||
if igGetScrollY() >= igGetScrollMaxY():
|
|
||||||
igSetScrollHereY(1.0f)
|
|
||||||
|
|
||||||
except IndexDefect:
|
|
||||||
# CTRL+A crashes when no items are in the eventlog
|
|
||||||
discard
|
|
||||||
|
|
||||||
finally:
|
|
||||||
igPopStyleColor(3)
|
|
||||||
igPopStyleVar(1)
|
|
||||||
igEndChild()
|
|
||||||
|
|
||||||
igDummy(vec2(0.0f, 10.0f))
|
igDummy(vec2(0.0f, 10.0f))
|
||||||
igSeparator()
|
igSeparator()
|
||||||
|
|||||||
@@ -60,13 +60,6 @@ proc draw*(component: ListenerModalComponent): UIListener =
|
|||||||
|
|
||||||
# HTTP Listener settings
|
# HTTP Listener settings
|
||||||
if component.protocols[component.protocol] == $HTTP:
|
if component.protocols[component.protocol] == $HTTP:
|
||||||
# Callback hosts
|
|
||||||
igText("Hosts (Callback): ")
|
|
||||||
igSameLine(0.0f, textSpacing)
|
|
||||||
igGetContentRegionAvail(addr availableSize)
|
|
||||||
igSetNextItemWidth(availableSize.x)
|
|
||||||
igInputTextMultiline("##InputCallbackHosts", addr component.callbackHosts[0], 256 * 32, vec2(0.0f, 3.0f * igGetTextLineHeightWithSpacing()), ImGui_InputTextFlags_CharsNoBlank.int32, nil, nil)
|
|
||||||
|
|
||||||
# Listener bindAddress
|
# Listener bindAddress
|
||||||
igText("Host (Bind): ")
|
igText("Host (Bind): ")
|
||||||
igSameLine(0.0f, textSpacing)
|
igSameLine(0.0f, textSpacing)
|
||||||
@@ -81,6 +74,13 @@ proc draw*(component: ListenerModalComponent): UIListener =
|
|||||||
igSetNextItemWidth(availableSize.x)
|
igSetNextItemWidth(availableSize.x)
|
||||||
igInputScalar("##InputPortBind", ImGuiDataType_U16.int32, addr component.bindPort, addr step, nil, "%hu", ImGui_InputTextFlags_CharsDecimal.int32)
|
igInputScalar("##InputPortBind", ImGuiDataType_U16.int32, addr component.bindPort, addr step, nil, "%hu", ImGui_InputTextFlags_CharsDecimal.int32)
|
||||||
|
|
||||||
|
# Callback hosts
|
||||||
|
igText("Hosts (Callback): ")
|
||||||
|
igSameLine(0.0f, textSpacing)
|
||||||
|
igGetContentRegionAvail(addr availableSize)
|
||||||
|
igSetNextItemWidth(availableSize.x)
|
||||||
|
igInputTextMultiline("##InputCallbackHosts", addr component.callbackHosts[0], 256 * 32, vec2(0.0f, 3.0f * igGetTextLineHeightWithSpacing()), ImGui_InputTextFlags_CharsNoBlank.int32, nil, nil)
|
||||||
|
|
||||||
igGetContentRegionAvail(addr availableSize)
|
igGetContentRegionAvail(addr availableSize)
|
||||||
|
|
||||||
igDummy(vec2(0.0f, 10.0f))
|
igDummy(vec2(0.0f, 10.0f))
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import ../../utils/[appImGui, colors, utils]
|
|||||||
import ../../../common/[types, utils]
|
import ../../../common/[types, utils]
|
||||||
|
|
||||||
type
|
type
|
||||||
DualListSelectionComponent*[T] = ref object of RootObj
|
DualListSelectionWidget*[T] = ref object of RootObj
|
||||||
items*: array[2, seq[T]]
|
items*: array[2, seq[T]]
|
||||||
selection: array[2, ptr ImGuiSelectionBasicStorage]
|
selection: array[2, ptr ImGuiSelectionBasicStorage]
|
||||||
display: proc(item: T): string
|
display: proc(item: T): string
|
||||||
@@ -14,8 +14,8 @@ type
|
|||||||
proc defaultDisplay[T](item: T): string =
|
proc defaultDisplay[T](item: T): string =
|
||||||
return $item
|
return $item
|
||||||
|
|
||||||
proc DualListSelection*[T](items: seq[T], display: proc(item: T): string = defaultDisplay, compare: proc(x, y: T): int, tooltip: proc(item: T): string = nil): DualListSelectionComponent[T] =
|
proc DualListSelection*[T](items: seq[T], display: proc(item: T): string = defaultDisplay, compare: proc(x, y: T): int, tooltip: proc(item: T): string = nil): DualListSelectionWidget[T] =
|
||||||
result = new DualListSelectionComponent[T]
|
result = new DualListSelectionWidget[T]
|
||||||
result.items[0] = items
|
result.items[0] = items
|
||||||
result.items[1] = @[]
|
result.items[1] = @[]
|
||||||
result.selection[0] = ImGuiSelectionBasicStorage_ImGuiSelectionBasicStorage()
|
result.selection[0] = ImGuiSelectionBasicStorage_ImGuiSelectionBasicStorage()
|
||||||
@@ -24,7 +24,7 @@ proc DualListSelection*[T](items: seq[T], display: proc(item: T): string = defau
|
|||||||
result.compare = compare
|
result.compare = compare
|
||||||
result.tooltip = tooltip
|
result.tooltip = tooltip
|
||||||
|
|
||||||
proc moveAll[T](component: DualListSelectionComponent[T], src, dst: int) =
|
proc moveAll[T](component: DualListSelectionWidget[T], src, dst: int) =
|
||||||
for m in component.items[src]:
|
for m in component.items[src]:
|
||||||
component.items[dst].add(m)
|
component.items[dst].add(m)
|
||||||
component.items[dst].sort(component.compare)
|
component.items[dst].sort(component.compare)
|
||||||
@@ -33,7 +33,7 @@ proc moveAll[T](component: DualListSelectionComponent[T], src, dst: int) =
|
|||||||
ImGuiSelectionBasicStorage_Swap(component.selection[src], component.selection[dst])
|
ImGuiSelectionBasicStorage_Swap(component.selection[src], component.selection[dst])
|
||||||
ImGuiSelectionBasicStorage_Clear(component.selection[src])
|
ImGuiSelectionBasicStorage_Clear(component.selection[src])
|
||||||
|
|
||||||
proc moveSelection[T](component: DualListSelectionComponent[T], src, dst: int) =
|
proc moveSelection[T](component: DualListSelectionWidget[T], src, dst: int) =
|
||||||
var keep: seq[T]
|
var keep: seq[T]
|
||||||
for i in 0 ..< component.items[src].len():
|
for i in 0 ..< component.items[src].len():
|
||||||
let item = component.items[src][i]
|
let item = component.items[src][i]
|
||||||
@@ -47,10 +47,10 @@ proc moveSelection[T](component: DualListSelectionComponent[T], src, dst: int) =
|
|||||||
ImGuiSelectionBasicStorage_Swap(component.selection[src], component.selection[dst])
|
ImGuiSelectionBasicStorage_Swap(component.selection[src], component.selection[dst])
|
||||||
ImGuiSelectionBasicStorage_Clear(component.selection[src])
|
ImGuiSelectionBasicStorage_Clear(component.selection[src])
|
||||||
|
|
||||||
proc reset*[T](component: DualListSelectionComponent[T]) =
|
proc reset*[T](component: DualListSelectionWidget[T]) =
|
||||||
component.moveAll(1, 0)
|
component.moveAll(1, 0)
|
||||||
|
|
||||||
proc draw*[T](component: DualListSelectionComponent[T]) =
|
proc draw*[T](component: DualListSelectionWidget[T]) =
|
||||||
|
|
||||||
if igBeginTable("split", 3, ImGuiTableFlags_None.int32, vec2(0.0f, 0.0f), 0.0f):
|
if igBeginTable("split", 3, ImGuiTableFlags_None.int32, vec2(0.0f, 0.0f), 0.0f):
|
||||||
|
|
||||||
|
|||||||
120
src/client/views/widgets/textarea.nim
Normal file
120
src/client/views/widgets/textarea.nim
Normal file
@@ -0,0 +1,120 @@
|
|||||||
|
import strutils, sequtils, algorithm, times
|
||||||
|
import imguin/[cimgui, glfw_opengl, simple]
|
||||||
|
import ../../utils/[appImGui, colors, utils]
|
||||||
|
import ../../../common/[types, utils]
|
||||||
|
|
||||||
|
type
|
||||||
|
TextareaWidget* = ref object of RootObj
|
||||||
|
content: ConsoleItems
|
||||||
|
contentDisplayed: ConsoleItems
|
||||||
|
textSelect: ptr TextSelect
|
||||||
|
showTimestamps: bool
|
||||||
|
|
||||||
|
# Text highlighting
|
||||||
|
proc getText(item: ConsoleItem): cstring =
|
||||||
|
if item.itemType != LOG_OUTPUT:
|
||||||
|
# let timestamp = item.timestamp.fromUnix().format("dd-MM-yyyy HH:mm:ss")
|
||||||
|
return "[" & item.timestamp & "]" & $item.itemType & item.text
|
||||||
|
else:
|
||||||
|
return $item.itemType & item.text
|
||||||
|
|
||||||
|
|
||||||
|
proc getNumLines(data: pointer): csize_t {.cdecl.} =
|
||||||
|
if data.isNil:
|
||||||
|
return 0
|
||||||
|
let content = cast[ConsoleItems](data)
|
||||||
|
return content.items.len().csize_t
|
||||||
|
|
||||||
|
proc getLineAtIndex(i: csize_t, data: pointer, outLen: ptr csize_t): cstring {.cdecl.} =
|
||||||
|
if data.isNil:
|
||||||
|
return nil
|
||||||
|
let content = cast[ConsoleItems](data)
|
||||||
|
let line = content.items[i].getText()
|
||||||
|
if not outLen.isNil:
|
||||||
|
outLen[] = line.len.csize_t
|
||||||
|
return line
|
||||||
|
|
||||||
|
proc Textarea*(showTimestamps: bool = true): TextareaWidget =
|
||||||
|
result = new TextareaWidget
|
||||||
|
result.content = new ConsoleItems
|
||||||
|
result.content.items = @[]
|
||||||
|
result.contentDisplayed = new ConsoleItems
|
||||||
|
result.contentDisplayed.items = @[]
|
||||||
|
result.textSelect = textselect_create(getLineAtIndex, getNumLines, cast[pointer](result.contentDisplayed), 0)
|
||||||
|
result.showTimestamps = showTimestamps
|
||||||
|
|
||||||
|
# API to add new content entry
|
||||||
|
proc addItem*(component: TextareaWidget, itemType: LogType, data: string, timestamp: string = now().format("dd-MM-yyyy HH:mm:ss")) =
|
||||||
|
for line in data.split("\n"):
|
||||||
|
component.content.items.add(ConsoleItem(
|
||||||
|
timestamp: timestamp,
|
||||||
|
itemType: itemType,
|
||||||
|
text: line
|
||||||
|
))
|
||||||
|
|
||||||
|
proc clear*(component: TextareaWidget) =
|
||||||
|
component.content.items.setLen(0)
|
||||||
|
component.contentDisplayed.items.setLen(0)
|
||||||
|
component.textSelect.textselect_clear_selection()
|
||||||
|
|
||||||
|
# Drawing
|
||||||
|
proc print(component: TextareaWidget, item: ConsoleItem) =
|
||||||
|
|
||||||
|
if item.itemType != LOG_OUTPUT and component.showTimestamps:
|
||||||
|
igTextColored(GRAY, "[" & item.timestamp & "]", nil)
|
||||||
|
igSameLine(0.0f, 0.0f)
|
||||||
|
|
||||||
|
case item.itemType:
|
||||||
|
of LOG_INFO, LOG_INFO_SHORT:
|
||||||
|
igTextColored(CONSOLE_INFO, $item.itemType)
|
||||||
|
of LOG_ERROR, LOG_ERROR_SHORT:
|
||||||
|
igTextColored(CONSOLE_ERROR, $item.itemType)
|
||||||
|
of LOG_SUCCESS, LOG_SUCCESS_SHORT:
|
||||||
|
igTextColored(CONSOLE_SUCCESS, $item.itemType)
|
||||||
|
of LOG_WARNING, LOG_WARNING_SHORT:
|
||||||
|
igTextColored(CONSOLE_WARNING, $item.itemType)
|
||||||
|
of LOG_COMMAND:
|
||||||
|
igTextColored(CONSOLE_COMMAND, $item.itemType)
|
||||||
|
of LOG_OUTPUT:
|
||||||
|
igTextColored(vec4(0.0f, 0.0f, 0.0f, 0.0f), $item.itemType)
|
||||||
|
|
||||||
|
igSameLine(0.0f, 0.0f)
|
||||||
|
igTextUnformatted(item.text.cstring, nil)
|
||||||
|
|
||||||
|
proc draw*(component: TextareaWidget, size: ImVec2, filter: ptr ImGuiTextFilter = nil) =
|
||||||
|
try:
|
||||||
|
# Set styles of the eventlog window
|
||||||
|
igPushStyleColor_Vec4(ImGui_Col_FrameBg.int32, vec4(0.1f, 0.1f, 0.1f, 1.0f))
|
||||||
|
igPushStyleColor_Vec4(ImGui_Col_ScrollbarBg.int32, vec4(0.1f, 0.1f, 0.1f, 1.0f))
|
||||||
|
igPushStyleColor_Vec4(ImGui_Col_Border.int32, vec4(0.2f, 0.2f, 0.2f, 1.0f))
|
||||||
|
igPushStyleVar_Float(ImGui_StyleVar_FrameBorderSize .int32, 1.0f)
|
||||||
|
|
||||||
|
let childWindowFlags = ImGuiChildFlags_NavFlattened.int32 or ImGui_ChildFlags_Borders.int32 or ImGui_ChildFlags_AlwaysUseWindowPadding.int32 or ImGuiChildFlags_FrameStyle.int32
|
||||||
|
if igBeginChild_Str("##TextArea", size, childWindowFlags, ImGuiWindowFlags_HorizontalScrollbar.int32):
|
||||||
|
|
||||||
|
component.contentDisplayed.items.setLen(0)
|
||||||
|
|
||||||
|
# Display items
|
||||||
|
for item in component.content.items:
|
||||||
|
# Handle search/filter
|
||||||
|
if not filter.isNil():
|
||||||
|
if filter.ImGuiTextFilter_IsActive():
|
||||||
|
if not filter.ImGuiTextFilter_PassFilter(item.getText(), nil):
|
||||||
|
continue
|
||||||
|
component.contentDisplayed.items.add(item)
|
||||||
|
component.print(item)
|
||||||
|
|
||||||
|
# Auto-scroll to bottom
|
||||||
|
if igGetScrollY() >= igGetScrollMaxY():
|
||||||
|
igSetScrollHereY(1.0f)
|
||||||
|
|
||||||
|
component.textSelect.textselect_update()
|
||||||
|
|
||||||
|
except IndexDefect:
|
||||||
|
# CTRL+A crashes when no items are in the eventlog
|
||||||
|
discard
|
||||||
|
|
||||||
|
finally:
|
||||||
|
igPopStyleColor(3)
|
||||||
|
igPopStyleVar(1)
|
||||||
|
igEndChild()
|
||||||
@@ -27,7 +27,7 @@ when (MODULES == cast[uint32](MODULE_ALL)):
|
|||||||
bof,
|
bof,
|
||||||
dotnet,
|
dotnet,
|
||||||
screenshot,
|
screenshot,
|
||||||
situationalAwareness
|
systeminfo
|
||||||
registerModule(sleep.module)
|
registerModule(sleep.module)
|
||||||
registerModule(shell.module)
|
registerModule(shell.module)
|
||||||
registerModule(bof.module)
|
registerModule(bof.module)
|
||||||
@@ -35,7 +35,7 @@ when (MODULES == cast[uint32](MODULE_ALL)):
|
|||||||
registerModule(filesystem.module)
|
registerModule(filesystem.module)
|
||||||
registerModule(filetransfer.module)
|
registerModule(filetransfer.module)
|
||||||
registerModule(screenshot.module)
|
registerModule(screenshot.module)
|
||||||
registerModule(situationalAwareness.module)
|
registerModule(systeminfo.module)
|
||||||
|
|
||||||
# Import modules individually
|
# Import modules individually
|
||||||
when ((MODULES and cast[uint32](MODULE_SLEEP)) == cast[uint32](MODULE_SLEEP)):
|
when ((MODULES and cast[uint32](MODULE_SLEEP)) == cast[uint32](MODULE_SLEEP)):
|
||||||
@@ -60,8 +60,8 @@ when ((MODULES and cast[uint32](MODULE_SCREENSHOT)) == cast[uint32](MODULE_SCREE
|
|||||||
import screenshot
|
import screenshot
|
||||||
registerModule(screenshot.module)
|
registerModule(screenshot.module)
|
||||||
when ((MODULES and cast[uint32](MODULE_SITUATIONAL_AWARENESS)) == cast[uint32](MODULE_SITUATIONAL_AWARENESS)):
|
when ((MODULES and cast[uint32](MODULE_SITUATIONAL_AWARENESS)) == cast[uint32](MODULE_SITUATIONAL_AWARENESS)):
|
||||||
import situationalAwareness
|
import systeminfo
|
||||||
registerModule(situationalAwareness.module)
|
registerModule(systeminfo.module)
|
||||||
|
|
||||||
proc getCommandByType*(cmdType: CommandType): Command =
|
proc getCommandByType*(cmdType: CommandType): Command =
|
||||||
return manager.commandsByType[cmdType]
|
return manager.commandsByType[cmdType]
|
||||||
|
|||||||
@@ -3,11 +3,10 @@ import ../common/[types, utils]
|
|||||||
# Declare function prototypes
|
# Declare function prototypes
|
||||||
proc executePs(ctx: AgentCtx, task: Task): TaskResult
|
proc executePs(ctx: AgentCtx, task: Task): TaskResult
|
||||||
proc executeEnv(ctx: AgentCtx, task: Task): TaskResult
|
proc executeEnv(ctx: AgentCtx, task: Task): TaskResult
|
||||||
proc executeWhoami(ctx: AgentCtx, task: Task): TaskResult
|
|
||||||
|
|
||||||
# Module definition
|
# Module definition
|
||||||
let module* = Module(
|
let module* = Module(
|
||||||
name: protect("situational-awareness"),
|
name: protect("systeminfo"),
|
||||||
description: protect("Retrieve information about the target system and environment."),
|
description: protect("Retrieve information about the target system and environment."),
|
||||||
moduleType: MODULE_SITUATIONAL_AWARENESS,
|
moduleType: MODULE_SITUATIONAL_AWARENESS,
|
||||||
commands: @[
|
commands: @[
|
||||||
@@ -26,14 +25,6 @@ let module* = Module(
|
|||||||
example: protect("env"),
|
example: protect("env"),
|
||||||
arguments: @[],
|
arguments: @[],
|
||||||
execute: executeEnv
|
execute: executeEnv
|
||||||
),
|
|
||||||
Command(
|
|
||||||
name: protect("whoami"),
|
|
||||||
commandType: CMD_WHOAMI,
|
|
||||||
description: protect("Get user information."),
|
|
||||||
example: protect("whoami"),
|
|
||||||
arguments: @[],
|
|
||||||
execute: executeWhoami
|
|
||||||
)
|
)
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
@@ -42,7 +33,6 @@ let module* = Module(
|
|||||||
when not defined(agent):
|
when not defined(agent):
|
||||||
proc executePs(ctx: AgentCtx, task: Task): TaskResult = nil
|
proc executePs(ctx: AgentCtx, task: Task): TaskResult = nil
|
||||||
proc executeEnv(ctx: AgentCtx, task: Task): TaskResult = nil
|
proc executeEnv(ctx: AgentCtx, task: Task): TaskResult = nil
|
||||||
proc executeWhoami(ctx: AgentCtx, task: Task): TaskResult = nil
|
|
||||||
|
|
||||||
when defined(agent):
|
when defined(agent):
|
||||||
|
|
||||||
@@ -144,17 +134,5 @@ when defined(agent):
|
|||||||
|
|
||||||
return createTaskResult(task, STATUS_COMPLETED, RESULT_STRING, string.toBytes(output))
|
return createTaskResult(task, STATUS_COMPLETED, RESULT_STRING, string.toBytes(output))
|
||||||
|
|
||||||
except CatchableError as err:
|
|
||||||
return createTaskResult(task, STATUS_FAILED, RESULT_STRING, string.toBytes(err.msg))
|
|
||||||
|
|
||||||
proc executeWhoami(ctx: AgentCtx, task: Task): TaskResult =
|
|
||||||
|
|
||||||
echo protect(" [>] Getting user information.")
|
|
||||||
|
|
||||||
try:
|
|
||||||
|
|
||||||
let output = protect("Not implemented")
|
|
||||||
return createTaskResult(task, STATUS_FAILED, RESULT_STRING, string.toBytes(output))
|
|
||||||
|
|
||||||
except CatchableError as err:
|
except CatchableError as err:
|
||||||
return createTaskResult(task, STATUS_FAILED, RESULT_STRING, string.toBytes(err.msg))
|
return createTaskResult(task, STATUS_FAILED, RESULT_STRING, string.toBytes(err.msg))
|
||||||
@@ -110,7 +110,6 @@ proc handleResult*(resultData: seq[byte]) =
|
|||||||
of RESULT_STRING:
|
of RESULT_STRING:
|
||||||
if int(taskResult.length) > 0:
|
if int(taskResult.length) > 0:
|
||||||
cq.client.sendConsoleItem(agentId, LOG_INFO, "Output:")
|
cq.client.sendConsoleItem(agentId, LOG_INFO, "Output:")
|
||||||
cq.info("Output:")
|
|
||||||
cq.client.sendConsoleItem(agentId, LOG_OUTPUT, Bytes.toString(taskResult.data))
|
cq.client.sendConsoleItem(agentId, LOG_OUTPUT, Bytes.toString(taskResult.data))
|
||||||
|
|
||||||
of RESULT_BINARY:
|
of RESULT_BINARY:
|
||||||
|
|||||||
Reference in New Issue
Block a user