diff --git a/src/client/layout.ini b/src/client/layout.ini index fbb0955..5f04485 100644 --- a/src/client/layout.ini +++ b/src/client/layout.ini @@ -1,24 +1,24 @@ [Window][Sessions [Table View]] Pos=10,43 -Size=1477,357 +Size=1533,389 Collapsed=0 DockId=0x00000003,0 [Window][Listeners] Pos=10,43 -Size=1477,357 +Size=1533,389 Collapsed=0 DockId=0x00000003,1 [Window][Eventlog] -Pos=1489,43 -Size=409,357 +Pos=1545,43 +Size=353,389 Collapsed=0 DockId=0x00000004,0 [Window][Dear ImGui Demo] -Pos=1489,43 -Size=409,357 +Pos=1545,43 +Size=353,389 Collapsed=0 DockId=0x00000004,1 @@ -31,13 +31,13 @@ Collapsed=0 Pos=956,326 Size=942,663 Collapsed=0 -DockId=0x00000002,0 +DockId=0x00000005,0 [Window][[C9D8E7F6] charlie@SERVER-03] -Pos=10,402 -Size=1888,587 +Pos=10,434 +Size=1888,555 Collapsed=0 -DockId=0x00000002,0 +DockId=0x00000006,1 [Window][Debug##Default] Pos=60,60 @@ -45,22 +45,22 @@ Size=400,400 Collapsed=0 [Window][[G1H2I3J5] diana@WORKSTATION-04] -Pos=10,402 -Size=1888,587 +Pos=10,434 +Size=1888,555 Collapsed=0 -DockId=0x00000002,1 +DockId=0x00000006,0 [Window][[DEADBEEF] alice@DESKTOP-01] Pos=10,402 Size=1888,587 Collapsed=0 -DockId=0x00000002,1 +DockId=0x00000005,1 [Window][Example: Console] Pos=10,572 Size=2848,1113 Collapsed=0 -DockId=0x00000002,2 +DockId=0x00000005,2 [Window][Example: Assets Browser] Pos=60,60 @@ -137,8 +137,8 @@ Column 3 Weight=0.9746 [Docking][Data] DockNode ID=0x00000009 Pos=100,200 Size=754,103 Selected=0x64D005CF DockSpace ID=0x85940918 Window=0x260A4489 Pos=10,43 Size=1888,946 Split=Y - DockNode ID=0x00000001 Parent=0x85940918 SizeRef=1024,357 Split=X - DockNode ID=0x00000003 Parent=0x00000001 SizeRef=613,159 CentralNode=1 Selected=0x61E02D75 - DockNode ID=0x00000004 Parent=0x00000001 SizeRef=409,159 Selected=0x5E5F7166 - DockNode ID=0x00000002 Parent=0x85940918 SizeRef=1024,587 Selected=0x65D642C0 + DockNode ID=0x00000005 Parent=0x85940918 SizeRef=1888,389 Split=X + DockNode ID=0x00000003 Parent=0x00000005 SizeRef=1533,159 CentralNode=1 Selected=0x61E02D75 + DockNode ID=0x00000004 Parent=0x00000005 SizeRef=353,159 Selected=0x0FA43D88 + DockNode ID=0x00000006 Parent=0x85940918 SizeRef=1888,555 Selected=0x65D642C0 diff --git a/src/client/utils/colors.nim b/src/client/utils/colors.nim index b7436d6..39e4e65 100644 --- a/src/client/utils/colors.nim +++ b/src/client/utils/colors.nim @@ -1,6 +1,7 @@ import imguin/[cimgui, glfw_opengl, simple] import ../utils/appImGui +# https://rgbcolorpicker.com/0-1 const CONSOLE_ERROR* = vec4(0.878f, 0.188f, 0.149f, 1.0f) const CONSOLE_INFO* = vec4(0.588f, 0.843f, 0.89f, 1.0f) const CONSOLE_SUCCESS* = vec4(0.176f, 0.569f, 0.075f, 1.0f) diff --git a/src/client/views/console.nim b/src/client/views/console.nim index d550823..4ad0864 100644 --- a/src/client/views/console.nim +++ b/src/client/views/console.nim @@ -26,30 +26,6 @@ proc getText(item: ConsoleItem): cstring = else: return fmt"{$item.itemType}{item.text}".string -proc print(item: ConsoleItem) = - if item.timestamp > 0: - let timestamp = item.timestamp.fromUnix().format("dd-MM-yyyy HH:mm:ss") - igTextColored(vec4(0.6f, 0.6f, 0.6f, 1.0f), fmt"[{timestamp}]".cstring) - igSameLine(0.0f, 0.0f) - - # https://rgbcolorpicker.com/0-1 - case item.itemType: - of LOG_INFO: - igTextColored(CONSOLE_INFO, $item.itemType) - of LOG_ERROR: - igTextColored(CONSOLE_ERROR, $item.itemType) - of LOG_SUCCESS: - igTextColored(CONSOLE_SUCCESS, $item.itemType) - of LOG_WARNING: - 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 getNumLines(data: pointer): csize_t {.cdecl.} = if data.isNil: return 0 @@ -133,7 +109,45 @@ proc callback(data: ptr ImGuiInputTextCallbackData): cint {.cdecl.} = discard else: discard + +#[ + API to add new console item +]# +proc addItem*(component: ConsoleComponent, itemType: LogType, data: string) = + + for line in data.split("\n"): + component.console.items.add(ConsoleItem( + timestamp: if itemType == LOG_OUTPUT: 0 else: now().toTime().toUnix(), + itemType: itemType, + text: line + )) + +#[ + Drawing +]# +proc print(item: ConsoleItem) = + if item.timestamp > 0: + let timestamp = item.timestamp.fromUnix().format("dd-MM-yyyy HH:mm:ss") + igTextColored(vec4(0.6f, 0.6f, 0.6f, 1.0f), fmt"[{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: ConsoleComponent) = igBegin(fmt"[{component.agent.agentId}] {component.agent.username}@{component.agent.hostname}", addr component.showConsole, 0) defer: igEnd() @@ -177,6 +191,7 @@ proc draw*(component: ConsoleComponent) = igText("Press CTRL+F to focus console filter.") igText("Use \",\" as a delimiter to filter for multiple values.") igText("Use \"-\" to exclude values.") + igText("Example: \"-warning,a,b\" returns all lines that do not include \"warning\" but include \"a\" or \"b\".") igEndTooltip() if igIsWindowFocused(ImGui_FocusedFlags_ChildWindows.int32) and io.KeyCtrl and igIsKeyPressed_Bool(ImGuiKey_F, false): @@ -237,45 +252,15 @@ proc draw*(component: ConsoleComponent) = if igInputText("##Input", addr component.inputBuffer[0], MAX_INPUT_LENGTH, inputFlags, callback, cast[pointer](component)): let command = $(addr component.inputBuffer[0]).cstring - var commandItem = ConsoleItem( - timestamp: now().toTime().toUnix(), - itemType: LOG_COMMAND, - text: command - ) - component.console.items.add(commandItem) + component.addItem(LOG_COMMAND, command) # For testing - commandItem = ConsoleItem( - timestamp: now().toTime().toUnix(), - itemType: LOG_ERROR, - text: "error" - ) - component.console.items.add(commandItem) - commandItem = ConsoleItem( - timestamp: now().toTime().toUnix(), - itemType: LOG_SUCCESS, - text: "success" - ) - component.console.items.add(commandItem) - commandItem = ConsoleItem( - timestamp: now().toTime().toUnix(), - itemType: LOG_WARNING, - text: "warn" - ) - component.console.items.add(commandItem) - commandItem = ConsoleItem( - timestamp: 0, - itemType: LOG_OUTPUT, - text: "output" - ) - component.console.items.add(commandItem) - commandItem = ConsoleItem( - timestamp: now().toTime().toUnix(), - itemType: LOG_INFO, - text: "info" - ) - component.console.items.add(commandItem) - + component.addItem(LOG_ERROR, "error message") + component.addItem(LOG_SUCCESS, "success message") + component.addItem(LOG_INFO, "info message") + component.addItem(LOG_WARNING, "warning message") + component.addItem(LOG_OUTPUT, "error message\nLong output\n\tindented output\nasdasd") + # TODO: Handle command execution # console.handleCommand(command) @@ -295,4 +280,4 @@ proc draw*(component: ConsoleComponent) = ]# let sessionInfo = fmt"{component.agent.username}@{component.agent.hostname}.{component.agent.domain} [{component.agent.ip}] [{component.agent.process}/{$component.agent.pid}]" igTextColored(vec4(0.75f, 0.75f, 0.75f, 1.0f), sessionInfo) - + \ No newline at end of file diff --git a/src/client/views/eventlog.nim b/src/client/views/eventlog.nim index f0f94cb..3d5cffd 100644 --- a/src/client/views/eventlog.nim +++ b/src/client/views/eventlog.nim @@ -1,19 +1,109 @@ -import times +import strformat, strutils, times import imguin/[cimgui, glfw_opengl, simple] -import ../utils/appImGui -import ../../common/[types] +import ../utils/[appImGui, colors] +import ../../common/types type EventlogComponent = ref object of RootObj title: string + log*: ConsoleItems + textSelect: ptr TextSelect + +proc getText(item: ConsoleItem): cstring = + if item.timestamp > 0: + let timestamp = item.timestamp.fromUnix().format("dd-MM-yyyy HH:mm:ss") + return fmt"[{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 = result = new EventlogComponent result.title = title + result.log = new ConsoleItems + result.log.items = @[] + result.textSelect = textselect_create(getLineAtIndex, getNumLines, cast[pointer](result.log), 0) + +#[ + API to add new log entry +]# +proc addItem*(component: EventlogComponent, itemType: LogType, data: string) = + + for line in data.split("\n"): + component.log.items.add(ConsoleItem( + timestamp: if itemType == LOG_OUTPUT: 0 else: now().toTime().toUnix(), + itemType: itemType, + text: line + )) + +#[ + Drawing +]# +proc print(item: ConsoleItem) = + if item.timestamp > 0: + let timestamp = item.timestamp.fromUnix().format("dd-MM-yyyy HH:mm:ss") + igTextColored(vec4(0.6f, 0.6f, 0.6f, 1.0f), fmt"[{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) = - igSetNextWindowSize(vec2(800, 600), ImGuiCond_Once.int32) igBegin(component.title, showComponent, 0) defer: igEnd() - igText("Eventlog") + 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("##Log", vec2(-1.0f, -1.0f), childWindowFlags, ImGuiWindowFlags_HorizontalScrollbar.int32): + # Display eventlog items + for item in component.log.items: + item.print() + + 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() diff --git a/src/client/views/listeners.nim b/src/client/views/listeners.nim index 2520dc4..82a636c 100644 --- a/src/client/views/listeners.nim +++ b/src/client/views/listeners.nim @@ -46,6 +46,7 @@ proc draw*(component: ListenersTableComponent, showComponent: ptr bool) = let listener = component.startListenerModal.draw() if listener != nil: # TODO: Start listener + component.listeners.add(listener) #[ diff --git a/src/common/types.nim b/src/common/types.nim index 2230531..b51a639 100644 --- a/src/common/types.nim +++ b/src/common/types.nim @@ -81,18 +81,16 @@ type CONFIG_PROFILE = 5'u8 LogType* = enum - # LOG_INFO = "[ * ] " - # LOG_ERROR = "[ - ] " - # LOG_SUCCESS = "[ + ] " - # LOG_WARNING = "[ ! ] " - # LOG_COMMAND = "[ > ] " - # LOG_OUTPUT = "" LOG_INFO = " [INFO] " LOG_ERROR = " [FAIL] " LOG_SUCCESS = " [DONE] " LOG_WARNING = " [WARN] " LOG_COMMAND = " [>>>>] " LOG_OUTPUT = "" + LOG_INFO_SHORT = " [*] " + LOG_ERROR_SHORT = " [-] " + LOG_SUCCESS_SHORT = " [+] " + LOG_WARNING_SHORT = " [!] " SleepObfuscationTechnique* = enum NONE = 0'u8