You are browsing the archive for Sandboxing.

Enter Sandbox – part 14: Reading the old Delphi Scrolls…

March 16, 2017 in Batch Analysis, Clustering, File Formats ZOO, Reversing, Sandboxing

Sandboxing regular PE (not .NET) files is easy and tricky at the same time. API monitoring is trivial. What is not is not is this:

  • The crazy number of API functions (Native, Win32)
  • Function calls that are a bit harder to monitor, because the functionality is delivered via a complex maze of virtual tables f.ex. COM
  • Monitoring of functions or methods that are placed on a higher level of abstraction f.ex. scripts (AutoIT, VBS, VBA), as well as installers (f.ex. NullSoft)
  • The variety of library functions that are included inside the executables (statically)

The last item on the list requires a bit more attention.

Hooking API, or intercepting their calls any other way is relatively easy as long as you know where they are (and perhaps can handle the stolen bytes well since some malware is using this trick). With code embedded directly inside the executable there is no import table, no list of pointers of any kind, no virtual tables, no RTTI, nothing. Of course, using tools like IDA, or a good disassembly library, or perhaps instrumented execution it may be possible to determine the exact location of these functions, but it’s a pretty complex and time consuming task, especially for commercial sandboxes that must run FAST.

On top of that, there is another issue. The code is not located at a fixed address, but can be placed all over the place. No, I am not talking about ASLR. I am talking about wrappers that use RunPE to run executables from memory. If you intercept Windows API calls, running programs via RunPE doesn’t make a difference – the APIs will eventually be executing from a known location inside the system libraries in memory. With relocated code the statically linked functions need to be found _every_ time the executable is loaded, mapped to a different processes, or simply relocated (direct code inject, process hollowing, some unpackers, etc.). Yes, for the malware that spawns a number of child processes and plays with RunPE a number of times during the session it will significantly slow down the tagging of functions in memory.

So… after a bit of scaremongering let’s have a look at a very good example.

The enfant terrible of programs that are truly annoying for analysis are Delphi executables (and all the other brands of Delphish executables f.es. Embarcadero). They rely heavily on the custom Delphi libraries and as such are hard to understand no matter whether they are debugged, or disassembled. Of course, there exist good decompilers that can help a lot, and flirt signatures for Delphi executables do a lot of magic during static program analysis as well. However, I am not aware of any of the available sandboxes or monitors doing dynamic analysis of Delphi code during the run-time.

I remember the moment when I tested the first Delphi function hooking that I implemented a few years ago. My mind was blown. The sudden insight into the program business logic that the hooking gave me was incredible… !!!

I hope this functionality will be implemented in commercial sandboxes soon. There is a tremendous amount of metadata just waiting to be discovered…

Let’s have a look at a couple of examples – the one below shows a progressive parsing of the config for a trojan:

LStrPos |, <someip>|1337|IPKServer|IPKMutex|encpassword|-1|AdobeART.exe|AdobeART|-1|
LStrPos |, <someip>|1337|IPKServer|IPKMutex|encpassword|-1|AdobeART.exe|AdobeART|-1|
LStrPos |, <someip>|1337|IPKServer|IPKMutex|encpassword|-1|AdobeART.exe|AdobeART|-1|
LStrPos |, 1337|IPKServer|IPKMutex|encpassword|-1|AdobeART.exe|AdobeART|-1|
LStrPos |, 1337|IPKServer|IPKMutex|encpassword|-1|AdobeART.exe|AdobeART|-1|
LStrPos |, 1337|IPKServer|IPKMutex|encpassword|-1|AdobeART.exe|AdobeART|-1|
LStrPos |, IPKServer|IPKMutex|encpassword|-1|AdobeART.exe|AdobeART|-1|
LStrPos |, IPKServer|IPKMutex|encpassword|-1|AdobeART.exe|AdobeART|-1|
LStrPos |, IPKServer|IPKMutex|encpassword|-1|AdobeART.exe|AdobeART|-1|
LStrPos |, IPKMutex|encpassword|-1|AdobeART.exe|AdobeART|-1|
LStrPos |, IPKMutex|encpassword|-1|AdobeART.exe|AdobeART|-1|
LStrPos |, IPKMutex|encpassword|-1|AdobeART.exe|AdobeART|-1|
LStrPos |, encpassword|-1|AdobeART.exe|AdobeART|-1|
LStrPos |, encpassword|-1|AdobeART.exe|AdobeART|-1|
LStrPos |, encpassword|-1|AdobeART.exe|AdobeART|-1|
LStrPos |, -1|AdobeART.exe|AdobeART|-1|
LStrPos |, -1|AdobeART.exe|AdobeART|-1|
LStrPos |, -1|AdobeART.exe|AdobeART|-1|
LStrPos |, AdobeART.exe|AdobeART|-1|
LStrPos |, AdobeART.exe|AdobeART|-1|
LStrPos |, AdobeART.exe|AdobeART|-1|
LStrPos |, AdobeART|-1|
LStrPos |, AdobeART|-1|
LStrPos |, AdobeART|-1|
LStrPos |, -1|
LStrPos |, -1|
LStrPos |, -1|
LStrPos |,

