Implemented widgets for showing loot: Downloads & Screenshots. Textures are read from a byte sequence and displayed in the UI. Currently tested using hard-coded values.
This commit is contained in:
@@ -3,6 +3,6 @@
|
|||||||
-d:release
|
-d:release
|
||||||
--opt:size
|
--opt:size
|
||||||
--passL:"-s" # Strip symbols, such as sensitive function names
|
--passL:"-s" # Strip symbols, such as sensitive function names
|
||||||
-d:CONFIGURATION="PLACEHOLDERAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPLACEHOLDER"
|
-d:CONFIGURATION="PLACEHOLDERAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPLACEHOLDER"
|
||||||
-d:MODULES="127"
|
-d:MODULES="255"
|
||||||
-o:"/mnt/c/Users/jakob/Documents/Projects/conquest/bin/monarch.x64.exe"
|
-o:"/mnt/c/Users/jakob/Documents/Projects/conquest/bin/monarch.x64.exe"
|
||||||
@@ -2,8 +2,8 @@ import whisky
|
|||||||
import tables, strutils, strformat, json, parsetoml, base64, os # native_dialogs
|
import tables, strutils, strformat, json, parsetoml, base64, os # native_dialogs
|
||||||
import ./utils/[appImGui, globals]
|
import ./utils/[appImGui, globals]
|
||||||
import ./views/[dockspace, sessions, listeners, eventlog, console]
|
import ./views/[dockspace, sessions, listeners, eventlog, console]
|
||||||
|
import ./views/loot/[screenshots, downloads]
|
||||||
import ./views/modals/generatePayload
|
import ./views/modals/generatePayload
|
||||||
import ./views/loot/[downloads, screenshots]
|
|
||||||
import ../common/[types, utils, crypto]
|
import ../common/[types, utils, crypto]
|
||||||
import ./core/websocket
|
import ./core/websocket
|
||||||
|
|
||||||
@@ -33,8 +33,8 @@ proc main(ip: string = "localhost", port: int = 37573) =
|
|||||||
views["Sessions [Table View]"] = addr showSessionsTable
|
views["Sessions [Table View]"] = addr showSessionsTable
|
||||||
views["Listeners"] = addr showListeners
|
views["Listeners"] = addr showListeners
|
||||||
views["Eventlog"] = addr showEventlog
|
views["Eventlog"] = addr showEventlog
|
||||||
views["Loot::Downloads"] = addr showDownloads
|
views["Loot:Downloads"] = addr showDownloads
|
||||||
views["Loot::Screenshots"] = addr showScreenshots
|
views["Loot:Screenshots"] = addr showScreenshots
|
||||||
|
|
||||||
# Create components
|
# Create components
|
||||||
var
|
var
|
||||||
@@ -43,7 +43,8 @@ proc main(ip: string = "localhost", port: int = 37573) =
|
|||||||
listenersTable = ListenersTable("Listeners")
|
listenersTable = ListenersTable("Listeners")
|
||||||
eventlog = Eventlog("Eventlog")
|
eventlog = Eventlog("Eventlog")
|
||||||
lootDownloads = LootDownloads("Downloads")
|
lootDownloads = LootDownloads("Downloads")
|
||||||
lootScreenshots = LootScreenshots("Screenshots")
|
lootScreenshots = LootScreenshots("Screenshots")
|
||||||
|
|
||||||
|
|
||||||
let io = igGetIO()
|
let io = igGetIO()
|
||||||
|
|
||||||
@@ -174,7 +175,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()
|
||||||
|
|||||||
@@ -147,3 +147,52 @@ when not defined(SDL):
|
|||||||
else:
|
else:
|
||||||
echo "Not found: ",iconName
|
echo "Not found: ",iconName
|
||||||
glfw.setWindowIcon(window, 0, nil)
|
glfw.setWindowIcon(window, 0, nil)
|
||||||
|
|
||||||
|
# Load a texture from a byte sequence, as this is the data type that is received by the team server
|
||||||
|
proc loadTextureFromBytes*(imageBytes: seq[byte], textureID: var uint32): tuple[width: int, height: int] =
|
||||||
|
var width, height, channels: int
|
||||||
|
|
||||||
|
var imageLen = imageBytes.len()
|
||||||
|
|
||||||
|
# Decode image from memory
|
||||||
|
let imageData = stbi.load_from_memory(
|
||||||
|
imageBytes,
|
||||||
|
width,
|
||||||
|
height,
|
||||||
|
channels,
|
||||||
|
stbi.RGBA
|
||||||
|
)
|
||||||
|
|
||||||
|
if imageData == @[]:
|
||||||
|
raise newException(IOError, "Failed to decode image from bytes")
|
||||||
|
|
||||||
|
# Create texture if needed
|
||||||
|
if textureID == 0:
|
||||||
|
glGenTextures(1, addr textureID)
|
||||||
|
|
||||||
|
glBindTexture(GL_TEXTURE_2D, textureID)
|
||||||
|
|
||||||
|
# Setup filtering parameters
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR.GLint)
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR.GLint)
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE.GLint)
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE.GLint)
|
||||||
|
|
||||||
|
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0)
|
||||||
|
|
||||||
|
# Upload texture
|
||||||
|
glTexImage2D(GL_TEXTURE_2D,
|
||||||
|
0,
|
||||||
|
GL_RGBA.GLint,
|
||||||
|
width.GLSizei,
|
||||||
|
height.GLSizei,
|
||||||
|
0,
|
||||||
|
GL_RGBA,
|
||||||
|
GL_UNSIGNED_BYTE,
|
||||||
|
addr imageData[0])
|
||||||
|
|
||||||
|
let err = glGetError().int
|
||||||
|
if err != 0:
|
||||||
|
raise newException(IOError, fmt"OpenGL Error [0x{err:X}]: glTexImage2D()")
|
||||||
|
|
||||||
|
result = (width: width, height: height)
|
||||||
|
|||||||
@@ -76,18 +76,18 @@ proc draw*(component: DockspaceComponent, showComponent: ptr bool, views: Table[
|
|||||||
if igBeginMenu("Views", true):
|
if igBeginMenu("Views", true):
|
||||||
# Create a menu item to toggle each of the main views of the application
|
# Create a menu item to toggle each of the main views of the application
|
||||||
for view, showView in views:
|
for view, showView in views:
|
||||||
if not view.contains("::"):
|
if not view.startsWith("Loot:"):
|
||||||
if igMenuItem(view, nil, showView[], showView != nil):
|
if igMenuItem(view, nil, showView[], showView != nil):
|
||||||
showView[] = not showView[]
|
showView[] = not showView[]
|
||||||
|
|
||||||
if igBeginMenu("Loot", true):
|
|
||||||
for view, showView in views:
|
|
||||||
if view.startsWith("Loot"):
|
|
||||||
let item = view.split("::", 1)[1].strip()
|
|
||||||
if igMenuItem(item, nil, showView[], showView != nil):
|
|
||||||
showView[] = not showView[]
|
|
||||||
igEndMenu()
|
|
||||||
|
|
||||||
|
if igBeginMenu("Loot", true):
|
||||||
|
for view, showView in views:
|
||||||
|
if view.startsWith("Loot:"):
|
||||||
|
let itemName = view.split(":")[1]
|
||||||
|
if igMenuItem(itemName, nil, showView[], showView != nil):
|
||||||
|
showView[] = not showView[]
|
||||||
|
igEndMenu()
|
||||||
|
|
||||||
igEndMenu()
|
igEndMenu()
|
||||||
|
|
||||||
igEndMenuBar()
|
igEndMenuBar()
|
||||||
@@ -1,19 +1,106 @@
|
|||||||
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 ../../../common/types
|
import ../../../common/[types, utils]
|
||||||
|
|
||||||
type
|
type
|
||||||
LootDownloadsComponent* = ref object of RootObj
|
DownloadsComponent* = ref object of RootObj
|
||||||
title: string
|
title: string
|
||||||
|
items: seq[LootItem]
|
||||||
|
selectedIndex: int
|
||||||
|
|
||||||
|
|
||||||
|
proc LootDownloads*(title: string): DownloadsComponent =
|
||||||
proc LootDownloads*(title: string): LootDownloadsComponent =
|
result = new DownloadsComponent
|
||||||
result = new LootDownloadsComponent
|
|
||||||
result.title = title
|
result.title = title
|
||||||
|
result.items = @[]
|
||||||
|
result.selectedIndex = -1
|
||||||
|
|
||||||
proc draw*(component: LootDownloadsComponent, showComponent: ptr bool) =
|
result.items.add(@[LootItem(
|
||||||
|
agentId: "DEADBEEF",
|
||||||
|
path: "C:\\Software\\Conquest\\README.md",
|
||||||
|
timestamp: now().toTime().toUnix(),
|
||||||
|
size: 1000,
|
||||||
|
host: "WKS-1",
|
||||||
|
data: string.toBytes("README.md\nPreview\nHello world.")
|
||||||
|
),
|
||||||
|
LootItem(
|
||||||
|
agentId: "DEADBEEF",
|
||||||
|
path: "C:\\Software\\Conquest\\README.md",
|
||||||
|
timestamp: now().toTime().toUnix(),
|
||||||
|
size: 1000,
|
||||||
|
host: "WKS-1",
|
||||||
|
data: string.toBytes("README.md\nPreview\nHello world.")
|
||||||
|
)
|
||||||
|
])
|
||||||
|
|
||||||
|
proc draw*(component: DownloadsComponent, showComponent: ptr bool) =
|
||||||
igBegin(component.title, showComponent, 0)
|
igBegin(component.title, showComponent, 0)
|
||||||
defer: igEnd()
|
defer: igEnd()
|
||||||
|
|
||||||
igText("asd")
|
var availableSize: ImVec2
|
||||||
|
igGetContentRegionAvail(addr availableSize)
|
||||||
|
let textSpacing = igGetStyle().ItemSpacing.x
|
||||||
|
|
||||||
|
# Left panel (file table)
|
||||||
|
let childFlags = ImGui_ChildFlags_ResizeX.int32 or ImGui_ChildFlags_NavFlattened.int32
|
||||||
|
if igBeginChild_Str("##Left", vec2(availableSize.x * 0.66f, 0.0f), childFlags, ImGui_WindowFlags_None.int32):
|
||||||
|
|
||||||
|
let tableFlags = (
|
||||||
|
ImGui_TableFlags_Resizable.int32 or
|
||||||
|
ImGui_TableFlags_Reorderable.int32 or
|
||||||
|
ImGui_TableFlags_Hideable.int32 or
|
||||||
|
ImGui_TableFlags_HighlightHoveredColumn.int32 or
|
||||||
|
ImGui_TableFlags_RowBg.int32 or
|
||||||
|
ImGui_TableFlags_BordersV.int32 or
|
||||||
|
ImGui_TableFlags_BordersH.int32 or
|
||||||
|
ImGui_TableFlags_ScrollY.int32 or
|
||||||
|
ImGui_TableFlags_ScrollX.int32 or
|
||||||
|
ImGui_TableFlags_NoBordersInBodyUntilResize.int32 or
|
||||||
|
ImGui_TableFlags_SizingStretchSame.int32
|
||||||
|
)
|
||||||
|
|
||||||
|
let cols: int32 = 4
|
||||||
|
if igBeginTable("##Items", cols, tableFlags, vec2(0.0f, 0.0f), 0.0f):
|
||||||
|
igTableSetupColumn("Path", ImGuiTableColumnFlags_None.int32, 0.0f, 0)
|
||||||
|
igTableSetupColumn("Creation Date", ImGuiTableColumnFlags_None.int32, 0.0f, 0)
|
||||||
|
igTableSetupColumn("Size", ImGuiTableColumnFlags_None.int32, 0.0f, 0)
|
||||||
|
igTableSetupColumn("Host", ImGuiTableColumnFlags_None.int32, 0.0f, 0)
|
||||||
|
igTableSetupScrollFreeze(0, 1)
|
||||||
|
igTableHeadersRow()
|
||||||
|
|
||||||
|
for i, item in component.items:
|
||||||
|
igTableNextRow(ImGuiTableRowFlags_None.int32, 0.0f)
|
||||||
|
|
||||||
|
if igTableSetColumnIndex(0):
|
||||||
|
igPushID_Int(i.int32)
|
||||||
|
let isSelected = component.selectedIndex == i
|
||||||
|
if igSelectable_Bool(item.path.cstring, isSelected, ImGuiSelectableFlags_SpanAllColumns.int32 or ImGuiSelectableFlags_AllowOverlap.int32, vec2(0, 0)):
|
||||||
|
component.selectedIndex = i
|
||||||
|
igPopID()
|
||||||
|
|
||||||
|
if igTableSetColumnIndex(1):
|
||||||
|
igText(item.timestamp.fromUnix().local().format("dd-MM-yyyy HH:mm:ss"))
|
||||||
|
|
||||||
|
if igTableSetColumnIndex(2):
|
||||||
|
igText($item.size)
|
||||||
|
|
||||||
|
if igTableSetColumnIndex(3):
|
||||||
|
igText(item.host.cstring)
|
||||||
|
|
||||||
|
igEndTable()
|
||||||
|
|
||||||
|
igEndChild()
|
||||||
|
igSameLine(0.0f, 0.0f)
|
||||||
|
|
||||||
|
# Right panel (file content)
|
||||||
|
if igBeginChild_Str("##Preview", vec2(0.0f, 0.0f), ImGui_ChildFlags_Borders.int32, ImGui_WindowFlags_None.int32):
|
||||||
|
|
||||||
|
if component.selectedIndex >= 0 and component.selectedIndex < component.items.len:
|
||||||
|
let item = component.items[component.selectedIndex]
|
||||||
|
|
||||||
|
igText(item.path)
|
||||||
|
|
||||||
|
else:
|
||||||
|
igText("Select item to preview contents")
|
||||||
|
igEndChild()
|
||||||
@@ -1,19 +1,124 @@
|
|||||||
import strformat, strutils, times
|
import strformat, strutils, times, os, tables
|
||||||
import imguin/[cimgui, glfw_opengl, simple]
|
import imguin/[cimgui, glfw_opengl, simple]
|
||||||
import ../../utils/[appImGui, colors]
|
import ../../utils/[appImGui, colors]
|
||||||
import ../../../common/types
|
import ../../../common/[types, utils]
|
||||||
|
|
||||||
type
|
type
|
||||||
LootScreenshotsComponent* = ref object of RootObj
|
ScreenshotTexture* = ref object
|
||||||
title: string
|
textureId*: GLuint
|
||||||
|
width: int
|
||||||
|
height: int
|
||||||
|
|
||||||
|
ScreenshotsComponent* = ref object of RootObj
|
||||||
|
title: string
|
||||||
|
items: seq[LootItem]
|
||||||
|
selectedIndex: int
|
||||||
|
textures: Table[string, ScreenshotTexture]
|
||||||
|
|
||||||
proc LootScreenshots*(title: string): LootScreenshotsComponent =
|
proc LootScreenshots*(title: string): ScreenshotsComponent =
|
||||||
result = new LootScreenshotsComponent
|
result = new ScreenshotsComponent
|
||||||
result.title = title
|
result.title = title
|
||||||
|
result.items = @[]
|
||||||
|
result.selectedIndex = -1
|
||||||
|
|
||||||
proc draw*(component: LootScreenshotsComponent, showComponent: ptr bool) =
|
result.items.add(@[LootItem(
|
||||||
|
agentId: "DEADBEEF",
|
||||||
|
timestamp: now().toTime().toUnix(),
|
||||||
|
size: 1000,
|
||||||
|
path: "/mnt/c/Users/jakob/Documents/Projects/conquest/data/loot/570DCB57/screenshot_1757769346.bmp",
|
||||||
|
host: "WKS-1",
|
||||||
|
data: string.toBytes(readFile("/mnt/c/Users/jakob/Documents/Projects/conquest/data/loot/570DCB57/screenshot_1757769346.bmp"))
|
||||||
|
),
|
||||||
|
LootItem(
|
||||||
|
agentId: "DEADBEEF",
|
||||||
|
timestamp: now().toTime().toUnix(),
|
||||||
|
path: "/mnt/c/Users/jakob/Documents/Projects/conquest/data/loot/C2468819/screenshot_1759238569.png",
|
||||||
|
size: 1000,
|
||||||
|
host: "WKS-1",
|
||||||
|
data: string.toBytes(readFile("/mnt/c/Users/jakob/Documents/Projects/conquest/data/loot/C2468819/screenshot_1759238569.png"))
|
||||||
|
)
|
||||||
|
])
|
||||||
|
|
||||||
|
result.textures = initTable[string, ScreenshotTexture]()
|
||||||
|
|
||||||
|
for item in result.items:
|
||||||
|
var textureId: GLuint
|
||||||
|
let (width, height) = loadTextureFromBytes(item.data, textureId)
|
||||||
|
|
||||||
|
result.textures[item.path] = ScreenshotTexture(
|
||||||
|
textureId: textureId,
|
||||||
|
width: width,
|
||||||
|
height: height
|
||||||
|
)
|
||||||
|
|
||||||
|
proc draw*(component: ScreenshotsComponent, showComponent: ptr bool) =
|
||||||
igBegin(component.title, showComponent, 0)
|
igBegin(component.title, showComponent, 0)
|
||||||
defer: igEnd()
|
defer: igEnd()
|
||||||
|
|
||||||
igText("asd")
|
var availableSize: ImVec2
|
||||||
|
igGetContentRegionAvail(addr availableSize)
|
||||||
|
let textSpacing = igGetStyle().ItemSpacing.x
|
||||||
|
|
||||||
|
# Left panel (file table)
|
||||||
|
let childFlags = ImGui_ChildFlags_ResizeX.int32 or ImGui_ChildFlags_NavFlattened.int32
|
||||||
|
if igBeginChild_Str("##Left", vec2(availableSize.x * 0.66f, 0.0f), childFlags, ImGui_WindowFlags_None.int32):
|
||||||
|
|
||||||
|
let tableFlags = (
|
||||||
|
ImGui_TableFlags_Resizable.int32 or
|
||||||
|
ImGui_TableFlags_Reorderable.int32 or
|
||||||
|
ImGui_TableFlags_Hideable.int32 or
|
||||||
|
ImGui_TableFlags_HighlightHoveredColumn.int32 or
|
||||||
|
ImGui_TableFlags_RowBg.int32 or
|
||||||
|
ImGui_TableFlags_BordersV.int32 or
|
||||||
|
ImGui_TableFlags_BordersH.int32 or
|
||||||
|
ImGui_TableFlags_ScrollY.int32 or
|
||||||
|
ImGui_TableFlags_ScrollX.int32 or
|
||||||
|
ImGui_TableFlags_NoBordersInBodyUntilResize.int32 or
|
||||||
|
ImGui_TableFlags_SizingStretchSame.int32
|
||||||
|
)
|
||||||
|
|
||||||
|
let cols: int32 = 4
|
||||||
|
if igBeginTable("##Items", cols, tableFlags, vec2(0.0f, 0.0f), 0.0f):
|
||||||
|
igTableSetupColumn("Path", ImGuiTableColumnFlags_None.int32, 0.0f, 0)
|
||||||
|
igTableSetupColumn("Creation Date", ImGuiTableColumnFlags_None.int32, 0.0f, 0)
|
||||||
|
igTableSetupColumn("Size", ImGuiTableColumnFlags_None.int32, 0.0f, 0)
|
||||||
|
igTableSetupColumn("Host", ImGuiTableColumnFlags_None.int32, 0.0f, 0)
|
||||||
|
igTableSetupScrollFreeze(0, 1)
|
||||||
|
igTableHeadersRow()
|
||||||
|
|
||||||
|
for i, item in component.items:
|
||||||
|
igTableNextRow(ImGuiTableRowFlags_None.int32, 0.0f)
|
||||||
|
|
||||||
|
if igTableSetColumnIndex(0):
|
||||||
|
igPushID_Int(i.int32)
|
||||||
|
let isSelected = component.selectedIndex == i
|
||||||
|
if igSelectable_Bool(item.path.cstring, isSelected, ImGuiSelectableFlags_SpanAllColumns.int32 or ImGuiSelectableFlags_AllowOverlap.int32, vec2(0, 0)):
|
||||||
|
component.selectedIndex = i
|
||||||
|
igPopID()
|
||||||
|
|
||||||
|
if igTableSetColumnIndex(1):
|
||||||
|
igText(item.timestamp.fromUnix().local().format("dd-MM-yyyy HH:mm:ss"))
|
||||||
|
|
||||||
|
if igTableSetColumnIndex(2):
|
||||||
|
igText($item.size)
|
||||||
|
|
||||||
|
if igTableSetColumnIndex(3):
|
||||||
|
igText(item.host.cstring)
|
||||||
|
|
||||||
|
igEndTable()
|
||||||
|
|
||||||
|
igEndChild()
|
||||||
|
igSameLine(0.0f, 0.0f)
|
||||||
|
|
||||||
|
# Right panel (file content)
|
||||||
|
if igBeginChild_Str("##Preview", vec2(0.0f, 0.0f), ImGui_ChildFlags_Borders.int32, ImGui_WindowFlags_None.int32):
|
||||||
|
|
||||||
|
if component.selectedIndex >= 0 and component.selectedIndex < component.items.len:
|
||||||
|
let item = component.items[component.selectedIndex]
|
||||||
|
let texture = component.textures[item.path]
|
||||||
|
|
||||||
|
igImage(ImTextureRef(internal_TexData: nil, internal_TexID: texture.textureId), vec2(texture.width, texture.height), vec2(0, 0), vec2(1, 1))
|
||||||
|
|
||||||
|
else:
|
||||||
|
igText("Select item to preview contents")
|
||||||
|
igEndChild()
|
||||||
@@ -143,7 +143,7 @@ proc draw*(component: AgentModalComponent, listeners: seq[UIListener]): AgentBui
|
|||||||
|
|
||||||
igText("Build log: ")
|
igText("Build log: ")
|
||||||
try:
|
try:
|
||||||
# Set styles of the eventlog window
|
# Set styles of the log window
|
||||||
igPushStyleColor_Vec4(ImGui_Col_FrameBg.int32, vec4(0.1f, 0.1f, 0.1f, 1.0f))
|
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_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))
|
igPushStyleColor_Vec4(ImGui_Col_Border.int32, vec4(0.2f, 0.2f, 0.2f, 1.0f))
|
||||||
|
|||||||
@@ -53,17 +53,6 @@ type
|
|||||||
CMD_DOTNET = 16'u16
|
CMD_DOTNET = 16'u16
|
||||||
CMD_SLEEPMASK = 17'u16
|
CMD_SLEEPMASK = 17'u16
|
||||||
|
|
||||||
ModuleType* = enum
|
|
||||||
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
|
StatusType* = enum
|
||||||
STATUS_COMPLETED = 0'u8
|
STATUS_COMPLETED = 0'u8
|
||||||
STATUS_FAILED = 1'u8
|
STATUS_FAILED = 1'u8
|
||||||
@@ -100,6 +89,17 @@ type
|
|||||||
ZILEAN = 2'u8
|
ZILEAN = 2'u8
|
||||||
FOLIAGE = 3'u8
|
FOLIAGE = 3'u8
|
||||||
|
|
||||||
|
ModuleType* = enum
|
||||||
|
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
|
||||||
|
|
||||||
# Custom iterator for ModuleType, as it uses powers of 2 instead of standard increments
|
# Custom iterator for ModuleType, as it uses powers of 2 instead of standard increments
|
||||||
iterator items*(e: typedesc[ModuleType]): ModuleType =
|
iterator items*(e: typedesc[ModuleType]): ModuleType =
|
||||||
yield MODULE_SLEEP
|
yield MODULE_SLEEP
|
||||||
@@ -264,8 +264,9 @@ type
|
|||||||
CLIENT_AGENT_PAYLOAD = 104'u8 # Return agent payload binary
|
CLIENT_AGENT_PAYLOAD = 104'u8 # Return agent payload binary
|
||||||
CLIENT_CONSOLE_ITEM = 105'u8 # Add entry to a agent's console
|
CLIENT_CONSOLE_ITEM = 105'u8 # Add entry to a agent's console
|
||||||
CLIENT_EVENTLOG_ITEM = 106'u8 # Add entry to the eventlog
|
CLIENT_EVENTLOG_ITEM = 106'u8 # Add entry to the eventlog
|
||||||
CLIENT_BUILDLOG_ITEM = 107'u8 # Add entry to the build log
|
CLIENT_BUILDLOG_ITEM = 107'u8 # Add entry to the build log
|
||||||
CLIENT_LOOT = 108'u8 # Download file or screenshot to the operator desktop
|
CLIENT_LOOT_ADD = 108'u8 # Add file or screenshot stored on the team server to preview on the client
|
||||||
|
CLIENT_SYNC_LOOT = 109'u8 # Download a file/screenshot to the operator desktop
|
||||||
|
|
||||||
Event* = object
|
Event* = object
|
||||||
eventType*: EventType
|
eventType*: EventType
|
||||||
@@ -347,3 +348,11 @@ type
|
|||||||
sleepTechnique*: SleepObfuscationTechnique
|
sleepTechnique*: SleepObfuscationTechnique
|
||||||
spoofStack*: bool
|
spoofStack*: bool
|
||||||
modules*: uint32
|
modules*: uint32
|
||||||
|
|
||||||
|
LootItem* = ref object
|
||||||
|
agentId*: string
|
||||||
|
path*: string
|
||||||
|
timestamp*: int64
|
||||||
|
size*: int
|
||||||
|
host*: string
|
||||||
|
data*: seq[byte]
|
||||||
|
|||||||
Reference in New Issue
Block a user