| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334 | 
							- /******************************************************************************
 
-     Copyright (C) 2023 by Richard Stanway
 
-     This program is free software: you can redistribute it and/or modify
 
-     it under the terms of the GNU General Public License as published by
 
-     the Free Software Foundation, either version 2 of the License, or
 
-     (at your option) any later version.
 
-     This program is distributed in the hope that it will be useful,
 
-     but WITHOUT ANY WARRANTY; without even the implied warranty of
 
-     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
-     GNU General Public License for more details.
 
-     You should have received a copy of the GNU General Public License
 
-     along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
- ******************************************************************************/
 
- #include <Windows.h>
 
- #include <psapi.h>
 
- #include <stdint.h>
 
- #include <stdbool.h>
 
- #include <inttypes.h>
 
- #include "detours.h"
 
- #include "obs.h"
 
- // Undocumented NT structs / function definitions !
 
- typedef enum _SECTION_INHERIT { ViewShare = 1, ViewUnmap = 2 } SECTION_INHERIT;
 
- typedef enum _SECTION_INFORMATION_CLASS {
 
- 	SectionBasicInformation = 0,
 
- 	SectionImageInformation
 
- } SECTION_INFORMATION_CLASS;
 
- typedef struct _SECTION_BASIC_INFORMATION {
 
- 	PVOID BaseAddress;
 
- 	ULONG Attributes;
 
- 	LARGE_INTEGER Size;
 
- } SECTION_BASIC_INFORMATION;
 
- typedef NTSTATUS(STDMETHODCALLTYPE *fn_NtMapViewOfSection)(
 
- 	HANDLE, HANDLE, PVOID, ULONG_PTR, SIZE_T, PLARGE_INTEGER, PSIZE_T,
 
- 	SECTION_INHERIT, ULONG, ULONG);
 
- typedef NTSTATUS(STDMETHODCALLTYPE *fn_NtUnmapViewOfSection)(HANDLE, PVOID);
 
- typedef NTSTATUS(STDMETHODCALLTYPE *fn_NtQuerySection)(
 
- 	HANDLE, SECTION_INFORMATION_CLASS, PVOID, SIZE_T, PSIZE_T);
 
- static fn_NtMapViewOfSection ntMap;
 
- static fn_NtUnmapViewOfSection ntUnmap;
 
- static fn_NtQuerySection ntQuery;
 
- #define STATUS_UNSUCCESSFUL ((NTSTATUS)0xC0000001L)
 
- // Method of matching timestamp of DLL in PE header
 
- typedef enum {
 
- 	TS_IGNORE = 0,      // Ignore timestamp; block all DLLs with this name
 
- 	TS_EQUAL,           // Block only DLL with this exact timestamp
 
- 	TS_LESS_THAN,       // Block all DLLs with an earlier timestamp
 
- 	TS_GREATER_THAN,    // Block all DLLs with a later timestamp
 
- 	TS_ALLOW_ONLY_THIS, // Invert behavior: only allow this specific timestamp
 
- } ts_compare_t;
 
- typedef struct {
 
- 	// DLL name, lower case
 
- 	const wchar_t *name;
 
- 	// Length of name, calculated at startup - leave as zero
 
- 	size_t name_len;
 
- 	// PE timestamp
 
- 	const uint32_t timestamp;
 
- 	// How to treat the timestamp field
 
- 	const ts_compare_t method;
 
- 	// Number of times we've blocked this DLL, for logging purposes
 
- 	uint64_t blocked_count;
 
- } blocked_module_t;
 
- /*
 
-  * Note: The name matches at the end of the string based on its length, this allows
 
-  * for matching DLLs that may have generic names but a problematic version only
 
-  * exists in a certain directory. A name should always include a path component
 
-  * so that e.g. fraps.dll doesn't match notfraps.dll.
 
-  */
 
