A Windows InjectDll plugin for Sandboxie-Plus
that hides Sandboxie's own artifacts from a program running inside a
sandbox, so that software which refuses to run under a sandbox runs normally
while staying fully contained.
Some applications check whether they are sandboxed and bail out if they are. That breaks two legitimate workflows:
- Malware analysis. An analyst wants a sandbox-evasive sample to actually execute so its behavior can be observed, instead of detecting Sandboxie and exiting. Obscura makes the sandbox look absent so the sample runs and is contained for study.
- Compatibility / privacy. A user wants to run a picky, anti-tamper, or DRM-laden application inside a sandbox for isolation, but the app refuses when it sees Sandboxie.
Obscura is in the same family as the open-source SbieHide, which Sandboxie-Plus references. It is a user-mode concealment plugin: it never breaks out of the sandbox, never escalates privilege, and never weakens the container. It only filters or normalizes the query results that would otherwise reveal Sandboxie to the contained process. The security boundary stays intact; the contained program stays contained.
It conceals only Sandboxie's own artifacts. It is not a generic process-hiding tool, and it is not for defeating anti-cheat (which risks account bans).
Obscura is a standalone superset of SbieHide: it reimplements the core concealment and adds the vectors SbieHide leaves open. Where a query would leak a box path, Obscura normalizes it to the real host equivalent so the call still succeeds with a plausible value (no new "this call suddenly fails" oracle); only where there is no clean host value does it deny or filter the entry.
| Area | Vector | ntdll hook | Action |
|---|---|---|---|
| Loaded module | SbieDll in module name / handle | (PEB unlink) | removed from all 4 Ldr lists |
| PEB | InLoadOrder/InMemoryOrder/InInitializationOrder/HashLinks |
(PEB unlink) | unlinked + names zeroed |
| Memory | mapped-file name of SbieDll region | NtQueryVirtualMemory |
image hidden; box paths normalized |
| Memory | MEM_IMAGE of SbieDll region |
NtQueryVirtualMemory |
reported as MEM_PRIVATE |
| Section | original base of SbieDll section | NtQuerySection |
denied for hidden ranges |
| Object | box-rooted object name | NtQueryObject |
normalized to host; box-only -> unnamed |
| File | box-rooted file path | NtQueryInformationFile |
normalized to host path |
| System | SbieDrv.sys in module list |
NtQuerySystemInformation |
slot removed + list compacted |
| System | SbieSvc.exe / box procs |
NtQuerySystemInformation |
entries spliced out |
| Process | box path / command line | NtQueryInformationProcess |
normalized to host |
| Objects | Sandboxie named objects | NtQueryDirectoryObject |
filtered; size-probe status preserved |
| Device | \Device\SandboxieDriverApi |
NtOpenFile / NtCreateFile |
reads as not found |
| Registry | Services\SbieDrv / SbieSvc |
NtOpenKey / NtEnumerateKey |
gated / index-skipped |
| Registry | box hive key path | NtQueryKey |
normalized to real hive |
| Token | integrity below Medium | NtQueryInformationToken |
raised to Medium |
Nothing is hardcoded to a box or user name: the box roots are discovered at
runtime from SbieDll's own SbieApi_QueryBoxPath export.
Obscura conceals its own module the same way it conceals SbieDll - by image range (the PEB unlink works on the mapped base address), so the plugin's filename is irrelevant. SbieHide, by contrast, keys on its own name.
These are inherent to a user-mode DLL and are not "bugs to fix later":
- Direct syscalls. A program that builds its own
syscallinstruction bypasses every user-mode hook (Obscura's and Sandboxie's) and reads the unfiltered sandboxed truth. No DLL closes this. The probe demonstrates it. - TLS-callback timing. A target's TLS callback can run detection during
loader init, before Obscura's hooks are installed. Obscura does the PEB unlink
as early as possible (in
DllMain, before hooking) to cover the cheapest such checks, but full coverage would need a separate launcher (out of scope here). - Hook self-detection. Inline hooks are visible to prologue scanning, a fresh-ntdll byte compare, or timing. Partly inherent to any hooking approach.
- Kernel objects.
SbieDrv.sys, the service, and the driver device exist in the kernel regardless of user-mode action. Obscura filters them from queries but cannot remove them; doing so would need a driver (PatchGuard risk). - Token group SID (
tok-sid). The box's injected group SID is generated per box/session. Blindly filtering token groups is risky, so that filter ships disabled; only integrity normalization is on by default. To enable it, capture the box's group SID in-box, flipOBSCURA_ENABLE_TOKEN_GROUP_FILTER, and implement the discriminator insrc/filter_token.cpp.
- Windows with Sandboxie-Plus installed.
- Install both
Obscura32.dllandObscura64.dllto cover 32- and 64-bit sandboxed processes. - Path normalization resolves the box roots from SbieDll's
SbieApi_QueryBoxPathexport. If that export is unavailable, normalization no-ops and the range- and name-based filters still act.
Requires Visual Studio 2022 (MSVC x64 + x86), CMake >= 3.21.
cmake --preset obscura-x64 && cmake --build --preset obscura-x64
cmake --preset obscura-x86 && cmake --build --preset obscura-x86
(MSVC cannot emit both bitnesses from one configure, hence two presets.) Output
lands in dist\:
dist\Obscura64.dll dist\Obscura32.dll
dist\obscura_probe_x64.exe dist\obscura_probe_x86.exe
Both DLLs link the static CRT and depend only on ntdll.dll and KERNEL32.dll,
so they carry nothing extra into a sandboxed process.
Dependencies are vendored under extern\: the phnt
native headers and MinHook v1.3.3
(built from source with the same flags). See their licenses in extern\.
Obscura does not modify your Sandboxie configuration. To enable it, copy the
two InjectDll/InjectDll64 lines from docs\InjectDll.snippet.ini into the
target box's section (back up Sandboxie.ini first). To remove it, delete those
lines and reload.
obscura_probe.exe --selftest validates the path-rewrite logic against synthetic
box paths on the host - no sandbox needed. Run inside a box, the same probe reports
each detection vector as LEAK or CLEAN.
src\ entry.cpp, hook_engine, peb_hide, image_registry, box_roots,
path_normalizer, filter_objdir, filter_registry, filter_token, nt_shims
test\ obscura_probe.cpp (detection-vector harness + --selftest)
docs\ InjectDll.snippet.ini (documented-only config snippet)
extern\ phnt\ minhook\ (vendored dependencies)
MIT - see LICENSE. Vendored dependencies under extern\ keep their
own licenses (phnt, MinHook).