Unpacking and Analyzing Purelog Stealer (ft. a quick trick using Powershell)

 Introduction

In this blog post, I'll be showcasing via example a useful trick to invoke .NET methods from Powershell and skipping all the anti-analysis routines. The same technique could be used for string decryption and other things. We'll be unpacking a sample which I suspect, based on the loading steps, to be Purelog Stealer (This is an advanced stage. I won't bother you with how I got to this stage tldr; boring stuff, AutoIt.) using Powershell and then presenting an analysis of how the sample works and what I think it does.

Hash of this stage sha256:46ddbdbe28dbdfb95cefa95b3597b989a50cd415fb978fe7fb14d2b8e3b5dee8

How is the payload stored?

Skimming through the method, we find this memory stream


Usually, something like this is very interesting and worth exploring.

Tracing this method. We find the decrypted stream used in this method.


Something is loaded, so that's a giveaway that we're dealing with an unpacking routine. Another method is called before the loading.


So, a memory stream is decrypted, decompressed and then loaded.

You could set a breakpoint and retrieve the values of the memory stream and do the decryption manually. 
That's not only boring, but there could also be anti-analysis techniques that'll prevent you from reaching this part of the program.

You could write the decompiled code to a file and retrieve the stream from there then implement the decryption and decompressions routines. But, there's a better and faster solution.

Invoking the methods from Powershell

Powershell is build on top of the .NET framework which allows smooth interaction with .NET binaries.

Instead of a pointer, methods (pretty much everything) in .NET is referenced by tokens. Method tokens start with "0x06...". This is how we're going to find our method.

For example, the method that decrypts the memory stream is identified with the token 0x06000008



Before interacting with the binary, we need to load it and this can be done via the command 


Afterwards, we retrieve the decryption method by its token as follows


We then proceed to Invoke the method and save the return value which is the decrypted stream in a variable. 

N.B: You could also attach DnSpy's debugger to the powershell process and set a breakpoint at whichever instruction you want inside the method. 

The reason we pass $null as first argument is because the method is static so we don't need to pass a class instance to it.


The call to the method was successful



Now, we need to call the decompression method on this result.

The decompression method is identified with the token 0x0600000D


We follow the same steps again.

Retrieving the method by its token.


This time we need to pass the decrypted stream as argument.


Let's see if the result is actually an executable



Seems so!

Anti-Analysis Techniques

Let's save the unpacked executable into a file and inspect it.

We save it to unpacked.exe with this command


Let's open it in Detect It Easy


It's a .NET DLL obfuscated with .NET Reactor.

Luckily there's a tool called NetReactorSlayer ( https://github.com/SychicBoy/NETReactorSlayer ) that deobfuscates such assemblies.


Let's open it in DnSpy. It's more readable now.

We can see anti-sandbox techniques


A BIOS check if the system is running in a virtualized environment



A check to see if the sample is run from cmd.exe to prevent running from a script



A check to see if the sample is running ina VMWare Virtual Machine


This is a very interesting check since it verifies the common virtual machine resolutions



Extracting the configuration

Skimming through the methods, we find this interesting one.



It's a base64 encoded string that is passed to a method.


The method deserializes it. Finally it is casted as (Class20) Object.

It's a Protobuf!




We can use an online website to deserialize the object.



We can clearly see the configuration!

One small issue is which one is the mutex? (lmao)

Class20 looks like this


Instea of keeping the member names like this. I'll rename them depending on the order so we can see which one is which in the deserialized object since we don't have names.

We found the method that initialized the mutex


The field that's passed to it is the 4th


So the mutex is 5bec48dd15fbca32

As for C2 communication is established with 



It is either establishing a connection to the first element in the object which is the IP address 134.255.234.103 with port 5888

OR, via a SOCKS5 Proxy via port 9050 Which is associated with TOR.

Another location where the a field in the serialized object is used which is to send bytes to the socket.


Bytes are compressed with GZIP


And then encrypted with 3DES with key 5bec48dd15fbca32 (3rd element in the serialized object)


The sample also allow sending and execution of raw assemblies


These methods (from right to left) decrypt from 3DES with the same key, decompress from Gzip, deserializes, load and execute the first method from the result.


IOCs:

    - IP134.255.234.103:5888
     mutex5bec48dd15fbca32 

Conclusion

So far, we didn't encounter any information stealing routines. Since, it receives and executes .NET assemblies then it is most likely a loader. The reaons I believe this is a PureLog stealer sample, is that the stages follow the same patterns here https://any.run/cybersecurity-blog/pure-malware-family-analysis/ . 

Comments