Green with Evil: Analyzing the new Lockbit 4 Green

Eli Salem
15 min readJan 2, 2025

--

Threat Background

The LockBit ransomware group, active since around 2019, is a highly organized cybercriminal gang known for operating a Ransomware-as-a-Service (RaaS) model[12], allowing affiliates to deploy their ransomware in exchange for a revenue share.
They specialize in double extortion tactics, where they not only encrypt victims’ data but also exfiltrate it, threatening to leak sensitive information unless a ransom is paid.
LockBit is notorious for targeting organizations globally, leveraging advanced evasion techniques, and exploiting vulnerabilities to infiltrate networks, with sectors ranging from healthcare to critical infrastructure among their victims.

The group is also the most prolific ransomware with the largest amount of victims overall, and in 2024 specifically[1].
During the group operations, there have been several versions, the latest being dubbed LockBit Black ( or version 3.0 ).
In December 2024, the group announced its newest ransomware version, “Lockbit 4”.
Lockbit 4 has two versions, Black and Green, In this article we will analyze the green version.

Similar to my previous articles, I will do it in a way of a hybrid step-by-step tutorial and an actual presentation.
As usual, I will focus on the aspects I find most intriguing, particularly how the malware attempts to evade detection, rather than delving deeply into the ransomware encryption process.

  1. PART 1: The initial packer
    - Unpacking the first stage
    - Dump the decrypted binary
    - Fixing Tips
  2. PART 2: Lockbit 4 Green
    - Dynamic resolving through API hashing
    - Evasion technique: Proxying DLL loading
    - Evasion technique: Decryption functions
    - Evasion technique: Verify DLLs
    - Evasion technique: Evading ETW
    - Evasion technique: Disabling DLL loading notifications
    - Evasion technique: Clearing Vectored Exception Handler
    - Checking Machine Language
    - Checking Machine Architecture
    - Ransomware CommandLine Arguments
    - Decrypting the Ransom Note
    - Disabling VSS Service
    - Encryption Exclusions
    - Partial Encryption Mechanism

Part 1: The Initial Stage

File hash: 8ff61e4156c10b085e0c2233f24e8501

Initial assessment

Lockbit’s 4 initial stage is a 64-bit file and from first glance at PEstudio[2], we can already have some assumptions. The file has an entropy of slightly more than 7.8, which indicates that this file is most likely to be packed and not the actual Lockbit payload.
Also, it appears that the only dynamic linked library on its import table is Kernel32.dll which further solidifies the hypothesis that this file is packed.

In the optional header section of PEstudio, we can observe that ASLR[3] is enabled for this sample. To ensure the addresses in IDA and x64dbg align consistently, I always enable ASLR.
Note: Although not appear in the file header, PEID considers this packer as some sort of custom UPX.

Initial assesment

One of the ways to disable the ASLR is by using CFF Explorer

  1. Go to Optional Header
  2. Scroll to DllCharacteristics -> Click here
  3. Unmark the V in DLL can move
Disable ASLR

Unpacking the first stage

As we inspect the initial stage in IDA, we can see several things

  1. There are only three functions that IDA interprets as actual code
  2. In the .data section, there is a huge chunk of unexplored bytes at the address 140001000 (which often indicates that this area is yet to be populated)
  3. Obfuscated TEXT section
  4. There is a variable named “byte_14011901D” which will be manipulated
Unpacking first stage

We can see the two lines

lea rsi, byte_14011901D
lea rdi, [rsi-11801Dh]

And if we will do simple calculation 14011901D — 11801D = 140001000

Therefore we can assume that the content that will populate the unexplored .data section will arrive from this “byte_14011901D” variable

To help with our tracking we can follow in dump in the rdi register

Unpacking first stage

Next, we enter sub_140125010. We can see that the function itself (and its inner function sub_140124FD2) is filled with what can be defined as potential decryption operators.
For example:

  1. Loops
  2. Data manipulating operators (shl \ xor \ byteswaps)

