MABR 0x02 | DoubleTrouble - Analysis of STOP Ransomware & Vidar Stealer | Unpacking

Back to malware analysis, i recently decided to analyse a completely random sample (as long as it isn’t .NET lol) found on MalwareBazaar, this sample appears to be STOP ransomware.

Preview

I’ve never analysed a ransomware already, and to be honest i thought that this sample was « only » a stealer, but after a quick analysis on Any.run and some initial research, i realised that it was a ransomware dropping a stealer too.

This technique is increasingly used nowadays, threat actors are no longer satisfied by just locking up data and ask for ransom, they actually steal data, and then encrypts it to apply a double pressure on the infected user. So if the user doesn’t want to pay for the ransom, threat actors can still sell or use data stolen to make profit.

Initial analysis

When analysing a sample, i first insure that the malware is packed or not, if it contains resources or interesting strings inside.

For this purpose, i use DiE (Detect it Easy) and PE Studio to gather initial information about the sample.

DiE informs us that the .text section (the section that contains all the executable code) has a very high entropy (7.92) which means the executable is packed or highly obfuscated.

image.png.webp

Entropy of .text section

We know that the sample is packed, but, PE Studio shows that it has a decent amount of imports, strings and even an export.. for the moment i cannot understand what is happening here, so let’s fire up IDA to see the code.

Informations returned by PE Studio

Disassembling

The flow starts with the start function that leads to WinMain.

This type of flow belongs to a Windows application created with Visual Studio (the easy way out). We can assume that this sample was not created by an APT or some big fish, they avoid creating these types of applications because they create bigger executables and leave more tracks of the way that they were created.

Flow graph of WinMain

Except leaving debug traces, Visual Studio applications leave a lot of compiler related functions which can be annoying during analysis, and this sample is no exception to the rule.

Obfuscation

The flow graph of this executable is tricky to understand because it has a lot of branches and a lot of compiler related functions, so i jump to pseudocode view of IDA, and i can see that the malware is heavily obfuscated :

image-4.png.webp

Lot of API calls with 0 parameters or dummy strings

Despite the obfuscation, the flow is rather simple to analyse in pseudocode, because we can easily spot dummy functions.

If found an interesting function responsible of changing the protection of a memory page in order to prepare the field for the decryption of some shellcode. It uses stack strings to load VirtualProtect :

image-6.png.webp

The new protect is PAGE_EXECUTE_READWRITE, a prerequisite to execute code.

Shellcode decryption

I don’t know by which way the shellcode decrypts, but i found the function for. I think it simply copies data to the newly unprotected memory section :

image-7.png.webp

It takes 3 args, a chunk of encrypted data and the address to inject the shellcode.

It then jump to shellcode by a call to the injected memory region :

image-8.png.webp

Call to memory region in pseudocode mode

Newly discovered anti-debugging technique

When i unpacked this sample, i already knew where to jump to go to the shellcode, so i put a breakpoint on the call to shellcode in memory… BUUUT

image-9.png.webp

This guy

When i reversed it, i thought it was only a bug by my fault, when execute the program until the call, i have an ACCESS_VIOLATION error, and impossible to continue.

Without much information, i simply NOPed the bytes out to continue my analysis, but i found this tweet randomly while scrolling on Twitter.

https://twitter.com/fr0gger_/status/1387694972976128003?s=20&t=VeeqmCOPdaCytczCQoMklQ

This technique is apparently used to trap the debugger and beginner reversers, but it is simple to counter, just NOP out the call bytes and reassemble the binary.

I also created a capa rule to detect this technique:

rule:

  meta:

    name: trap debugger with localsize

    namespace: anti-analysis/anti-debugging

    author: lordtmk@protonmail.com

    scope: basic block

    examples:

      - B67E5B1985742F62785122B637EF4FBD:0x4B1F5B

  features:

    - and:

      - api: LocalSize

      - mnemonic: push 

      - number: 0

Jump in the shellcode

The first function is responsible for loading LoadLibraryA and GetProcAddress, the 2 APIs used to resolve all other APIs :

image-11.png.webp

Loading APIs by hash

Then, it loads in memory all the APIs needed to pursue its goal.

image-10.png.webp

VirtualAlloc is here the most important API to perform injection

