02 Nov

Complicated state machines – or how Unit42 “discovered” .NET Reactor

While browsing through my RSS reader, I ran into article from 09-Oct-2017, called OilRig Group Steps Up Attacks with New Delivery Documents and New Injector Trojan.

One part in the article caught my attention:

The “Run” method calls functions that has a state machine that dictates the actions taken. At a high level, these state machines attempt to create a process and inject the constructed payload into the newly created process. The use of state machines complicates analysis efforts because it makes the flow of execution jump around in a non-sequential fashion.
...
The state values jump around dramatically, which requires an analyst to also jump around the code to determine its functionality. This is an interesting anti-analysis technique we have not seen the OilRig actors use in their other tools.

.NET? State machines? Complicated technique we haven't seen before? Show me, show me, show me! bigsmile

Finding the DLL was relatively easy, finding the method they were describing was much harder. In the end I had to search for the constant "19" they mentioned in the article.. So, here is the method, in all its beauty:

If you're screaming "Dude, that code is obfuscated!", you're right. It is obfuscated.

If you're screaming "It's .NET Reactor!", you've spent too much time reversing .NET applications.

But you're right. It's easy to recognize the .NET Reactor by first few instructions, method renaming pattern and plenty of other things.

Have you heard of de4dot?

Let's try to run de4dot on this dll:

So, apparently, the latest versions of de4dot are buggy. Let's use an older version:

And let's look at the method again.

Strings are still unreadable, but where's the state machine? It's gone! Because it was never part of the OilRig actors toolkit, it was just a part of .NET Reactor control-flow obfuscation. smile

Decode strings and rename few variables and you'll see a very ordinary RunPE (aka. process hollowing) code:

Lessons learned

The lesson is simple - you should know the subject you're writing about. And if you don't know something, ask your friends and colleagues. Otherwise you'll just embarrass yourself and your company.

Further reading

If you want to learn more about this malware, I would suggest reading analysis by DarkMatter. At least they can identify .NET Reactor correctly. wink

24 Apr

Sniffing correct serial in .NET crackmes

Introduction

In this tutorial I'll show you a generic way how to break most of the crackmes written in VB.NET. It uses the fact that most crackmes made by beginners will calculate correct serial and do a simple comparison "if enteredSerial = correctSerial then"...

To break such a crackme, you only need to find this comparison and sniff the correct serial. This is a very common approach in x86 world but in .NET world it's not that popular yet.

As for my target, I'm using "RDG Simple Crackme .NET v4 2015"

GetProcAddress in .NET

In x86 world you can use GetProcAddress function to get address of any API function from any DLL. Can we do something similar in managed environment like .NET? It turns out that we can, but it's a little bit harder.

So, for example, to get address of Assembly.Load(byte[]) you need to do:

This works well with static classes and static methods. How about non-static methods like RijndaelManaged.CreateDecryptor(byte[], byte[])?

That's doable as well, like this:

To make this reference almost complete - here's how to get address of .ctor:

There are a few gotchas, however..

  • In case your target type is located in assembly that's not NGEN'ed yet, I suggest that you use ngen and install the assembly in cache. That can prevent certain problems later.
  • Addresses of functions are obviously different in .NET 2.0 and 4.0. You must compile for correct framework version and target the correct .NET assembly.
  • Addresses of functions are different for x86 and x64 framework versions, too. Make sure your assembly is compiled correctly.

Sniffing string compare

Suprisingly, string comparison in VisualBasic.NET and other .NET languages is different. It's caused by Option Compare statement present in Visual Basic language. So, if the crackme is made in VB.NET, you need to examine Operators.CompareString(string,string,bool) function. For crackmes made in other languages, you'll need to examine string.Equals(string) or some other variation of this method.

So, using the code I mentioned above, I learned that address of Operators.CompareString(string,string,bool) on my PC is 599F1D30. Now I need to sniff data passed to this function.

There are several possible approaches. You can try using VisualStudio & Reflector plugin as SpoonStudio tried, you can try using ILSpy and it's debugger plugin, or you can inject DLL into crackme process, as suggested by noth!ng - but I prefer to use OllyDbg.

Load crackme in OllyDbg, make sure that all the anti-anti-debug plugins are working, all the exceptions ignored, put a breakpoint on 599F1D30 and hope for the best.

Nope. Operators.CompareString is called literally thousands of times. So, we need to do something smarter.

For example, we can use conditional logging breakpoints in Olly. Those breakpoints are quite slow, but it's still faster than to write some sort of hooking DLL and inject it into crackme. So, we need to set 2 logging breakpoints - one for each string compared. Here is first one:
crackme_conditional_breakpoint
Place second breakpoint at the next instruction (59CD1D31) and log string at edx+8.

Run the crackme, enter some fake but easily recognizable serial and few minutes later we have the answer:
crackme_logged_results
My entered serial was "1234567890123456789012345678901234567890" and it's being compared to "C49476D583364356253377056314435396D456F44796C7A55746431564433544". Hmm, could that be the correct serial for my nickname? wink Yes, it is!

