If you come from x86 reversing world, .NET application protections will look really simple for you. If you've done more than one static x86 unpacker, you won't have much problems with .NET.
- In most cases, .NET protector hooks into JIT engine, decrypts IL code on the fly and passes decrypted code to original JIT engine. That's pure x86 goodness.
- String protections are usually (but not always) done in managed code. In 90% of cases they are trivial.
- Resource protection usually depends on setting unresolved resource handler (managed code). Trivial.
- Control-flow obfuscation, junk code and other obfuscation methods have the same principles for all platforms. .NET makes it even easier because of IL code must be verifiable.
- Using .cctor's to initialize protection, invalid .NET metadata, using delegates and strong name key protection are the only things that are really .NET specific.
Just to give you the idea of (lack of) complexity - static XHEO unpacker fits in 800 lines + standard libs for zlib and xxtea + library for .NET metadata processing. Yes, it's that simple.