Implemented dual list selection widgets for choosing modules.

This commit is contained in:
Jakob Friedl
2025-09-24 16:30:29 +02:00
parent d4bdf56224
commit b6c81755a0
7 changed files with 195 additions and 15 deletions

View File

@@ -119,10 +119,14 @@ IsChild=1
Size=1363,540
[Window][Generate Payload]
Pos=704,337
Size=500,325
Pos=1071,500
Size=717,677
Collapsed=0
[Window][Generate Payload/0_B6B17D5F]
IsChild=1
Size=326,310
[Table][0x32886A44,8]
Column 0 Weight=0.6465
Column 1 Weight=0.9697
@@ -148,6 +152,6 @@ DockNode ID=0x00000009 Pos=100,200 Size=754,103 Selected=0x64D005CF
DockSpace ID=0x85940918 Window=0x260A4489 Pos=10,43 Size=2848,1642 Split=Y
DockNode ID=0x00000005 Parent=0x85940918 SizeRef=1888,474 Split=X
DockNode ID=0x00000003 Parent=0x00000005 SizeRef=2101,159 CentralNode=1 Selected=0x61E02D75
DockNode ID=0x00000004 Parent=0x00000005 SizeRef=745,159 Selected=0x0FA43D88
DockNode ID=0x00000004 Parent=0x00000005 SizeRef=745,159 Selected=0x5E5F7166
DockNode ID=0x00000006 Parent=0x85940918 SizeRef=1888,1166 Selected=0x6BE22050

View File

@@ -2,6 +2,7 @@ import imguin/[cimgui, glfw_opengl, simple]
import ../utils/appImGui
# https://rgbcolorpicker.com/0-1
const GRAY* = vec4(0.369f, 0.369f, 0.369f, 1.0f)
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)

View File

@@ -59,9 +59,6 @@ proc draw*(component: ListenersTableComponent, showComponent: ptr bool, ws: WebS
component.generatePayloadModal.draw()
#[
Listener table
]#

View File

@@ -1,8 +1,8 @@
import strutils
import strutils, sequtils
import imguin/[cimgui, glfw_opengl, simple]
import ../../utils/appImGui
import ../../utils/[appImGui, colors]
import ../../../common/[types, utils]
import ../widgets/dualListSelection
type
AgentModalComponent* = ref object of RootObj
@@ -12,6 +12,7 @@ type
spoofStack: bool
listeners: seq[string]
sleepMaskTechniques: seq[string]
moduleSelection: DualListSelectionComponent
proc AgentModal*(listeners: seq[Listener]): AgentModalComponent =
result = new AgentModalComponent
@@ -23,8 +24,16 @@ proc AgentModal*(listeners: seq[Listener]): AgentModalComponent =
for l in listeners:
result.listeners.add(l.listenerId)
for s in SleepObfuscationTechnique.low .. SleepObfuscationTechnique.high:
result.sleepMaskTechniques.add($s)
for technique in SleepObfuscationTechnique.low .. SleepObfuscationTechnique.high:
result.sleepMaskTechniques.add($technique)
var modules: seq[string]
for module in ModuleType:
# Magic to convert MODULE_SITUATIONAL_AWARENESS into SituationalAwareness, etc.
var name = ($module).split("_")[1..^1].mapIt(it.toLowerAscii().capitalizeAscii()).join("")
modules.add(name)
result.moduleSelection = DualListSelection(modules)
proc resetModalValues(component: AgentModalComponent) =
discard
@@ -86,7 +95,7 @@ proc draw*(component: AgentModalComponent) =
igText("Modules: ")
component.moduleSelection.draw()
igGetContentRegionAvail(addr availableSize)

View File

