Ceras icon indicating copy to clipboard operation
Ceras copied to clipboard

How is Ceras with Obfuscation?

Open FutureTD opened this issue 5 years ago • 5 comments

Currently I am using protobuf.net for my classes, I typically use the Protomember attribute for versioning my classes/fields, which works well with obfuscation.

How does Ceras's Version-Tolerance stand up to obfuscation?

FutureTD avatar Apr 25 '19 07:04 FutureTD

Depends on if your serialized types are getting renamed. But you're obviously aiming to do that otherwise you wouldn't ask, right? :P

Since one of Ceras's main goals from the start was to specifically avoid the need for any sort of attributes ('ProtoMember', or 'Key', or ...), it makes heavy use of names (only during initialization, but still, the names completely determine how the dynamic serializers are generated). It uses type-name, member-type (field or prop), member-name, and in some cases even declaring type information.

So as it is obfuscation will likely mess things up completely when your data types and/or members are renamed. Keep in mind that messing with the type name means that the namespace will be different as well (obfuscators often even completely remove the namespace information as well), and that will cause trouble as well.

Luckily however...

Ceras is well designed so the names are only used in the beginning to create the Schema (what to serialize, with what name, in what order). Since Schema-ta are pretty lightweight and straightforward it's pretty easy to create them in other ways.

So if you want, I can probably add some sort of API pretty quickly! :smile:
so lets discuss how that could look like, what our options are, ...

rikimaru0345 avatar Apr 25 '19 08:04 rikimaru0345

So here are my thoughts on what we can do:

Make Ceras even more configurable

For complete control I could probably make Schema public or something. That'd give the greatest flexibility. It'd allow users to manually construct schemata for their types. But they'd need to know a few things about how to construct them correctly though - so maybe not the best idea.

Then again that much flexibility is probably not really needed here I guess? The focus should rather be comfort, ease of use and simplicity (as long as performance isn't impacted at all).

Straightforward approach

I'd just implement this as a feature directly.

  • For fields/properties it would be as easy as adding something like a [MemberName()] attribute (or maybe MemberId?); and then also enforcing that if one member of a type has it, all of the must have it (so no members can accidentally be forgotten).

  • For type-names I could make it so any type that uses this new attribute would have to be in KnownTypes, which I think is already a perfect solution here. Any other approach has a few problems, but I guess I'll write them down here just to provide a better picture.

  • If you don't want KnownTypes for some reason (even though it is the most efficient thing) then Ceras needs some other way to obtain the name of a type. We obviously can't just use the obfuscated name, because that might be random, or not stable across builds. To customize how type names are written Ceras already has 'ITypeBinder', which would definitely work here, but it doesn't really feel like an elegant design here. We'd need to somehow enforce that a user actually customizes the type-name... ugh. Maybe another attribute like [TypeName()] or something? But then how would Ceras find the type again at deserialization time? Crawling through all loaded assemblies, inspecting every type, searching for the one that has the matching attribute is pretty slow. Also, should that be in the TypeConfig as well then? And what if the user uses a custom ITypeBinder would that just get ignored for that type then?

I think me providing a "proper implementation" is likely the best thing because then everyone can use the feature and people won't have to spend time investigating the internals of Ceras to figure out if that's possible at all and how to do it. Just slap on the attributes, done, easy. :joy:
It shouldn't take long to implement (maybe a day or so?).

Definitely let me know what you think! Maybe you had a different approach in mind? Or there's something I missed?

rikimaru0345 avatar Apr 25 '19 09:04 rikimaru0345

Yea that sounds like a good Idea, I saw you were trying to avoid attributes, so that is why I did not suggest them, but when dealing with obfuscation I guess its the easiest way to identify types.

To be honest, For me I was hoping ceras just took care of attributes, so I would not have to use them in protobuf.net. My software is a WPF application so I serialize many classes.

FutureTD avatar Apr 25 '19 09:04 FutureTD

To be honest, For me I was hoping ceras just took care of attributes, so I would not have to use them in protobuf.net.

Can you elaborate on that? I don't think I understand what you mean. Like Ceras using the attributes from the protobuf lib? That's not what you meant, or is it?

rikimaru0345 avatar Apr 25 '19 09:04 rikimaru0345

I saw you were trying to avoid attributes

You mean in Ceras's design in general / because of that part in the readme? Ah, well, I don't have anything against attributes in general, the only thing I don't like is when you are forced to use them. :laughing: Like for example in libs like protobuf, where you have to put an attribute on every single type and field just to get basic functionality.

I think for any sort of customization or advanced use cases (like this one) attributes are perfectly fine though :)

rikimaru0345 avatar Apr 25 '19 10:04 rikimaru0345