Intro
Imagine, that you know that attackers are on a particular host but you have no idea whether they are persisted on another ones, servers, domain controllers. Detecting fileless artifacts, such as beacons in the case of Cobalt Strike, is not as easy as it may seem. Two interesting techniques that can be used here are:
- Working with processes and threads, tools like https://github.com/Apr4h/CobaltStrikeScan.git
- Dumping memory of the process/OS and analyzing it with the appropriate tool.
Below are some my old notes so maybe they could be interesting for readers. Interesting moment is that you can even create a VMware ESX snapshot that can be converted to a .dmp file for analyzing by WinDbg or Volatility.
Next, you can use SwishDbgExt Windbg extensions to scan the dumped memory of the processes with YARA signatures.
SwishDbgExt
Let’s take a look at the part of the SwishDbgExt source code – Yara.cpp
YaraScan(
In MsProcessObject *ProcObj,
In PCSTR FileName
)
YaraScan performs a scan process’s address space specified by the MsProcessObject, searching for matches with the given YARA file.
First, the YARA library is initialized, and rules are added from the file
if (yr_initialize() == ERROR_SUCCESS) {
if (yr_compiler_create(&Compiler) == ERROR_SUCCESS) {
if (fopen_s(&File, FileName, "r") == ERROR_SUCCESS) {
if (yr_compiler_add_file(Compiler, File, NULL, NULL) == 0) {
if (yr_compiler_get_rules(Compiler, &Rules) == ERROR_SUCCESS) {
Buffer = (PBYTE)calloc(PAGE_SIZE, sizeof(BYTE));
then we get the VAD list of the process
ProcObj->MmGetVads();
switch context to that process
ProcObj->SwitchContext();
enumerate all VADs and check if they are valid and define ranges for scanning
for each (VAD_OBJECT Vad in ProcObj->m_Vads) {
..
if ((Vad.StartingVpn & ~0xFFFFFFFFFF) || (Vad.EndingVpn & ~0xFFFFFFFFFF)) {
..
RangeStart = Vad.StartingVpn * PAGE_SIZE;
RangeEnd = Vad.EndingVpn * PAGE_SIZE;
read memory and execute callback in case of the matching
for (Offset = RangeStart; Offset < RangeEnd; Offset += PAGE_SIZE) {
if (ExtRemoteTypedEx::ReadVirtual(Offset, Buffer, PAGE_SIZE, NULL) != S_OK) {
...
yr_rules_scan_mem(Rules, Buffer, PAGE_SIZE, 0, YaraCallback, &Offset, 0);
that will perform DML output in Windbg and execute db for diapason
g_Ext->Dml("<col fg=\"changed\">Rule:</col> %s\n\n", Rule->identifier);
...
g_Ext->Execute("db %p", BaseAddress + Match->offset);
g_Ext->Dml("\n");
The YARA rule is
rule metsrv_dll {
meta:
author = "chort (@chort0)"
description = "metsrv.dll"
strings:
$b = { 6d 65 74 73 72 76 2e 64 6c 6c } // metsrv.dll
condition:
$b
}
Below is an example of DML output generated by the extension for the McAfee antivirus process after execution.
!for_each_process "r? @$t0 = (nt!_EPROCESS *) @#Process; .process /r /p @$t0; !ms_yarascan /pid @@C++(@$t0->UniqueProcessId) /yarafile D:\\_widbg\\metsrv4.yar"
Process: mcshield.exe, Pid: 0xa3c

Thus, this sequence relates to the address space of the mcshield.exe process. By the virtual address, we will obtain the VAD.
0: kd> !vad 07fc3fc1 1
VAD @ 888d8588
Start VPN 6330 End VPN 832f Control Area 00000000
FirstProtoPte 00000000 LastPte 00000000 Commit Charge 2000 (0n8192)
Secured.Flink 0 Blink 0 Banked/Extend 0
File Offset 0
ViewUnmap PrivateMemory READWRITE
Let’s dump the memory defined by the VAD and see what’s inside.
0: kd> .writemem c:\temp1\ddd.bin 0x6330*0x1000 0x832f*0x1000
Writing 1fff001 bytes
strings64.exe ddd.bin > dddd.txt
There are quite a few different strings there, including this part of them
cobalt_mode.dll
?ReflectiveLoader@@YGKPAX@Zt
*.ahk>
class Cert
COM_Init(t
SELECT host,name,value,
where host='.facebook.com'
User Data\Default\Cookiest
www.gaintt.pw
www.jsxjbxx.pw
www.xxxinfo.pw
keylogger>
on_press
pynput.keyboard
Listenert
B M
:\Users\Android\
\Projects\Keylogger\
\Keylogger.pdb
И т.д. и т.п.
MaxUploads=
[Search Screen]t
>Star Wars Episode 2 - Attack Of The Clones Full Downloader.exe
How To Hack Websites.exe
Hacking Tool Collection.exe
%d,%d,%d,%dt
codeguru.com
CWebBrows
@GL
/C START
The presence of signatures like metsrv.dll cannot mean anything on its own, take a look at this YARA rule – https://github.com/Neo23x0/signature-base/blob/master/yara/gen_loaders.yar
rule ReflectiveLoader {
meta:
description = "Detects a unspecified hack tool, crack or malware using a reflective loader - no hard match - further investigation recommended"
reference = "Internal Research"
score = 70
date = "2017-07-17"
modified = "2021-03-15"
author = "Florian Roth"
nodeepdive = 1
strings:
$x1 = "ReflectiveLoader" fullword ascii
$x2 = "ReflectivLoader.dll" fullword ascii
$x3 = "?ReflectiveLoader@@" ascii
$x4 = "reflective_dll.x64.dll" fullword ascii
$x5 = "reflective_dll.dll" fullword ascii
$fp1 = "Sentinel Labs, Inc." wide
$fp2 = "Panda Security, S.L." wide ascii
condition:
uint16(0) == 0x5a4d and (
1 of ($x*) or
pe.exports("ReflectiveLoader") or
pe.exports("_ReflectiveLoader@4") or
pe.exports("?ReflectiveLoader@@YGKPAX@Z")
)
and not 1 of ($fp*)
}
Most likely, it is applied to the address space of the entire process, as it checks for a sequence like ‘_ReflectiveLoader@4’, but not, for example, ‘Panda Security, S.L.’. We also understand that Panda Security can now be seen as not just a ‘good’ antivirus, but as one that avoids falling into the abyss of constantly generating false positives
Clean Windows 10 installation
On the another Windows server they didn’t have McAfee antivirus, but there was a byte sequence in the dump:
6d 65 74 73 72 76 2e 64 6c 6c - metsrv.dll
Let’s check how it could be. Create an installation ISO image for Windows 10 using MediaCreationTool downloaded from the Microsoft website and perform just search by metsrv.dll bytes in created ISO, we dind’t find anything .

Start OS installation and reach the stage of selecting the region

stop it make a snapshot and converted it from VMware ESX shanpshot to DMP
- Windows 10 x32-bfa6c2f8.vmem
- Windows 10 x32-bfa6c2f8.vmss
and now we can find this sequence in the memory using WinDbg. We see that this sequence belongs to the address space of the Windows Defender process


So, we just ran into byte sequences of unpacked AV signatures.
0f668311 6d 65 74 73 72 76 2e 64-6c 6c 00 00 52 74 6c 43 metsrv.dll..RtlC
0f668321 72 65 61 74 65 55 73 65-72 54 68 72 65 61 64 5c reateUserThread\
0f668331 5c 2e 5c 70 69 70 65 5c-25 73 00 63 6d 64 2e 65 \.\pipe\%s.cmd.e
0f668341 78 65 20 2f 63 20 65 63-68 6f 20 25 73 20 3e 20 xe /c echo %s >
0f668351 25 73 00 25 73 25 73 2e-64 6c 6c 72 75 6e 64 6c %s.%s%s.dllrundl
0f668361 6c 33 32 2e 65 78 65 20-25 73 2c 61 20 2f 70 3a l32.exe %s,a /p:
0f668371 25 73 00 2f 74 3a 30 78-25 30 38 58 02 60 02 00 %s./t:0x%08X.`..
0f668381 36 a9 03 80 c1 23 a5 4f-c5 f1 00 00 25 8c 85 99 6....#.O....%...
0f6c813b 6d 65 74 73 72 76 2e 64-6c 6c 00 00 52 74 6c 43 metsrv.dll..RtlC
0f6c814b 72 65 61 74 65 55 73 65-72 54 68 72 65 61 64 5c reateUserThread\
0f6c815b 5c 2e 5c 70 69 70 65 5c-25 73 00 63 6d 64 2e 65 \.\pipe\%s.cmd.e
0f6c816b 78 65 20 2f 63 20 65 63-68 6f 20 25 73 20 3e 20 xe /c echo %s >
0f6c817b 25 73 00 25 73 25 73 2e-64 6c 6c 72 75 6e 64 6c %s.%s%s.dllrundl
0f6c818b 6c 33 32 2e 65 78 65 20-25 73 2c 61 20 2f 70 3a l32.exe %s,a /p:
0f6c819b 25 73 00 2f 74 3a 30 78-25 30 38 58 d9 41 4a 73 %s./t:0x%08X.AJs
0f6c81ab 70 72 61 74 21 72 66 6e-00 ac 21 42 61 6e 63 74 prat!rfn..!Banct
106e6160 6d 65 74 73 72 76 2e 64-6c 6c 00 00 52 65 66 6c metsrv.dll..Refl
106e6170 65 63 74 69 76 65 4c 6f-61 64 65 72 5f 52 65 66 ectiveLoader_Ref
106e6180 6c 65 63 74 69 76 65 4c-6f 61 64 65 72 40 30 02 lectiveLoader@0.
106e6190 a0 06 00 04 00 00 70 70-ad c8 9b 78 41 00 00 2a ......pp...xA..*
106e61a0 7a 5d e6 d3 a7 34 39 c9-da 82 bb 5f e8 f4 4e 53 z]...49...._..NS
106e61b0 8a e0 7a 10 75 2b 09 1d-90 01 03 10 83 65 fc 00 ..z.u+.......e..
106e61c0 8d 45 90 01 01 50 8d 45-90 01 01 50 b9 90 01 03 .E...P.E...P....
106e61d0 10 e8 90 01 02 ff ff 68-90 01 03 10 e8 90 01 03 .......h........
Conclusions
- It is common to see YARA rules from interesting projects on GitHub aimed at detecting “illegitimate code,” such as in the address space of processes. However, simply finding a string like metsrv.dll is not enough to make a final judgment.
- Seeing many of the strings listed above in a memory snapshot taken on VMware ESX on your servers running Windows 10 is not exactly a “pleasant and expected” sight. However, further investigation is necessary—specifically, converting the snapshot into a Windbg dump and analyzing the address space to determine which process the byte sequences belong to.
- There are useful extensions for Windbg, such as SwishDbgExt, which help automate certain tasks. Without this extension, we would need to traverse the entire VAD tree starting from the root and analyze the address space of each one. With YARA, we can achieve a very precise identification of what we’re looking for.
- Antivirus programs can contain “anything” in their address space. It is unfortunate that we cannot implement a unified database of “our” string signatures within a company based on their golden images.
- Pages from the virtual address space of a process can be unloaded to swap, so there is a chance that we might not find anything using this method.
- Working directly with memory allows you to find things that might be well hidden, and this approach can be quite useful.