@@ -0,0 +1,159 @@
import strutils
import imguin/[cimgui, glfw_opengl, simple]
import ../../utils/[appImGui, colors]
import ../../../common/[types, utils]
type
Direction = enum
Right = 0
Left = 1
DualListSelectionComponent* = ref object of RootObj
items: array[2, seq[string]]
selection: array[2, ptr ImGuiSelectionBasicStorage]
proc DualListSelection*(items: seq[string]): DualListSelectionComponent =
result = new DualListSelectionComponent
result.items[0] = items
result.items[1] = @[]
result.selection[0] = ImGuiSelectionBasicStorage_ImGuiSelectionBasicStorage()
result.selection[1] = ImGuiSelectionBasicStorage_ImGuiSelectionBasicStorage()
proc moveAll(component: DualListSelectionComponent, direction: Direction) =
if direction == Right:
for m in component.items[0]:
component.items[1].add(m)
component.items[0].setLen(0)
ImGuiSelectionBasicStorage_Swap(component.selection[0], component.selection[1])
ImGuiSelectionBasicStorage_Clear(component.selection[0])
else:
for m in component.items[1]:
component.items[0].add(m)
component.items[1].setLen(0)
ImGuiSelectionBasicStorage_Swap(component.selection[1], component.selection[0])
ImGuiSelectionBasicStorage_Clear(component.selection[1])
proc moveSelection(component: DualListSelectionComponent, direction: Direction) =
if direction == Right:
var
keep: seq[string]
for i in 0 ..< component.items[0].len():
let item = component.items[0][i]
if not component.selection[0].ImGuiSelectionBasicStorage_Contains(cast[ImGuiID](i)):
keep.add(item)
continue
component.items[1].add(item)
component.items[0] = keep
ImGuiSelectionBasicStorage_Swap(component.selection[0], component.selection[1])
ImGuiSelectionBasicStorage_Clear(component.selection[0])
else:
var
keep: seq[string]
for i in 0 ..< component.items[1].len():
let item = component.items[1][i]
if not component.selection[1].ImGuiSelectionBasicStorage_Contains(cast[ImGuiID](i)):
keep.add(item)
continue
component.items[0].add(item)
component.items[1] = keep
ImGuiSelectionBasicStorage_Swap(component.selection[1], component.selection[0])
ImGuiSelectionBasicStorage_Clear(component.selection[1])
proc draw*(component: DualListSelectionComponent) =
if igBeginTable("split", 3, ImGuiTableFlags_None.int32, vec2(0.0f, 0.0f), 0.0f):
igTableSetupColumn("", ImGuiTableColumnFlags_WidthStretch.int32, 0.0f, 0) # Left
igTableSetupColumn("", ImGuiTableColumnFlags_WidthFixed.int32, 0.0f, 0) # Buttons
igTableSetupColumn("", ImGuiTableColumnFlags_WidthStretch.int32, 0.0f, 0) # Right
igTableNextRow(ImGuiTableRowFlags_None.int32, 0.0f)
var containerHeight: float
# Left selection container
igTableSetColumnIndex(0)
var modules = component.items[0]
var selection = component.selection[0]
# Header
var text = "Available"
var textSize: ImVec2
igCalcTextSize(addr textSize, text, nil, false, 0.0f)
igSetCursorPosX(igGetCursorPosX() + (igGetColumnWidth(0) - textSize.x) * 0.5f)
igTextColored(GRAY, text)
# Set the size of selection box to fit all modules
igSetNextWindowContentSize(vec2(0.0f, float(modules.len()) * igGetTextLineHeightWithSpacing()))
igSetNextWindowSizeConstraints(vec2(0.0f, igGetTextLineHeightWithSpacing() * 10.0f), vec2(igGET_FLT_MAX(), igGET_FLT_MAX()), nil, nil) # Set minimum container size
if igBeginChild_Str("0", vec2(0.0f, -1.0f), ImGuiChildFlags_FrameStyle.int32 or ImGuiChildFlags_ResizeY.int32, ImGuiWindowFlags_None.int32):
containerHeight = igGetWindowHeight()
var multiSelectIO = igBeginMultiSelect(ImGuiMultiSelectFlags_None.int32, selection[].Size, int32(modules.len()))
ImGuiSelectionBasicStorage_ApplyRequests(selection, multiSelectIO)
for row in 0 ..< modules.len().int32:
var isSelected = ImGuiSelectionBasicStorage_Contains(selection, cast[ImGuiID](row))
igSetNextItemSelectionUserData(row)
discard igSelectable_Bool(modules[row], isSelected, ImGuiSelectableFlags_AllowDoubleClick.int32, vec2(0.0f, 0.0f))
multiSelectIO = igEndMultiSelect()
ImGuiSelectionBasicStorage_ApplyRequests(selection, multiSelectIO)
igEndChild()
# Buttons column
igTableSetColumnIndex(1)
igNewLine()
let buttonSize = vec2(igGetFrameHeight(), igGetFrameHeight())
if igButton(">>", buttonSize):
component.moveAll(Right)
if igButton(">", buttonSize):
component.moveSelection(Right)
if igButton("<", buttonSize):
component.moveSelection(Left)
if igButton("<<", buttonSize):
component.moveAll(Left)
# Right selection container
igTableSetColumnIndex(2)
modules = component.items[1]
selection = component.selection[1]
# Header
text = "Selected"
igCalcTextSize(addr textSize, text, nil, false, 0.0f)
igSetCursorPosX(igGetCursorPosX() + (igGetColumnWidth(2) - textSize.x) * 0.5f)
igTextColored(GRAY, text)
# Set the size of selection box to fit all modules
igSetNextWindowContentSize(vec2(0.0f, float(modules.len()) * igGetTextLineHeightWithSpacing()))
if igBeginChild_Str("1", vec2(0.0f, containerHeight), ImGuiChildFlags_FrameStyle.int32, ImGuiWindowFlags_None.int32):
var multiSelectIO = igBeginMultiSelect(ImGuiMultiSelectFlags_None.int32, selection[].Size, int32(modules.len()))
ImGuiSelectionBasicStorage_ApplyRequests(selection, multiSelectIO)
for row in 0 ..< modules.len().int32:
var isSelected = ImGuiSelectionBasicStorage_Contains(selection, cast[ImGuiID](row))
igSetNextItemSelectionUserData(row)
discard igSelectable_Bool(modules[row], isSelected, ImGuiSelectableFlags_AllowDoubleClick.int32, vec2(0.0f, 0.0f))
multiSelectIO = igEndMultiSelect()
ImGuiSelectionBasicStorage_ApplyRequests(selection, multiSelectIO)
igEndChild()
igEndTable()

View File

@@ -99,6 +99,18 @@ type
ZILEAN = 2'u8
FOLIAGE = 3'u8
# Custom iterator for ModuleType, as it uses powers of 2 instead of standard increments
iterator items*(e: typedesc[ModuleType]): ModuleType =
# yield MODULE_ALL
yield MODULE_SLEEP
yield MODULE_SHELL
yield MODULE_BOF
yield MODULE_DOTNET
yield MODULE_FILESYSTEM
yield MODULE_FILETRANSFER
yield MODULE_SCREENSHOT
yield MODULE_SITUATIONAL_AWARENESS
# Encryption
type
Uuid* = uint32

View File

@@ -39,8 +39,6 @@ proc serve(listener: Listener) {.thread.} =
discard
proc listenerStart*(cq: Conquest, name: string, host: string, port: int, protocol: Protocol) =
# Validate arguments
try:
# Create new listener
var router: Router