tl;dr
- At least one commercial post exploitation framework is using Vectored Exception Handling (VEH) on Microsoft Windows to hook functions in an attempt subvert hooking detection.
- e.g. We recently released a Copy on Write Detector which is capable of detecting patches to
EtwEventWrite
via traditional memory patching methods without the need for byte comparison.
- e.g. We recently released a Copy on Write Detector which is capable of detecting patches to
- NCC Group researched a way to enumerate and identify anomalous and/or potentially malicious VEH handlers present on a host.
- We have documented our approach and shared example code which is capable of identifying:
- if a process is using VEH or not
- which handlers are present and which modules they point to
- highlight if they don’t point to a known module
Prior Work
This research was aided significantly by the prior work of others:
- Dimitri Fourny’s post Dumping the VEH in Windows 10 [32 bit] from June 2020
- this work is excellent but due to pointer encoding changes and structure changes we were required to revisit parts for x64.
- rinse and REpeat and their PEB Structure 64-bit
- Geoff Chappell’s documentation of the Cross-Process Flags in the PEB
Problem Statement
In short we want to be able to:
- Enumerate which processes are using VEH
- Identify how many VEH handlers are present
- Identify which loaded modules those VEH handlers are serviced by
Malicious VEH Usage
VEH use is a well known technique in the gaming community as a means of bypassing integrity checking code used by games publishers. As such some in the cyber research community have adopted it as a technique for similar reasons.
An example malicious VEH installation would look something akin to:
Our objective is to detect such use.
Solution
VEH using Process Enumeration
Using the Process Environment Block (PEB) there is the CrossProcessFlags
bit mask which provides an indicator if a process is or is not using VEH.
To enumerate if a process is using VEH we:
- Open a handle to the process via
OpenProcess
- use
NtQueryInformationProcess
to get process basic information which includePebBaseAddress
- use
ReadProcessMemory
to read the PEB and check theCrossProcessFlags
bit mask for0x4
(VEH)
This provides a performant way to do initial process triage.
VEH Handler and Handling Module Enumeration
As documented by others previously the VEH handlers are stored in a doubly linked list. The address for the start of the doubly linked list is in an unexported variable called LdrpVectorHandlerList
in ntdll.dll
. The address LdrpVectorHandlerList
is obtainable from symbols or using a heuristic on RtlpCallVectoredHandlers
without.
Once we have the address of LdrpVectorHandlerList
we walk the list and its associated structure. It was at this point sadly that Dimitri’s excellent prior work did not translate to Windows 10 x64.
The structure we ended up using was:
#pragma pack(2)
struct VEH_HANDLER_ENTRY
{
LIST_ENTRY Entry;
PVOID UnKwn1;
PVOID UnKwn2;
PVOID VectoredHandler3;
};
With this structure we are able to:
- use
ReadProcessMemory
using the address ofLdrpVectorHandlerList
- walk the doubly linked list extracting
VectoredHandler3
from eachVEH_HANDLER_ENTRY
- decode
VectoredHandler3
– it is encoded viaEncodePointer
– to get the handler’s virtual address- note: this was done using
NtQueryInformationProcess
and the undocumentedProcessCookie
class (thank you Process Hacker team) as opposed toDecodeRemotePointer
- note: this was done using
- For each of the decoded pointers then identify via
EnumProcessModules
andGetModuleInformation
which modules (i.e. executables or libraries) each of the handlers point to.
With this done we are able to enumerate both which processes are or are not using VEH.
But also how many handlers are present for a particular process and which modules are serving them.
Identifying Anomalous or Malicious Handlers
VEH use doesn’t seem overly common in the unscientific sample size of one host. But what does an anomalous or malicious handler look like in the output? To test the concept we used the following as a cartoon:
Using our approach we can clearly see the last ‘mal’ handler points to a region of memory which isn’t hosted by a DLL or EXE.
Further work can be done here to ensure that the exception handler pointers reside in the .text
section and that the section is integral.
Summary and Conclusions
In this post we have documented the appeal of VEH use on Windows to avoid certain hooking detection techniques. We have also shown VEH use is easy to detect due to a low volume of usage coupled with high signal indicators when anomalously used – all in a performant manner.
We encourage EDR, telemetry and other observability vendors to integration these enumeration techniques into their Windows product lines to facilitate detection by cyber defense teams.
Code
The example code can be obtained from here.
However please note it is only example code , it is only known to work on Windows 10 x64
Footnotes
Some footnotes associated with the project.
x64dbg
The x64dbg team have support for dumping the VEH – however it produces incorrect pointers on x64 Windows 10 – we reported it and shared our code.
RtlpLogExceptionHandler
It was noted RtlpCallVectoredHandlers
contains a call to RtlpLogExceptionHandler
It was hypothesized that this might provide a further source of telemetry / forensic artifacts about which handlers have recently been called even if the handlers were no longer present. However it was unclear how it would be retrieved. In speaking to Alex Ionescu it transpires it first needs to be enabled via gflags
After only which it can be obtained via !exrlog
in WinDbg