# Transforms

Malcat is first and foremost a static analysis tool aimed at inspectin malicious programs. Since malicious binaries often come obfuscated, it is often needed to decrypt, decompress and manipulate data in the program in order to uncover the most interesting parts of the malware. You would be surprised how fast and how far you can go with a purely static approach in malware analysis.

Malcat embeds more than 60 algorithms than you can use inside The transform dialog in order to deobfuscate arbitrary data buffers in the analyzed data. And since these algorithms (aka transforms) are written in Python, it is very easy to Writing your own transform operation!

In this chapter, we will see how to make the best use of the The transform dialog and see how you can extend Malcat by writing your own python transforms.

## The transform dialog

### Transforming selected bytes

The simplest way to transform data in Malcat is by Selecting any arbitrary data range from within the Hexadecimal view or the Structure/text view and hit ``Ctrl`+`T``. You can alternatively use the menu: Analysis ‣ Transform. You will then be greated by the transform dialog shown below:

The transform dialog

If you are familiar with the excellent CyberChef website, the interface should look somewhat familiar to you. If not, you can get an idea of its work flow by reading the rest of this chapter.

Note

The transform dialog is a modeless window: it means you can continue to use Malcat’s UI while it is open. This is convenient if you need to copy/paste decryption keys found inside the program for instance.

### List of operators / transforms

On the left, you have the list of available transform operations, taken from both Malcat’s Data directory structure and the User data directory. You can search/filter the list using the search box on the top left corner of the dialog. You can add new operations to the transform chain (middle panel) by either:

- double-clicking the name of an operation: it will be appended to the end of the chain

- drag and dropping the name of operation at the position of your choice inside the chain

Each transform has a small help text than can be consulted either in the info field (bottom left) or by hovering the `?` icon of the corresponding block. If this is not enough, you can consult the python code directly by clicking on the ``View/edit` `python` `file`` button located at the bottom of the left panel: the code will be displayed inside Malcat’s python editor. Transforms defined in Malcat’s `data/transforms` directory can only be viewed (the python editor will be read-only). Transform defined in the User data directory on the contrary can be edited and saved.

### Parameters

Each operation have an arbitrary amount of parameters than you can modify directly from within the middle panel using standard GUI controls. If Auto preview is checked (the default), every parameter change will trigger a new evaluation of the transform chain (after a few milliseconds).

You can disable this behavior by unchecking the Auto preview option located at the top of the dialog. This can be useful if you want to decrypt large amount of data using CPU-intensive operations: having the whole transform chain applied for every small change can then be more annoying than useful.

### Preview and confirmation

The color of each operation block gives you information on the status of the corresponding operation:

- a blue panel means the operation is either disabled or has not been run yet

- a green panel means the operation was successful

- a red panel means the operation has thrown an exception. Details about the exception can be found in the output window (bottom right)

If everything went right, the output window will display a preview of the result as an hexadecimal dump. If you are happy with the preview, you can either:

- Click on ``In` `place`` to replace your selection with the result of the transform chain. Note that this is only possible if the result is smaller or of the same size as the initial input. If the result is smaller, the selection will be padded with null bytes.

Note

Transforms are similar to other edits from a UI perspective. You can undo your changes to the file using ``Ctrl`-`Z`` if you wish so.

- Click on ``New` `file`` to open the result as a new file in Malcat. Note that you can Switch between files to go back and forth between the result and your initial file.

And that’s it. Feel free to experiment with the system. If you wish to create your own transform operations, proceed to the next chapter.

## Transform text in the source code view

A recent addition to Malcat is the ability to transform text from within the Source code / pure text viewer. It works for either pure-text files or script decompilation, and is pretty handy if you are facing source-code obfuscation. If you select any text in this view and then hit ``Ctrl`+`T`` (or use the transform button in the Source code / pure text viewer’s toolbar), you will be greeted with the same transform dialog. But since you are modifying text (and not bytes), there are a few minor differences to keep in mind:

- You will only be able to transform text in place: the selected text inside the Source code / pure text viewer will simply be replaced by the result of your transformed text

- Your input (aka the selected text) will be encoded to bytes using UTF-8 before being fed to the transform chain

- At the end of the transform chain, the output will be converted back to text using UTF-8. If your transform chain did not produce UTF-8 text, an error will be risen

