6

I was reading a blog post over at Channel 9 about the release of an open source .NET/CLR decompiler. I was wondering as to why would you want to decompile a .NET/CLR application and look at its IL code? I'm just curious.

[Edit]

And are there any use for decompilers during the development phase?

[Edit]

I'm a little perverse; I want to know when was the last time you used a decompiler for a software development project, and why?

1

6 Answers 6

1
+50

I have had to look at it more times than I would care to admit. The most recent time was because we had to migrate a number of applications to a new database server. Included in this set of apps were numerous ones that had a connection string hard-coded and no source in version control. At that point you have two options, decompile, fix it and recompile or use a host file entry to set how the server name is resolved. Both are less than ideal although the decompiling route is less detrimental.

I also had to use one in lue of documentation for a CMS system that my company purchased. What documentation the vendor did provide was often times wrong and incredibly incomplete. Using a decompiler solved a number of problems including revealing a 64 bit related bug that I would have never guessed existed without a decompiler.

14

There are several reasons for using a decompiler, but they all boil down to a desire to figure out how a program works. Some specific reasons:

  • If due to e.g. a disk failure you've lost the source code to a program you wrote, but you still have a compiled version laying around, and the decompiler can make something understandable out of that then you don't have to start over from scratch. (For people with no version control & backups, mostly)
  • To figure out how to circumvent certain protections others put into their programs. This may be legal (e.g. if it's needed for interoperability), depending on your circumstances and local laws.
  • Similarly, it can help figure out how an opaque file format or undocumented protocol used by a program works (also typically for interoperability).
  • It can help debug compilers -- if what you get out isn't equivalent to what you put in then there's a bug somewhere. Equivalence is normally not trivial to decide though, due to the possibility of compiler optimizations changing the structure of the program quite extensively (In fact, in the general case it probably reduces to the halting problem, making it undecidable).
  • The Wikipedia page links to another page that lists a bunch of other uses: "Why Decompilation?"

[EDIT] Some more from the comments:

  • Looking at how a piece of code is optimized, e.g. to see whether code is optimized the way you want or to compare how two pieces of code are optimized. This can help write more readable code while ensuring that it will be optimized the same (or better), or knowing when sacrificing readability may be worth it because the optimizer "understands" the code better.
  • Figuring out how a poorly documented piece of code works.
2
  • +1. You can also add a major reason: knowing how the specific code is optimized to determine how to write code which will be optimized the way you want, or to show that two pieces of code are executing the same way with the same performance since their IL is the same. Apr 22, 2011 at 23:20
  • 1
    Also, just to help understand how some poorly documented code works. We do this all the time when consuming a third-party DLL. Using .Net Reflector, we even do this for built in .Net DLLS from time to time. Apr 22, 2011 at 23:52
4

And are there any use for decompilers during the development phase?

There are many uses for it. Remember what code you write is translated into something the machine can understand. What you assume that it is doing and what it actually does can be two entirely different things. One great example is when you need a very very fast piece of code. Knowing exactly where the compiler makes it's optimizations is key (wait why is this method getting pushed on the stack???? etc.). You can look at the code and guess what it should do, but you don't know until you actually look at what it was created.

1
  • 1
    +1 - but then again, you can't know what each VM instruction will do until you decompile the virtual machine. And you can't know what each CPU instruction will do until you decode the microcode/whatever they use these days. And if you do code for what your current compiler does, you have no guarantees about your next compiler - you may be building in a dependence on a compiler bug. For definitive answers, check what the language manuals and (where applicable) the standard says.
    – user8709
    Apr 23, 2011 at 2:40
3

There is one very typical reason you need to look at IL-code.

You have an issue with a library you are using, and which for some reason fails to work as expected (or even at all). You do not have the source, and you have no idea why it suddenly fails (or you have a very good idea and you need to figure out a way to avoid it happening).

By being able to decompile the code, you can get a humanly readable form of the underlying program, which you can then analyze - perhaps even debug - to understand what the code actually do, and then figure out what went wrong and how to either fix it or circumvent it.

You essentially put windows in the black box.

--
And to answer your question of how frequently I do this: On almost all projects, as they all have third-party libraries. In average on the size of around once a week in average.

1

If you are generating types at runtime using Reflection.Emit, inspecting IL is almost required during development. It is extremely helpful both for seeing how existing code looks as a guide, and also for ensuring your own code is generated properly (in conjunction with tests of course).

1

A little over 10 years ago, there was this apocalypse approaching. The year 2000 was near, and there was all this old software that stored years as two digits and couldn't handle the year 2000. Planes were going to fall out of the sky, hospital equipment was going to just stop, and industrial robots were going to rebel against their masters and exterminate the human race.

The infamous millenium bug. A non-event in practice, but in large part probably because of all the work done during the panic.

One issue is that many banks and other businesses were dependent on software (often written in COBOL) that was decades old, and for which the source code had long since been lost. They had put off dealing with that problem for a long time by always buying new machines that were backwards compatible with the old, but that wasn't going to work any more.

I don't know how these issues were resolved in practice, but I imagine there were three main approaches...

  1. Decompilation and other reverse engineering approaches to create "source" code that could be patched.

  2. In very simple cases, direct analysis and patching of binaries - or at least disassembly rather than decompiling.

  3. Redevelopment (of at least key components) from scratch.

An extreme case, but this kind of problem quite often arises. Until recently, versioning of source code was unusual, and even with systematic backups and archiving in place, over the long term there's always the transitions from one system to the next where things can get missed without anyone noticing.

In a way, it's no different to that crucial insurance policy paperwork or whatever that you can't find since you last moved house.

Another possibility is that decompilation is useful for learning what kinds of codes existing compilers generate, if you're thinking of writing a new compiler for .NET or some similar VM-based platform.

Your Answer

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

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