Malware’s New Playground: Inside the Box

Research by: Jiri Vinopal

Highlights:

  • Check Point Research (CPR) reveals the increasing abuse of BoxedApp products to deploy multiple known malware families.
  • BoxedApp products are general packers built on top of its SDK, which provides the ability to create Virtual Storage (Virtual File System, Virtual Registry), Virtual Processes, and a universal instrumentation system (WIN/NT API hooking).
  • Our investigation shows that the most abused BoxedApp products are the ready-to-use BoxedApp Packer, BxILMerge, and the BoxedApp SDK that simplifies the development of custom packers leveraging BoxedApp features, e.g., Virtual Storage and Virtual Processes.
  • CPR provides an in-depth analysis of the BoxedApp internals, focusing on the resulting packed binary structures.

Introduction

Over the past few months, we have been monitoring the increasing abuse of BoxedApp products in the wild. BoxedApp products are commercial packers that provide advanced features such as Virtual Storage (Virtual File System, Virtual Registry), Virtual Processes, and a universal instrumentation system (WIN/NT API hooking).

Even though BoxedApp has been commercially available for a while, in the past year we detected a significant increase in its abuse to deploy numerous known malware families, primarily related to RATs and stealers. The majority of the attributed malicious samples targeted financial institutions and government industries.

Our investigation shows that the main abused BoxedApp products are BoxedApp Packer and BxILMerge, which are built on top of the BoxedApp SDK. While both products provide threat actors with access to the most exciting features of the SDK, with the BoxedApp SDK itself they can create a custom, unique packer that leverages the most advanced features and is diverse enough to avoid static detection.

Packing the malware to lower its detection or to harden analysis is a known technique commonly applied to the malware´s payload. While using a known commercial packer has some disadvantages, the benefits of using advanced, unique features easily outweigh them. Among the most interesting features and capabilities of BoxedApp SDK are:

  • Virtual File System (part of the Virtual Storage)
  • Virtual Registry (part of the Virtual Storage)
  • Virtual Processes (PE Injection – launching processes from the memory)
  • WIN/NT API hooking SDK
  • General packing (destroying original PE Imports, compression, etc.)
  • Producing a single-file bundle (all required dependencies are a part of the Virtual Storage)
  • All I/O to Virtual Storage stays only in memory (no file is dropped to disk), e.g., DLL loading from Virtual Storage

In this report, we provide a general overview of BoxedApp products and their abuse for malicious purposes, as well as an in-depth analysis of the resulting packed binary structures with Yara signatures that can be used to statically detect the packer in use while distinguishing the product itself.

Background & Key Findings

Although BoxedApp products have been available for several years, in the past year there has been a significant increase in their abuse to deploy several different malware families without any public mention of their connection to BoxedApp.

The BoxedApp products are well-known commercial packers, so there are both pros and cons to abusing them to hide malicious payloads:

PROS:

  • Reliable, ready-to-use products providing advanced capabilities.
  • Available BoxedApp SDK to create custom diverse packers.
  • Uses a proprietary system of Virtual Storage (Virtual File System, Virtual Registry).
  • Creation of Virtual Processes (any process created from an executable file that is a part of the Virtual Storage) for PE injection.
  • Simple SDK to perform hooking of any WIN/NT API.
  • General packing (destroys original PE Imports, performs compression, etc.).
  • Produces a single-file bundle (all required dependencies are a part of the Virtual Storage).
  • All I/O to Virtual Storage stays only in memory (no file is dropped to disk), e.g., DLL loading from Virtual Storage.
  • It is difficult to distinguish between regular and malicious packed applications (high rate of False Positives).

CONS:

  • Easy static detection of the original BoxedApp products used to pack the malware.
  • Generic static detection of certain SDK features commonly abused for malicious purposes (e.g., WIN/NT API hooking, Virtual Process – PE injection).
  • High rate of FP (False Positive) detection from non-malicious applications packed by BoxedApp.

As you may expect, the abuse of BoxedApp to deploy malicious payloads and stay under the radar could result in discrepancies caused by its high-rate of FP detection even in non-malicious applications. The built-in Windows Defender and other top-notch AVs are usually not affected, but even a simple “Hello World” application packed by BoxedApp is initially detected by several AV engines.

