-
Notifications
You must be signed in to change notification settings - Fork 28
I. Creating Output Modules
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.
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.
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.
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);
}
}
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);
}
}
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'] }});
}
}
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'] }});
}
}
Finally, place the resulting template file in the appropriate subdirectory of DropEngine's templates
directory.
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.
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...
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...
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...
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...
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...
_fill in
fill in
fill in
fill in