This example shows a comparison of characters and the string ‘apocalypse’ can be read from a series of string comparisons:

LStrCmp2 (substring=a, string=|)
LStrCmp2 (substring=p, string=|)
LStrCmp2 (substring=o, string=|)
LStrCmp2 (substring=c, string=|)
LStrCmp2 (substring=a, string=|)
LStrCmp2 (substring=l, string=|)
LStrCmp2 (substring=y, string=|)
LStrCmp2 (substring=p, string=|)
LStrCmp2 (substring=s, string=|)
LStrCmp2 (substring=e, string=|)

Another example almost instantly tells me that the program requires a command line parameter:

WStrCmp (substring=, string=/debug)

What about Delphi-based Anti-routines? This is a whole new unexplored of area !!!

LStrPos (substring=SNIFFER, string=EXPLORER.EXE)

LStrPos (substring=WINDUMP, string=EXPLORER.EXE)

LStrPos (substring=NETPRYER, string=EXPLORER.EXE)

And last example – DarkComet config processing:

LStrCmp (substring=, string=GENCODE)
LStrCmp (substring=MUTEX, string=GENCODE)
LStrCmp (substring=SID, string=GENCODE)
LStrCmp (substring=FWB, string=GENCODE)
LStrCmp (substring=NETDATA, string=GENCODE)
LStrCmp (substring=GENCODE, string=GENCODE)
LStrCmp (substring=\, string=\)
LStrCmp (substring=, string=NETDATA)
LStrCmp (substring=MUTEX, string=NETDATA)
LStrCmp (substring=SID, string=NETDATA)
LStrCmp (substring=FWB, string=NETDATA)
LStrCmp (substring=NETDATA, string=NETDATA)
LStrCmp (substring=, string=SID)
LStrCmp (substring=MUTEX, string=SID)
LStrCmp (substring=SID, string=SID)
LStrCmp (substring=, string=MUTEX)
LStrCmp (substring=MUTEX, string=MUTEX)
LStrCmp (substring=, string=EDTPATH)
LStrCmp (substring=MUTEX, string=EDTPATH)
LStrCmp (substring=SID, string=EDTPATH)
LStrCmp (substring=FWB, string=EDTPATH)
LStrCmp (substring=NETDATA, string=EDTPATH)
LStrCmp (substring=GENCODE, string=EDTPATH)
LStrCmp (substring=OFFLINEK, string=EDTPATH)
LStrCmp (substring=, string=EDTPATH)
LStrCmp (substring=, string=COMBOPATH)
LStrCmp (substring=MUTEX, string=COMBOPATH)
LStrCmp (substring=SID, string=COMBOPATH)
LStrCmp (substring=FWB, string=COMBOPATH)
LStrCmp (substring=NETDATA, string=COMBOPATH)
LStrCmp (substring=GENCODE, string=COMBOPATH)
LStrCmp (substring=OFFLINEK, string=COMBOPATH)
LStrCmp (substring=, string=COMBOPATH)
LStrCmp (substring=, string=11)
LStrCmp (substring=, string=-1)
LStrCmp (substring=, string=0)
LStrCmp (substring=, string=1)
LStrCmp (substring=, string=2)
LStrCmp (substring=, string=3)
LStrCmp (substring=, string=4)
LStrCmp (substring=, string=5)
LStrCmp (substring=, string=6)
LStrCmp (substring=, string=7)
LStrCmp (substring=, string=8)
LStrCmp (substring=, string=9)
LStrCmp (substring=, string=10)
LStrCmp (substring=, string=GENCODE)
LStrCmp (substring=MUTEX, string=GENCODE)
LStrCmp (substring=SID, string=GENCODE)
LStrCmp (substring=FWB, string=GENCODE)
LStrCmp (substring=NETDATA, string=GENCODE)
LStrCmp (substring=GENCODE, string=GENCODE)
LStrCmp (substring=00df86ce377d71e66cb2451c446fede8, string=)
LStrCmp (substring=, string=INSTALL)
LStrCmp (substring=MUTEX, string=INSTALL)
LStrCmp (substring=SID, string=INSTALL)
LStrCmp (substring=FWB, string=INSTALL)
LStrCmp (substring=NETDATA, string=INSTALL)
LStrCmp (substring=GENCODE, string=INSTALL)
LStrCmp (substring=OFFLINEK, string=INSTALL)
LStrCmp (substring=, string=INSTALL)
LStrCmp (substring=, string=1)
LStrCmp (substring=, string=FAKEMSG)
LStrCmp (substring=MUTEX, string=FAKEMSG)
LStrCmp (substring=SID, string=FAKEMSG)
LStrCmp (substring=FWB, string=FAKEMSG)
LStrCmp (substring=NETDATA, string=FAKEMSG)
LStrCmp (substring=GENCODE, string=FAKEMSG)
LStrCmp (substring=OFFLINEK, string=FAKEMSG)
LStrCmp (substring=, string=FAKEMSG)
LStrCmp (substring=, string=1)
LStrCmp (substring=, string=PDNS)
LStrCmp (substring=MUTEX, string=PDNS)
LStrCmp (substring=SID, string=PDNS)
LStrCmp (substring=FWB, string=PDNS)
LStrCmp (substring=NETDATA, string=PDNS)
LStrCmp (substring=GENCODE, string=PDNS)
LStrCmp (substring=OFFLINEK, string=PDNS)
LStrCmp (substring=, string=PDNS)
LStrCmp (substring=, string=FILEATTRIB)
LStrCmp (substring=MUTEX, string=FILEATTRIB)
LStrCmp (substring=SID, string=FILEATTRIB)
LStrCmp (substring=FWB, string=FILEATTRIB)
LStrCmp (substring=NETDATA, string=FILEATTRIB)
LStrCmp (substring=GENCODE, string=FILEATTRIB)
LStrCmp (substring=OFFLINEK, string=FILEATTRIB)
LStrCmp (substring=, string=FILEATTRIB)
LStrCmp (substring=, string=DIRATTRIB)
LStrCmp (substring=MUTEX, string=DIRATTRIB)
LStrCmp (substring=SID, string=DIRATTRIB)
LStrCmp (substring=FWB, string=DIRATTRIB)
LStrCmp (substring=NETDATA, string=DIRATTRIB)
LStrCmp (substring=GENCODE, string=DIRATTRIB)
LStrCmp (substring=OFFLINEK, string=DIRATTRIB)
LStrCmp (substring=, string=DIRATTRIB)
LStrCmp (substring=, string=CHIDEF)
LStrCmp (substring=MUTEX, string=CHIDEF)
LStrCmp (substring=SID, string=CHIDEF)
LStrCmp (substring=FWB, string=CHIDEF)
LStrCmp (substring=NETDATA, string=CHIDEF)
LStrCmp (substring=GENCODE, string=CHIDEF)
LStrCmp (substring=OFFLINEK, string=CHIDEF)
LStrCmp (substring=, string=CHIDEF)
LStrCmp (substring=, string=1)
LStrCmp (substring=, string=CHIDED)
LStrCmp (substring=MUTEX, string=CHIDED)
LStrCmp (substring=SID, string=CHIDED)
LStrCmp (substring=FWB, string=CHIDED)
LStrCmp (substring=NETDATA, string=CHIDED)
LStrCmp (substring=GENCODE, string=CHIDED)
LStrCmp (substring=OFFLINEK, string=CHIDED)
LStrCmp (substring=, string=CHIDED)
LStrCmp (substring=, string=1)
LStrCmp (substring=, string=BIND)
LStrCmp (substring=MUTEX, string=BIND)
LStrCmp (substring=SID, string=BIND)
LStrCmp (substring=FWB, string=BIND)
LStrCmp (substring=NETDATA, string=BIND)
LStrCmp (substring=GENCODE, string=BIND)
LStrCmp (substring=OFFLINEK, string=BIND)
LStrCmp (substring=, string=BIND)
LStrCmp (substring=, string=1)
LStrCmp (substring=, string=PLUGS)
LStrCmp (substring=MUTEX, string=PLUGS)
LStrCmp (substring=SID, string=PLUGS)
LStrCmp (substring=FWB, string=PLUGS)
LStrCmp (substring=NETDATA, string=PLUGS)
LStrCmp (substring=GENCODE, string=PLUGS)
LStrCmp (substring=OFFLINEK, string=PLUGS)
LStrCmp (substring=, string=PLUGS)
LStrCmp (substring=, string=1)
LStrCmp (substring=, string=PERSINST)
LStrCmp (substring=MUTEX, string=PERSINST)
LStrCmp (substring=SID, string=PERSINST)
LStrCmp (substring=FWB, string=PERSINST)
LStrCmp (substring=NETDATA, string=PERSINST)
LStrCmp (substring=GENCODE, string=PERSINST)
LStrCmp (substring=OFFLINEK, string=PERSINST)
LStrCmp (substring=, string=PERSINST)
LStrCmp (substring=, string=1)
LStrCmp (substring=, string=SH1)
LStrCmp (substring=MUTEX, string=SH1)
LStrCmp (substring=SID, string=SH1)
LStrCmp (substring=FWB, string=SH1)
LStrCmp (substring=NETDATA, string=SH1)
LStrCmp (substring=GENCODE, string=SH1)
LStrCmp (substring=OFFLINEK, string=SH1)
LStrCmp (substring=, string=SH1)
LStrCmp (substring=, string=1)
LStrCmp (substring=, string=SH3)
LStrCmp (substring=MUTEX, string=SH3)
LStrCmp (substring=SID, string=SH3)
LStrCmp (substring=FWB, string=SH3)
LStrCmp (substring=NETDATA, string=SH3)
LStrCmp (substring=GENCODE, string=SH3)
LStrCmp (substring=OFFLINEK, string=SH3)
LStrCmp (substring=, string=SH3)
LStrCmp (substring=, string=1)
LStrCmp (substring=, string=SH4)
LStrCmp (substring=MUTEX, string=SH4)
LStrCmp (substring=SID, string=SH4)
LStrCmp (substring=FWB, string=SH4)
LStrCmp (substring=NETDATA, string=SH4)
LStrCmp (substring=GENCODE, string=SH4)
LStrCmp (substring=OFFLINEK, string=SH4)
LStrCmp (substring=, string=SH4)
LStrCmp (substring=, string=1)
LStrCmp (substring=, string=SH5)
LStrCmp (substring=MUTEX, string=SH5)
LStrCmp (substring=SID, string=SH5)
LStrCmp (substring=FWB, string=SH5)
LStrCmp (substring=NETDATA, string=SH5)
LStrCmp (substring=GENCODE, string=SH5)
LStrCmp (substring=OFFLINEK, string=SH5)
LStrCmp (substring=, string=SH5)
LStrCmp (substring=, string=1)
LStrCmp (substring=, string=SH6)
LStrCmp (substring=MUTEX, string=SH6)
LStrCmp (substring=SID, string=SH6)
LStrCmp (substring=FWB, string=SH6)
LStrCmp (substring=NETDATA, string=SH6)
LStrCmp (substring=GENCODE, string=SH6)
LStrCmp (substring=OFFLINEK, string=SH6)
LStrCmp (substring=, string=SH6)
LStrCmp (substring=, string=1)
LStrCmp (substring=, string=SH7)
LStrCmp (substring=MUTEX, string=SH7)
LStrCmp (substring=SID, string=SH7)
LStrCmp (substring=FWB, string=SH7)
LStrCmp (substring=NETDATA, string=SH7)
LStrCmp (substring=GENCODE, string=SH7)
LStrCmp (substring=OFFLINEK, string=SH7)
LStrCmp (substring=, string=SH7)
LStrCmp (substring=, string=1)
LStrCmp (substring=, string=SH8)
LStrCmp (substring=MUTEX, string=SH8)
LStrCmp (substring=SID, string=SH8)
LStrCmp (substring=FWB, string=SH8)
LStrCmp (substring=NETDATA, string=SH8)
LStrCmp (substring=GENCODE, string=SH8)
LStrCmp (substring=OFFLINEK, string=SH8)
LStrCmp (substring=, string=SH8)
LStrCmp (substring=, string=1)
LStrCmp (substring=, string=SH9)
LStrCmp (substring=MUTEX, string=SH9)
LStrCmp (substring=SID, string=SH9)
LStrCmp (substring=FWB, string=SH9)
LStrCmp (substring=NETDATA, string=SH9)
LStrCmp (substring=GENCODE, string=SH9)
LStrCmp (substring=OFFLINEK, string=SH9)
LStrCmp (substring=, string=SH9)
LStrCmp (substring=, string=1)
LStrCmp (substring=, string=SH10)
LStrCmp (substring=MUTEX, string=SH10)
LStrCmp (substring=SID, string=SH10)
LStrCmp (substring=FWB, string=SH10)
LStrCmp (substring=NETDATA, string=SH10)
LStrCmp (substring=GENCODE, string=SH10)
LStrCmp (substring=OFFLINEK, string=SH10)
LStrCmp (substring=, string=SH10)
LStrCmp (substring=, string=1)
LStrCmp (substring=, string=MULTIBIND)
LStrCmp (substring=MUTEX, string=MULTIBIND)
LStrCmp (substring=SID, string=MULTIBIND)
LStrCmp (substring=FWB, string=MULTIBIND)
LStrCmp (substring=NETDATA, string=MULTIBIND)
LStrCmp (substring=GENCODE, string=MULTIBIND)
LStrCmp (substring=OFFLINEK, string=MULTIBIND)
LStrCmp (substring=, string=MULTIBIND)
LStrCmp (substring=, string=1)
LStrCmp (substring=, string=MULTIPLUGS)
LStrCmp (substring=MUTEX, string=MULTIPLUGS)
LStrCmp (substring=SID, string=MULTIPLUGS)
LStrCmp (substring=FWB, string=MULTIPLUGS)
LStrCmp (substring=NETDATA, string=MULTIPLUGS)
LStrCmp (substring=GENCODE, string=MULTIPLUGS)
LStrCmp (substring=OFFLINEK, string=MULTIPLUGS)
LStrCmp (substring=, string=MULTIPLUGS)
LStrCmp (substring=, string=1)
LStrCmp (substring=, string=FWB)
LStrCmp (substring=MUTEX, string=FWB)
LStrCmp (substring=SID, string=FWB)
LStrCmp (substring=FWB, string=FWB)
LStrCmp (substring=0, string=1)
LStrCmp (substring=, string=GENCODE)
LStrCmp (substring=MUTEX, string=GENCODE)
LStrCmp (substring=SID, string=GENCODE)
LStrCmp (substring=FWB, string=GENCODE)
LStrCmp (substring=NETDATA, string=GENCODE)
LStrCmp (substring=GENCODE, string=GENCODE)
LStrCmp (substring=, string=PERS)
LStrCmp (substring=MUTEX, string=PERS)
LStrCmp (substring=SID, string=PERS)
LStrCmp (substring=FWB, string=PERS)
LStrCmp (substring=NETDATA, string=PERS)
LStrCmp (substring=GENCODE, string=PERS)
LStrCmp (substring=OFFLINEK, string=PERS)
LStrCmp (substring=, string=PERS)
LStrCmp (substring=, string=1)
LStrCmp (substring=, string=PWD)
LStrCmp (substring=MUTEX, string=PWD)
LStrCmp (substring=SID, string=PWD)
LStrCmp (substring=FWB, string=PWD)
LStrCmp (substring=NETDATA, string=PWD)
LStrCmp (substring=GENCODE, string=PWD)
LStrCmp (substring=OFFLINEK, string=PWD)
LStrCmp (substring=, string=PWD)
LStrCmp (substring=, string=OFFLINEK)
LStrCmp (substring=MUTEX, string=OFFLINEK)
LStrCmp (substring=SID, string=OFFLINEK)
LStrCmp (substring=FWB, string=OFFLINEK)
LStrCmp (substring=NETDATA, string=OFFLINEK)
LStrCmp (substring=GENCODE, string=OFFLINEK)
LStrCmp (substring=OFFLINEK, string=OFFLINEK)
LStrCmp (substring=1, string=1)
LStrCmp (substring=Unknow, string=Unknow)