Final notes

This was quite nice crackme and I only showed the simplest way to beat it. When you start looking into it, you'll find some nice anti-debug tricks, some nice anti-patching tricks and pretty nicely obfuscated code.

But that's a matter for another story. Have fun!

08 Apr

Catch me when you can

Introduction

Exception filters have been part of ECMA-335 specification since the very beginning. I'm guessing, they were added because Visual Basic used them extensively and therefore Visual Basic.NET had to support them as well. They look something like this:

Until now C# supported try/catch but did not have support for filters. That's going to change in C# 6.0/VS2015.

How does it work

In early versions of VS2015 the syntax was "catch-if", as you can see in the initial announcement. In the latest VS2015 CTP builds, they changed syntax to "catch-when", and there's a good reason for it.

So, how does it work and what does it mean for reversers?

It's a compiler-level feature

As I mentioned before, .NET Framework has supported exception filters since the very beginning. So, this feature works even in .NET 2.0 - if you decide to target .NET 2.0 Framework in VS2015 project settings. Not that you really want to do that..

It's very useful for debugging

catch-when is implemented as an IL exception filter. So, when an exception is thrown, exception filters are processed before the stack is unwound. This means that filter method has created an error report that included the current stack trace, it would show the frame in which the exception occurred. Sounds complicated? It isn't.

Let's implement exception filtering in the "old" way:

and this is how the stack looks when we get to filter(ex):
stack_trace_old
You can't see much here. All the context is gone, you must rely on exception stack trace and message. That's what we've always done, right? smile

If we write it in a "new" way, the code looks like this:

and stack trace will give us full context of exception:
stack_trace_new
Much better, isn't it? You can see which method threw the exception, on which line, you have access to local variables and everything else. Yummy! smile

Decompiler support for exception filters is crappy

They say, a picture is worth thousand words.. In a very simple example, Reflector gets the code structure right, just filter conditions are missing:
catch_when_reflector
ILSpy handles it slightly worse, filters are messed up and unreadable. Filter code is gone, too:
catch_when_ilspy
And the latest JustDecompile just throws an exception:
catch_when_justdecompile

Have fun with it!

Here is a small keygen-me for you to play with: https://www.mediafire.com/?k5b9vy0p9dfgb97

The difficulty is 2/10, you should be able to solve it in 30 minutes or so. The entire protection is designed to show you try-catch-when feature, so avoid patching - you can't learn anything by nopping-out few instructions. wink

23 Mar

.NET, ScyllaHide and HEAP_CREATE_ENABLE_EXECUTE

While doing some research on ILProtector, I loaded my test executable in Olly. To much of my surprise, it refused to run and all I could see in Olly log, was this:

Something smells fishy! wink

I disabled all non-standard plugins, and I was still getting the exception. It was only after I removed the remaining 2 plugins (ScyllaHide and ODBGScript) that my test application launched. Few more restarts and I was sure that ScyllaHide is the one causing the trouble.

OK, I've found a bug in ScyllaHide. But where is it? Which option is causing it? And how can I fix it?

Unfortunately, there is no easy way. Just go through one option after another, until you trigger the bug. 10 minutes and 100 rude words later I was sure that "HeapFlags" is the culprit.

A side note from Captain Obvious

If you're seeing access violation in Olly and want to know where it's happening, make sure you uncheck Ignore Memory access violation in Debugging Options:
olly debugging options
and then run your target:
crash on jit stub
Here we can see that there is a real code at this address - small stub calling mscorwks.dll and that the call comes from ILProtector's protect32.dll.

It immediately gives you plenty of useful information about what's happening. Unfortunately I debugged one instance of Olly from another instance of Olly - got the same results but it took me much longer.

Meet HEAP_CREATE_ENABLE_EXECUTE

It turns out that .NET Runtime Execution Engine (mscoreei.dll) loves to put executable code on heap:

but ScyllaHide prefers to mark all heaps as non-executable:

and these 2 options kinda conflict with each other. smile

Workaround & fix

This small bug can be used to detect ScyllaHide, as it's enabled by default in all configurations, and tooltip explicitly suggests to leave it as-is:

Very important option, a lot of protectors check for this value.

Here is a suggested patch:

If you don't want to recompile the entire Scylla, here's the binary patch for the official ScyllaHideOlly1.dll from ScyllaHide_v1.3fix_Olly1.rar package:

As a simple workaround, you could uncheck "HeapFlags" in ScyllaHide when debugging .NET applications. However, I would really suggest to fix ScyllaHide instead.

Have fun and keep it safe!

20 Feb

String decryption with de4dot

Introduction

de4dot is a wonderful tool for deobfuscating known and unknown .NET protections. Dealing with known and supported protections is easy - drag&drop executable on de4dot and it will create deobfuscated assembly. Removing unknown protections is a little bit harder and requires supplying correct command-line parameters to de4dot.

