> ## Documentation Index
> Fetch the complete documentation index at: https://docs.mythic-c2.net/llms.txt
> Use this file to discover all available pages before exploring further.

# Payload Type Definition

## 1.0 Payload Definition

Payload Type information must be set and pulled from a definition either in Python or in GoLang. Below are basic examples in Python and GoLang:

<Tabs>
  <Tab title="Python">
    ```python theme={"system"}
    from mythic_container.PayloadBuilder import *
    from mythic_container.MythicCommandBase import *
    from mythic_container.MythicRPC import *
    import json

    class Apollo(PayloadType):
       name = "apollo"
       file_extension = "exe"
       agent_type = AgentType.Agent
       author = "@djhohnstein, @its_a_feature_"
       mythic_encrypts = True
       supported_os = [
           SupportedOS.Windows
       ]
       semver = "2.3.51"
       wrapped_payloads = ["scarecrow_wrapper", "service_wrapper"]
       note = """
    A fully featured .NET 4.0 compatible training agent. Version: {}.
    NOTE: P2P Not compatible with v2.2 agents!
    NOTE: v2.3.2+ has a different bof loader than 2.3.1 and are incompatible since their arguments are different
       """.format(semver)
       supports_dynamic_loading = True
       shellcode_format_options = ["Binary", "Base64", "C", "Ruby", "Python", "Powershell", "C#", "Hex"]
       shellcode_bypass_options = ["None", "Abort on fail", "Continue on fail"]
       supports_multiple_c2_instances_in_build = False
       supports_multiple_c2_in_build = False
       c2_parameter_deviations = {
           "http": {
               "get_uri": C2ParameterDeviation(supported=False),
               "query_path_name": C2ParameterDeviation(supported=False),
               #"headers": C2ParameterDeviation(supported=True, dictionary_choices=[
               #    DictionaryChoice(name="User-Agent", default_value="Hello", default_show=True),
               #    DictionaryChoice(name="HostyHost", default_show=False, default_value=""),
               #])
           }
       }
       build_parameters = [
           BuildParameter(
               name="output_type",
               parameter_type=BuildParameterType.ChooseOne,
               choices=["WinExe", "Shellcode", "Service", "Source"],
               default_value="WinExe",
               description="Output as shellcode, executable, sourcecode, or service.",
           ),
           BuildParameter(
               name="shellcode_format",
               parameter_type=BuildParameterType.ChooseOne,
               choices=shellcode_format_options,
               default_value="Binary",
               description="Donut shellcode format options.",
               group_name="Shellcode Options",
               hide_conditions=[
                   HideCondition(name="output_type", operand=HideConditionOperand.NotEQ, value="Shellcode")
               ]
           ),
           BuildParameter(
               name="shellcode_bypass",
               parameter_type=BuildParameterType.ChooseOne,
               choices=shellcode_bypass_options,
               default_value="Continue on fail",
               description="Donut shellcode AMSI/WLDP/ETW Bypass options.",
               group_name="Shellcode Options",
               hide_conditions=[
                   HideCondition(name="output_type", operand=HideConditionOperand.NotEQ, value="Shellcode")
               ]
           ),
           BuildParameter(
               name="adjust_filename",
               parameter_type=BuildParameterType.Boolean,
               default_value=False,
               description="Automatically adjust payload extension based on selected choices.",
           ),
           BuildParameter(
               name="debug",
               parameter_type=BuildParameterType.Boolean,
               default_value=False,
               description="Create a DEBUG version.",
           )
       ]
       c2_profiles = ["http", "smb", "tcp", "websocket"]
       agent_path = pathlib.Path(".") / "apollo" / "mythic"
       agent_code_path = pathlib.Path(".") / "apollo" / "agent_code"
       agent_icon_path = agent_path / "agent_functions" / "apollo.svg"
       build_steps = [
           BuildStep(step_name="Gathering Files", step_description="Copying files to temp location"),
           BuildStep(step_name="Compiling", step_description="Compiling with nuget and dotnet"),
           BuildStep(step_name="Donut", step_description="Converting to Shellcode"),
           BuildStep(step_name="Creating Service", step_description="Creating Service EXE from Shellcode")
       ]
       # here you can optionally define your own help function for getting help with your payload type's commands
       #async def command_help_function(self, msg: HelpFunctionMessage) -> HelpFunctionMessageResponse:
           #    return HelpFunctionMessageResponse(output=f"we did it!\nInput: {msg}", success=False)

        async def build(self) -> BuildResponse:
            # this function gets called to create an instance of your payload
            resp = BuildResponse(status=BuildStatus.Success)
            return resp
    ```

    There are a couple key pieces of information here:

    * line 6 defines the new class (our agent). This can be called whatever you want, but the important piece is that it extends the `PayloadType` class as shown with the `()`.
    * the rest defines the parameters for the payload type that you'd see throughout the UI.
      * the name is the name of the payload type
      * supported\_os is an array of supported OS versions
      * supports\_dynamic\_loading indicates if the agent allows you to select only a subset of commands when creating an agent or not
      * build\_parameters is an array describing all of the build parameters when creating your agent
      * c2\_profiles is an array of c2 profile names that the agent supports
      * c2\_parameter\_deviations allows you to modify the parameters of supported c2 profiles. In this case the apollo agent doesn't support GET requests (only POST), so we mark the `http` profile's GET parameters as unsupported.
      * the "translation container" is something we will talk about in another section, but this allows you to support your own, non-mythic message format, custom crypto, etc.
    * The last piece is the function that's called to **build** the agent based on all of the information the user provides from the web UI.

    The `PayloadType` base class is in the `PayloadBuilder.py` file. This is an abstract class, so your instance needs to provide values for all these fields.
  </Tab>

  <Tab title="Go">
    ```go theme={"system"}
    package agentfunctions

    import (
    	"bytes"
    	"encoding/json"
    	"fmt"
    	agentstructs "github.com/MythicMeta/MythicContainer/agent_structs"
    	"github.com/MythicMeta/MythicContainer/mythicrpc"
    	"os"
    	"os/exec"
    	"path/filepath"
    	"strings"
    )

    var payloadDefinition = agentstructs.PayloadType{
    	Name:                                   "basicAgent",
    	FileExtension:                          "bin",
    	Author:                                 "@xorrior, @djhohnstein, @Ne0nd0g, @its_a_feature_",
    	SupportedOS:                            []string{agentstructs.SUPPORTED_OS_LINUX, agentstructs.SUPPORTED_OS_MACOS},
    	Wrapper:                                false,
    	CanBeWrappedByTheFollowingPayloadTypes: []string{},
    	SupportsDynamicLoading:                 false,
    	Description:                            "A fully featured macOS and Linux Golang agent",
    	SupportedC2Profiles:                    []string{"http", "websocket", "poseidon_tcp"},
    	MythicEncryptsData:                     true,
    	BuildParameters: []agentstructs.BuildParameter{
    		{
    			Name:          "mode",
    			Description:   "Choose the build mode option. Select default for executables, c-shared for a .dylib or .so file, or c-archive for a .Zip containing C source code with an archive and header file",
    			Required:      false,
    			DefaultValue:  "default",
    			Choices:       []string{"default", "c-archive", "c-shared"},
    			ParameterType: agentstructs.BUILD_PARAMETER_TYPE_CHOOSE_ONE,
    		},
    		{
    			Name:          "architecture",
    			Description:   "Choose the agent's architecture",
    			Required:      false,
    			DefaultValue:  "AMD_x64",
    			Choices:       []string{"AMD_x64", "ARM_x64"},
    			ParameterType: agentstructs.BUILD_PARAMETER_TYPE_CHOOSE_ONE,
    		},
    		{
    			Name:          "proxy_bypass",
    			Description:   "Ignore HTTP proxy environment settings configured on the target host?",
    			Required:      false,
    			DefaultValue:  false,
    			ParameterType: agentstructs.BUILD_PARAMETER_TYPE_BOOLEAN,
    		},
    		{
    			Name:          "garble",
    			Description:   "Use Garble to obfuscate the output Go executable.\nWARNING - This significantly slows the agent build time.",
    			Required:      false,
    			DefaultValue:  false,
    			ParameterType: agentstructs.BUILD_PARAMETER_TYPE_BOOLEAN,
    		},
    	},
    	BuildSteps: []agentstructs.BuildStep{
    		{
    			Name:        "Configuring",
    			Description: "Cleaning up configuration values and generating the golang build command",
    		},

    		{
    			Name:        "Compiling",
    			Description: "Compiling the golang agent (maybe with obfuscation via garble)",
    		},
    	},
    }

    func build(payloadBuildMsg agentstructs.PayloadBuildMessage) agentstructs.PayloadBuildResponse {
    	payloadBuildResponse := agentstructs.PayloadBuildResponse{
    		PayloadUUID:        payloadBuildMsg.PayloadUUID,
    		Success:            true,
    		UpdatedCommandList: &payloadBuildMsg.CommandList,
    	}
    	return payloadBuildResponse
    }
    ```
  </Tab>
