This guide seeks to explain how to develop decoders for DC3-Kordesii.
To create a simple decoder the high level steps are:
- Install DC3-Kordesii
- If you plan to contribute your decoder back to DC3-Kordesii, you can install in "development" mode and place your decoder directly into DC3-Kordesii's "decoders" directory.
- If this is not an upstream contribution, create a directory or python package to store your parsers.
- It is recommended you create your decoder in your own Python project. (See Formal Packaging)
- Create a new python file in your decoder directory.
- The name of this file is usually the name of the malware family or method of extraction (e.g. "StackStrings")
- Add a docstring containing "Description:" and "Author:" entries. These will be used by the framework
when
kordesii list
is called.
"""
Description: Sample decoder
Author: DC3
"""
-
Import
kordesii
,kordesii.utils.decoderutils
and possiblykordesii.utils.function_tracing
-
Create a logger with
kordesii.get_logger()
- Use this logger to log any messages you would like to present back the user. Messages are passed back in semi-realtime through the use of sockets.
- It is a good idea to use logging to help inform the user on the progress of the decoder and if the decoder may need to be updated due to a new variant of the sample.
-
Decorate your entry point with
kordesii.decoder_entry
. This is the function that the framework will call on startup. (The framework will call idc.Wait() and other necessary IDA functions for you.)- WARNING: It is important that the function you wrap with
decoder_entry
is the last thing in the module. Anything declared after it will not be available when the decoder runs.
- WARNING: It is important that the function you wrap with
import kordesii
# DECODER CODE
@kordesii.decoder_entry
def main():
# ...
# DON'T ADD ANY CODE HERE!
-
Find and extract encrypted strings (and their keys).
- Identify points of interest using the regex or yara helpers found in
kordesii.utils.decoderutils
- Then trace to extract keys and decrypted strings
- If you can, use
kordesii.utils.function_tracing
to emulate your sample to help simplify code and make your decoder more flexible with new samples.
- If you can, use
- Use the logger to report success and failure messages as well as debug message to help a future developer looking at your code.
- Identify points of interest using the regex or yara helpers found in
-
Create
EncodedString
orEncodedStackString
objects from found strings and set the decrypted data into thedecoded_data
attribute. -
Call
publish()
on your generatedEncodedString
/EncodedStackString
objects to output the string and optionally patch or rename the string within the IDB.
"""
Description: Sample decoder
Author: DC3
"""
import kordesii
from kordesii.utils import EncodedString
from kordesii.utils import ida_re
from kordesii.utils import function_tracing
logger = kordesii.get_logger()
emulator = function_tracing.Emulator()
def xor_decrypt(key, enc_data):
return bytes((x ^ key) for x in enc_data)
def find_strings():
"""
Extracts and publishes EncodedString objects for the parameters following xor encryption function:
void encrypt(char *s, char key)
{
while (*s)
*s++ ^= key;
}
"""
for encrypt_func in ida_re.find_functions(br"\x8b\x45\x08\x0f\xbe\x08"):
logger.info("Found XOR encrypt function at: 0x%x", encrypt_func.start_ea)
for call_ea in encrypt_func.calls_to:
logger.debug("Tracing 0x%08x", call_ea)
# Extract arguments for call to xor function.
context, args = emulator.get_function_args(call_ea)
enc_str_ptr, key = args
encoded_string = EncodedString(enc_str_ptr, string_reference=call_ea, key=key)
encoded_string.decoded_data = xor_decrypt(key, encoded_string.encoded_data)
encoded_string.publish(rename=True, patch=False)
@kordesii.decoder_entry
def main():
"""
Finds xor encrypted strings then decrypts and outputs them.
"""
find_strings()