Enter Sandbox – part 13: Sometimes it’s better to unfollow…

December 31, 2016 in Batch Analysis, Clustering, Sandboxing

The golden rule for many sandboxes is to attach the monitor to a every piece of executable code that is spawn by the analyzed sample. This approach has its obvious merits – many samples use lots of trickery and ‘seeing it all’ is a definite plus. It is also an unique selling point for some sandboxes to be able to ‘catch’ the most trickiest evasions that could otherwise potentially sneak-in under the radar of the monitor and do the evil thing while the sandbox would report nada…

I’d like to suggest a small, configurable optimization change to the sandbox behavior. One that should be relatively easy to implement for the most common use cases, and one that may be quite beneficial for readability and processing purposes.

Its name is ‘Unfollow’.

Let’s have a quick look at the below example:

Retrieves Module handle (via GetModuleHandleA): kernel32
Retrieves Procedure Address (via GetProcAddress): KERNEL32.dll, CreateProcessA
Retrieves Module handle (via GetModuleHandleA): kernel32
Retrieves Procedure Address (via GetProcAddress): KERNEL32.dll, GetModuleFileNameA
Loads Library (via LoadLibraryA): Shell32.dll
Retrieves Procedure Address (via GetProcAddress): SHELL32.dll, SHGetFolderPathA
Retrieves Module handle (via GetModuleHandleA): kernel32
Retrieves Procedure Address (via GetProcAddress): KERNEL32.dll, CreateProcessA
Creates Process (via CreateProcessA): , cmd=sc stop WinDefend, flags=
Retrieves Module handle (via GetModuleHandleA): kernel32
Retrieves Procedure Address (via GetProcAddress): KERNEL32.dll, CreateProcessA
Creates Process (via CreateProcessA): , cmd=sc config WinDefend start= disabled, flags=
Retrieves Module handle (via GetModuleHandleA): kernel32
Retrieves Procedure Address (via GetProcAddress): KERNEL32.dll, CreateProcessA
Creates Process (via CreateProcessA): , cmd=net stop msmpsvc, flags=

