views:

250

answers:

3

Hi all,

I'm trying to get the {smartassembly} .NET obfuscator to work with my system. I currently store user data in a series of serialized dictionary classes, and then deserialize those classes to get the data back. I'm already ignoring assembly version information, just because that way making life a pain. That code is adapted from MSDN:

//to avoid cross-versioning problems
public sealed class CrossVersionDeserializationBinder : SerializationBinder {
    public override Type BindToType(string assemblyName, string typeName) {
        Type typeToDeserialize = null;

        typeToDeserialize = Type.GetType(String.Format("{0}, {1}",
            typeName, assemblyName));

        return typeToDeserialize;
    }
}

Problem is, now my obfuscated app will ignore versioning information, but can't read data saved by the non-obfuscated app, and vice versa. We'll need to have a non-obfuscated version in order to debug the application, so this is a pretty big showstopper for us. Any way to get around this problem? Should I just not obfuscate the data classes? That seems like a pretty large security hole.

A: 

Obfuscation doesn't provide security in the first place. So, you may want to consider dropping it, period.

The two options I see are:

  1. Don't obfuscate those types. This will make things just work.
  2. Write your own serializer code.

Since you gain nothing by obfuscating, I'd go with #1.

MichaelGG
I need to obfuscate in order to make a dongle work, because without obfuscation, it will be easy to remove dongle calls.
mmr
Newsflash: it's gonna be real easy to remove the dongle calls even with the obfuscation.
MichaelGG
Maybe-- even with all the app-specific stuff we're going to put on the dongle. It's not meant to stop the dedicated hacker, it's meant to stop the idler who removes the key and can keep using the software.
mmr
Well, I don't know your business so maybe it's an excellent idea. But the risk of dongles for customers (dongle breaks = software dead?), coupled with the fact that only one person needs to break it...
MichaelGG
Typically, what happens is that the customer refuses to pay, and then the dongle just times out on them. Then, once they pay, we give them a functioning dongle. A savvy person with Reflector or Ildasm would just ignore the problem.
mmr
Well, like I said, I don't know your customers, etc. If that works for your company, great. It just seems interesting that you have customers smart enough to disassemble and reassemble, but not smart enough to use something like Cecil.
MichaelGG
But that's the point-- Cecil and Reflector and IlDasm are all from the same class of decompilers, and obfuscation is intended to hinder that approach. Obfuscation vendors pride themselves on breaking decompilers.
mmr
Disassemblers and metadata inspectors are not decompilers. Example: Switching Reflector into IL mode allows inspection of methods that otherwise might crash another system. Cecil also seems to tear right through everything. But hey, if it makes you happy, go for it.
MichaelGG
+3  A: 

Perhaps consider a serializer that isn't tied to the type and field-names? For example, protobuf-net is a binary serializer, but uses numeric tags set (via an attribute) against each member. This means:

  • serialization isn't tied to the assembly version at all
  • the field name information isn't in the serialized file
  • (by the above) it won't matter whether the code is obfuscated
  • (and) the file can't be used to trivially break the obfuscation (although the data might still suggest intent unless encrypted)

For example:

[ProtoContract]
public class Foo {
    [ProtoMember(1)]
    public string Bar {get;set;}
}

Here, the 1 is all that identified the member in the file. The key here is that it is contract-based, so can be deserialized later with an unrelated type:

[ProtoContract]
public class a12 {
    [ProtoMember(1)]
    public string a {get;set;}
}

(which is fine since obfuscation preserves metadata, IIRC).

Contrast this to other contract-based serializers (such as XmlSerializer or DataContractSerializer) - where you would be forced to put the member-name in the attributes, which would pretty much render obfuscation pointless:

[DataContract]
public class a12 {
    [DataMember(Name="Bar")]
    public string a {get;set;}
}
Marc Gravell
+1  A: 

Obfuscation and .NET patterns that heavily rely on reflection API don't go well together. The core of the problem is that during serialization the original class & fields names are serialized so that they can be used later, during serialization, to instantiate new classes and set their state according to the stored data. The problem is that during serialization class and method names were already renamed and therefore don't match the ones stored in the byte stream. Have you considered using other forms of obfuscation such as control flow obfuscation, method call obfuscation, code encryption, etc... You can find here a nice article discussing various forms of obfuscation

Gery Elema