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

kao

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! 😀

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:

F:\>F:\de4dot-appveyor\de4dot.exe d.dll --dont-rename

de4dot v3.1.41592.3405 Copyright (C) 2011-2015 de4dot@gmail.com
Latest version and source code: https://github.com/0xd4d/de4dot

Detected .NET Reactor (F:\d.dll)
Cleaning F:\d.dll
ERROR:
ERROR:
ERROR:
ERROR: Hmmmm... something didn't work. Try the latest version.


Press any key to exit...

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

F:\>F:\de4dot-3.0.2\de4dot.exe d.dll --dont-rename

de4dot v3.0.2.3405 Copyright (C) 2011-2013 de4dot@gmail.com
Latest version and source code: https://bitbucket.org/0xd4d/de4dot

Detected .NET Reactor (F:\d.dll)
Cleaning F:\d.dll
Saving F:\d-cleaned.dll


Press any key to exit...

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. 🙂

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. 😉

Sniffing correct serial in .NET crackmes

kao

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:

MethodBase mb = typeof(Assembly).GetMethod("Load", new Type[] { typeof(byte[]) });
IntPtr handle = mb.MethodHandle.GetFunctionPointer();
Console.WriteLine("Assembly.Load() = {0:X}", handle.ToInt32());

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:

RijndaelManaged rijndael = new RijndaelManaged();
mb = rijndael.GetType().GetMethod("CreateDecryptor", new Type[] { typeof(byte[]), typeof(byte[]) });
handle = mb.MethodHandle.GetFunctionPointer();
Console.WriteLine("RijndaelManaged.CreateDecryptor() = {0:X}", handle.ToInt32());

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

ConstructorInfo ctor = typeof(MyClass).GetConstructor(Type.EmptyTypes);
IntPtr ctorPtr = ctor.MethodHandle.GetFunctionPointer();
Console.WriteLine("MyClass constructor = {0:X}", ctorPtr.ToInt32());

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? 😉 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!

Catch me when you can

kao

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:

Try
   'Try statements.
Catch cle As ClassLoadException When cle.IsRecoverable()
   'Catch statements.
End Try

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:

private void button2_Click(object sender, EventArgs e)
{
   try
   {
      ThisCanThrow();
   }
   catch (Exception ex)
   {
      if (filter(ex))
         textBox1.AppendText("Interesting exception");
      else
         throw(ex);
   }
}

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? 🙂

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

private void button1_Click(object sender, EventArgs e)
{
   try
   {
      ThisCanThrow();
   }
   catch (Exception ex) when (filter(ex))
   {
      textBox1.AppendText("Interesting exception");
   }
}

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! 🙂

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. 😉

.NET, ScyllaHide and HEAP_CREATE_ENABLE_EXECUTE

kao

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:

Log data
Address    Message
           OllyDbg v1.10
           Command line: test.exe

           Console file 'C:\test.exe'
           ODbgScript v1.82.6 i686 VC2008 WDK7.1 CRT/STL60
             http://odbgscript.sf.net
           ScyllaHide Plugin v1.3
             Copyright (C) 2014 Aguila / cypher
           Hooked Olly Breakpoints handler for TLS at 0x2F918
           New process with ID 00002E2C created
00FC404E   Main thread with ID 00002754 created
           [ScyllaHide] Reading NT API Information C:\Tools\Olly\Plugins\NtApiCollection.ini
           [ScyllaHide] Hook Injection successful, Imagebase 00030000
00FC0000   Module C:\test.exe
             CRC changed, discarding .udd data
748C0000   Module C:\Windows\SYSTEM32\MSCOREE.DLL
             CRC changed, discarding .udd data
76070000   Module C:\Windows\syswow64\KERNEL32.dll
76180000   Module C:\Windows\syswow64\KERNELBASE.dll
             CRC changed, discarding .udd data
77100000   Module C:\Windows\SysWOW64\ntdll.dll
             CRC changed, discarding .udd data
771A103B   System startup breakpoint
76650000   Module C:\Windows\syswow64\ADVAPI32.dll
             CRC changed, discarding .udd data

...

5B820000   Module C:\Protect32.dll
             CRC changed, discarding .udd data
76840000   Module C:\Windows\syswow64\OLEAUT32.dll
             CRC changed, discarding .udd data
008B5BFF   Access violation when executing [008B5BFF]
7618C42D   Exception E0434F4D
7618C42D   Exception E06D7363
7618C42D   Exception E0434F4D
           Debugged program was unable to process exception

Something smells fishy! 😉

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:

.text:1000A424 ; int __stdcall DllMainProcessAttach()
.text:1000A424 ?DllMainProcessAttach@@YGHXZ proc near  ; CODE XREF: DllMain(x,x,x):loc_1000A6B4p

...

.text:1000A591   push    ebx             ; dwMaximumSize
.text:1000A592   push    ebx             ; dwInitialSize
.text:1000A593   push    HEAP_CREATE_ENABLE_EXECUTE ; flOptions
.text:1000A598   call    ds:__imp__HeapCreate@12 ; HeapCreate(x,x,x)
.text:1000A59E   mov     ?g_ExecutableHeapHandle@@3PAXA, eax ; void * g_ExecutableHeapHandle
...

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

if (ReadProcessMemory(hProcess, heapFlagsAddress, &heapFlags, sizeof(DWORD), 0))
{
  heapFlags &= HEAP_GROWABLE;
  WriteProcessMemory(hProcess, heapFlagsAddress, &heapFlags, sizeof(DWORD), 0);
}

