---
# System prepended metadata

title: Tsundere Deobfuscator
tags: [' obfuscator', ' RTN', .NET, ' deobfuscator']

---

---
title: Tsundere Deobfuscator
description: Design proposals for the Tsundere deobfuscator
tags: .NET, deobfuscator, obfuscator, RTN
---

# Tsundere deobfuscator

Tsundere is a generic .NET assembly modification framework. It takes a highly extensible approach where obfuscation and deobfuscation steps are defined in external modules which can be dynamically loaded, to allow for any kind of post-processing of binaries.

[toc]

## Execution plan

CLI executable is given a binary (or multiple binaries) and a “plan”. This plan is likely a yml file. The plan contains a list of steps to execute.

### Execution plan example

```yaml
modules:
  # modules can be loaded in a few ways:
  # 1. by public repo (TODO: how to keep updated?)
  #   - probably want a mechanism to load private repos eventually
  # 2. by path, loading from disk
  # a repo/directory contains a tsundere-meta.yaml file
  - name: built-in # technically not needed, built-in is implicitly added
    repo: github.com/tsundere-team/tsundere:v1 # pulls in v1 branch
  - name: holly-eaz
    repo: github.com/holly-hacker/eazfuscator-tsundere:v1
  - name: eaz-devirt
  path: C:/dev/eaz-devirt-tsundere/ # loads from local path, rather than cloning
steps:
  # built-in steps can also be defined without the `built-in` prefix
  - name: built-in:strip-snk
  - name: holly-eaz:assert-eaz
    store-in-var: $EAZ
  - name: built-in:run-yaml
    file: ./script.yml
  - name: holly-eaz:fix-strings
    # arguments can optionally be passed. these either have a default
    # or the step will fail with an error message if they are not present
    args:
      # string-method expects smth that resolves to a method
      # if you specify none, it may try to find it by itself
      # string-method: md-token: 0xABCDEF12
      string-method: $EAZ.string-method
      # string-method: fqn: 'MyBinary.Eaz.StringDecrypt'
      dynamic: invoke # default is echo
    # modules can optionally be scoped in some way, which serves as a filter
    # defining which types/methods/etc will be processed
    scope:
      - type: assembly-type
        value: executable # or library, netmodule, etc
      - type: md-tokens
        value: [0xAAAAAAAAA, 0xBBBBBBBB]
        inverted: true # turns this scope into a blocklist rather than an allowlist
      # fqn: ['MyBinary.Program.Main']
      # fqn-pattern: 'MyBinary.Program.*' # or regex?
      # example of custom scope/selector
      # demo:signature: string(string, string)
  - name: eaz-devirt:devirtualize
    # meta settings?
    options:
      allow-errors: true # aka --dont-crash
# options can also be defined globally
options:
  allow-errors: false # stop on error
```

### Modules

A module is loaded from one of the following sources:
- A git repo, with a specific commit, tag or branch.
    - Non-public repos will need credentials to log in
- A directory on the filesystem
- A github release?
- Already loaded DLL files
    - This should be useful when Tsundere is used within a sandboxed context such as a web frontend. Such environments can have several modules pre-loaded and allow using only them.

Each module contains a tsundere-module.yml file which contains instruction on how to load module files. They may need to be compiled in the case of a local or remote git repo.
Each module is a .NET DLL which links to a Tsundere core library. It contains a list of steps, scopes, etc which are classes that implement a shared interface or have a shared attribute applied.

### Scopes

A scope is a predicate function that decides whether a step will be applied to a function/type/member/etc.
Scopes are additive, if 2 scopes are defined they must both match.

## Library Interface

All is WIP/scratch

### Dependency Injection
Some stuff that should probably be in DI:
- `IExecutionPlan`

### `IStep`
```csharp
namespace Tsundere.Core;

/// <summary>
/// Describes a single stage
/// </summary>
interface IStep // TODO: bad name?
{
    /// <summary>
    /// Allows a step to prepare itself by inspecting the current execution plan or validating its step definition.
    /// </summary>
    /// <remarks>This function is executed before any assemblies are loaded.</remarks>
    void PreProcess(IYamlSection stepDefinition);
    
    void Process();
}
```


---

Use CLI to run a step on a binary, which adds a step to a pipeline. Afterwards you can run the pipeline on a binary.

Working directory contains:
1. input binary
2. the current "program", which lists a set of steps to execute
3. the output binary of the program, to analyze in a tool like dnSpy

```shell=
# create a program
tsun init
tsun add builtin:strip-snk
tsun add eaz:clean-junk
tsun add eaz:fix-strings
tsun export -o script.yaml

# run script
tsun run --file script.yaml -i file.exe -o out.exe

# run single-shot processing
tsun run builtin:strip-snk -i file.exe -o out.exe

# detect obfuscator
tsun run proxy:detect-obfuscator -i file.exe
```
