DC3-Kordesii is a framework for decoding encoded strings and files in malware via IDA Pro IDAPython scripting. One parser module is usually created per malware family. DC3-Kordesii was designed to ease the burden of encoded string extraction by doing it in an automated, static way as well as to provide a standard set of functionality and methodologies. DC3-Kordesii supports both an analyst directed analysis and large-scale automated executing, utilizing either the REST API, the CLI or by manually running decoders in IDA. DC3-Kordesii is authored by the Department of Defense Cyber Crime Center (DC3).
DC3-Kordesii requires the following:
- Windows
- python 2.7 (32 bit)
- IDA Pro 7.* (tested with 7.0)
- (optional) Hex Ray's Decompiler for x86/x64 architectures
- (Used to improve accuracy of getting function arguments in
function_tracingutils
)
- (Used to improve accuracy of getting function arguments in
The following modules are recommended as they are often used in decoders:
- pyCrypto
pip install kordesii
Alternatively you can clone this repo and install locally.
git clone https://github.com/Defense-Cyber-Crime-Center/kordesii.git
pip install ./kordesii
For a development mode use the -e
flag to install in editable mode:
git clone https://github.com/Defense-Cyber-Crime-Center/kordesii.git
pip install -e ./kordesii
To make a decoder available for use, place it a directory with the name <name>_StringDecoder.py
Then pass the directory containing your decoders through the command line.
kordesii --decoderdir=C:\my_decoders -p <name> <input_file>
If no decoder directory is specified it will default to the decoder directory that comes with this python package, which will be located in the site-packages. (e.g. C:\Python27\Lib\site-packages\kordesii\decoders)
DC3-Kordesii is designed to standardize automation of a task typically done by one-off scripts.
Most automated processing systems will use a condition, such as a YARA signature match, to trigger execution of a particular DC3-Kordesii decoder.
There are 2 options for integration of DC3-Kordesii:
- REST API based on wsgi/bottle:
kordesii-server
,kordesii-client
- CLI:
kordesii
DC3-Kordesii also includes a utility for test case execution: kordesii-test
The REST API provides two commonly used functions:
/run_decoder/<decoder>
-- executes a decoder on uploaded file/descriptions
-- provides list of available parsers
kordesii-client
and the following curl commands demonstrate how to use this web service:
curl --form data=@README.md http://localhost:8080/run_decoder/foo
curl http://localhost:8080/descriptions
bottle (bottlepy.org) is required for the server. The bottle provided web server or another wsgi can be used.
kordesii-tool provides functionality to run decoders on files:
kordesii -p foo README.md
see kordesii -h
for full set of options
The high level steps for module development are:
- Create new
<your decoder directory>\<name>_StringDecoder.py
module - Add the following stub to the bottom of the module (where
main
is the entry point)
if __name__ == '__main__':
idc.Wait()
main()
if 'exit' in idc.ARGV:
idc.Exit(0)
- When possible, subclass
StringTracer
and implement its search method - When necessary, subclass
EncodedString
sample_StringDecoder.py
is provided as an example and may be used as a template.
stack_string_StringDecoder.py
is provided as an example of how to traverse IDA's disassembly via IDAPython.
DC3-Kordesii includes an experimental tracing utility called function_tracingutils
that can be used to statically emulate
and trace instructions within a function.
from kordesii.utils import function_tracingutils
# First create a tracer for the function
addr = 0x401839
tracer = function_tracingutils.FunctionTracer(addr)
# Request the context for a particular address (within the function) to retreive
# operands, register values and memory data.
context = tracer.context_at(addr)
operand_1 = context.get_operand_value(0, size=12)
rbp = context.reg_read("RBP")
stack = context.mem_read(rbp, size=0x14)
# Get function arguments for a call instruction.
for context, args in tracer.get_function_args(0x40147f):
for i, arg in enumerate(args):
print "Arg {} -> 0x{:X}".format(i, arg)
# If arg is a pointer, you can use the context to dereference it.
value = context.mem_read(arg, size=100)
# NOTE: context_at() and get_function_args() will return the results for the first code path.
# Use iter_context() and iter_function_args() respectively to get results for all possible paths.
for context in tracer.iter_context(addr):
# ...
WARNING: function_tracingutils
uses the Hex Ray's decompiler to
help get more accurate function signatures for the get_function_args()
.
You are more likely to get an incorrect number of arguments if it is not available.
- Use the functions in
decoderutils
andfunction_tracingutils
where possible - When
string_decoder_main
cannot be used, use as many of it's main 5 functions as is feasible yara_find_decode_functions
(andgeneric_run_yara
)find_encoded_strings
(andfind_encoded_strings_inline
)decode_strings
output_strings
- Document the tracing algorithm in plain text