Added initial client UI structure.
This commit is contained in:
@@ -9,12 +9,12 @@ srcDir = "src"
|
||||
# Build tasks
|
||||
|
||||
import os, strformat
|
||||
let cqRoot = getCurrentDir()
|
||||
task server, "Build conquest server binary":
|
||||
let cqRoot = getCurrentDir()
|
||||
exec fmt"nim c -d:CONQUEST_ROOT={cqRoot} src/server/main.nim"
|
||||
|
||||
task client, "Build conquest client binary":
|
||||
discard
|
||||
exec fmt"nim c -d:release -d:CONQUEST_ROOT={cqRoot} src/client/main.nim"
|
||||
|
||||
# Dependencies
|
||||
|
||||
@@ -28,3 +28,4 @@ requires "tiny_sqlite >= 0.2.0"
|
||||
requires "prologue >= 0.6.6"
|
||||
requires "winim >= 3.9.4"
|
||||
requires "ptr_math >= 0.3.0"
|
||||
requires "imguin >= 1.92.2.0"
|
||||
36
data/layout.ini
Normal file
36
data/layout.ini
Normal file
@@ -0,0 +1,36 @@
|
||||
[Window][CQ]
|
||||
Size=2868,1695
|
||||
Collapsed=0
|
||||
|
||||
[Window][Dear ImGui Demo]
|
||||
Pos=0,30
|
||||
Size=2868,1665
|
||||
Collapsed=0
|
||||
DockId=0x00000001,0
|
||||
|
||||
[Window][Debug##Default]
|
||||
Pos=60,60
|
||||
Size=400,400
|
||||
Collapsed=0
|
||||
|
||||
[Window][Conquest]
|
||||
Pos=0,0
|
||||
Size=2868,1695
|
||||
Collapsed=0
|
||||
|
||||
[Window][Dear ImGui Style Editor]
|
||||
Pos=123,79
|
||||
Size=1080,1629
|
||||
Collapsed=0
|
||||
|
||||
[Window][Example: Console]
|
||||
Pos=0,781
|
||||
Size=2868,914
|
||||
Collapsed=0
|
||||
DockId=0x00000002,0
|
||||
|
||||
[Docking][Data]
|
||||
DockSpace ID=0x3674675E Window=0x538FB738 Pos=0,30 Size=2868,1665 Split=Y Selected=0x5E5F7166
|
||||
DockNode ID=0x00000001 Parent=0x3674675E SizeRef=2868,749 CentralNode=1 Selected=0x5E5F7166
|
||||
DockNode ID=0x00000002 Parent=0x3674675E SizeRef=2868,914 Selected=0x1BCA3180
|
||||
|
||||
@@ -27,7 +27,7 @@ Basic API-only Commands
|
||||
Execution Commands
|
||||
------------------
|
||||
- [x] shell : Execute shell command (to be implemented using Windows APIs instead of execCmdEx)
|
||||
- [ ] bof : Execute Beacon Object File in memory and retrieve output (bof /local/path/file.o)
|
||||
- [x] bof : Execute Beacon Object File in memory and retrieve output (bof /local/path/file.o)
|
||||
- Read from listener endpoint directly to memory
|
||||
- Base for all kinds of BOFs (Situational Awareness, ...)
|
||||
- [ ] pe : Execute PE file in memory and retrieve output (pe /local/path/mimikatz.exe)
|
||||
@@ -35,10 +35,10 @@ Execution Commands
|
||||
|
||||
Post-Exploitation
|
||||
-----------------
|
||||
- [ ] upload : Upload file from server to agent (upload /local/path/to/file C:\Windows\Tasks)
|
||||
- [x] upload : Upload file from server to agent (upload /local/path/to/file C:\Windows\Tasks)
|
||||
- File to be downloaded moved to specific endpoint on listener, e.g. GET /<listener>/<agent>/<upload-task>/file
|
||||
- Read from webserver and written to disk
|
||||
- [ ] download : Download file from agent to teamserver
|
||||
- [x] download : Download file from agent to teamserver
|
||||
- Create loot directory for agent to store files in
|
||||
- Read file into memory and send byte stream to specific endpoint, e.g. POST /<listener>/<agent>/<download>-task/file
|
||||
- Encrypt file in-transit!!!
|
||||
|
||||
73
src/client/config.nims
Normal file
73
src/client/config.nims
Normal file
@@ -0,0 +1,73 @@
|
||||
switch "o", "bin/client"
|
||||
|
||||
# Select compiler
|
||||
var TC = "gcc"
|
||||
# var TC = "clang"
|
||||
|
||||
# Dismiss background window
|
||||
switch "app", "gui"
|
||||
|
||||
# Select static link or shared/dll link
|
||||
when defined(windows):
|
||||
const STATIC_LINK_GLFW = false
|
||||
const STATIC_LINK_CC = true #libstd++ or libc
|
||||
if TC == "vcc":
|
||||
switch "passL","d3d9.lib kernel32.lib user32.lib gdi32.lib winspool.lib"
|
||||
switch "passL","comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib"
|
||||
switch "passL","uuid.lib odbc32.lib odbccp32.lib"
|
||||
switch "passL","imm32.lib"
|
||||
else:
|
||||
switch "passL","-lgdi32 -limm32 -lcomdlg32 -luser32 -lshell32"
|
||||
else: # for Linux
|
||||
const STATIC_LINK_GLFW = true
|
||||
const STATIC_LINK_CC= false
|
||||
|
||||
when STATIC_LINK_GLFW: # GLFW static link
|
||||
switch "define","glfwStaticLib"
|
||||
else: # shared/dll
|
||||
when defined(windows):
|
||||
if TC == "vcc":
|
||||
discard
|
||||
else:
|
||||
switch "passL","-lglfw3.dll"
|
||||
switch "define", "glfwDLL"
|
||||
#switch "define","cimguiDLL"
|
||||
else:
|
||||
switch "passL","-lglfw"
|
||||
|
||||
when STATIC_LINK_CC: # gcc static link
|
||||
case TC
|
||||
of "vcc":
|
||||
discard
|
||||
else:
|
||||
switch "passC", "-static"
|
||||
switch "passL", "-static "
|
||||
|
||||
# Set compiler options
|
||||
case TC
|
||||
of "vcc" , "clang_cl":
|
||||
switch "define","lto"
|
||||
else:
|
||||
if "" == findExe(TC): # GCC is default compiler if TC dosn't exist on the PATH
|
||||
echo "#### Set to cc = ",TC
|
||||
TC = "gcc"
|
||||
if "" == findExe(TC): # if gcc dosn't exist, try clang
|
||||
TC = "clang"
|
||||
echo "#### Set to cc = ",TC
|
||||
|
||||
# Reduce code size further
|
||||
when false:
|
||||
switch "gc", "arc"
|
||||
switch "define", "useMalloc"
|
||||
switch "define", "noSignalHandler"
|
||||
|
||||
case TC
|
||||
of "gcc":
|
||||
switch "passC", "-ffunction-sections"
|
||||
switch "passC", "-fdata-sections"
|
||||
switch "passL", "-Wl,--gc-sections"
|
||||
switch "cc",TC
|
||||
of "clang":
|
||||
switch "cc.exe","clang"
|
||||
switch "cc.linkerexe","clang"
|
||||
switch "cc",TC
|
||||
112
src/client/main.nim
Normal file
112
src/client/main.nim
Normal file
@@ -0,0 +1,112 @@
|
||||
import nimgl/[opengl, glfw]
|
||||
import imguin/glfw_opengl
|
||||
import ./utils/[lib, windowInit]
|
||||
|
||||
proc main(hWin: glfw.GLFWWindow) =
|
||||
var
|
||||
clearColor: CColor
|
||||
showWindowDelay = 1
|
||||
showMainWindow = true
|
||||
windowClass = ImGuiWindowClass_ImGuiWindowClass()
|
||||
opt_fullscreen: bool = true
|
||||
opt_padding: bool = false
|
||||
dockspaceFlags: ImGuiDockNodeFlags = ImGuiDockNodeFlags_None.int32
|
||||
windowFlags: ImGuiWindow_Flags = ImGuiWindowFlags_MenuBar.int32 or ImGuiWindowFlags_NoDocking.int32
|
||||
|
||||
# Setup background and theme colors (Background is only seen when opt_padding = true)
|
||||
clearColor = CColor(elm:(x:0.0f, y:0.0f, z:0.0f, w:0.0f))
|
||||
igStyleColorsClassic(nil)
|
||||
|
||||
# Setup fonts
|
||||
discard setupFonts()
|
||||
|
||||
let io = igGetIO()
|
||||
|
||||
# main loop
|
||||
while not hWin.windowShouldClose:
|
||||
glfwPollEvents()
|
||||
|
||||
if getWindowAttrib(hWin, GLFW_ICONIFIED) != 0:
|
||||
ImGui_ImplGlfw_Sleep(10)
|
||||
continue
|
||||
|
||||
# Start ImGUI frame
|
||||
ImGui_ImplOpenGL3_NewFrame()
|
||||
ImGui_ImplGlfw_NewFrame()
|
||||
igNewFrame()
|
||||
|
||||
# Create Dockspace where all windows are placed in
|
||||
if opt_fullscreen:
|
||||
var vp = igGetMainViewport()
|
||||
igSetNextWindowPos(vp.WorkPos, ImGui_Cond_None.int32, vec2(0.0f, 0.0f))
|
||||
igSetNextWindowSize(vp.WorkSize, 0)
|
||||
igSetNextWindowViewport(vp.ID)
|
||||
igPushStyleVar_Float(ImGuiStyleVar_WindowRounding.int32, 0.0f)
|
||||
igPushStyleVar_Float(ImGuiStyleVar_WindowBorderSize.int32, 0.0f)
|
||||
|
||||
windowFlags = windowFlags or ImGuiWindowFlags_NoTitleBar.int32 or ImGuiWindowFlags_NoCollapse.int32 or ImGuiWindowFlags_NoResize.int32 or ImGuiWindowFlags_NoMove.int32
|
||||
windowFlags = windowFlags or ImGuiWindowFlags_NoBringToFrontOnFocus.int32 or ImGuiWindowFlags_NoNavFocus.int32
|
||||
|
||||
else:
|
||||
dockspaceFlags = cast[ImGuiDockNodeFlags](dockspaceFlags and not ImGuiDockNodeFlags_PassthruCentralNode.int32)
|
||||
|
||||
if (dockspaceFlags and ImGuiDockNodeFlags_PassthruCentralNode.int32) == ImGuiDockNodeFlags_None.int32:
|
||||
windowFlags = cast[ImGuiWindow_Flags](windowFlags or ImGuiWindowFlags_NoBackground.int32)
|
||||
|
||||
if not opt_padding:
|
||||
igPushStyleVar_Vec2(ImGuiStyleVar_WindowPadding.int32, vec2(0.0f, 0.0f))
|
||||
|
||||
igBegin("Conquest", addr showMainWindow, windowFlags)
|
||||
|
||||
if not opt_padding:
|
||||
igPopStyleVar(1)
|
||||
|
||||
if opt_fullscreen:
|
||||
igPopStyleVar(2)
|
||||
|
||||
# Create dockspace
|
||||
if (io.ConfigFlags and ImGui_ConfigFlags_DockingEnable.int32) != ImGui_ConfigFlags_None.int32:
|
||||
igDockSpace(igGetID_Str("Conquest-Dockspace"), vec2(0.0f, 0.0f), dockspaceFlags, windowClass)
|
||||
|
||||
# Create Dockspace menu bar
|
||||
if igBeginMenuBar():
|
||||
if igBeginMenu("Options", true):
|
||||
|
||||
igMenuItem("Fullscreen", nil, addr opt_fullscreen, true)
|
||||
igMenuItem("Padding", nil, addr opt_padding, true)
|
||||
|
||||
if igMenuItem("Close", nil, false, (addr showMainWindow) != nil):
|
||||
showMainWindow = false
|
||||
igEndMenu()
|
||||
igEndMenuBar()
|
||||
|
||||
# Components and widgets
|
||||
igShowDemoWindow(nil)
|
||||
|
||||
|
||||
|
||||
|
||||
igEnd()
|
||||
|
||||
# render
|
||||
igRender()
|
||||
glClearColor(clearColor.elm.x, clearColor.elm.y, clearColor.elm.z, clearColor.elm.w)
|
||||
glClear(GL_COLOR_BUFFER_BIT)
|
||||
ImGui_ImplOpenGL3_RenderDrawData(igGetDrawData())
|
||||
|
||||
if 0 != (io.ConfigFlags and ImGui_ConfigFlags_ViewportsEnable.int32):
|
||||
var backup_current_window = glfwGetCurrentContext()
|
||||
igUpdatePlatformWindows()
|
||||
igRenderPlatformWindowsDefault(nil, nil)
|
||||
backup_current_window.makeContextCurrent()
|
||||
|
||||
hWin.swapBuffers()
|
||||
|
||||
if showWindowDelay > 0:
|
||||
dec showWindowDelay
|
||||
else:
|
||||
once: # Avoid flickering screen at startup.
|
||||
hWin.showWindow()
|
||||
|
||||
when isMainModule:
|
||||
windowInit(main)
|
||||
@@ -1,2 +0,0 @@
|
||||
-d:"adwminor=4"
|
||||
--outdir:"../bin"
|
||||
97
src/client/utils/lib.nim
Normal file
97
src/client/utils/lib.nim
Normal file
@@ -0,0 +1,97 @@
|
||||
import imguin/cimgui
|
||||
|
||||
type
|
||||
Vec2* = ImVec2
|
||||
Vec4* = ImVec4
|
||||
|
||||
proc vec2*(x, y: auto): ImVec2 =
|
||||
ImVec2(x: x.cfloat, y: y.cfloat)
|
||||
|
||||
proc vec4*(x, y, z, w: auto): ImVec4 =
|
||||
ImVec4(x: x.cfloat , y: y.cfloat , z: z.cfloat , w: w.cfloat)
|
||||
|
||||
# Tooltips
|
||||
proc setTooltip*(str:string, delay=Imgui_HoveredFlags_DelayNormal.cint, color=ImVec4(x: 1.0, y: 1.0, z: 1.0, w: 1.0)) =
|
||||
if igIsItemHovered(delay):
|
||||
if igBeginTooltip():
|
||||
igPushStyleColorVec4(ImGuiCol_Text.cint, color)
|
||||
igText(str)
|
||||
igPopStyleColor(1)
|
||||
igEndTooltip()
|
||||
|
||||
# IM_COL32
|
||||
proc IM_COL32*(a,b,c,d:uint32): ImU32 =
|
||||
return igGetColorU32_Vec4(vec4(a.cfloat/255, b.cfloat/255, c.cfloat/255, d.cfloat/255))
|
||||
|
||||
# Definitions from imguin/simple (https://github.com/dinau/imguin/blob/main/src/imguin/simple.nim)
|
||||
{.push discardable.} # Push discardable applies the {.discardable.} pragma to all functions until the {.pop.} pragma is reached
|
||||
when false:
|
||||
type CColor* = object
|
||||
x,y,z,w: cfloat
|
||||
|
||||
proc array3(self:ccolor): array[3,cfloat] =
|
||||
result = cast[array[3,cfloat]]([self.x,self.y,self.z])
|
||||
|
||||
proc newCColor(col:ImVec4):ccolor =
|
||||
result.x = col.x
|
||||
result.y = col.y
|
||||
result.z = col.z
|
||||
result.w = col.w
|
||||
|
||||
proc vec4*(self:ccolor): ImVec4 =
|
||||
ImVec4(x:self.x,y:self.y,z:self.z,w:self.z)
|
||||
|
||||
else:
|
||||
type CColor* {.union.} = object
|
||||
elm*: tuple[x,y,z,w: cfloat]
|
||||
array3*: array[3, cfloat]
|
||||
vec4*: ImVec4
|
||||
|
||||
proc igInputTextWithHint*(label: string, hint: string, buf: string, bufsize: int = buf.len, flags:Imguiinputtextflags = 0.Imguiinputtextflags, callback: ImguiInputTextCallback = nil, userdata: pointer = nil): bool {.inline,discardable.} =
|
||||
igInputTextWithHint(label.cstring, hint.cstring, buf.cstring, bufsize.cuint, flags, callback, userdata)
|
||||
|
||||
proc igPlotLines*[T](label:string, arry: openArray[T], size:int= arry.len, offset:int = 0, overlayText:string = "", smin:float = igGetFLTMax(), smax:float = igGetFLTMax(), graphSize:Imvec2 = ImVec2(x:0,y:0), stride:int = sizeof(cfloat)) {.inline.} =
|
||||
igPlotLinesFloatPtr(label.cstring, cast[ptr T](addr arry), size.cint, offset.cint, overlayText.cstring, smin.cfloat, smax.cfloat, graphSize, stride.cint)
|
||||
|
||||
when defined(ImKnobsEnable) or defined(ImKnobs):
|
||||
proc IgKnobEx*(label: cstring; p_value: ptr cfloat; v_min: cfloat; v_max: cfloat; speed: cfloat; format: cstring; variant: IgKnobVariant; size: cfloat; flags: IgKnobFlags; steps: cint; angle_min: cfloat; angle_max: cfloat): bool =
|
||||
return IgKnobFloat(label, p_value, v_min, v_max, speed, format, variant, size, flags, steps, angle_min, angle_max)
|
||||
|
||||
proc IgKnob*(label: cstring; p_value: ptr cfloat; v_min: cfloat; v_max: cfloat): bool =
|
||||
return IgKnobFloat(label, p_value, v_min, v_max, 0, "%.3f", IgKnobVariant_Tick.IgKnobVariant,0, cast[IgKnobFlags](0),10,-1,-1)
|
||||
|
||||
proc igPushStyleColor*(idx: ImGuiCol; col: ImU32) = igPushStyleColor_U32(idx, col)
|
||||
proc igPushStyleColor*(idx: ImGuiCol; col: ImVec4) = igPushStyleColor_Vec4(idx, col)
|
||||
proc igSameLine*() = igSameLine(0.0, -1.0)
|
||||
|
||||
proc igBeginMenuEx*(label: cstring, icon: cstring, enabled: bool = true): bool {.importc: "igBeginMenuEx".}
|
||||
proc igMenuItem*(label: cstring, shortcut: cstring = nil, selected: bool = false, enabled: bool = true): bool {.importc: "igMenuItem_Bool".}
|
||||
proc igMenuItem*(label: cstring, shortcut: cstring, p_selected: ptr bool, enabled: bool = true): bool {.importc: "igMenuItem_BoolPtr".}
|
||||
proc igMenuItemEx*(label: cstring, icon: cstring, shortcut: cstring = nil, selected: bool = false, enabled: bool = true): bool {.importc: "igMenuItemEx".}
|
||||
|
||||
proc igBeginChild*(str_id: cstring, size: ImVec2 = ImVec2(x: 0, y: 0), border: bool = false, flags: ImGuiWindowFlags = 0.ImGuiWindowFlags): bool {.importc: "igBeginChild_Str".}
|
||||
proc igBeginChild*(id: ImGuiID, size: ImVec2 = ImVec2(x: 0, y: 0), border: bool = false, flags: ImGuiWindowFlags = 0.ImGuiWindowFlags): bool {.importc: "igBeginChild_ID".}
|
||||
|
||||
when not defined(igGetIO):
|
||||
template igGetIO*(): ptr ImGuiIO =
|
||||
igGetIO_Nil()
|
||||
|
||||
{.pop.}
|
||||
|
||||
# Fonts
|
||||
proc pointToPx*(point: float32): cfloat =
|
||||
return ((point * 96) / 72).cfloat
|
||||
|
||||
proc setupFonts*(): (bool, string, string) =
|
||||
|
||||
let io = igGetIO()
|
||||
let
|
||||
fontPath = "/usr/share/fonts/truetype/noto/NotoMono-Regular.ttf"
|
||||
fontName = "NotoMono-Regular"
|
||||
fontSize = pointToPx(18.0f)
|
||||
|
||||
# Set base font
|
||||
io.Fonts.ImFontAtlas_AddFontFromFileTTF(fontPath.cstring, fontSize, nil, nil)
|
||||
|
||||
result = (true, fontPath, fontName)
|
||||
|
||||
62
src/client/utils/windowInit.nim
Normal file
62
src/client/utils/windowInit.nim
Normal file
@@ -0,0 +1,62 @@
|
||||
import os
|
||||
import nimgl/[opengl, glfw]
|
||||
import imguin/glfw_opengl
|
||||
import ./lib
|
||||
|
||||
const CONQUEST_ROOT* {.strdefine.} = ""
|
||||
|
||||
when defined(windows):
|
||||
when not defined(vcc): # imguinVcc.res TODO WIP
|
||||
include ./res/resource
|
||||
import tinydialogs
|
||||
|
||||
# Forward definitions
|
||||
proc windowInit*(winMain: proc(win: glfw.GLFWWindow)) =
|
||||
doAssert glfwInit()
|
||||
defer: glfwTerminate()
|
||||
|
||||
glfwWindowHint(GLFWContextVersionMajor, 3)
|
||||
glfwWindowHint(GLFWContextVersionMinor, 3)
|
||||
glfwWindowHint(GLFWOpenglForwardCompat, GLFW_TRUE)
|
||||
glfwWindowHint(GLFWOpenglProfile, GLFW_OPENGL_CORE_PROFILE)
|
||||
glfwWindowHint(GLFWResizable, GLFW_TRUE)
|
||||
glfwWindowHint(GLFWVisible, GLFW_FALSE)
|
||||
glfwWindowHint(GLFWMaximized, GLFW_TRUE) # Maximize Window on startup
|
||||
|
||||
var glfwWin = glfwCreateWindow(1024, 800, "Conquest")
|
||||
if glfwWin.isNil:
|
||||
quit(-1)
|
||||
|
||||
glfwWin.makeContextCurrent()
|
||||
defer: glfwWin.destroyWindow()
|
||||
|
||||
glfwSwapInterval(1) # Enable vsync
|
||||
|
||||
# TODO: Set application icon (requires imguin_examples/utils/loadImage [https://github.com/dinau/imguin_examples/blob/main/utils/opengl/loadImage.nim])
|
||||
# var IconName = joinPath(CONQUEST_ROOT, "src/client/resources/icon.png")
|
||||
# LoadTileBarIcon(glfwWin, IconName)
|
||||
|
||||
doAssert glInit() # OpenGL init
|
||||
|
||||
# Setup ImGui
|
||||
let context = igCreateContext(nil)
|
||||
defer: context.igDestroyContext()
|
||||
|
||||
# Configure docking
|
||||
var pio = igGetIO()
|
||||
pio.ConfigFlags = pio.ConfigFlags or ImGui_ConfigFlags_DockingEnable.int32
|
||||
|
||||
# GLFW + OpenGL
|
||||
const glsl_version = "#version 130" # GL 3.0 + GLSL 130
|
||||
doAssert ImGui_ImplGlfw_InitForOpenGL(cast[ptr GLFWwindow](glfwwin), true)
|
||||
defer: ImGui_ImplGlfw_Shutdown()
|
||||
doAssert ImGui_ImplOpenGL3_Init(glsl_version)
|
||||
defer: ImGui_ImplOpenGL3_Shutdown()
|
||||
|
||||
# Set ini filename
|
||||
pio.IniFileName = CONQUEST_ROOT & "/data/layout.ini"
|
||||
|
||||
glfwWin.winMain()
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user