At the end of the function, we can see two VirtualProtect API calls and a jump to 0x140013A9F which is located inside the .data section to be populated.

Unpacking first stage

Traditionally, this behavior is something that we often see in shellcodes after decryption. It is also very common to see this activity in the context of code injection used by shellcodes. However, in our case, there is no newly allocated memory, but the concept is the same.

We can set a breakpoint just before the jump and see the decrypted content. We can also see that as we thought, this is the same buffer of the .data section that was populated.

Unpacking first stage

Dump the decrypted binary

The next step we will want to do is to inspect the new payload in IDA and debug it.

  1. To debug it we can simply step into the jump.
  2. To analyze in IDA we can dump the entire fixed executable using Scylla
Dumping unpacked payload

Fixing Tips

After dumping, we can see that we do see many new functions, however, there are still unexplored bytes in the area that are supposed to be code.

Fixing data

In this case, we can help IDA understand that we want to see it as code
Note: Not every unexplored bytes are automatically code, but we can try and see.

  1. Click C to tell IDA to convert these bytes into code
Fixing data

2. Click P to tell IDA to look at your code as a function
Note: It is sometimes better to look where the stack subtracts and adds just to make sure you get the entire function.
For example:

  1. In this image, we can see sub rsp,20
  2. Look for add rsp, 20 to make sure where the function ends
Fixing data

An entire transition should look like this

Fixing data

In this sample there are multiple cases like this, I suggest doing it for any unexplored bytes and checking if there are more functions that can be revealed.

Part 2: Lockbit 4 Green

After finishing the entire fixing we can finally look at the ransomware itself. The file itself is importless, therefore, dynamic resolving must happen.

Dynamic resolving through API hashing:

API hashing in malware[4][8] is not a new trick, however, Lockbit 4 uses a slightly more complex (or annoying) way to resolve it.

The resolving mechanism is spread between several hashing functions that eventually lead to xor decryption.
Because this behavior is slightly changing (using different hashing functions or adding constant hash instead of creating it) I will demonstrate it one time, the first time that we encounter this behavior.

sub_1400044BC
This function will be responsible for generating a hash constant.
(This function is present only at the beginning and is replaced by sub_140003D26 which takes as an argument a hash constant that represents a .dll, it then turns an area in the DOS stub of that .dll)

sub_140003FE7
This function will be responsible for understanding who the requested API is.
Note: Traditionally in API hashing, these kinds of functions will return the requested API address in the RAX\EAX register.

However, here comes the trick, the function returns an address that is not the address of the requested API but a couple of bytes before it.
Also, it stores the pointer to this address in RSI.

sub_14000435C
Another function for generating hash constant

sub_14000446F
XOR a first byte of a given content

  1. This function will usually get the RSI pointer and change its first byte
  2. Once the first byte is changed, the pointer to the address is changed
  3. The newly changed pointer will hold the address of the requested API

So in our case, we first see this behavior in this place

API Resolving

Let's observe this dynamically

  1. After executing sub_140003FE7 we can see that it returns some address inside Kernel32.dll (0000000077352F51), however, this address is not an API beginning address.
API Resolving

Also, if we observe it on the disassembler it does not seem important

API Resolving

2. This is where sub_14000446F comes in, as mentioned, it gets two parameters:

a. Hash constant that is in RDX
b. A pointer to the address 0000000077352F51 which resides in RSI

API Resolving

Once we step over sub_14000446F we can see that the first byte was changed, and the new outcome points to 0000000077352F40

API Resolving

We see that the address 000000000012F9A0 which holds RSI is now colored in red, which means that it points to an actual API.
We can see in the disassembler who is the requested API, in this case, GetThreadContext.

API Resolving

Eventually, the API's initial steps of resolving look like this

API Resolving

