---
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
```