- static blocked_module_t blocked_modules[] = {
 
- 	// Dell / Alienware Backup & Recovery, crashes during "Browse" dialogs
 
- 	{L"\\dbroverlayiconbackuped.dll", 0, 0, TS_IGNORE},
 
- 	// RTSS, no good reason for this to be in OBS
 
- 	{L"\\rtsshooks.dll", 0, 0, TS_IGNORE},
 
- 	// Dolby Axon overlay
 
- 	{L"\\axonoverlay.dll", 0, 0, TS_IGNORE},
 
- 	// Action! Recorder Software
 
- 	{L"\\action_x64.dll", 0, 0, TS_IGNORE},
 
- 	// ASUS GamerOSD, breaks DX11 things
 
- 	{L"\\atkdx11disp.dll", 0, 0, TS_IGNORE},
 
- 	// Malware
 
- 	{L"\\sendori.dll", 0, 0, TS_IGNORE},
 
- 	// Astril VPN Proxy, hooks stuff and crashes
 
- 	{L"\\asproxy64.dll", 0, 0, TS_IGNORE},
 
- 	// Nahimic Audio
 
- 	{L"\\nahimicmsidevprops.dll", 0, 0, TS_IGNORE},
 
- 	{L"\\nahimicmsiosd.dll", 0, 0, TS_IGNORE},
 
- 	// FRAPS hook
 
- 	{L"\\fraps64.dll", 0, 0, TS_IGNORE},
 
- 	// ASUS GPU TWEAK II OSD
 
- 	{L"\\gtii-osd64.dll", 0, 0, TS_IGNORE},
 
- 	{L"\\gtii-osd64-vk.dll", 0, 0, TS_IGNORE},
 
- 	// EVGA Precision, D3D crashes
 
- 	{L"\\pxshw10_x64.dll", 0, 0, TS_IGNORE},
 
- 	// Wacom / Other tablet driver, locks up UI
 
- 	{L"\\wintab32.dll", 0, 0, TS_IGNORE},
 
- 	// Adobe Dynamic Link (Adobe CC), crashes in its own thread
 
- 	{L"\\mc_trans_video_imagescaler.dll", 0, 0, TS_IGNORE},
 
- 	// Weird Polish banking "security" software, breaks UI
 
- 	{L"\\wslbscr64.dll", 0, 0, TS_IGNORE},
 
- 	// Various things hooking with EasyHook that probably shouldn't touch OBS
 
- 	{L"\\easyhook64.dll", 0, 0, TS_IGNORE},
 
- 	// Ultramon
 
- 	{L"\\rtsultramonhook.dll", 0, 0, TS_IGNORE},
 
- 	// HiAlgo Boost, locks up UI
 
- 	{L"\\hookdll.dll", 0, 0, TS_IGNORE},
 
- 	// Adobe Core Sync? Crashes NDI.
 
- 	{L"\\coresync_x64.dll", 0, 0, TS_IGNORE},
 
- 	// Fasso DRM, crashes D3D
 
- 	{L"\\f_sps.dll", 0, 0, TS_IGNORE},
 
- 	// Korean banking "security" software, crashes randomly
 
- 	{L"\\t_prevent64.dll", 0, 0, TS_IGNORE},
 
- 	// Generic named unity capture filter. Unfortunately only a forked version
 
- 	// has a critical fix to prevent deadlocks during enumeration. We block
 
- 	// all versions since if someone didn't change the DLL name they likely
 
- 	// didn't implement the deadlock fix.
 
- 	// Reference: https://github.com/schellingb/UnityCapture/commit/2eabf0f
 
- 	{L"\\unitycapturefilter64bit.dll", 0, 0, TS_IGNORE},
 
- 	// VSeeFace capture filter < v1.13.38b3 without above fix implemented
 
- 	{L"\\vseefacecamera64bit.dll", 0, 1666993098, TS_LESS_THAN},
 
- };
 
- static bool is_module_blocked(wchar_t *dll, uint32_t timestamp)
 
- {
 
- 	blocked_module_t *first_allowed = NULL;
 
- 	size_t len;
 
- 	len = wcslen(dll);
 
- 	wcslwr(dll);
 
- 	// Default behavior is to not block
 
- 	bool should_block = false;
 
- 	for (int i = 0; i < _countof(blocked_modules); i++) {
 
- 		blocked_module_t *b = &blocked_modules[i];
 
- 		wchar_t *dll_ptr;
 
- 		if (len >= b->name_len)
 
- 			dll_ptr = dll + len - b->name_len;
 
- 		else
 
- 			dll_ptr = dll;
 
- 		if (!wcscmp(dll_ptr, b->name)) {
 
- 			if (b->method == TS_IGNORE) {
 
- 				b->blocked_count++;
 
- 				return true;
 
- 			} else if (b->method == TS_EQUAL &&
 
- 				   timestamp == b->timestamp) {
 
- 				b->blocked_count++;
 
- 				return true;
 
- 			} else if (b->method == TS_LESS_THAN &&
 
- 				   timestamp < b->timestamp) {
 
- 				b->blocked_count++;
 
- 				return true;
 
- 			} else if (b->method == TS_GREATER_THAN &&
 
- 				   timestamp > b->timestamp) {
 
- 				b->blocked_count++;
 
- 				return true;
 
- 			} else if (b->method == TS_ALLOW_ONLY_THIS) {
 
- 				// Invert default behavior to block if
 
- 				// we don't find any matching timestamps
 
- 				// for this DLL.
 
- 				should_block = true;
 
- 				if (timestamp == b->timestamp)
 
- 					return false;
 
- 				// Bit of a hack to support counting of
 
- 				// TS_ALLOW_ONLY_THIS blocks as there may
 
- 				// be multiple entries for the same DLL.
 
- 				if (!first_allowed)
 
- 					first_allowed = b;
 
- 			}
 
- 		}
 
- 	}
 
- 	if (first_allowed)
 
- 		first_allowed->blocked_count++;
 
- 	return should_block;
 
- }
 
