Skip to content

I. Creating Output Modules

s0lst1c3 edited this page Nov 16, 2020 · 5 revisions

Output modules are a bit more complicated than input modules, since they consist of a template file as well as Python class file. The template file is a templatized block of code that is rendered and mutated during the payload creation file. The Python file contains all of the information needed by DropEngine to successfully render and mutate the template file.

This section will begin by describing how to create an output module by hand from a piece of CSharp code. We'll then demonstrate how to automate this process using DropEngine's Module Maker.

Creating Output Modules by Hand

To understand how this process works, it’s best to go over how to create an output module from scratch. In this example, we’ll create a decryption key (or DKey) module from a piece of CSharp code.

Creating the Template File

We begin with the following block of CSharp code, which simply returns a static decryption key.

public class DKey
{
    public static string Generate()
    {
        byte[] dkey = { 0, 0, 0, 25 };

        return Encoding.UTF8.GetString(dkey);
    }
}

The first thing we need to do is convert this block of code into a Jinja template. If you’re not familiar with Jinja, check out this guide here:

For symbolic substitution to work, we need to provide DropEngine with a way of keeping track of symbol names in this file. We do this using the follow steps.

Step 1: Convert master class name to Jinja variable

The first thing we do is substitute the name of our class with the Jinja variable special[‘class_name’], as shown in the example below.

using System;

public class {{ special['class_name'] }}
{
    public static string Generate()
    {
        byte[] dkey = { 0, 0, 0, 25 };

        return Encoding.UTF8.GetString(dkey);
    }
}

Step 2: Convert entry-point function name to Jinja variable

Next, we substitute the name of our entry-point function with the Jinja variable func_name, as shown in the next example.

using System;

public class {{ special['class_name'] }}
{
    public static string {{ func_name }}()
    {
        byte[] dkey = { 0, 0, 0, 25 };

        return Encoding.UTF8.GetString(dkey);
    }
}

Step 3: Wrap remaining symbols in Jinja variables

Next, we substitute all remaining symbols with the Jinja variable v[‘$SYMBOL’], where $SYMBOL is the name of symbol we are wrapping.

using System;

public class {{ special['class_name'] }}
{
    public static string {{ func_name }}()
    {
        byte[] {{ v['dkey'] }} = {{ special['ekey_data']['val_array'] }};

        return Encoding.UTF8.GetString({{ v['dkey'] }});
    }
}

Step 4: Remove all import statements

Finally, we remove the modules imports from the template. Save the list of imports – you’ll need them when you create the Module Class Definition in the next section.

using System;

public class {{ special['class_name'] }}
{
    public static string {{ func_name }}()
    {
        byte[] {{ v['dkey'] }} = {{ special['ekey_data']['val_array'] }};

        return Encoding.UTF8.GetString({{ v['dkey'] }});
    }
}

Step 5: Place template in its appropriate folder

Finally, place the resulting template file in the appropriate subdirectory of DropEngine's templates directory.

Creating the Module Class Definition

We now have a completed Jinja template file. Next, we need to create the module class definition. We begin with the following template:

import json
import config

from base.output.example.csharp_example import CSharpExample

class MExample(CSharpExample):

    def __init__(self):     

        super().__init__()

        self.name = ''
        self.mtype = ''
        self.author = ''
        self.description = ''

        self.compatible_interfaces = [

            'csharp_runner_interface',
        ]
        self.compatible_imodules = [

            'ekey_static',
        ]

        self.functions = []
        self._vars = [

            'dkey',
        ]
        self.comments = []
        self.whitespaces = []

        self.imports = []

        self.template = ''

        self.func_name = ''
        self.class_name = ''

        self.mutate_func_name = True
        self.mutate_class_name = True

To create your Module Class Definition, you’ll need to perform the following steps.

Step 1: Add list of symbol names

Remember the list of symbol names that you wrapped with Jinja variables when you built the module template? DropEngine needs them to render your module into a payload component. Edit the template by adding these symbol names to as strings within self._vars list as shown below.

import json
import config

from base.output.example.csharp_example import CSharpExample

class MExample(CSharpExample):

    def __init__(self):     

        super().__init__()

#...snip...

        self._vars = [

            'dkey',
        ]
#...snip...

Step 2: Add class name and entry-point function name

You’ll want to add the original class and entry-point function names to the self.class_name and self.func_name attributes, respectively (see the example below).

import json
import config

from base.output.example.csharp_example import CSharpExample

class MExample(CSharpExample):

    def __init__(self):     

        super().__init__()
#...snip...

        self.func_name = 'generate'
        self.class_name = 'DKey'
#...snip...

Step 3: Add path to template file

You’ll want to specify the path to your template file (you should place the template file in one of the subdirectories of DropEngine’s template folder). You can do this by editing the value of the self.template attribute.

import json
import config

from base.output.example.csharp_example import CSharpExample

class MExample(CSharpExample):

    def __init__(self):     

        super().__init__()
#...snip...

        self.template = 'dkeys/dkey_csharp_static.cs'

#...snip...

Step 4: Specify whether to mutate class and function name

If you don’t want the class or function name to be mutated, you’ll need to change the values of self.mutate_func_name and self.mutate_class_name as shown below.

import json
import config

from base.output.example.csharp_example import CSharpExample

class MExample(CSharpExample):

    def __init__(self):     

        super().__init__()
#...snip...

        self.mutate_func_name = True
        self.mutate_class_name = True

#...snip...

Step 5: Add list of imports

Remember the list of module imports that you removed from the template file? You need to add these as members of self.imports as shown below.

import json
import config

from base.output.example.csharp_example import CSharpExample

class MExample(CSharpExample):

    def __init__(self):     

        super().__init__()
#...snip...

        self.imports = [
            'System',
        ]

#...snip...

Step 6: Fill out module metadata

_fill in

Step 7: Modify class definition

fill in

Step 7: Modify parent class import

fill in

Step 8: Place Module Class Definition in its appropriate folder

fill in

Generating Output Modules Using Module Maker

Clone this wiki locally