In this article I'll show how de4dot can be used to deobfuscate strings in almost any .NET assembly, some undocumented features of de4dot, and a few bugs in de4dot too. smile

Basics of string encryption/decryption

To show how string encryption works, let's start with a simple C# program.

Hint - you don't have to copy-paste all the code, sample files are available in the archive at the bottom of the post.

As you can see, all the strings are in the clear view and it's obvious that correct password is "secret". No protection whatsoever.

To slow down reversing efforts, obfuscators offer to encrypt user strings. They locate all strings in assembly, encode them somehow, and replace access to string with call to obfuscator code. To keep the code simple, I'll just encode all strings using Base64 - however, the same approach would work for almost any string encryption method (xor, Rijndael, or anything else).

New code looks like this:

No more obvious strings! smile Let's see how we can decrypt them using de4dot..

de4dot and basic string decryption

If you check de4dot help, you'll see that you need to supply 2 command line options for a string decryption to work. First, you need to choose a string decrypter type using --strtyp option: static, delegate, emulate. Then you need to tell de4dot which is string decrypter method using --strtok option.

Let's find which method is responsible for string decryption. Good decompiler can show method tokens, for example, SAE shows it as a tooltip, when you hover over the method:SAE method token

So, for our very basic protection we could run de4dot with commandline:

and the result will look like this:
decompiled cleaned file
So far, so good!

Advanced string decryption

But what happens if obfuscator uses more than one string decryptor? Let's change the code a little bit:

Now there are 3 methods that decrypt strings, and each of them is slightly different. Of course you could run de4dot 3 times, but it's just a pain-in-the-butt.

de4dot help doesn't tell you this, but it is possible to to specify more than one string decryption method:

This is a little bit awkward, but works.

But what to do if there are hundreds of methods - specifying each of them by token is time-consuming and command-line might get too long.

de4dot has solution for that too. Hidden in the middle of help file, is this little gem:

--strtok METHOD String decrypter method token or [type::][name][(args,...)]

It turns out that you can tell de4dot the name of obfuscator class/methods responsible for string decryption and it will resolve tokens automatically. smile

So, the following command-lines will work:

  •  
    This tells de4dot that string decryptor is method with full name Demo.Obfuscator::DecryptString.
  •   This tells de4dot to check all methods in class Demo.Obfuscator and pick the ones which look like string decryptors.
  •   This tells de4dot which class to look at and what kind of parameters string decryption method has.
  •   This tells de4dot to look at all classes for a method called DecryptStringA and use that as string decryptor.

If you want to know more about possible options and the combinations, I suggest that you look at de4dot source code, file de4dot.code\ObfuscatedFile.cs, lines 454-511.

You said something about bugs?

Ok, ok, there are few issues here.. It still works 99% of the time, so no complaining!

First bug is in the checking of string decryptor parameters. When I said that --strtok "Demo.Obfuscator::(System.Int32)" will select only methods that take Int32 as a parameter, I lied. smile

Look at the source:

The continue instruction here does nothing, it just goes on to check next parameter. I guess 0xd4d wanted to stop evaluating this method and go to next one, but got it wrong.

Second bug is in selecting string decryptors - you cannot select a method which takes no parameters. Sample code showing this type of protection is in hello-4.cs (see below).

Look again at the source:

If you don't supply hints about parameters, then methods with 0 parameters will be ignored because of 2nd if. If you do supply hints - then no method with 0 parameters can pass the 3rd if.

Fixing these 2 bugs is left as an exercise to the reader.

Conclusion

In this article explained how to use de4dot to decrypt strings in any .NET assembly, including some lesser known options. Hope this helps you next time you encounter .NET protection that's not directly supported by de4dot. smile

All sample files and their source code: https://www.mediafire.com/?2kwnf7d7vre4uv8

09 Feb

.NET exception “The remote certificate is invalid”

For one project I needed to make a simple tool that fetches file from webserver via HTTPS connection. Sounds easy, right?

There are plenty of ways of doing things, but to keep it simple, lets ignore error handling, timeouts, authorization and other features:

It should work, right?

And yes, it works most of the time. For example, it fetches page from https://google.com/ without any problems.

But for some sites it mysteriously crashes with exception:

Cause of the error

It turns out that sites that are using self-signed, expired and otherwise bad certificates will cause this exception. How nice from .NET devs - they're trying to protect me! Well, no, because I still need to download that information!

Solution

I found lots of solutions of the web - and quite a few of them failed. Some of them are .NET 4.5 only, some of them are overly complicated class consisting of 20+ lines. I need something simple, that works everywhere from .NET 2.0 up and is actually readable!

This one works for me: put this line before doing any HTTPS requests:

It effectively suppresses all certificate validation errors. Problem solved!

Example site for testing your code: https://www.pcwebshop.co.uk/