Washi

Developer - Reverse engineer - CTF player - Scrub

2025-04-18

After #flareon11 challenge 7, I got inspired to build tooling for #dotnet Native AOT reverse engineering.

As such, I built a #Ghidra Analyzer that can automatically recover most .NET types, methods and frozen objects (e.g., strings).

πŸ‘‰blog.washi.dev/posts/recoverin

Ghidra with a Native AOT Analyzer active, displaying all type definitions and virtual methods defined in a binary.
2025-03-08

#AsmResolver 6.0.0-beta.3 just got pushed to NuGet!

More bugs were found and squashed. We are closing in on a full release with most of the public API being stable.

Get it on GitHub or NuGet πŸ‘‰ github.com/Washi1337/AsmResolv

#dotnet #pe #reversing

2025-01-11

#AsmResolver 6.0.0-beta.2 has been released

This is a maintenance release that addresses many regressions introduced by the refactors in 6.0.0-beta.1.

Get it on NuGet or GitHub
πŸ‘‰ github.com/Washi1337/AsmResolv

2024-11-17

I just published my writeups for all challenges of #flareon11:

πŸ‘‰ blog.washi.dev/posts/flareon11

πŸ‘‰ washi1337.github.io/ctf-writeu

Hope you like them as much as I liked writing them!

Washi boosted:
2024-07-19

CrowdStrike Global:Offensive

2024-02-27

#AsmResolver 5.5.1 is out!

This is a maintenance release, adding #dotnet 8.0 targets and fixes issues related to type signatures, CIL optimizations, as well as some rare edge cases in .NET metadata directory parsing.

Get it on GitHub/NuGet:
πŸ‘‰ github.com/Washi1337/AsmResolv

2024-01-23

@cxiao @still Unfortunately, there's not really a golden rule. Different obfuscators encrypt/decrypt CIL in different ways.

My go-to advice would be to always look at the module initializer (<Module>::.cctor) first. If that is readable in e.g., dnSpy but the remainder of the methods isn't, usually it means this cctor is trying to either A) decrypt all other methods or B) set up some kind of JIT hook to decrypt methods on-the-fly as methods are being JIT'ed.

Option A is the easiest to deal with: You can just step over the lines of this .cctor, and just dump the entire module using dnSpy/ExtremeDumper/WinDbg/x64dbg and then open it in your favourite decompiler (after potentially fixing some PE headers). Option B) is harder, you'll have to trigger the JIT for every method and hook into the JIT compiler itself to catch the compiled CIL code. There are JIT dumper tools out there that do this (e.g., github.com/Anonym0ose/JitDumpe), but obfuscators like DNGuard make that hard to work out-of-the-box. I usually just look at the generated code instead then, whilst having a close look at called BCL methods and the object heap.

As for tools, Harmony is powerful but also has issues from my experience, mainly because it relies on loading the target assembly with Reflection which many obfuscators know how to prevent. dnSpy(Ex) has improved quite a bit though over the years, it can nowadays view the JIT'ed assembly of a method during execution (right click "View Disassembly" during execution). But WinDBG is kind of the tool that always just works^tm, provided that you know how to bend it to your will (which can be a real pain sometimes). Can recommend the series by UbbeLol on some basics of windbg+sos (youtube.com/watch?v=q-IWHHFQcX), although they are a bit dated by now probably. Mostly the way I learnt to work with it was to "just f*ck around" with my own samples in WinDbg. The good news is that .NET binaries are still executables that eventually run x86 code, so a lot of the standard RE strategies should still work.

There seems to be a bit of a lack of up-to-date content on this to be honest (maybe good ideas for new blog posts :^)). Regardless, I hope this gives some pointers :).

2024-01-21

Did you know you could write entire #csharp programs just by using the "await" keyword?

OK, well not really, but I spent some weekends developing AwaitFuscator: A (dumb) #obfuscator that turns your #dotnet program into nothing but "await" expressions!