</Tabs>

### 1.1 Wrapper Payloads

A quick note about wrapper payload types - there's only a few differences between a wrapper payload type and a normal payload type. A configuration variable, `agent_type = AgentType.Wrapper`, determines if something is a wrapper or not. A wrapper payload type takes as input the output of a previous build (normal payload type or wrapper payload type) along with build parameters and generates a new payload. A wrapper payload type does NOT have any c2 profiles associated with it because it's simply wrapping an existing payload.

An easy example is thinking of the `service_wrapper` - this wrapper payload type takes in the shellcode version of another payload and "wraps" it in the execution of a service so that it'll properly respond to the service control manager on windows. A similar example would be to take an agent and wrap it in an MSBuild format. These things don't have their own C2, but rather just package/wrap an existing agent into a new, more generic, format.

<Tabs>
  <Tab title="Python">
    To access the payload that you're going to wrap, use the `self.wrapped_payload` attribute during your `build` execution. This will be the base64 encoded version of the payload you're going to wrap.
  </Tab>

  <Tab title="Go">
    To access the payload that you're going to wrap, use the `payloadBuildMsg.WrappedPayload` attribute during your `build` execution. This will be the raw bytes of the payload you're going to wrap. If you want to fetch more details about the payload that's wrapped, you can use the `payloadBuildMsg.WrappedPayloadUUID` and Mythic Scripting/MythicRPC
  </Tab>