- static NTSTATUS
 
- NtMapViewOfSection_hook(HANDLE SectionHandle, HANDLE ProcessHandle,
 
- 			PVOID *BaseAddress, ULONG_PTR ZeroBits,
 
- 			SIZE_T CommitSize, PLARGE_INTEGER SectionOffset,
 
- 			PSIZE_T ViewSize, SECTION_INHERIT InheritDisposition,
 
- 			ULONG AllocationType, ULONG Win32Protect)
 
- {
 
- 	SECTION_BASIC_INFORMATION section_information;
 
- 	wchar_t fileName[MAX_PATH];
 
- 	SIZE_T wrote = 0;
 
- 	NTSTATUS ret;
 
- 	uint32_t timestamp = 0;
 
- 	ret = ntMap(SectionHandle, ProcessHandle, BaseAddress, ZeroBits,
 
- 		    CommitSize, SectionOffset, ViewSize, InheritDisposition,
 
- 		    AllocationType, Win32Protect);
 
- 	// Verify map and process
 
- 	if (ret < 0 || ProcessHandle != GetCurrentProcess())
 
- 		return ret;
 
- 	// Fetch section information
 
- 	if (ntQuery(SectionHandle, SectionBasicInformation,
 
- 		    §ion_information, sizeof(section_information),
 
- 		    &wrote) < 0)
 
- 		return ret;
 
- 	// Verify fetch was successful
 
- 	if (wrote != sizeof(section_information))
 
- 		return ret;
 
- 	// We're not interested in non-image maps
 
- 	if (!(section_information.Attributes & SEC_IMAGE))
 
- 		return ret;
 
- 	// Examine the PE header. Perhaps the map is small
 
- 	// so wrap it in an exception handler in case we
 
- 	// read past the end of the buffer.
 
- 	__try {
 
- 		BYTE *p = (BYTE *)*BaseAddress;
 
- 		IMAGE_DOS_HEADER *dos = (IMAGE_DOS_HEADER *)p;
 
- 		if (dos->e_magic != IMAGE_DOS_SIGNATURE)
 
- 			return ret;
 
- 		IMAGE_NT_HEADERS *nt = (IMAGE_NT_HEADERS *)(p + dos->e_lfanew);
 
- 		if (nt->Signature != IMAGE_NT_SIGNATURE)
 
- 			return ret;
 
- 		timestamp = nt->FileHeader.TimeDateStamp;
 
- 	} __except (EXCEPTION_EXECUTE_HANDLER) {
 
- 		return ret;
 
- 	}
 
- 	// Get the actual filename if possible
 
- 	if (K32GetMappedFileNameW(ProcessHandle, *BaseAddress, fileName,
 
- 				  _countof(fileName)) == 0)
 
- 		return ret;
 
- 	if (is_module_blocked(fileName, timestamp)) {
 
- 		ntUnmap(ProcessHandle, BaseAddress);
 
- 		ret = STATUS_UNSUCCESSFUL;
 
- 	}
 
- 	return ret;
 
- }
 
- void install_dll_blocklist_hook(void)
 
- {
 
- 	HMODULE nt = GetModuleHandle(L"NTDLL");
 
- 	if (!nt)
 
- 		return;
 
- 	ntMap = (fn_NtMapViewOfSection)GetProcAddress(nt, "NtMapViewOfSection");
 
- 	if (!ntMap)
 
- 		return;
 
- 	ntUnmap = (fn_NtUnmapViewOfSection)GetProcAddress(
 
- 		nt, "NtUnmapViewOfSection");
 
- 	if (!ntUnmap)
 
- 		return;
 
- 	ntQuery = (fn_NtQuerySection)GetProcAddress(nt, "NtQuerySection");
 
- 	if (!ntQuery)
 
- 		return;
 
- 	// Pre-compute length of all DLL names for exact matching
 
- 	for (int i = 0; i < _countof(blocked_modules); i++) {
 
- 		blocked_module_t *b = &blocked_modules[i];
 
- 		b->name_len = wcslen(b->name);
 
- 	}
 
- 	DetourTransactionBegin();
 
- 	if (DetourAttach((PVOID *)&ntMap, NtMapViewOfSection_hook) != NO_ERROR)
 
- 		DetourTransactionAbort();
 
- 	else
 
- 		DetourTransactionCommit();
 
- }
 
- void log_blocked_dlls(void)
 
- {
 
- 	for (int i = 0; i < _countof(blocked_modules); i++) {
 
- 		blocked_module_t *b = &blocked_modules[i];
 
- 		if (b->blocked_count) {
 
- 			blog(LOG_WARNING,
 
- 			     "Blocked loading of '%S' %" PRIu64 " time%S.",
 
- 			     b->name, b->blocked_count,
 
- 			     b->blocked_count == 1 ? L"" : L"s");
 
- 		}
 
- 	}
 
- }
 
 
  |