It then calls VirtualAlloc to alloc a memory page to inject the shellcode.

image-12.png.webp

Again, i cannot identify the algorithm used to decrypt the shellcode, but i know this is actually decryption compared to the previous function.

image-13.png.webp

Flow of decryption function

When the decryption is finished, the program simply jumps to address of new shellcode:

image-15.png.webp

Jump to shellcode

Last layer of unpacking

The flow starts again with a lot of stack strings that are translated to APIs using GetProcAddress :

image-16.png.webp

VirtualProtectEx stack string followed by a call to GetProcAddress

Then we have another layer of obfuscation, with dummy function calls, but one of them catches my attention, a call to CreateWindowExA that leads to a stack overflow.

image-17.png.webp

Dummy call that leads to stack overflow

I searched if this call was an anti debugging technique but it seems not. It is easy bypassable if we go back to user code.

Dealing with process hollowing

The last step of this shellcode is to inject next code into a newly created process of the program itself, and for that purpose, it uses process hollowing, which is one of the most used technique nowadays.

1st : Create a process in suspended state

image-18.png.webp

Always check the args of CreateProcessA

Here, GetCommandLineA is used to retrieve the command line used in the program. This function will retrieve the full path of the executable.

image-19.png.webp

Program starts child in suspended mode

In suspended state, the program doesn’t run and just waits for his parent to resume it.

2nd : Delete all content of executable and writes data to it

image-20.png.webp

NtUnmapViewOfSection is a low-level, poorly documented API that is used to wipe all sections from a program. It is mainly used to inject into legitimate programs, because the header stays the same (for example we can inject malicious code inside a legitimate executable of notepad.exe. The headers will stay the same but the data will be our malicious code.) This technique was first seen in Stuxnet and is used to execute legitimate looking programs in Windows.

image-21.png.webp

1st memory write attempt

ZwWriteVirtualMemory is another low level call that is used to write data inside memory pages.

image-22.png.webp

2nd memory write attempt

It then calls the more conventional WriteProcessMemory, which is a highest level call, to achieve the same goal.

3rd : Setting thread context and resume it

This is the most important part of the technique, we can catch the new process start address :

image-23.png.webp

First, a call to GetThreadContext is made to retrieve the CONTEXT structure that contains data about the program execution, you can find more information here : https://www.nirsoft.net/kernel_struct/vista/CONTEXT.html

image-24.png.webp

Then, a call to SetThreadContext is made. it will set the start address of the newly created process. It is important to keep this address because we will use it in a moment.

image-25.png.webp

StartAddress

We can find the address in the hexdump of CONTEXT structure. After this call, we must edit the memory of the program to be launched.

image-26.png.webp

Memory page of suspended process (make sure it is RWX)

The base address of the process is 0x400000, so we must go to 0x24141 to find the entry point :

image-27.png.webp

These are the bytes that will be executed when the program will launch

To prevent program for executing, we will patch these 2 bytes to create an infinite loop. Save carefully these 2 bytes (E8 3D) and replace them with EB FE, which will create an infinite jump to the address.

image-28.png.webp

Patched bytes

Next, we can safely step over the ResumeThread call, and finally attach to the newly resumed process.

image-29.png.webp

The process is now resumed

When we attach to the running process, we will see this ; the program is jumping to the same address over and over. Don’t forget to put a breakpoint on this after continue :

Endless jump

We next have to patch the bytes back :

Patched bytes

image-32.png.webp

Instruction has changed

We can safely end the parent process :

image-33.png.webp

The parent programs ends with ExitProcess

There is the great article that i referred to achieve this : https://airbus-cyber-security.com/following-process-hollowing-ollydbg/

End of the 1st part

Basically we are here :

Capture-décran-2021-06-15-à-17.11.08.png.webp

We just covered 1 injection

And there is a looooot more to do : 😅

Capture-décran-2021-06-15-à-17.15.04.png.webp

The entire execution flow of the program

This 1st part of the sample was quite easy, just dealing with obfuscation and anti-debugging technique, and then follow process hollowing to unveil the real malicious sample.

You can search this hash on MalwareBazaar if you want to study this malware : b67e5b1985742f62785122b637ef4fbd

Stay tuned for part 2!

comments powered by Disqus
Built with Hugo
Theme Stack designed by Jimmy