</Tabs>

When you're done generating the payload, you'll return your new result the exact same way as normal payloads (as part of the [build](./#building) process).

## 2.0 Build Parameters

Build parameters define the components shown to the user when creating a payload. The `BuildParameter` class has a couple of pieces of information that you can use to customize and validate the parameters supplied to your build:

<Tabs>
  <Tab title="Python">
    ```python theme={"system"}
    class BuildParameterType(str, Enum):
        """Types of parameters available for building payloads

        Attributes:
            String:
                A string value
            ChooseOne:
                A list of choices for the user to select exactly one
            ChooseMultiple:
                A list of choices for the user to select 0 or more
            Array:
                The user can supply multiple values in an Array format
            Date:
                The user can select a Date in YYYY-MM-DD format
            Dictionary:
                The user can supply a dictionary of values
            Boolean:
                The user can toggle a switch for True/False
            File:
                The user can select a file that gets uploaded - a file UUID gets passed in during build
            TypedArray:
                The user can supply an array where each element also has a drop-down option of choices
        """
        String = "String"
        ChooseOne = "ChooseOne"
        ChooseMultiple = "ChooseMultiple"
        Array = "Array"
        Date = "Date"
        Dictionary = "Dictionary"
        Boolean = "Boolean"
        File = "File"
        TypedArray = "TypedArray"

    class BuildParameter:
        """Build Parameter Definition for use when generating payloads

        Attributes:
            name (str):
                Name of the parameter for scripting and for when building payloads
            description (str):
                Informative description displayed when building a payload
            default_value (any):
                Default value to pre-populate
            randomize (bool):
                Should this value be randomized (requires format_string)
            format_string (str):
                A regex used for randomizing values if randomize is true
            parameter_type (BuildParameterType):
                The type of parameter this is
            required (bool):
                Is this parameter required to have a non-empty value or not
            verifier_regex (str):
                Regex used to verify that the user typed something appropriate
            choices (list[str]):
                Choices for ChooseOne parameter type
            dictionary_choices (list[DictionaryChoice]):
                Configuration options for the Dictionary parameter type
            crypto_type (bool):
                Indicate if this value should be used to generate a crypto key or not
            group_name (str):
                An optional name used to group parameters together in the UI
            supported_os (list[str]):
                An optional list of supported operating systems where this parameter applies
            hide_conditions (list[HideCondition]):
                An optional list of conditions where this parameter should be hidden from view (this is a series of OR not AND conditions)
        """

        def __init__(
                self,
                name: str,
                parameter_type: BuildParameterType = None,
                description: str = None,
                required: bool = None,
                randomize: bool = None,
                format_string: str = "",
                crypto_type: bool = False,
                verifier_regex: str = None,
                default_value: any = None,
                choices: list[str] = None,
                dictionary_choices: list[DictionaryChoice] = None,
                value: any = None,
                verifier_func: callable = None,
                group_name: str = None,
                supported_os: list[str] = None,
                hide_conditions: list[HideCondition] = None,
        ):
            self.name = name
            self.verifier_func = verifier_func
            self.parameter_type = (
                parameter_type if parameter_type is not None else BuildParameterType.String
            )
            self.description = description if description is not None else ""
            self.required = required if required is not None else True
            self.verifier_regex = verifier_regex if verifier_regex is not None else ""
            self.default_value = default_value
            if value is None:
                self.value = default_value
            else:
                self.value = value
            self.choices = choices
            self.dictionary_choices = dictionary_choices
            self.crypto_type = crypto_type
            self.randomize = randomize
            self.format_string = format_string
            self.group_name = group_name
            self.supported_os = supported_os
            self.hide_conditions = hide_conditions

        def to_json(self):
            return {
                "name": self.name,
                "description": self.description,
                "default_value": self.default_value,
                "randomize": self.randomize,
                "format_string": self.format_string,
                "required": self.required,
                "parameter_type": self.parameter_type.value,
                "verifier_regex": self.verifier_regex,
                "crypto_type": self.crypto_type,
                "choices": self.choices,
                "dictionary_choices": [x.to_json() for x in
                                       self.dictionary_choices] if self.dictionary_choices is not None else None,
                "group_name": self.group_name,
                "supported_os": self.supported_os,
                "hide_conditions": [x.to_json() for x in self.hide_conditions] if self.hide_conditions is not None else None
            }

        def __str__(self):
            return json.dumps(self.to_json(), sort_keys=True, indent=2)
    ```
  </Tab>

  <Tab title="Go">
    ```go theme={"system"}
    type BuildParameterType = string

    const (
       BUILD_PARAMETER_TYPE_STRING          BuildParameterType = "String"
       BUILD_PARAMETER_TYPE_BOOLEAN                            = "Boolean"
       BUILD_PARAMETER_TYPE_CHOOSE_ONE                         = "ChooseOne"
       BUILD_PARAMETER_TYPE_CHOOSE_ONE_CUSTOM                  = "ChooseOneCustom"
       BUILD_PARAMETER_TYPE_CHOOSE_MULTIPLE                    = "ChooseMultiple"
       BUILD_PARAMETER_TYPE_DATE                               = "Date"
       BUILD_PARAMETER_TYPE_DICTIONARY                         = "Dictionary"
       BUILD_PARAMETER_TYPE_ARRAY                              = "Array"
       BUILD_PARAMETER_TYPE_NUMBER                             = "Number"
       BUILD_PARAMETER_TYPE_FILE                               = "File"
       BUILD_PARAMETER_TYPE_TYPED_ARRAY                        = "TypedArray"
    )

    // BuildParameter - A structure defining the metadata about a build parameter for the user to select when building a payload.
    type BuildParameter struct {
    	// Name - the name of the build parameter for use during the Payload Type's build function
    	Name string `json:"name"`
    	// Description - the description of the build parameter to be presented to the user during build
    	Description string `json:"description"`
    	// Required - indicate if this requires the user to supply a value or not
    	Required bool `json:"required"`
    	// VerifierRegex - if the user is supplying text and it needs to match a specific pattern, specify a regex pattern here and the UI will indicate to the user if the value is valid or not
    	VerifierRegex string `json:"verifier_regex"`
    	// DefaultValue - A default value to show the user when building in the Mythic UI. The type here depends on the Parameter Type - ex: for a String, supply a string. For an array, provide an array
    	DefaultValue interface{} `json:"default_value"`
    	// ParameterType - The type of parameter this is so that the UI can properly render components for the user to modify
    	ParameterType BuildParameterType `json:"parameter_type"`
    	// FormatString - If Randomize is true, this regex format string is used to generate a value when presenting the option to the user
    	FormatString string `json:"format_string"`
    	// Randomize - Should this value be randomized each time it's shown to the user so that each payload has a different value
    	Randomize bool `json:"randomize"`
    	// IsCryptoType -If this is True, then the value supplied by the user is for determining the _kind_ of crypto keys to generate (if any) and the resulting stored value in the database is a dictionary composed of the user's selected and an enc_key and dec_key value
    	IsCryptoType bool `json:"crypto_type"`
    	// Choices - If the ParameterType is ChooseOne or ChooseMultiple, then the options presented to the user are here.
    	Choices []string `json:"choices"`
    	// DictionaryChoices - if the ParameterType is Dictionary, then the dictionary choices/preconfigured data is set here
    	DictionaryChoices []BuildParameterDictionary    `json:"dictionary_choices"`
    	GroupName         string                        `json:"group_name"`
    	SupportedOS       []string                      `json:"supported_os"`
    	HideConditions    []BuildParameterHideCondition `json:"hide_conditions"`
    }
    ```
  </Tab>
</Tabs>

* `name` is the name of the parameter, if you don't provide a longer description, then this is what's presented to the user when building your payload
* `parameter_type` describes what is presented to the user - valid types are:
  * `BuildParameterType.String`
    * During build, this is a string
  * `BuildParameterType.ChooseOne`
    * During build, this is a string
  * `BuildParameterType.ChooseOneCustom`
    * During build, this is a string
  * `BuildParameterType.ChooseMultiple`
    * During build, this is an array of strings
  * `BuildParameterType.Array`
    * During build, this is an array of strings
  * `BuildParameterType.Date`
    * During build, this is a string of the format `YYYY-MM-DD`
  * `BuildParameterType.Dictionary`
    * During build, this is a dictionary
  * `BuildParameterType.Boolean`
    * During build, this is a boolean
  * `BuildParameterType.File`
    * During build, this is a string UUID of the file (so that you can use a MythicRPC call to fetch the contents of the file)
  * `BuildParameterType.TypedArray`
    * During build, this is an arrray of arrays, always in the format `[ [ type, value], [type value], [type, value] ...]`
* `required` indicates if there must be a value supplied. If no value is supplied by the user and no default value supplied here, then an exception is thrown before execution gets to the `build` function
* `verifier_regex` is a regex the web UI can use to provide some information to the user about if they're providing a valid value or not
* `default_value` is the default value used for building if the user doesn't supply anything
* `choices` is where you can supply an array of options for the user to pick from if the parameter\_type is ChooseOne
* `dictionary_choice`s are the choices and metadata about what to display to the user for key-value pairs that the user might need to supply
* `value` is the component you access when building your payload - this is the final value (either the default value or the value the user supplied)
* `verifier_func` is a function you can provide for additional checks on the value the user supplies to make sure it's what you want. This function should either return nothing or raise an exception if something isn't right

## 3.0 Building

You have to implement the `build` function and return an instance of the `BuildResponse` class. This response has these fields:

* `status` - an instance of BuildStatus (Success or Error)
  * Specifically, `BuildStatus.Success` or `BuildStatus.Error`
* `payload` - the raw bytes of the finished payload (if you failed to build, set this to `None` or empty bytes like `b''` in Python.
* `build_message` - any stdout data you want the user to see
* `build_stderr` - any stderr data you want the user to see
* `build_stdout` - any stdout data you want the user to see
* `updated_filename` - if you want to update the filename to something more appropriate, set it here
  * For example: the user supplied a filename of `apollo.exe` but based on the build parameters, you're actually generating a dll, so you can update the filename to be `apollo.dll`. This is particularly useful if you're optionally returning a zip of information so that the user doesn't have to change the filename before downloading. If you plan on doing this to update the filename for a wide variety of options, then it might be best to leave the file extension field in your payload type definition blank `""` so that you can more easily adjust the extension.
* `updated_command_list` - if you want to adjust the list of commands that are included by default in the payload - this is helpful if you need to include extra commands or dependencies based on what the user selected.
  The most basic version of the build function would be:

<Tabs>
  <Tab title="Python">
    ```python theme={"system"}
    async def build(self) -> BuildResponse:
            # this function gets called to create an instance of your payload
            return BuildResponse(status=BuildStatus.Success)
    ```
  </Tab>

  <Tab title="Go">
    ```go theme={"system"}
    func build(payloadBuildMsg agentstructs.PayloadBuildMessage) agentstructs.PayloadBuildResponse {
    	payloadBuildResponse := agentstructs.PayloadBuildResponse{
    		PayloadUUID:        payloadBuildMsg.PayloadUUID,
    		Success:            true,
    	}
    	return payloadBuildResponse
    }
    ```
  </Tab>
</Tabs>

Once the `build` function is called, all of your `BuildParameters` will already be verified (all parameters marked as `required` will have a `value` of some form (user supplied or default\_value) and all of the verifier functions will be called if they exist). This allows you to *know* that by the time your `build` function is called that all of your parameters are valid.
Your build function gets a few pieces of information to help you build the agent (other than the build parameters):
From within your build function, you'll have access to the following pieces of information:

<Tabs>
  <Tab title="Python">
    * `self.uuid` - the UUID associated with your payload
      * This is how your payload identifies itself to Mythic before getting a new Staging and final Callback UUID
    * `self.commands` - a wrapper class around the names of all the commands the user selected.
      * Access this list via `self.commands.get_commands()`

    ```python theme={"system"}
    for cmd in self.commands.get_commands():
        command_code += open(self.agent_code_path / "{}.js".format(cmd), 'r').read() + "\n"
    ```

    * `self.agent_code_path` - a `pathlib.Path` object pointing to the path of the `agent_code` directory that holds all the code for your payload. This is something you pre-define as part of your agent definition.
      * To access "test.js" in that "agent\_code" folder, simply do:\
        `f = open(self.agent_code_path / "test.js", 'r')`.
      * With `pathlib.Path` objects, the `/` operator allows you to concatenate paths in an OS agnostic manner. This is the recommended way to access files so that your code can work anywhere.
    * `self.get_parameter("parameter name here")`
      * The build parameters that are validated from the user. If you have a build\_parameter with a name of "version", you can access the user supplied or default value with `self.get_parameter("version")`
    * `self.selected_os` - This is the OS that was selected on the first step of creating a payload
    * `self.c2info` - this holds a list of dictionaries of the c2 parameters and c2 class information supplied by the user. This is a list because the user can select multiple c2 profiles (maybe they want HTTP and SMB in the payload for example). For each element in self.c2info, you can access the information about the c2 profile with `get_c2profile()` and access to the parameters via `get_parameters_dict()`. Both of these return a dictionary of key-value pairs.
      * the dictionary returned by `self.c2info[0].get_c2profile()` contains the following:
        * `name` - name of the c2 profile
        * `description` - description of the profile
        * `is_p2p` - boolean of if the profile is marked as a p2p profile or not
      * the dictionary returned by `self.c2info[0].get_parameters_dict()`contains the following:
        * `key` - value
          * where each `key` is the `key` value defined for the c2 profile's parameters and `value` is what the user supplied. You might be wondering where to get these keys? Well, it's not too crazy and you can view them right in the UI - [Name Fields](broken-reference).
          * If the C2 parameter has a value of `crypto_type=True`, then the "value" here will be a bit more than just a string that the user supplied. Instead, it'll be a dictionary with three pieces of information: `value` - the value that the user supplied, `enc_key` - a base64 string (or None) of the encryption key to be used, `dec_key` - a base64 string (or None) of the decryption key to be used. This gives you more flexibility in automatically generating encryption/decryption keys and supporting crypto types/schemas that Mythic isn't aware of. In the HTTP profile, the key `AESPSK` has this type set to True, so you'd expect that dictionary.
          * If the C2 parameter has a type of "Dictionary", then things are a little different.&#x20;
            * Let's take the "headers" parameter in the `http` profile for example. This allows you to set header values for your `http` traffic such as User-Agent, Host, and more. When you get this value on the agent side, you get an array of values that look like the following:\
              `{"User-Agent": "the user agent the user supplied", "MyCustomHeader": "my custom value"}`. You get the final "dictionary" that's created from the user supplied fields.
    * One way to leverage this could be:

    ```python theme={"system"}
    for c2 in self.c2info:
        c2_code = ""
        try:
            profile = c2.get_c2profile()
            c2_code = open(
                self.agent_code_path
                / "c2_profiles"
                / "{}.js".format(profile["name"]),
                "r",
            ).read()
            for key, val in c2.get_parameters_dict().items():
                if key == "AESPSK":
                    c2_code = c2_code.replace(key, val["enc_key"] if val["enc_key"] is not None else "")
                elif not isinstance(val, str):
                    c2_code = c2_code.replace(key, json.dumps(val))
                else:
                    c2_code = c2_code.replace(key, val)
        except Exception as p:
            build_msg += str(p)
            pass
    ```
  </Tab>

  <Tab title="Go">
    ```go theme={"system"}
    // PayloadBuildMessage - A structure of the build information the user provided to generate an instance of the payload type.
    // This information gets passed to your payload type's build function.
    type PayloadBuildMessage struct {
    	// PayloadType - the name of the payload type for the build
    	PayloadType string `json:"payload_type" mapstructure:"payload_type"`
    	// Filename - the name of the file the user originally supplied for this build
    	Filename string `json:"filename" mapstructure:"filename"`
    	// CommandList - the list of commands the user selected to include in the build
    	CommandList []string `json:"commands" mapstructure:"commands"`
    	// build param name : build value
    	// BuildParameters - map of param name -> build value from the user for the build parameters defined
    	// File type build parameters are supplied as a string UUID to use with MythicRPC for fetching file contents
    	// Array type build parameters are supplied as []string{}
    	BuildParameters PayloadBuildArguments `json:"build_parameters" mapstructure:"build_parameters"`
    	// C2Profiles - list of C2 profiles selected to include in the payload and their associated parameters
    	C2Profiles []PayloadBuildC2Profile `json:"c2profiles" mapstructure:"c2profiles"`
    	// WrappedPayload - bytes of the wrapped payload if one exists
    	WrappedPayload *[]byte `json:"wrapped_payload,omitempty" mapstructure:"wrapped_payload"`
    	// WrappedPayloadUUID - the UUID of the wrapped payload if one exists
    	WrappedPayloadUUID *string `json:"wrapped_payload_uuid,omitempty" mapstructure:"wrapped_payload_uuid"`
    	// SelectedOS - the operating system the user selected when building the agent
    	SelectedOS string `json:"selected_os" mapstructure:"selected_os"`
    	// PayloadUUID - the Mythic generated UUID for this payload instance
    	PayloadUUID string `json:"uuid" mapstructure:"uuid"`
    	// PayloadFileUUID - The Mythic generated File UUID associated with this payload
    	PayloadFileUUID string `json:"payload_file_uuid" mapstructure:"payload_file_uuid"`
    }
    ```
  </Tab>
</Tabs>

Depending on the status of your build (success or error), either the message or build\_stderr values will be presented to the user via the UI notifications. However, at any time you can go back to the Created Payloads page and view the build message, build errors, and build stdout for any payload.

<Info>
  When building your payload, if you have to modify files on disk, then it's helpful to do this in a "copy" of the files. You can make a temporary copy of your code and operate there with the following sample:

  ```python theme={"system"}
  agent_build_path = tempfile.TemporaryDirectory(suffix=self.uuid)
  # shutil to copy payload files over
  copy_tree(self.agent_code_path, agent_build_path.name)
  # now agent_build_path.name maps to the root folder for your agent code
  ```
</Info>

### 3.1 Build Steps

The last thing to mention are build steps. These are defined as part of the agent and are simply descriptions of what is happening during your build process. The above example makes some RPC calls for `SendMythicRPCPayloadUpdatebuildStep` to update the build steps back to Mythic while the build process is happening. For something as fast as the `apfell` agent, it'll appear as though all of these happen at the same time. For something that's more computationally intensive though, it's helpful to provide information back to the user about what's going on - stamping in values? obfuscating? compiling? more obfuscation? opsec checks? etc. Whatever it is that's going on, you can provide this data back to the operator complete with stdout and stderr.

### 3.2 Execution flow

So, what's the actual, end-to-end execution flow that goes on? A diagram can be found here: [#what-happens-for-building-payloads](../../../message-flow/#what-happens-for-building-payloads "mention").

1. PayloadType container is started, it connects to Mythic and sends over its data (by parsing all these python files or GoLang structs)
2. An operator wants to create a payload from it, so they click the hazard icon at the top of Mythic, click the "Actions" dropdown and select "Generate New Payload".
3. The operator selects an OS type that the agent supports (ex. Linux, macOS, Windows)
4. The operator selects the payload type they want to build (this one)
   1. edits all build parameters as needed
5. The operator selects all commands they want included in the payload
6. The operator selects all c2 profiles they want included
   1. and for each c2 selected, provides any c2 required parameters
7. Mythic takes all of this information and sends it to the payload type container
8. The container sends the `BuildResponse` message back to the Mythic server.

## 4.0 On New Callback

Starting with Mythic v3.2.12, PyPi version 0.4.1, and MythicContainer version 1.3.1, there's a new function you can define as part of your Payload Type definition. In addition to defining a `build` process, you can also define a `on_new_callback` (or `onNewCallbackFunction`) function that will get executed whenever there's a new callback based on this payload type.&#x20;

Below are examples in Python and in Golang for how to define and leverage this new functionality. One of the great things about this is that you can use this to automatically issue tasking for new callbacks. The below examples will automatically issue a `shell` command with parameters of `whoami`.

These function calls get almost all the same data that you'll see in your [Create Tasking](../create_tasking/#create-tasking) calls, except they're missing information about a `Task`. That's simply because there's no task yet, this is the moment that a new callback is created.

<Warning>
  Mythic tracks an operator for all issued tasking. Since there's no operator directly typing out and issuing these tasks, Mythic associates the operator that built the payload with any tasks automatically created in this function.
</Warning>

<Tabs>
  <Tab title="Python">
    ```python theme={"system"}
    class Apfell(PayloadType):
        name = "apfell"
        ...
        async def build ...

        async def on_new_callback(self, newCallback: PTOnNewCallbackAllData) -> PTOnNewCallbackResponse:
                new_task_resp = await SendMythicRPCTaskCreate(MythicRPCTaskCreateMessage(
                    AgentCallbackUUID=newCallback.Callback.AgentCallbackID,
                    CommandName="shell",
                    Params="whoami",
                ))
                if new_task_resp.Success:
                    return PTOnNewCallbackResponse(AgentCallbackUUID=newCallback.Callback.AgentCallbackID, Success=True)
                return PTOnNewCallbackResponse(AgentCallbackUUID=newCallback.Callback.AgentCallbackID, Success=False,
                                               Error=new_task_resp.Error)
    ```
  </Tab>

  <Tab title="Go">
    ```go theme={"system"}
    func onNewBuild(data agentstructs.PTOnNewCallbackAllData) agentstructs.PTOnNewCallbackResponse {
        newTasking, err := mythicrpc.SendMythicRPCTaskCreate(mythicrpc.MythicRPCTaskCreateMessage{
    		AgentCallbackID: data.Callback.AgentCallbackID,
    		CommandName:     "shell",
    		Params:          "whoami",
    	})
    	if err != nil {
    		logging.LogError(err, "failed to create new task")
    	}
    	if newTasking.Success {
    		logging.LogInfo("created new task")
    	} else {
    		logging.LogError(err, "failed to create new tasking")
    	}
    	return agentstructs.PTOnNewCallbackResponse{
    		AgentCallbackID: data.Callback.AgentCallbackID,
    		Success:         true,
    		Error:           "",
    	}
    }
    func Initialize() {
    	agentstructs.AllPayloadData.Get("poseidon").AddPayloadDefinition(payloadDefinition)
    	agentstructs.AllPayloadData.Get("poseidon").AddBuildFunction(build)
    	agentstructs.AllPayloadData.Get("poseidon").AddOnNewCallbackFunction(onNewBuild)
    	agentstructs.AllPayloadData.Get("poseidon").AddIcon(filepath.Join(".", "poseidon", "agentfunctions", "poseidon.svg"))
    }
    ```
  </Tab>
</Tabs>

## 5.0 CustomRPCFunctions

Payload types have an optional field that can be defined:

<Tabs>
  <Tab title="Python">
    ```python theme={"system"}
    class PTOtherServiceRPCMessage:
        """Request to call an RPC function of another C2 Profile or Payload Type

        Attributes:
            ServiceName (str): Name of the C2 Profile or Payload Type
            ServiceRPCFunction (str): Name of the function to call
            ServiceRPCFunctionArguments (dict): Arguments to that function

        Functions:
            to_json(self): return dictionary form of class
        """

        def __init__(self,
                     ServiceName: str = None,
                     service_name: str = None,
                     ServiceRPCFunction: str = None,
                     service_function: str = None,
                     ServiceRPCFunctionArguments: dict = None,
                     service_arguments: dict = None,
                     **kwargs):
            self.ServiceName = ServiceName
            if self.ServiceName is None:
                self.ServiceName = service_name
            self.ServiceRPCFunction = ServiceRPCFunction
            if self.ServiceRPCFunction is None:
                self.ServiceRPCFunction = service_function
            self.ServiceRPCFunctionArguments = ServiceRPCFunctionArguments
            if self.ServiceRPCFunctionArguments is None:
                self.ServiceRPCFunctionArguments = service_arguments
            for k, v in kwargs.items():
                logger.error(f"unknown kwarg {k} {v}")

        def to_json(self):
            return {
                "service_name": self.ServiceName,
                "service_function": self.ServiceRPCFunction,
                "service_arguments": self.ServiceRPCFunctionArguments
            }

        def __str__(self):
            return json.dumps(self.to_json(), sort_keys=True, indent=2)


    class PTOtherServiceRPCMessageResponse:
        """Result of running an RPC call from another service

        Attributes:
            Success (bool): Did the RPC succeed or fail
            Error (str): Error message if the RPC check failed
            Result (dict): Result from the RPC

        Functions:
            to_json(self): return dictionary form of class
        """

        def __init__(self,
                     success: bool = None,
                     error: str = None,
                     result: dict = None,
                     Success: bool = None,
                     Error: str = None,
                     Result: dict = None,
                     **kwargs):
            self.Success = Success
            if self.Success is None:
                self.Success = success
            self.Error = Error
            if self.Error is None:
                self.Error = error
            self.Result = Result
            if self.Result is None:
                self.Result = result
            for k, v in kwargs.items():
                logger.error(f"unknown kwarg {k} {v}")

        def to_json(self):
            return {
                "success": self.Success,
                "error": self.Error,
                "result": self.Result
            }

        def __str__(self):
            return json.dumps(self.to_json(), sort_keys=True, indent=2)
    custom_rpc_functions: dict[
            str, Callable[[PTOtherServiceRPCMessage], Awaitable[PTOtherServiceRPCMessageResponse]]] = {}
    ```
  </Tab>

  <Tab title="Go">
    ```go theme={"system"}
    // PTRPCOtherServiceRPCMessage - A message to call RPC functionality exposed by another Payload Type or C2 Profile
    type PTRPCOtherServiceRPCMessage struct {
    	// Name - The name of the remote Payload type or C2 Profile
    	Name string `json:"service_name"` //required
    	// RPCFunction - The name of the function to call for that remote service
    	RPCFunction string `json:"service_function"`
    	// RPCFunctionArguments - A map of arguments to supply to that remote function
    	RPCFunctionArguments map[string]interface{} `json:"service_arguments"`
    }

    // PTRPCOtherServiceRPCMessageResponse - The result of calling RPC functionality exposed by another Payload Type or C2 Profile
    type PTRPCOtherServiceRPCMessageResponse struct {
    	// Success - An indicator if the call was successful or not
    	Success bool `json:"success"`
    	// Error - If the call was unsuccessful, this is an error message about what happened
    	Error string `json:"error"`
    	// Result - The result returned by the remote service
    	Result map[string]interface{} `json:"result"`
    }
    CustomRPCFunctions map[string]func(message PTRPCOtherServiceRPCMessage) PTRPCOtherServiceRPCMessageResponse `json:"-"`
    ```
  </Tab>
</Tabs>

This dictionary of functions is a way for a Payload Type/C2 Profile to define custom RPC functions that are callable from other containers.
This can be particularly handy if you have a Payload Build function that needs to ask a C2 Profile to configure something in a specific way on its behalf. The same thing also applies to C2 Profiles - C2 Profiles can ask Payload Type containers to do things.&#x20;

The definitions are particularly vague in the arguments needed (ex: a generic dictionary/map) because it's up to the function to define what is needed.