During the malware execution, it will invoke them dynamically without storing them in a variable like in this case. therefore, I recommend observing the pattern of sub_140003FE7 + sub_14000446F followed by a call to a register.

Evasion technique: Proxying DLL loading

The second method that the ransomware uses to dynamically load its modules is called proxy DLL Loading[5][6].

The technique works as follows:

  1. The ransomware executes RtlQueueWorkItem
  2. The first parameter is LoadLibraryW Address
  3. The second parameter is a path of a given DLL
Proxy DLL loading

Then, the function ZwWaitForSingleObject will be executed

Proxy DLL loading

Which eventually caused the requested DLL to be loaded

Proxy DLL loading

Why this technique is evasive?

Loading a library using RtlQueueWorkItem is more evasive because it executes the library load in a separate thread managed by a worker thread pool, creating a clean stack trace that potentially does not include suspicious RX (executable memory) regions as the origin if code injection was involved.
This could bypass ETWTI (Event Tracing for Windows Telemetry Infrastructure) because some detections that are based on ETWTI rely on stack tracing to detect malicious activity, and the clean stack obfuscates the true origin of the LoadLibrary call.

Evasion technique: Decryption functions

Before we continue with more mechanisms, we must talk about the sample’s decryption functions.
They are spread over the sample and usually are a simple loop with an XOR of 0x3A, where only the length of the loop is changed.

An example of this function can be seen in the following image:

Decrypting function

To find them all, in IDA we can simply

  1. Go to Search
  2. Go to Text
  3. Search add edx, 3Ah
Searching for decrypting function

Then when we see them all, we can just label them in IDA as decrypting functions

Searching for decrypting function

An example of a vast activity of these types of functions can be seen in the following image:

Decrypting drives

Evasion technique: Verify DLLs

One of the common activities that malware likes to check is if there are any hooks or other kinds of traps in the loaded modules of the process, and this ransomware is no different.

The ransomware uses a common trick to unhook the loaded modules in the following way:

  1. It checks the loaded modules from the KnownDlls path
  2. It uses NtOpenSection + NtMapViewOfSection to map the desired dll to memory
  3. It then uses WriteProcessMemory (from kernelbase.dll) to write the content of the newly loaded dll to overwrite the existing loaded dll.
    This confirms that the DLL is loaded without any modification from any security product.
Verifying DLL content
Verifying DLL content

Evasion technique: Evading ETW

The next evasion technique the ransomware uses is to disable ETW-related functions. It does it as follows:

  1. It uses NtProtectVirtualMemory to allow writing into EtwEventWrite
Bypass EtwEventWrite

2. It uses ZwWriteVitualMemory to write the byte C3 at the beginning of EtwEventWrite

Bypass EtwEventWrite

After the execution of ZwWriteVitualMemory, we can see that the function starts with C3 which means “ret”

Bypass EtwEventWrite

How this is helping the ransomware to avoid detection?

The C3 instruction causes the function to immediately return without executing its original logic. Any call to EtwEventWrite will effectively do nothing, as it will return control to the caller right away.

EtwEventWrite is used by Windows for event logging and telemetry, often leveraged by security tools (e.g., EDRs) to monitor process activities. By overwriting the function, the ransomware disables its ability to write events, effectively bypassing any logging or monitoring that relies on it.

Evasion technique: Disabling DLL loading notifications

Another evasion technique the ransomware uses is the ability to disable notifications of newly loaded DLLs, and it does it in the following way:

  1. The ransomware iterates the PEB
  2. The ransomware decrypts the string “.data”
  3. sub_140003451 returns the base address of the .data section and its size
  4. The ransomware loops over the .data section
  5. Using the functions LdrRegisterDllNotification and LdrUnRegisterDllNotification to disable the notifications of newly loaded DLLs in the current process context.
Remove DLL notifications

This technique was mentioned in a Proofpoint report[10] about Nighthawk and was well explained:

