Improved dual list selection widget.
This commit is contained in:
@@ -4,5 +4,5 @@
|
||||
--opt:size
|
||||
--passL:"-s" # Strip symbols, such as sensitive function names
|
||||
-d:CONFIGURATION="PLACEHOLDERAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPLACEHOLDER"
|
||||
-d:MODULES=1
|
||||
-d:MODULES=0
|
||||
-o:"/mnt/c/Users/jakob/Documents/Projects/conquest/bin/monarch.x64.exe"
|
||||
@@ -1,30 +1,30 @@
|
||||
[Window][Sessions [Table View]]
|
||||
Pos=10,43
|
||||
Size=2101,474
|
||||
Size=1141,338
|
||||
Collapsed=0
|
||||
DockId=0x00000003,0
|
||||
|
||||
[Window][Listeners]
|
||||
Pos=10,519
|
||||
Size=2848,1166
|
||||
Pos=10,383
|
||||
Size=1888,654
|
||||
Collapsed=0
|
||||
DockId=0x00000006,0
|
||||
|
||||
[Window][Eventlog]
|
||||
Pos=2113,43
|
||||
Size=745,474
|
||||
Pos=1153,43
|
||||
Size=745,338
|
||||
Collapsed=0
|
||||
DockId=0x00000004,0
|
||||
|
||||
[Window][Dear ImGui Demo]
|
||||
Pos=2113,43
|
||||
Size=745,474
|
||||
Pos=1153,43
|
||||
Size=745,338
|
||||
Collapsed=0
|
||||
DockId=0x00000004,1
|
||||
|
||||
[Window][Dockspace]
|
||||
Pos=0,0
|
||||
Size=2868,1695
|
||||
Size=1908,1047
|
||||
Collapsed=0
|
||||
|
||||
[Window][[FACEDEAD] bob@LAPTOP-02]
|
||||
@@ -110,7 +110,7 @@ Size=76,76
|
||||
Collapsed=0
|
||||
|
||||
[Window][Start Listener]
|
||||
Pos=713,369
|
||||
Pos=704,411
|
||||
Size=500,225
|
||||
Collapsed=0
|
||||
|
||||
@@ -119,13 +119,13 @@ IsChild=1
|
||||
Size=1363,540
|
||||
|
||||
[Window][Generate Payload]
|
||||
Pos=1071,500
|
||||
Size=717,677
|
||||
Pos=704,185
|
||||
Size=500,677
|
||||
Collapsed=0
|
||||
|
||||
[Window][Generate Payload/0_B6B17D5F]
|
||||
IsChild=1
|
||||
Size=326,310
|
||||
Size=217,310
|
||||
|
||||
[Table][0x32886A44,8]
|
||||
Column 0 Weight=0.6465
|
||||
@@ -149,9 +149,9 @@ 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=2848,1642 Split=Y
|
||||
DockNode ID=0x00000005 Parent=0x85940918 SizeRef=1888,474 Split=X
|
||||
DockSpace ID=0x85940918 Window=0x260A4489 Pos=10,43 Size=1888,994 Split=Y
|
||||
DockNode ID=0x00000005 Parent=0x85940918 SizeRef=1888,338 Split=X
|
||||
DockNode ID=0x00000003 Parent=0x00000005 SizeRef=2101,159 CentralNode=1 Selected=0x61E02D75
|
||||
DockNode ID=0x00000004 Parent=0x00000005 SizeRef=745,159 Selected=0x5E5F7166
|
||||
DockNode ID=0x00000006 Parent=0x85940918 SizeRef=1888,1166 Selected=0x6BE22050
|
||||
DockNode ID=0x00000006 Parent=0x85940918 SizeRef=1888,654 Selected=0x6BE22050
|
||||
|
||||
|
||||
@@ -27,12 +27,9 @@ proc AgentModal*(listeners: seq[Listener]): AgentModalComponent =
|
||||
for technique in SleepObfuscationTechnique.low .. SleepObfuscationTechnique.high:
|
||||
result.sleepMaskTechniques.add($technique)
|
||||
|
||||
var modules: seq[string]
|
||||
var modules: seq[ModuleType]
|
||||
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)
|
||||
|
||||
modules.add(module)
|
||||
result.moduleSelection = DualListSelection(modules)
|
||||
|
||||
proc resetModalValues(component: AgentModalComponent) =
|
||||
@@ -103,12 +100,27 @@ proc draw*(component: AgentModalComponent) =
|
||||
igSeparator()
|
||||
igDummy(vec2(0.0f, 10.0f))
|
||||
|
||||
# Enable "Build" button if at least one module has been selected
|
||||
igBeginDisabled(component.moduleSelection.items[1].len() == 0)
|
||||
|
||||
if igButton("Build", vec2(availableSize.x * 0.5 - textSpacing * 0.5, 0.0f)):
|
||||
|
||||
# Get values
|
||||
echo component.listeners[component.listener]
|
||||
echo $component.sleepDelay
|
||||
echo component.sleepMaskTechniques[component.sleepMask]
|
||||
echo $component.spoofStack
|
||||
|
||||
# Iterate over modules
|
||||
var module: uint32 = 0
|
||||
for m in component.moduleSelection.items[1]:
|
||||
module = module or uint32(m)
|
||||
echo module
|
||||
|
||||
component.resetModalValues()
|
||||
igCloseCurrentPopup()
|
||||
|
||||
igEndDisabled()
|
||||
igSameLine(0.0f, textSpacing)
|
||||
|
||||
if igButton("Close", vec2(availableSize.x * 0.5 - textSpacing * 0.5, 0.0f)):
|
||||
|
||||
@@ -1,73 +1,45 @@
|
||||
import strutils
|
||||
import strutils, sequtils, algorithm
|
||||
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]]
|
||||
items*: array[2, seq[ModuleType]]
|
||||
selection: array[2, ptr ImGuiSelectionBasicStorage]
|
||||
|
||||
proc DualListSelection*(items: seq[string]): DualListSelectionComponent =
|
||||
proc DualListSelection*(items: seq[ModuleType]): 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) =
|
||||
proc moveAll(component: DualListSelectionComponent, src, dst: int) =
|
||||
for m in component.items[src]:
|
||||
component.items[dst].add(m)
|
||||
component.items[dst].sort()
|
||||
component.items[src].setLen(0)
|
||||
|
||||
if direction == Right:
|
||||
for m in component.items[0]:
|
||||
component.items[1].add(m)
|
||||
component.items[0].setLen(0)
|
||||
ImGuiSelectionBasicStorage_Swap(component.selection[src], component.selection[dst])
|
||||
ImGuiSelectionBasicStorage_Clear(component.selection[src])
|
||||
|
||||
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)):
|
||||
proc moveSelection(component: DualListSelectionComponent, src, dst: int) =
|
||||
var keep: seq[ModuleType]
|
||||
for i in 0 ..< component.items[src].len():
|
||||
let item = component.items[src][i]
|
||||
if not component.selection[src].ImGuiSelectionBasicStorage_Contains(cast[ImGuiID](i)):
|
||||
keep.add(item)
|
||||
continue
|
||||
component.items[1].add(item)
|
||||
component.items[0] = keep
|
||||
component.items[dst].add(item)
|
||||
component.items[dst].sort()
|
||||
component.items[src] = keep
|
||||
|
||||
ImGuiSelectionBasicStorage_Swap(component.selection[0], component.selection[1])
|
||||
ImGuiSelectionBasicStorage_Clear(component.selection[0])
|
||||
ImGuiSelectionBasicStorage_Swap(component.selection[src], component.selection[dst])
|
||||
ImGuiSelectionBasicStorage_Clear(component.selection[src])
|
||||
|
||||
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 moduleName(module: ModuleType): string =
|
||||
return ($module).split("_")[1..^1].mapIt(it.toLowerAscii().capitalizeAscii()).join("")
|
||||
|
||||
proc draw*(component: DualListSelectionComponent) =
|
||||
|
||||
@@ -80,7 +52,7 @@ proc draw*(component: DualListSelectionComponent) =
|
||||
|
||||
var containerHeight: float
|
||||
|
||||
# Left selection container
|
||||
# Left selection column
|
||||
igTableSetColumnIndex(0)
|
||||
|
||||
var modules = component.items[0]
|
||||
@@ -105,7 +77,14 @@ proc draw*(component: DualListSelectionComponent) =
|
||||
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))
|
||||
discard igSelectable_Bool(modules[row].moduleName(), isSelected, ImGuiSelectableFlags_AllowDoubleClick.int32, vec2(0.0f, 0.0f))
|
||||
|
||||
# Move on Enter and double-click
|
||||
if igIsItemFocused():
|
||||
if igIsKeyPressed_Bool(ImGuiKey_Enter, false) or igIsKeyPressed_Bool(ImGuiKey_KeypadEnter, false):
|
||||
component.moveSelection(0, 1)
|
||||
if igIsMouseDoubleClicked_Nil(ImGui_MouseButton_Left.int32):
|
||||
component.moveSelection(0, 1)
|
||||
|
||||
multiSelectIO = igEndMultiSelect()
|
||||
ImGuiSelectionBasicStorage_ApplyRequests(selection, multiSelectIO)
|
||||
@@ -118,15 +97,15 @@ proc draw*(component: DualListSelectionComponent) =
|
||||
|
||||
let buttonSize = vec2(igGetFrameHeight(), igGetFrameHeight())
|
||||
if igButton(">>", buttonSize):
|
||||
component.moveAll(Right)
|
||||
component.moveAll(0, 1)
|
||||
if igButton(">", buttonSize):
|
||||
component.moveSelection(Right)
|
||||
component.moveSelection(0, 1)
|
||||
if igButton("<", buttonSize):
|
||||
component.moveSelection(Left)
|
||||
component.moveSelection(1, 0)
|
||||
if igButton("<<", buttonSize):
|
||||
component.moveAll(Left)
|
||||
component.moveAll(1, 0)
|
||||
|
||||
# Right selection container
|
||||
# Right selection column
|
||||
igTableSetColumnIndex(2)
|
||||
|
||||
modules = component.items[1]
|
||||
@@ -148,12 +127,18 @@ proc draw*(component: DualListSelectionComponent) =
|
||||
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))
|
||||
discard igSelectable_Bool(modules[row].moduleName(), isSelected, ImGuiSelectableFlags_AllowDoubleClick.int32, vec2(0.0f, 0.0f))
|
||||
|
||||
# Move on Enter and double-click
|
||||
if igIsItemFocused():
|
||||
if igIsKeyPressed_Bool(ImGuiKey_Enter, false) or igIsKeyPressed_Bool(ImGuiKey_KeypadEnter, false):
|
||||
component.moveSelection(1, 0)
|
||||
if igIsMouseDoubleClicked_Nil(ImGui_MouseButton_Left.int32):
|
||||
component.moveSelection(1, 0)
|
||||
|
||||
multiSelectIO = igEndMultiSelect()
|
||||
ImGuiSelectionBasicStorage_ApplyRequests(selection, multiSelectIO)
|
||||
|
||||
igEndChild()
|
||||
|
||||
|
||||
igEndTable()
|
||||
@@ -53,15 +53,15 @@ type
|
||||
CMD_SLEEPMASK = 17'u16
|
||||
|
||||
ModuleType* = enum
|
||||
MODULE_ALL = 1'u32
|
||||
MODULE_SLEEP = 2'u32
|
||||
MODULE_SHELL = 4'u32
|
||||
MODULE_BOF = 8'u32
|
||||
MODULE_DOTNET = 16'u32
|
||||
MODULE_FILESYSTEM = 32'u32
|
||||
MODULE_FILETRANSFER = 64'u32
|
||||
MODULE_SCREENSHOT = 128'u32
|
||||
MODULE_SITUATIONAL_AWARENESS = 256'u32
|
||||
MODULE_ALL = 0'u32
|
||||
MODULE_SLEEP = 1'u32
|
||||
MODULE_SHELL = 2'u32
|
||||
MODULE_BOF = 4'u32
|
||||
MODULE_DOTNET = 8'u32
|
||||
MODULE_FILESYSTEM = 16'u32
|
||||
MODULE_FILETRANSFER = 32'u32
|
||||
MODULE_SCREENSHOT = 64'u32
|
||||
MODULE_SITUATIONAL_AWARENESS = 128'u32
|
||||
|
||||
StatusType* = enum
|
||||
STATUS_COMPLETED = 0'u8
|
||||
@@ -101,7 +101,6 @@ type
|
||||
|
||||
# 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
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import tables, strformat
|
||||
import ../common/types
|
||||
|
||||
const MODULES {.intdefine.} = 1
|
||||
const MODULES {.intdefine.} = 0
|
||||
|
||||
type
|
||||
ModuleManager* = object
|
||||
@@ -16,7 +16,7 @@ proc registerModule(module: Module) {.discardable.} =
|
||||
manager.commandsByName[cmd.name] = cmd
|
||||
|
||||
# Import all modules
|
||||
when ((MODULES and cast[uint32](MODULE_ALL)) == cast[uint32](MODULE_ALL)):
|
||||
when (MODULES == cast[uint32](MODULE_ALL)):
|
||||
import
|
||||
sleep,
|
||||
shell,
|
||||
|
||||
Reference in New Issue
Block a user