The story the log tells us is pretty clear – the sample is launching ‘sc’ and ‘net’ commands to kill/change the config of security services:

  • sc stop WinDefend
  • sc config WinDefend start= disabled
  • net stop msmpsvc

Look how clear the malicious behavior it is, and how easy it is to cherry-pick it from the logs, even in a textual format! Running a full-blown monitor over the spawn ‘utilities’ would be completely unnecessary… (unless of course, you want full report on IOCs, etc.).

In this particular case, my monitor just continues w/o following the programs the malware spawns i.e. recognizes their presence, but ‘unfollows’ them.

And what would happen if these were to be followed?

Let’s look at another example – the malware is executed, it connects to SCM, and first tries to Open, and if it doesn’t exist, Create the service called ‘vom’:

Connects to SCM database (via OpenSCMManagerA)
Opens a service (via OpenServiceA): vom
Creates Service (via CreateServiceA): vom

– at this moment the monitor would need to start monitoring the ‘services.exe’ that is responsible for service creation:

services.exe
...
Creates/Opens Registry Key: vom
Sets Registry Value (via NtSetValueKey): HKEY_LOCAL_MACHINE\SYSTEM\
     ControlSet001\Services\vom\Type, REG_DWORD, 1
Sets Registry Value (via NtSetValueKey): HKEY_LOCAL_MACHINE\SYSTEM\
     ControlSet001\Services\vom\Start, REG_DWORD, 0