“Nighthawk implements a technique that can prevent endpoint detection products from receiving notifications for newly loaded DLLs in the current process context via callbacks that were registered with LdrRegisterDllNotification. This technique is enabled by the clear-dll-notifications option.

The intended way to unregister a DLL load notification callback is to use LdrUnregisterDllNotification; however, this requires a cookie value that is returned by the initial LdrRegisterDllNotification. Nighthawk works around this by directly modifying the list of structures that store callbacks for a given process.”

Evasion technique: Clearing Vectored Exception Handler

Yet another trick of the ransomware is to clean the Vectored Exception Handler[11].

Background:
A vectored exception handler is a mechanism in Windows that allows applications to register custom exception handlers to be called before the structured exception handling (SEH) mechanism processes exceptions. It provides a way to globally intercept and handle exceptions (e.g., access violations or breakpoints) using functions like AddVectoredExceptionHandler, enabling advanced debugging, error handling, or anti-debugging techniques.

The ransomware deleted the VEH in the following way:

  1. In sub_1400036E7 The ransomware added a new vectored exception handler of its own (without any intention to have a meaningful purpose)
    This handler serves as a starting point to identify and traverse the linked list of existing exception handlers.
  2. The ransomware decrypts the string “.data”
  3. sub_140003451 returns the starting address of the VEH and its size
    (the VEH address is in the .data section)
  4. The ransomware iterates through the VEH until it reaches the newly added VEH
Deleting VEH

5. sub_1400036E7 returns the LdrpVectorHandlerList structure

6. The main code continues to iterate the returned list and remove every VEH using RtlRemoveVectoredExceptionHandler if found

Deleting VEH

How this is helping the ransomware to avoid detection?

  1. Security tools may use Vectored Exception Handlers (VEH) to monitor exceptions (e.g., access violations, invalid instructions) caused by malicious code.
    By removing or disabling these handlers, malware can evade detection or disrupt these monitoring systems.
  2. Debuggers often rely on VEH to handle exceptions during the debugging process.
    Removing or tampering with VEH could make it harder for a reverse engineer or debugger to analyze the malware.
  3. Some software uses VEH to enforce protections such as anti-tamper mechanisms, code integrity checks, or anti-debugging measures.

Checking Machine Language

As with many ransomware, Lockbit 4 also checks the language identifier of the keyboard using GetKeyboardLayoutList.
And there is no surprise that this ransomware also checks if the spoken language is Russian, possibly to avoid encryption.

Checking Machine Language

Checking Machine Architecture

The ransomware will try to verify the machine’s architecture.
To do so, it will use the API RtlGetNativeSystemInformation and will check whether the machine is:

  1. 64-bit systems (x86_64)
  2. ARM-based system
  3. Older architecture
Checking Machine Architecture

Ransomware CommandLine Arguments

As I mentioned, there are multiple string decryption functions in the sample, and during my analysis, I found that they are also responsible for decrypting some of the command line arguments.

Command Line Arguments

When I started my analysis I didn't know about the command line arguments, but after seeing the “- -help” argument I simply tried it.
The command line arguments are self-explanatory.

CommandLine Arguments

A key point to consider is the “-q” argument, which could pose a challenge to security vendors. By allowing the ransomware to encrypt files without altering their extension, creation time, or modification time, it can create difficulties for detection methods that rely on these attributes.

Decrypting the Ransom Note

Like many ransomware, the Lockbit 4 ransom note is encrypted and embedded in the PE.
The decryption mechanism goes as follows:

  1. A heap is allocated
  2. Data is written to the allocated heap
  3. The data is decrypted via a custom RC4 algorithm
Decrypting the ransom note

To inspect it dynamically we can simply:

  1. Observe the data that is returned from sub_140004D84 which will be our newly allocated heap (In our case the buffer starts at 0000000000382F60)
Decrypting the ransom note

2. Step over sub_14000225B which copies content to the newly allocated heap

Decrypting the ransom note

