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