Sets Registry Value (via NtSetValueKey): HKEY_LOCAL_MACHINE\SYSTEM\
     ControlSet001\Services\vom\ErrorControl, REG_DWORD, 1
Sets Registry Value (via NtSetValueKey): HKEY_LOCAL_MACHINE\SYSTEM\
     ControlSet001\Services\vom\ImagePath, REG_EXPAND_SZ, 
     system32\drivers\vom.sys
Sets Registry Value (via NtSetValueKey): HKEY_LOCAL_MACHINE\SYSTEM\
     ControlSet001\Services\vom\DisplayName, REG_SZ, vom
Creates/Opens Registry Key: Security
Sets Registry Value (via NtSetValueKey): HKEY_LOCAL_MACHINE\SYSTEM\
     ControlSet001\Services\vom\Security\Security, REG_BINARY,
...
and many many logs for all services affected

From the full-IOC report perspective – it makes sense, but if we talk about in-depth analysis where very specific high-level info is needed it actually adds a lot of noise to the report. We actually want to know what the sample does. Not how the service creation works (of course, it’s interesting, but not at this stage!).

Again, I emphasize it could be an optional setting – one that could enable individual analysts to speed up the log analysis by removing a lot of clutter from the final report, and perhaps enable the sandbox to ‘see’ more (as CPU cycles required by the ‘utility’ process monitoring and logging can be fully delegated to the main malware during – the typically short – session time). Of course, many modern reports can be ‘collapsed’ to hide the artifacts that are not that interesting + the process hierarchy is typically clearly shown on a graph, or a tree, but still – following processes is quite CPU-expensive and not always necessary.