string encryption ships you the key
The deobfuscator half of that project had two real targets: ProGuard and Allatori. Upfront caveat, because it matters more than usual here: this is a 2021/2022 project, I'm writing from memory rather than from the code, and an earlier draft of this post had the two swapped in a way that didn't match what actually happened. What follows is the corrected version, and I'd still hold it loosely.
proguard was the more annoying one#
As best I remember it, ProGuard-obfuscated jars were the side that actually made me do work. I ran into something like five different methods for deriving or decrypting a key, and which one a given jar used didn't seem consistent from jar to jar — possibly tied to a version or a build setting, but I never actually isolated which.
That's the honest shape of that half: not one algorithm, a catalogue. You recognise a pattern, write the reversal, and go looking for the next variant. I don't have a clean account of why there were around five rather than three or eight — that's just how many distinct methods I ran into before I stopped looking.
allatori's obstacle wasn't the encryption#
Allatori's actual hurdle was different in kind, and simpler than I originally described it: a deliberately malformed class, built to crash decompilers like Luyten rather than to resist a targeted tool. It's a cheap trick — it does nothing against something that isn't a general-purpose decompiler — but it's effective against exactly the tool most people would reach for first.
Once that class was out of the way, decrypting the strings underneath it wasn't the hard part. Which is worth sitting with, because it's the general shape of this problem regardless of which tool you're pointed at:
You cannot ship someone a program that runs on their machine and also withhold from them what the program needs in order to run.
A program that has to decrypt a string to use it has to carry the routine, the key, and the call site into that decryption, all in the same artefact it hands you. The string isn't protected. It's inconvenienced — one indirection away from plaintext, with the indirection included in the download. That's true of string encryption generally, independent of which specific tool I was pointed at, and it's the part of this whole project I'm actually confident about.
what I'm not confident about anymore#
I'd previously ranked name mangling, string encryption, and control-flow obfuscation by how much they resisted the deobfuscator, with control flow as "the one that actually cost me." I don't have a solid memory of testing control flow obfuscation specifically as part of this project, so I'm dropping that ranking rather than keep repeating a claim I can't back up.
What I'll stand behind: name mangling destroys information rather than hiding it, so there's nothing to reverse, only to relabel. String encryption is reversible in principle for the reason above. Past that, I'd rather say "I don't remember clearly" than restate specifics that didn't hold up the first time I wrote them down.
the part I still use#
I wrote about why building both halves was the point separately, and the lesson from that post is the one part of this project I'd still defend without hedging: you cannot tell which of your own transformations are strong by admiring the output. You find out by writing the thing that comes at it from the other side — and, apparently, you should also double-check your own memory before writing it up years later.