and these 2 options kinda conflict with each other. 🙂

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 (ReadProcessMemory(hProcess, heapFlagsAddress, &heapFlags, sizeof(DWORD), 0))
{
  heapFlags &= (HEAP_GROWABLE | HEAP_CREATE_ENABLE_EXECUTE) ;
  WriteProcessMemory(hProcess, heapFlagsAddress, &heapFlags, sizeof(DWORD), 0);
}

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:

00005A0B: 85 81
00005A0C: C0 65
00005A0D: 74 FC
00005A0E: 14 02
00005A0F: 83 00
00005A10: 65 04
00005A11: FC 00
00005A12: 02 90

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!

String decryption with de4dot

kao

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. 🙂

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.

using System;

namespace Demo
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Hello, world!");
            Console.Write("Please enter password: ");
            string pass = Console.ReadLine();
            if (pass == "secret")
            {
               Console.WriteLine("Password accepted");
            }
            else
            {
               Console.WriteLine("Bad password");
            }
            Console.ReadKey();
        }
    }
}

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:

using System;
using System.Text;

namespace Demo
{
    static class Obfuscator
    {
       static string[] hiddenStrings = {
         "SGVsbG8sIHdvcmxkIQ==",
         "UGxlYXNlIGVudGVyIHBhc3N3b3JkOiA=",
         "c2VjcmV0",
         "UGFzc3dvcmQgYWNjZXB0ZWQ=",
         "QmFkIHBhc3N3b3Jk"
       };

       public static string DecryptString(int index)
       {
          return Encoding.UTF8.GetString(Convert.FromBase64String(hiddenStrings[index]));
       }
    }

    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine(Obfuscator.DecryptString(0));
            Console.Write(Obfuscator.DecryptString(1));
            string pass = Console.ReadLine();
            if (pass == Obfuscator.DecryptString(2))
            {
               Console.WriteLine(Obfuscator.DecryptString(3));
            }
            else
            {
               Console.WriteLine(Obfuscator.DecryptString(4));
            }
            Console.ReadKey();
        }
    }
}

No more obvious strings! 🙂 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:

de4dot hello-2.exe --strtyp delegate --strtok 0x06000001

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:

using System;
using System.Text;

namespace Demo
{
    static class Obfuscator
    {
       static string[] hiddenStrings = {
         "SGVsbG8sIHdvcmxkIQ==",
         "UGxlYXNlIGVudGVyIHBhc3N3b3JkOiA=",
         "c2VjcmV0",
         "UGFzc3dvcmQgYWNjZXB0ZWQ=",
         "QmFkIHBhc3N3b3Jk"
       };

       public static string DecryptStringA(int key)
       {
          return Encoding.UTF8.GetString(Convert.FromBase64String(hiddenStrings[key ^ 0x666]));
       }

       public static string DecryptStringB(int key)
       {
          return Encoding.UTF8.GetString(Convert.FromBase64String(hiddenStrings[key + 0xDEAD]));
       }

       public static string DecryptStringC(int key)
       {
          return Encoding.UTF8.GetString(Convert.FromBase64String(hiddenStrings[key - 0xC0DE]));
       }

    }

    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine(Obfuscator.DecryptStringC(0xC0DE));
            Console.Write(Obfuscator.DecryptStringA(0x667));
            string pass = Console.ReadLine();
            if (pass == Obfuscator.DecryptStringB(-57003))
            {
               Console.WriteLine(Obfuscator.DecryptStringA(0x665));
            }
            else
            {
               Console.WriteLine(Obfuscator.DecryptStringC(0xC0E2));
            }
            Console.ReadKey();
        }
    }
}

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:

de4dot hello-3.exe --strtyp delegate --strtok 0x06000001 --strtok 0x06000002 --strtok 0x06000003

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. 🙂

So, the following command-lines will work:

  •  
    de4dot hello-2.exe --strtyp delegate --strtok "Demo.Obfuscator::DecryptString"

    This tells de4dot that string decryptor is method with full name Demo.Obfuscator::DecryptString.

  •  
    de4dot hello-3.exe --strtyp delegate --strtok "Demo.Obfuscator::"

    This tells de4dot to check all methods in class Demo.Obfuscator and pick the ones which look like string decryptors.

  •  
    de4dot hello-3.exe --strtyp delegate --strtok "Demo.Obfuscator::(System.Int32)"

    This tells de4dot which class to look at and what kind of parameters string decryption method has.

  •  
    de4dot hello-3.exe --strtyp delegate --strtok "::DecryptStringA"

    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. 🙂

Look at the source:

for (int i = 0; i < argsStrings.Length; i++) {
   if (argsStrings[i] != sig.Params[i].FullName)
      continue;
}

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 (argsStrings == null) {
    if (sig.Params.Count == 0)
        continue;
else {
    if (argsStrings.Length != sig.Params.Count)
        continue;
}

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. 🙂

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

.NET exception “The remote certificate is invalid”

kao

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:

HttpWebRequest httpRequest = (HttpWebRequest)WebRequest.Create({url_here});
HttpWebResponse response = (HttpWebResponse)httpRequest.GetResponse();
... process response ...

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:

Error: System.Net.WebException: The underlying connection was closed: 
Could not establish trust relationship for the SSL/TLS secure channel. ---> 
System.Security.Authentication.AuthenticationException: The remote certificate is invalid according to the validation procedure.

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:

ServicePointManager.ServerCertificateValidationCallback += delegate {return true;};

It effectively suppresses all certificate validation errors. Problem solved!

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