Beside this three limitations, you’ll have access to the complete list of transform operators. Don’t hesitate to Contact us if you have any feedback on this feature: it is still in beta and we are happy to improve it as needed.

## Writing your own transform operation

Malcat has a lot of Customisation options, and transforms are no exception. Using python, it is very easy to add your own transform as you will see below.

### Using the user code transform

If you do not find what you want in Malcat’s embedded transform operators, the easiest way is to use the custom user code operator. This is a simple operator that let you write your own transformation in python using Malcat’s integrated python editor:

Using the custom python transform operator

For small one-shot operations, this is the way to go. But if you want to program something you’ll be able to reuse in the future, you are better off creating a custom operator.

### Creating a custom transform

#### Creating the operator

If you have setup a User data directory, you can create python (.py) files in the `transforms/` subdirectory of the user directory. These files will be imported dynamically every time the transform dialog is shown. Each python file in this directory can contain one or more transform operators. A transform operator is simply defined as a class inheriting `transforms.base.Transform`. Each transform operator must respect the following constraints:

- It needs to have a `category` class variable (string): this will tell Malcat in which folder to put your new transform operator. Try to reuse an existing folder if it fits. If you leave it blank, your transform will be put at the root of the operators tree.

- It needs to have a `name` class variable (string): this will be the name of your operator inside the transform dialog.

- It needs to implement a `run()` method:

  > - The first parameter of this method (after `self`) is fixed and will be the input buffer (type: `bytes`)

  > - It can accept an arbitrary amount of additional Parameters. Each parameter needs to be annotated with a type and a default value

  > - It needs to return either a `bytes` or `bytearray` object: this will be the output of your transform operator

And that’s it! Malcat will take care of the rest and automatically create the GUI elements for your transform using python introspection. You can find below an small example shipped with Malcat: the bzip2 compression operator:

    from transforms.base import Transform
    import bz2

    class Bzip2Compress(Transform):
    # documentation/ help text shown in the transform dialog:
    """
    Compress a stream using bzip2
    level: compression level between 1 and 9
    """
    category = "compress"               # <-- will be put under this folder in the transform dialog
    name = "bz2 compress"               # <-- name shown in the transform dialog

    # the only method you have to implement is run():
    def run(self, data:bytes, level:int=9):
        if level < 1 or level > 9:
            raise ValueError("Invalid level value")
        return bz2.compress(data, level)

#### Parameters

As said above, the `run()` method can accept an arbitrary number of parameters after the fixed `data` input parameter. There are a two rules to follow though:

- Parameter must be annotated with their type

- A default value must be given

Malcat will then use this information in order to create the corresponding UI controls, following the rules below:

Parameter type | Control
--- | ---
bool | Checkbox
int | Text box accepting decimal or hexadecimal numbers
bytes | Text box accepting either hexadecimal bytes (`{ 78 56 34 12}`), an ascii string (`"hello"`) or a number (`0xdeadbeef`)
Tuple[str] (enums) | A Choice control to chose from a fixed list of enum values
str | A python code editor (only used for the user code operations, cf. Using the user code transform)

An example with `bytes`, `bool` and `enum` parameters is given below:

    from transforms.base import *
    from Cryptodome.Cipher import AES, Blowfish, DES, DES3
    from Cryptodome.Util import Padding

    class AesDecrypt(Transform):
    """
    AES cipher decryption
    """
    category = "crypto (block)"
    name = "aes decrypt"

    def run(self, data:bytes, mode:("ecb","cbc","cfb")="ecb", key:bytes=b"aaaaaaaaaaaaaaaa", iv:bytes=b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", unpad:bool=False):
        if mode == "ecb":
            decryptor = AES.new(key, AES.MODE_ECB)
        elif mode == "cbc":
            decryptor = AES.new(key, AES.MODE_CBC, iv=iv)
        elif mode == "cfb":
            decryptor = AES.new(key, AES.MODE_CFB, iv=iv)
        data = decryptor.decrypt(data)
        if unpad:
            data = Padding.unpad(data, 16)
        return data

#### Testing

To test your newly created transform operator, just use it in Malcat! If you make modifications to your transform operation, there is a “reload” button located on the top left part of the transform dialog. Just hit it and all the transforms will be reloaded.