6

See top answer here: Obfuscation at source-code level more effective than obfuscators?, specifically "Code it in a language so not easy to decompile such as C/C++"

I'm looking to write a new application that will be sold for $500 per license, so I'd like to prevent decompilers.

Should C# be avoided, or is using an obfuscator sufficient to prevent this sort of thing?

9
  • 6
    Best rule: don't have the proprietary parts exist client-side. Keep your IP server-side and have your client be a thin (or web) UI on top of it. Thereby, your good stuff doesn't get decompiled. Feb 1, 2013 at 21:20
  • 1
    I'm looking to write a program similar to AutoCAD here, so I don't know that that would be feasible?
    – Michael
    Feb 1, 2013 at 21:22
  • 2
    Ah. To be honest then, if it were me, I'd do the UI in C# (as that's my current main language) and do the calculation-bits (which I assume is your program's chunk of awesome) in straight C and p/Invoke over to them from the UI. Best of both worlds, maybe? Feb 1, 2013 at 21:25
  • 1
    p/Invoke is a moniker for the practice of pasting native and COM code signatures into managed code so that unmanaged code can be called. See pinvoke.net Feb 1, 2013 at 21:41
  • 1
    @Carson63000 It's more or less already made in VB6, but I felt I should abandon VB6 because support for it is very lacking. Although it's not fully functional, it's perhaps halfway done. Most of the changes will be syntactic in nature, and after reading a 1,000-page book on C# and porting 4K lines of code over to C#, I think I should be good enough to continue adding functionality.
    – Michael
    Feb 2, 2013 at 12:34

3 Answers 3

14

C# assemblies contain metadata that c++ assemblies do not, which can aid in decompilation. C# also compiles down to an intermediate language which maps much better to the original source code than does C++'s machine code output. Obfuscators can help, but you can't prevent reverse-engineering; you can only make it harder.

In practice, nobody wants your code for free anyway. Companies want to be legitimately licensed; they don't want to go to the trouble (or legal exposure) of hacking your code to get a free license. At $500 per license, it's unlikely you're targeting ordinary consumers, so the only ones who will be interested in hacking your software will be those folks who aren't in your target market anyway.

So take sensible precautions, like having a licensing scheme, install codes, phone home, or whatever the latest thing is for securing your software, and focus your efforts on adding new features to make your software better and more attractive, choosing the language that provides you with the best possible productivity.

NB: If you aren't getting ripped off occasionally by the hackers, your software isn't important enough. At that point, you can probably hire someone to issue takedown notices and work on better technological solutions.

4
  • Oh, and it's been done before, so make sure yours is better than the others. Feb 1, 2013 at 21:33
  • Haha... it's not exactly AutoCAD... but perhaps similar in its demands on the system. :)
    – Michael
    Feb 1, 2013 at 21:34
  • Decompilation of C# is easy enough that Lutz Roeder's .NET Reflector has been a part of every serious C# developer's toolkit for years. It even used to be free. Feb 2, 2013 at 2:37
  • Example: The concept of a class does not exist as far as the binary format on disk for machine code is concerned. But it is a concept for C#'s Common Intermediate Language. Feb 2, 2013 at 19:30
6

Fundamentally, any executable program can be disassembled and inspected. The ease with which a reverse engineer can recreate the original source code depends on how much information or meta-data about the original source code exists within the executable. Can the reverse engineer discover the original variable names, functions, data structures, etc.? A compiler essentially "compresses" source code, turning it into a format which is more amenable to machine execution, such as native machine code or byte code which is processed by an intermediate runtime. But generally speaking, the compression is lossy, meaning that a lot of information about the original source code is simply not there. However, certain compiler outputs are more lossy than others.

C and C++ generally compile directly to native machine code. But neither the C nor C++ standard describes the layout of a binary executable created by the compiler. An optimizing C++ compiler, for example, is free to do many things to increase performance, including optimizing out certain variable declarations or removing entire functions and classes. Very little information about the original C++ code necessarily needs to exist in the binary executable. A reverse engineer would still be able to disassemble it, but gleaning any C or C++ code out of the assembly would be an act of guessing and interpretation.

C#, however, compiles to CIL (Common Intermediate Language). Typically, a lot more information about the original source code, such as object oriented concepts including class structure, can be gleaned from reading the CIL than from reading, let's say, highly optimized x86 machine code produced from a C++ compiler.

2
  • Do the classes and methods from the decompiled CIL retain their original names, or is that all obfuscated away?
    – Michael
    Feb 1, 2013 at 21:54
  • @Michael By default, the names are kept IIUC (your very own code may rely on it, e.g. if it uses reflection). But even if you use these names in other assemblies, it should be relatively straightforward to replace them with arbitrary strings, and IIRC most "obfuscators" for .NET do that.
    – user7043
    Feb 1, 2013 at 22:17
2

C# shouldn't necessarily be avoided. I work for PreEmptive Solutions on their Dotfuscator team, though this is a fairly unbiased answer. (without a single plug :) )

C# is inherently easier to decompile into source code because it contains meta-data and most C# code must comply with a set of rules called "verifiable code". Decompilers take advantage of the adherence to these rules along with attached metadata to make decompilation much better than equivalent C++ decompilers. It's hard to get into with a thorough understanding of IL, but basically each class in your code will end up having metadata. It's how .Net prevents you from having to ship header or symbol files for someone to use an assembly/API you write. And for the verifiable code bit, it basically means that you can only use code that the .Net runtime can verify is "safe". The runtime is limited in it's static analysis capabilities, so there is a lot of code that can be verified is "safe and correct", but won't be verifiable by the runtime. Decompilers take advantage of this set of rules.

If you're shipping a product in C# and have IP you want to protect, you basically have to use an obfuscation product. It's the same in similar languages/runtimes such as Java. Obfuscation products for .Net do a variety of things:

  • Obfuscate control flow (turn if statements into loops with goto and reorder everything)
  • Inject garbage no-operation instructions to "hide" the real code
  • Rename metadata so it doesn't really help. (turning class names like FooBar into a)
  • Change how classes are structured (moving 5 methods into a single method taking all the arguments from the 5 methods)
  • Inject unverifiable code or metadata (though this is usually easily defeated by deobfuscators)
  • Encrypt strings so that they aren't just plain text
  • Encrypt resources such as attached configuration files, XAML pages, etc
  • Add tamper protection (detection that the application has been changed)

Depending on which obfuscator you use, these methods can make it so for all intents and purposes the code is a huge "black box" without diving into the IL and hand deobfuscating it(very time consuming)

C++ has the plus that obfuscation isn't nearly as important. There is no metadata so decompilers have a much harder time. However, there are still a great deal of hackers that can read x86 assembly. And C++ applications very commonly get cracked. (good) C++ obfuscators are also much harder to come by. This is because they are about as difficult to obfuscate as they are to decompile. .Net has a set of rules that obfuscators use to both read your code, and obfuscate it. C++ doesn't have these rules.

So, in summary

  • C# basically requires obfuscation
  • C++ is much harder to decompile, but obfuscation support is lacking
  • No matter which one you choose, it is always possible to crack. All you can do is slow it down or make it undesirable to crack due to the amount of time required

Also, as one more note. C# obfuscators which produce verifiable code basically give you an application which will run everywhere, as long as they have a new enough version of .Net. C# obfuscators which don't produce verifiable code will usually work everywhere, but they aren't guaranteed to. It's possible Microsoft would come out with some JIT optimization in the next version of .Net that will break your unverifiable obfuscated code. C++ code inherently does not usually run "everywhere", but it usually does. Obfuscated C++ code will probably work everywhere you intend to, but it's not guaranteed. Writing correct and thread-safe C++ is hard enough, much less worrying about an obfuscator screwing that up.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.