Introduction
As Microsoft publishes new updates, we get new tools to explore. This time, Microsoft introduced new functionality that can be used to virtualize parts of the filesystem.
This article explains how BindLink works, how it was introduced, and why it matters from a security perspective.
The feature
The BindLink feature lets administrators map a filesystem "backing path" to a local "virtual path" through the Bind Filter driver (bindflt.sys), transparently redirecting I/O.
Examples:
C:\App\Config ➤ C:\Windows\System32\cfg
BindLink also supports remote backing paths:
C:\VirtualDir ➤ \server\share\realdir
Note: Bind links are not persistent across reboots and must be recreated after a restart.
BindFltApi's Origin
The user-mode library used to manage bind links is BindFltApi.dll (C:\Windows\System32\bindfltapi.dll).
Checking the file’s ProductVersion indicates the release build that introduced it: 10.0.26100.3194.
Searching for this build leads to the KB5051987 update: https://support.microsoft.com/en-us/topic/february-11-2025-kb5051987-os-build-26100-3194-63fb007d-3f52-4b47-85ea-28414a24be2d
Per Microsoft's practice, we can verify the inclusion of BindFltApi.dll via the CSV linked in the KB article: https://go.microsoft.com/fwlink/?linkid=2302954
| File name | File version | Date | Time | File size |
|---|---|---|---|---|
| bindfltapi.dll | 10.0.26100.3194 | 2025-02-08 | 13:42 | 229376 |
We can confirm that BindFltApi.dll has been available since Windows 11 build 26100.3194 (2025‑02‑11).
Use cases
This functionality can be used to, but is not limited to:
- Hiding files by storing them under virtual paths.
- Evading security tooling that monitors specific directories by redirecting I/O to unexpected backing paths.
- Making remote content appear local to bypass application checks requiring local file access.
- Virtually renaming or reshuffling directory structures to confuse audits and incident response.
- Redirecting high‑value targets to attacker‑controlled locations.
- Proxying execution by mapping paths to attacker-controlled locations.
- Disrupting EDRs by redirecting their own installation directories (see example: https://www.zerosalarium.com/2025/10/DR-Redir-Break-EDR-Via-BindLink-Cloud-Filter.html).
The implementation
#include <Windows.h>
#include <stdio.h>
// Define the mask bits for the Bind Link flags.
typedef enum CREATE_BIND_LINK_FLAGS
{
CREATE_BIND_LINK_FLAG_NONE = 0x00000000,
CREATE_BIND_LINK_FLAG_READ_ONLY = 0x00000001,
CREATE_BIND_LINK_FLAG_MERGED = 0x00000002,
} CREATE_BIND_LINK_FLAGS;
// Allow bitwise operations on the CREATE_BIND_LINK_FLAGS enum.
DEFINE_ENUM_FLAG_OPERATORS(CREATE_BIND_LINK_FLAGS);
// Define the type for the `BfSetupFilter` function.
typedef HRESULT(__stdcall* PtrCreateBindLink)(
PVOID jobHandle,
CREATE_BIND_LINK_FLAGS createBindLinkFlags,
PCWSTR virtualPath,
PCWSTR backingPath,
UINT32 exceptionCount,
PCWSTR* const exceptionPaths);
// Define the type for the `BfRemoveMapping` function.
typedef HRESULT(__stdcall* PtrRemoveBindLink)(
PVOID reserved,
PCWSTR backingPath);
// Function to remove an existing bind link.
int RemoveBindLink(PCWSTR from) {
HMODULE hBindflt = LoadLibraryW(L"bindfltapi.dll");
if (!hBindflt) {
wprintf(L"Failed to load bindfltapi.dll.\n");
return 1;
}
PtrRemoveBindLink RemoveBindLink = (PtrRemoveBindLink)GetProcAddress(hBindflt, "BfRemoveMapping");
if (!RemoveBindLink) {
wprintf(L"Failed to retrieve BfRemoveMapping function.\n");
FreeLibrary(hBindflt);
return 1;
}
HRESULT hrr = RemoveBindLink(
0, // Reserved parameter (set to 0).
from // Path to remove the bind link.
);
if (FAILED(hrr)) {
if (hrr != 0x80070490) {
wprintf(L"RemoveBindLink failed with error code: 0x%08X\n", hrr);
FreeLibrary(hBindflt);
return 1;
}
}
wprintf(L"RemoveBindLink succeeded.\n");
FreeLibrary(hBindflt);
return 0;
}
// Function to create a new bind link.
int CreateBindLink(PCWSTR from, PCWSTR to) {
HMODULE hBindflt = LoadLibraryW(L"bindfltapi.dll");
if (!hBindflt) {
wprintf(L"Failed to load bindfltapi.dll.\n");
return 1;
}
PtrCreateBindLink CreateBindLink = (PtrCreateBindLink)GetProcAddress(hBindflt, "BfSetupFilter");
if (!CreateBindLink) {
wprintf(L"Failed to retrieve BfSetupFilter function.\n");
FreeLibrary(hBindflt);
return 1;
}
CREATE_BIND_LINK_FLAGS flags = CREATE_BIND_LINK_FLAG_NONE;
HRESULT hrc = CreateBindLink(
NULL, // No specific job handle.
flags, // Flags for the bind link.
from, // Source folder (virtual path).
to, // Destination folder (backing path).
0, // No exception paths.
NULL // No exception paths provided.
);
if (FAILED(hrc)) {
wprintf(L"CreateBindLink failed with error code: 0x%08X\n", hrc);
FreeLibrary(hBindflt);
return 1;
}
wprintf(L"CreateBindLink succeeded.\n");
FreeLibrary(hBindflt);
return 0;
}
int printusage(const wchar_t* path) {
wprintf(L"Usage:\n");
wprintf(L" %s enable <from> <to>\n", path);
wprintf(L" %s disable <from>\n", path);
return 1;
}
int wmain(int argc, wchar_t** argv) {
// Check parameters
if (argc < 2) {
return printusage(argv[0]);
}
if (_wcsicmp(argv[1], L"enable") == 0) {
if (argc == 4) {
// Remove any existing bind link before creating a new one.
RemoveBindLink(argv[2]);
CreateBindLink(argv[2], argv[3]);
}
else {
return printusage(argv[0]);
}
}
else if (_wcsicmp(argv[1], L"disable") == 0) {
if (argc == 3) {
RemoveBindLink(argv[2]);
}
else {
return printusage(argv[0]);
}
}
else {
return printusage(argv[0]);
}
return 0;
}
Detection
Use this Sigma rule to detect processes that load bindfltapi.dll.
title: Potential Directory Tampering via Bindfilter Redirection
id: 269e6be0-8a4c-46be-ae86-818b39655eb8
status: stable
description: Adversaries may abuse Windows BindFilter to overlay a process’s files or directories with benign ones, hiding its real metadata or executables from system tools. This redirection can also disrupt normal application behavior, such as preventing programs from finding required DLLs.
author: serrac
date: 01-12-2025
tags:
- attack.t1098
logsource:
product: windows
category: library_event
detection:
selection:
- ImageLoaded|endswith: '\bindfltapi.dll'
condition: selection
falsepositives:
- unknown
level: high
Credits
Credits to research and inspiration from:
- https://www.zerosalarium.com/2025/10/DR-Redir-Break-EDR-Via-BindLink-Cloud-Filter.html
- https://x.com/TwoSevenOneT