3. Set a breakpoint after the RC4 algorithm and observe the buffer

Decrypting the ransom note

Disabling VSS service

Like many other ransomware, Lockbit 4 Green also disables the VSS service.
Background: The Volume Shadow Copy Service (VSS) is a Windows technology that enables the creation of consistent point-in-time snapshots, called shadow copies, for backup and recovery purposes. Shadow copies allow users or applications to access previous versions of files or entire volumes, even when they are in use, ensuring data consistency for backups, restores, or system recovery.

The ransomware uses the APIs:

  1. OpenSCManager
  2. QueryServiceStatusEx: To check if the VSS service is running
  3. EnumServicesStatusExA: To enumerate the services
  4. OpenServiceW: To open a handle to the VSS service
Get handle to VSS service

5. ControlService: To stop the service

Stopping the service

6. ChangeServiceConfigA: To disable the service

Disabling the Service

Note: Similar to the VSS service, the WSearch service is disabled as well

Encryption Exclusions

By default, the ransomware will avoid encrypting the following files & file types:

  1. iconcache.db
  2. thumbs.db
  3. .exe
  4. .lnk
  5. .dll
  6. .cpl
  7. .sys
Exclusions

Also, each encrypted directory will contain the ransom note .txt file with the name “Restore-My-Files.txt”

Directory after encryption (only txt file was encrypted)

In addition, the ransomware will avoid encrypting the following paths

  1. Windows
  2. $Recycle.Bin
  3. All Users
  4. boot
  5. chocolatey
  6. Microsoft Visual Studio
  7. System Volume Information
Exclusions

Partial Encryption Mechanism

Although I didn’t focus heavily on the ransomware’s encryption aspects, as I couldn’t find a command-line argument suggesting partial encryption, I wondered if the ransomware employs this concept.

Background:
Partial encryption in ransomware is a technique where only a portion of the file is encrypted, typically the first few megabytes or specific chunks, leaving the rest of the file intact. This approach significantly speeds up the encryption process, making it harder for detection mechanisms to interrupt, while still rendering the file unusable and achieving the ransomware’s goal of extortion.

In the Lockbit 4 case, the ransomware uses the concept of partial encryption in the following way:

  1. If the file size is less than 1MB it will encrypt the entire file
  2. If the file size is larger than 1MB it will encrypt approximately 27 % of the file

Logic:
In each iteration, 9% of the file size is encrypted. Therefore, over 3 iterations, the total portion encrypted is: 27%

Partial encryption logic

The result itself can also be shown if we drop the encrypted files to Cyberchef and check their Entropy

Partial encryption
Partial encryption

References:

[1] https://www.rapid7.com/blog/post/2024/12/16/2024-threat-landscape-statistics-ransomware-activity-vulnerability-exploits-and-attack-trends/
[2] https://www.winitor.com/download2
[3] https://en.wikipedia.org/wiki/Address_space_layout_randomization
[4] https://www.ired.team/offensive-security/defense-evasion/windows-api-hashing-in-malware
[5] https://0xdarkvortex.dev/proxying-dll-loads-for-hiding-etwti-stack-tracing/
[6] https://github.com/rad9800/misc/blob/main/bypasses/WorkItemLoadLibrary.c
[7] https://x.com/vxunderground/status/1869869561421389914
[8] https://www.youtube.com/watch?v=3FPY4cLaELU
[9] https://github.com/rad9800/misc/blob/main/bypasses/UnregisterAllLdrRegisterDllNotification.c
[10] https://gist.github.com/Neo23x0/eff6a644c2a6ce715eefdd92650e10a7
[11] https://github.com/rad9800/misc/blob/main/bypasses/ClearVeh.c
[12] https://redsense.com/publications/lockbit-story-a-three-year-investigative-journey/

--

--

Eli Salem
Eli Salem

Written by Eli Salem

Malware Researcher & Threat Hunter

No responses yet