This artifact enables enumeration of process memory sections via the Virtual Address Descriptor (VAD). The VAD is used by the Windows memory manager to describe allocated process memory ranges.
Available filters include process, mapping path, memory permissions or by content with yara.
Use the UploadSection switch to upload any sections.
A notebook suggestion is available for Strings analysis on uploaded sections.
NOTE:
name: Windows.System.VAD
author: "Matt Green - @mgreen27"
description: |
This artifact enables enumeration of process memory sections via the Virtual
Address Descriptor (VAD). The VAD is used by the Windows memory manager to
describe allocated process memory ranges.
Available filters include process, mapping path, memory permissions
or by content with yara.
Use the UploadSection switch to upload any sections.
A notebook suggestion is available for Strings analysis on uploaded sections.
NOTE:
- ProtectionChoice is a choice to filter on section protection. Default is
all sections and ProtectionRegex can override selection.
- To filter on unmapped sections the MappingNameRegex: ^$ can be used.
- When uploading sections during analysis, its recommended to run once for
scoping, then a second time once confirmed for upload.
parameters:
- name: ProcessRegex
description: A regex applied to process names.
default: .
type: regex
- name: PidRegex
default: .
type: regex
- name: ProtectionChoice
type: choices
description: Select memory permission you would like to return. Default All.
default: Any
choices:
- Any
- Execute, read and write
- Any executable
- name: ProtectionRegex
type: regex
description: Allows a manual regex selection of section Protection permissions. If configured take preference over Protection choice.
- name: MappingNameRegex
type: regex
- name: UploadSection
description: Upload suspicious section.
type: bool
- name: SuspiciousContent
description: A yara rule of suspicious section content
type: yara
- name: ContextBytes
description: Include this amount of bytes around yara hit as context.
default: 0
type: int
sources:
- query: |
-- firstly find processes in scope
LET processes = SELECT int(int=Pid) AS Pid,
Name, Exe, CommandLine, StartTime
FROM process_tracker_pslist()
WHERE Name =~ ProcessRegex
AND format(format="%d", args=Pid) =~ PidRegex
AND log(message="Scanning pid %v : %v", args=[Pid, Name])
-- next find sections in scope
LET sections = SELECT * FROM foreach(
row=processes,
query={
SELECT StartTime as ProcessCreateTime,Pid, Name, MappingName,
format(format='%x-%x', args=[Address, Address+Size]) AS AddressRange,
Address as _Address,
State,Type,ProtectionMsg,Protection,
Size as SectionSize,
pathspec(
DelegateAccessor="process",
DelegatePath=Pid,
Path=Address) AS _PathSpec
FROM vad(pid=Pid)
WHERE if(condition=MappingNameRegex,
then= MappingName=~MappingNameRegex,
else= True)
AND if(condition = ProtectionRegex,
then= Protection=~ProtectionRegex,
else= if(condition= ProtectionChoice='Any',
then= TRUE,
else= if(condition= ProtectionChoice='Execute, read and write',
then= Protection= 'xrw',
else= if(condition= ProtectionChoice='Any executable',
then= Protection=~'x'))))
})
-- if suspicious yara added, search for it
LET yara_sections = SELECT *
FROM foreach(row={
SELECT * FROM sections
WHERE NOT State =~ "RESERVE"
}, query={
SELECT
ProcessCreateTime, Pid, Name,MappingName,
AddressRange,State,Type,ProtectionMsg,
Protection,SectionSize,
dict(Rule=Rule,
Meta=Meta,
Tags=Tags,
Offset=String.Offset,
Name=String.Name) as YaraHit,
upload( accessor='scope',
file='String.Data',
name=format(format="%v-%v_%v.bin-%v-%v",
args=[
Name, Pid, AddressRange,
if(condition= String.Offset - ContextBytes < 0,
then= 0,
else= String.Offset - ContextBytes),
if(condition= String.Offset + ContextBytes > SectionSize,
then= SectionSize,
else= String.Offset + ContextBytes ) ])
) as HitContext,
_PathSpec, _Address
FROM yara( blocksize=if(condition= SectionSize < 10000000,
then= SectionSize,
else= 10000000 ),
accessor='offset',
files=_PathSpec,
rules=SuspiciousContent,
end=SectionSize, key='X',
number=1,
context=ContextBytes
)
})
-- finalise results
LET results = SELECT *,
process_tracker_callchain(id=Pid).Data as ProcessChain
FROM if(condition= SuspiciousContent,
then= yara_sections,
else= sections)
-- upload sections if selected
LET upload_results = SELECT *,
upload(accessor='sparse',
file=pathspec(
DelegateAccessor="process",
DelegatePath=Pid,
Path=[dict(Offset=_Address, Length=SectionSize),]),
name=pathspec(
Path=format(
format='%v-%v_%v.bin',
args= [ Name, Pid, AddressRange ]))) as SectionDump
FROM results
-- output rows
SELECT * FROM if(condition= UploadSection,
then= upload_results,
else= results)
notebook:
- type: vql_suggestion
name: Strings analysis
template: |
/*
# Strings analysis
*/
LET MinStringSize = 8
LET FindPrintable = '''
rule find_strings {
strings:
$wide = /(^|[^ -~\s]\x00)([ -~\s]\x00){%#%,}(\x00|[^ -~\s]|$)/
$ascii = /(^|[^ -~\s])([ -~\s]{%#%,})([^ -~\s]|$)/
condition:
any of them
}'''
LET YaraRule = regex_replace(source=FindPrintable,re='''\%\#\%''',replace=str(str=MinStringSize))
LET sections = SELECT vfs_path, client_path,file_size, uploaded_size
FROM uploads(client_id=ClientId, flow_id=FlowId)
WHERE vfs_path =~ '\.bin$'
LET find_result(name) = SELECT *
FROM source(artifact="Windows.System.VAD")
WHERE SectionDump.StoredName = name
LIMIT 1
LET row_results = SELECT *, find_result(name=client_path)[0] as Result
FROM sections
WHERE Result
SELECT * FROM foreach(row=row_results,
query={
SELECT
regex_replace(source=String.Data,re='[^ -~]',replace='') as String,
strip(prefix='$',string=String.Name) as Type,
String.Offset as Offset,
Result.MappingName as MappingName,
Result.AddressRange as AddressRange,
Result.Name as ProcesName,
Result.Pid as Pid,
Result.Protection as Protection
--,vfs_path
FROM yara(
accessor='fs',
files=vfs_path,
rules=YaraRule,
key='X',
number=9999999999999999 )
})
WHERE NOT String =~ '''^\s*$'''
column_types:
- name: HitContext
type: preview_upload