πŸ‘‰blog.washi.dev/posts/awaitfusc

2023-12-23

"Noo! Ghidra has such a bad UI! IDA is much better!"

Explain to me: In what world does a hex view need column selection that crosses multiple columns (and beyond) and disappears upon scrolling?

The decompiler may be good but I genuinely don't see how people put up with IDA's UI.

2023-12-13

I wrote a quick post with my thoughts on the recent VMProtect leaks, and why I think it is a bad thing in general:

πŸ‘‰ blog.washi.dev/posts/on-the-vm

#reversing #ethics #leaks

2023-11-16

Ever tried #reversing #dotnet binaries compiled with #nativeaot? I decided to publish some of my (hacky) #ghidra scripts that may help you out with mundane tasks like finding strings.

πŸ‘‰github.com/Washi1337/ghidra-na

The scripts could probably use some work but at least it's a startπŸ˜ƒ

2023-09-23

Earlier this month I found a way to consistently pop calculators in #dnSpy by opening a file and clicking some nodes in its browser.

Today I release a write-up on how this can be done:

πŸ‘‰ blog.washi.dev/posts/popping-c

Update dnSpy if you haven't already!

#dotnet #reversing #bug

Washi boosted:
2023-09-20

dnSpyEX contributors (Elliesaur and @washi) has discovered critical security concern involving arbitrary code execution. If you are .NET (software) reverse engineer, you should update to this new release:
github.com/dnSpyEx/dnSpy/relea
#vulnerability #arbitrarycodeexecution

2023-07-16

Another day, another #AsmResolver version bump: 5.4.0 is out now.

This release includes support for #PE certificate tables, PE forwarder exports, more quality of life improvements and more bug fixes.

πŸ‘‰ github.com/Washi1337/AsmResolv

#reversing

2023-07-08

I spent my Saturday on a dumb project answering the following question:

What is the smallest #dotnet Hello World binary?

Turns out, this rabbit hole is deeper than you may expect, so I wrote a blog post about it:
πŸ‘‰ blog.washi.dev/posts/tinysharp

#reversing #obfuscation #asmresolver

2023-06-03

I participated in DEFCON CTF Qualifiers of this year with Shellphish (thanks for inviting me!), and solved a web/rev/pwn challenge where we pwned a Javascript VM with... Python PicklesπŸ₯’?

Have a read how we ended up doing this on my blog πŸ‘‰ blog.washi.dev/posts/defcon-br

2023-05-17

#AsmResolver 5.3.0 is out!

More performance and #pe reader bugfixes, new docs, and we also made it easier to ignore errors when writing #dotnet modules.

Changelog and download links:
πŸ‘‰ github.com/Washi1337/AsmResolv

#malware #reversing

2023-03-22

#AsmResolver 5.2.0 is out now.

This version includes read support for many more #PDB symbols, #dotnet AppHost patching, .NET TypeSignature::IsAssignableTo(type), QoL improvements and bug fixes.

πŸ‘‰ Full changelog and download links:
github.com/Washi1337/AsmResolv

#reversing #malware

2023-03-06

@0xced @khalidabuhakmeh
True, however this is not exactly the same as a module constructor. It generates one but the code you'd be writing will actually not end up in the constructor itself but in a separate method. See sharplab.io/#v2:CYLg1APgAgTAjA==

It is a subtle difference and in practice that difference is negligible, but the purpose of my post was to show the places where user code really starts, and that is thus on this technicality not in one of those c# "module initializers".

Thanks for reading my post :)

2023-03-04

What really is the entry point of a #dotnet application? Is it `public static void Main()`, or are there other places that we should look at when reverse engineering .NET samples?

πŸ‘‰Read about it in my new blog post: washi.dev/blog/posts/entry-poi

#reversing #malware

Client Info

Server: https://mastodon.social
Version: 2025.07
Repository: https://github.com/cyevgeniy/lmst