On .NET Executable Protections
I recently wanted to persuade a coworker to not rely purely on an executable protector to protect the license checking routine of his home brew shareware software. After years of products like this on regular windows PE executables with quite good outcome if used wisely I was quite disappointed of what is happening here. To protect his product a won't be disclosing the name here, the .NET protector used was EZIRIS .NET Reactor (http://www.eziriz.com/dotnet_reactor.htm). The licensing plugin of the software was not used but self made.
I used the following software for this little project:
The since the program is running on top of the .NET 2.0 framework the executable should be importing mscoree.dll. However it does not.
This imports table looks like one of a regular non managed executable, though the number of imports is too low. You see the standard windows api dlls being references (kernel, user, ...). Btw. if you compress regular non managed executables with a packer like UPX you see similar results. Just enough imports for the decompressor are available and in the decompresssion process the imports of the original executable are resolved dynamically in code.
At this point when dealing with non managed executables you would follow the flow of the unpacking routine until it finishes and jumps back into the uncompressed original code and then create a dump of the process. Where you fix up entry point and imports. However for managed code you can use ready made tools like dotNet Sniffer. This will let you launch an executable and dump the process when being compiled. Since .NET code is an intermediate language (like java) that gets compiled by a just in time compiler you know that you must have a somehow valid image being passed to the JIT compiler. At this point dotNet sniffer can dump the process. Actually the tool allows to create dumps at two different stages of the compilation/execution process. I selected to create both dumps.
As you see there are multiple files in the dumps:
- One with a trashed unicode filename. This appears to be a .NET executable with the size of 345kb.
- Lincense.dll. This seems like a manged code DLL, 20kb in size.
- MC.exe. A .NET executable with the size of 10kb.
- Module034A0000.bin this looks like the original EXE, since it's 1.6mb big.
My first idea was to just rename the .bin file to .exe and launch it. However when launching the executable I recieved the following error (something like "Invalid IL Range" in english):
At this point I had the idea of comparing the two different dumps dotNet sniffer created for me and found out that there are lots of changes in the .bin file of the two versions. Since the version in the /jit folder is created later I assume that this is the one we should go for. Comparing can easily be done with HxD. I renamed the .bin file in the /jit folder to .exe and launched this one. However now I got the following error:
I have to admit that this really puzzled me. The error appears to be raised by windows itself and seems quite .NET agnostic. So there must be something really wrong about the executable. I inspected the PE header of the executable to look for interesting hint and found two:
- The checksum is invalid. This somehow seems not to bother windows (I did a little test correcting it).
- The files is defined as a DLL instead of an executable.
I used HxD to change that characteristic (change 0x0201 in the PE header to 0xe01 - note the LSB first)
At this point the executable could be launched again and decompiled with .NET reflector. Since the executable is not signed it can also be patched without problems. The object/function names inside the executable are garbled, however using the resource texts and strings it's quite easy to get to the important parts.
As you see there was not too much effert required to get past the protection. Actually I find it quite questionable to use obfuscators/executable crypters at all because they give a false feeling of protection. If you want something secure do it a way to be secure, even if someone has the source code right in front of his eyes. Probably protectors will get better get better in the next months raising the bar, but they will definitely not shut everyone out.
I hope this article has been a little interesting for you.