Product Original PE Format Initial VT Detection Link
BoxedApp Packer Native PE (C/C++) 14/71 VirusTotal
BoxedApp Packer .NET PE (C#, .NET Framework) 20/71 VirusTotal
BoxedApp BxILMerge .NET PE (C#, .NET Framework) 2/70 VirusTotal

As a side note, the number of FP detections could be significantly lowered by signing the resulted packed binary (regardless of what signature is used) or by using a custom packer built on top of the BoxedApp SDK.

Because of the high rate of AV FP in static detection, which detonates right at the moment of processing BoxedApp SDK, we decided to use the most suitable method (based on the sample´s behavior) to separate the FP from the actual malicious samples.

Among approximately 1200 tested samples (packed by BoxedApp) submitted to VT (VirusTotal) in the last 3 years and successfully processed by VT sandboxes, 25% were detected as “malicious” based on their behavior. The VT submission timeline of those malicious samples shows the increasing trend of BoxedApp abuse for malware deployment.

Figure 1: Malicious BoxedApp samples - VT submission timeline.
Figure 1: Malicious BoxedApp samples – VT submission timeline.

The table below shows the most deployed, attributed malware families. While a significant portion of the malicious samples are either RATs or stealers, we also detected several instances of ransomware, some of which belong to the notorious LockBit strain.

QuasarRAT NanoCore NjRAT Neshta AsyncRAT XWorm LodaRAT
RevengeRAT AgentTesla LockBit RedLine Remcos ZXShell Ramnit

To illustrate the more generic malware classification (based on the VT sandbox results), we separated and sorted the malicious BoxedApp samples based on their Behavior Verdicts.

Figure 2: Malicious BoxedApp samples - generic malware
classification.
Figure 2: Malicious BoxedApp samples – generic malware classification.

Half of the malicious samples submitted to VT were primarily from Turkey, the United States, and Germany, but the increasing trend of BoxedApp abuse is apparently worldwide.

Figure 3: Malicious BoxedApp samples - country submission (VT).
Figure 3: Malicious BoxedApp samples – country submission (VT).

Most of the attributed malicious samples were used in attacks against financial institutions and government industries. Using BoxedApp products to pack the malicious payloads enabled the attackers to lower the detection rate, harden their analysis, and use the advanced capabilities of BoxedApp SDK (e.g., Virtual Storage) that would normally take a long time to develop from scratch.

Internals of BoxedApp

When an application is packed by BoxedApp, the resulting format is a single self-contained PE binary, where the original PE’s imports are destroyed and resolved only during runtime via a stubbed TLS Callback. The TLS Callback is responsible not only for the runtime API resolving but also for initializing Virtual Storage and possibly decompressing its content.

All required dependencies of the original application may be part of the proprietary system of Virtual Storage, which consists of a Virtual File System and Virtual Registry. BoxedApp interceptions of I/O (inline hooking of certain WIN/NT API) handle such virtual files and registry in memory, resulting in the creation of a fake (Virtual) Registry and no files dropping to disk.

When the packed application performs I/O on files or registries that are a part of the Virtual Storage, the BoxedApp internals intercept these I/O operations and direct them to the Virtual Storage (the application does not recognize that it is not interacting with the real registry and files). On the other hand, when the packed application tries to interact with files and registry that are not a part of the Virtual Storage, the internal logic of BoxedApp directs the I/O to the real registry and files on the disk. The Virtual Storage can also be used to fake and mark certain files or registries as non-existing for the packed application despite the fact they exist on a real system. A simplified logic of BoxedApp internals is shown below.

Figure 4: Simplified logic of BoxedApp internals.
Figure 4: Simplified logic of BoxedApp internals.

By default, the content of files embedded in the Virtual Storage is clearly readable on disk (and also the main binary), but other compression options can be set. This results in all the embedded virtual files being compressed with the Zlib – DEFLATE algorithm, which makes all virtual files unreadable on disk. The decompression is processed only in memory during the runtime.

One of the other capabilities of BoxedApp is the creation of Virtual Processes that occur after the process is created from an executable file (PE) that is recognized as a virtual file (part of the Virtual Storage). A certain suitable PE binary from the System32/SysWOW64 (depending on the architecture) directory is selected and started as a suspended process. The original PE “Virtual File” is injected into the memory of the remote process (PE Injection is similar to PE Hollowing without unmapping the original main module) with a combination of WIN APIs (VirtualAllocExVirtualProtectExWriteProcessMemoryCreateRemoteThreadEx), and no file is dropped to disk.

Among the main BoxedApp products built on top of the BoxedApp SDK are BoxedApp Packer and BxILMerge. While the BoxedApp Packer can pack both native and .NET PEs, the latter is purely tailored to .NET applications.

BoxedApp Packer

BoxedApp Packer is a utility that packs the application into a self-contained PE binary (both native and .NET applications are supported). The self-contained PE binary is a single executable binary with all the files that the targeted original application depends on, such as ActiveX controls, dynamic libraries, “squeezed” into that single file. In other words, the packer creates an individual (virtual) work environment for the application.

Figure 5: The BoxedApp Packer UI.
Figure 5: The BoxedApp Packer UI.

The other files and registry that the targeted application depends on can be embedded into the Virtual Storage (creating virtual files and registry). BoxedApp interceptions of I/O (inline hooking of certain WIN/NT API) handle virtual files and registry in memory, resulting in no files dropped to disk and creating a fake Registry system (Virtual).

If a compression is selected, the content of files embedded in the Virtual Storage is compressed with the Zlib – DEFLATE algorithm. When packing a native PE binary with the compress option, the original packed binary is still readable on disk. It is not compressed; only the Virtual Storage is compressed.

However, in the case of packing a .NET PE binary with the compress option, the packed stub native PE binary DotNetAppStub is still readable on disk and not compressed; the original .NET PE Binary and the Virtual Storage are compressed.

The structure of the Original Packed Native PE Binary:

Figure 6: The structure of the packed native PE binary (BoxedApp
Packer).
Figure 6: The structure of the packed native PE binary (BoxedApp Packer).
  • The Original Packed Native PE Binary (the destroyed Imports, resolved during the runtime via TLS Callback) – not affected by the compression option:
    • Virtual Files/Registry embedded into the Virtual Storage, in the .bxpck PE section – affected by the compression option.
    • bxsdk32.dll/bxsdk64.dll – 32/64-bit version of native DLL, depending on the architecture (the main part of BoxedAppSDK), in the .main PE section – not affected by the compression option:
      • BoxedAppSDK_AppDomainManager.dll – 32/64-bit version of .NET DLL.
      • BoxedAppSDKThunk.dll – 32/64-bit version of native DLL.
      • TLSSupport.dll – 32/64-bit version of native DLL (BoxedApp helper library setting the DllMain Callback).

The structure of the Original Packed .NET PE Binary:

When the BoxedApp Packer is used to pack a .NET application, a special stub native PE DotNetAppStub is created that wraps the original .NET PE into the .bxpck section right above the Virtual Storage. The Packed Stub Native PE Binary is responsible for the initialization of BoxedApp internals where the in-memory execution of the original .NET PE follows.

Figure 7: The structure of packed .NET PE binary (BoxedApp
Packer).
Figure 7: The structure of packed .NET PE binary (BoxedApp Packer).
  • The Packed Stub Native PE Binary DotNetAppStub – 32/64-bit version, depending on the architecture of the original .NET PE binary (initialization via TLS Callback) – not affected by the compression option:
    • Original .NET PE Binary, in the .bxpck PE section – affected by the compression option.
    • Virtual Files/Registry embedded into the Virtual Storage, in the .bxpck PE section – affected by the compression option.
    • bxsdk32.dll/bxsdk64.dll – 32/64-bit version of native DLL, depending on the architecture (the main part of BoxedAppSDK), in the .main PE section – not affected by the compression option:
      • BoxedAppSDK_AppDomainManager.dll – 32/64-bit version of .NET DLL.
      • BoxedAppSDKThunk.dll – 32/64-bit version of native DLL.
      • TLSSupport.dll – 32/64-bit version of native DLL (BoxedApp helper library setting the DllMain Callback).

BoxedApp BxILMerge

BxILMerge is similar to ILMerge, a utility that merges multiple .NET assemblies into a single assembly. However, it can also bundle unmanaged DLLs/PEs and any other files such as data files, images, videos, and databases. BxILMerge provides support for packing managed assemblies, their unmanaged dependencies, and other files into a single-file .NET assembly that uses the internal logic of BoxedApp to handle any interactions with them.

Figure 8: The BoxedApp BxILMerge.
Figure 8: The BoxedApp BxILMerge.

The additional merged files (.NET assemblies, unmanaged DLLs, and other files) are embedded into the resulting packed .NET assembly resources. A created module constructor (a part of the packed .NET assembly) is responsible for the initialization of a custom assembly resolver and Virtual Storage where all merged files that are a part of the packed .NET assembly resources become a part of this Virtual Storage as virtual files. All I/O operations that interact with these virtual files (e.g., dependency loading of referenced .NET Assemblies, unmanaged DLLs) are handled via BoxedApp interceptions in a similar way as in the case of BoxedApp Packer (inline hooking of certain WIN/NT API). No file is dropped to disk.

The structure of the Original Packed .NET PE Binary:

Figure 9: The structure of packed .NET PE binary (BoxedApp
BxILMerge).
Figure 9: The structure of packed .NET PE binary (BoxedApp BxILMerge).
  • The Original Packed .NET PE Binary – Module constructor, custom assembly resolver, initialization of Virtual Storage, original managed code:
    • BoxedAppSDK.Managed.dll – AnyCPU version (managed wrapper for BoxedAppSDK), embedded in .NET Resources of the packed .NET PE binary:
      • Both bxsdk32.dll and bxsdk64.dll – 32/64-bit versions of native DLLs (the main part of BoxedAppSDK), embedded in .NET resources of the BoxedAppSDK.Managed.dll:
        • BoxedAppSDK_AppDomainManager.dll – 32/64-bit version of .NET DLL.
        • BoxedAppSDKThunk.dll – 32/64-bit version of native DLL.
        • TLSSupport.dll – 32/64-bit version of native DLL (BoxedApp helper library setting the DllMain Callback).
    • BxIlMerge.Api.dll – AnyCPU version (managed assembly interacting with BoxedAppSDK.Managed.dll, initialization of BoxedApp internals, Virtual Storage, creation of virtual files), embedded in .NET resources of the packed .NET PE binary.
    • Additional merged files that will be a part of the initialized Virtual Storage (creation of virtual files), embedded in .NET resources of the packed .NET PE binary.

With our understanding of the binary structures packed by different BoxedApp products, unpacking the original PE binary and all the virtual files is a relatively straightforward task. While the static approach can be used to extract files that are a part of the Virtual Storage (e.g., DIE – Extractor feature, HEX editor), we recommend the dynamic approach to dump the packed PE from the memory and reconstruct the runtime-resolved IAT that was destroyed by the packing algorithm (e.g., combination of x64dbg and Scylla). Unfortunately, existing tools for static unpacking (e.g., unboxed) are not as good or reliable.

Conclusion

We monitored the increasing abuse of BoxedApp products for a few months and discovered how these products are used to deploy numerous known malware families, primarily related to RATs and stealers. The majority of the attributed malicious samples were used in attacks against financial institutions and government industries. Packing the malicious payloads enabled the attackers to lower the detection of known threats, harden their analysis, and use the advanced capabilities of BoxedApp SDK (e.g., Virtual Storage) without needing to develop them from scratch.

Even though BoxedApp has been available for several years, the past year saw a significant increase in its abuse. Among the main abused BoxedApp products are BoxedApp Packer and BxILMerge, which are both built on top of the BoxedApp SDK. Both products give the attackers a direct opportunity to leverage the most exciting features of the SDK, but the BoxedApp SDK itself opens a space to create a custom, unique packer that leverages the most advanced features and is diverse enough to avoid static detection.

By conducting an in-depth analysis of the BoxedApp internals, with the main focus on the resulting binary structures packed by different products, we gained and shared enough knowledge that can help with the unpacking of the Virtual Storage and reconstruction of the main malicious binaries. The provided Yara signatures can be used to statically detect the packer in use while distinguishing the product itself.

Yara

import "pe"

rule Packer_BoxedApp {
    meta:
        description = "Detects .NET/Native PE binary packed by BoxedApp Packer/BxILMerge"
        author = "Jiri Vinopal @ Check Point Research"
        date = "2024-04-29"
        modified = "2024-04-29"
        reference = "https://www.boxedapp.com/"
        hash = "77c30d1e3f12151b4e3d3090355c8ce06582f4d0dd3cdb395caa836bd80a97f6" // Native PE binary packed by BoxedApp Packer
        hash = "c76d2e396d654f6f92ea7cd58d43e739b9f406529369709adece23638436cd25" // .NET PE binary packed by BoxedApp Packer
        hash = "aefaf8401437262004d384c8f92968cfee9f5563d13c35b347c9f9eefccab7fc" // .NET PE binary packed by BoxedApp BxILMerge
        tags = "BoxedApp"
        tool = "BoxedApp"
    strings:
        $boxedapp_s1 = "bxsdk" ascii wide
        $boxedapp_s2 = "BoxedAppSDK_Init" ascii
        $boxedapp_dotnet1 = "BoxedAppSDK.Managed" ascii wide
        $boxedapp_dotnet2 = "BxIlMerge.Api" ascii wide
    condition:
        uint16(0) == 0x5a4d and uint16(uint32(0x3c)) == 0x4550 and (
        (all of ($boxedapp_s*) and for any section in pe.sections : ( section.name == ".bxpck" )) or
        (all of them and pe.data_directories[pe.IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR].virtual_address != 0))
}
import "pe"

rule Packer_BoxedAppPacker_Native {
    meta:
        description = "Detects Native PE binary packed by BoxedApp Packer (result is Native PE binary)"
        author = "Jiri Vinopal @ Check Point Research"
        date = "2024-04-29"
        modified = "2024-04-29"
        reference = "https://www.boxedapp.com/boxedapppacker/"
        hash = "77c30d1e3f12151b4e3d3090355c8ce06582f4d0dd3cdb395caa836bd80a97f6"
        tags = "BoxedApp"
        tool = "BoxedApp"
    strings:
        $boxedapp_s1 = "bxsdk" ascii wide
        $boxedapp_s2 = "BoxedAppSDK_Init" ascii
        $boxedapp_dotnet1 = "DotNetAppStub" ascii
    condition:
        uint16(0) == 0x5a4d and uint16(uint32(0x3c)) == 0x4550 and
        all of ($boxedapp_s*) and not $boxedapp_dotnet1 and
        for any section in pe.sections : ( section.name == ".bxpck" )
}
import "pe"

rule Packer_BoxedAppPacker_Dotnet {
    meta:
        description = "Detects .NET PE binary packed by BoxedApp Packer (result is Native PE binary)"
        author = "Jiri Vinopal @ Check Point Research"
        date = "2024-04-29"
        modified = "2024-04-29"
        reference = "https://www.boxedapp.com/boxedapppacker/"
        hash = "c76d2e396d654f6f92ea7cd58d43e739b9f406529369709adece23638436cd25"
        tags = "BoxedApp"
        tool = "BoxedApp"
    strings:
        $boxedapp_s1 = "bxsdk" ascii wide
        $boxedapp_s2 = "BoxedAppSDK_Init" ascii
        $boxedapp_dotnet1 = "DotNetAppStub" ascii
    condition:
        uint16(0) == 0x5a4d and uint16(uint32(0x3c)) == 0x4550 and
        all of ($boxedapp_*) and
        for any section in pe.sections : ( section.name == ".bxpck" )
}
import "pe"

rule Packer_BoxedAppBxILMerge_Dotnet {
    meta:
        description = "Detects .NET PE binary packed by BoxedApp BxILMerge (result is .NET PE binary)"
        author = "Jiri Vinopal @ Check Point Research"
        date = "2024-04-29"
        modified = "2024-04-29"
        reference = "https://github.com/boxedapp/bxilmerge"
        hash = "aefaf8401437262004d384c8f92968cfee9f5563d13c35b347c9f9eefccab7fc"
        tags = "BoxedApp"
        tool = "BoxedApp"
    strings:
        $boxedapp_s1 = "bxsdk" ascii wide
        $boxedapp_s2 = "BoxedAppSDK_Init" ascii
        $boxedapp_dotnet1 = "BoxedAppSDK.Managed" ascii wide
        $boxedapp_dotnet2 = "BxIlMerge.Api" ascii wide
    condition:
        uint16(0) == 0x5a4d and uint16(uint32(0x3c)) == 0x4550 and
        all of ($boxedapp_*) and
        pe.data_directories[pe.IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR].virtual_address != 0
}

References

BoxedApp: https://www.boxedapp.com/

BoxedApp Packer: https://www.boxedapp.com/boxedapppacker/

BxILMerge: https://www.boxedapp.com/boxedappsdk/usecases/ilmerge_unmanaged_dll.html

BxILMerge: https://github.com/boxedapp/bxilmerge

ILMerge: https://github.com/dotnet/ILMerge

BoxedApp SDK: https://www.boxedapp.com/boxedappsdk/

The post Inside the Box: Malware’s New Playground appeared first on Check Point Research.