Skip to content

Instantly share code, notes, and snippets.

@valinet
Created May 23, 2026 19:51
Show Gist options
  • Select an option

  • Save valinet/ef2ba8f2de4e2017d4f16d394d266bb6 to your computer and use it in GitHub Desktop.

Select an option

Save valinet/ef2ba8f2de4e2017d4f16d394d266bb6 to your computer and use it in GitHub Desktop.
WinRing0 fix
/*
WinRing0 Fix(ish)
=================
Recently, there's been a ton of debate about how WinRing0 is the worst thing to have hit
the planet. A lot of overexaggerated crap, yet the conclusion seems to be that WinRing0
is the ultimate sin because it doesn't protect its device with a DACL that disallows
non-elevated processes from interacting with it. For now, until "security" becomes even
more "secure", the consensus is that it is okayish for apps to mess with arbitrary
memory regions (or at least, there's not much you can do about it), only when elevated tho.
So, this is a patch to WinRing0 that sets a DACL on the device it creates from user space.
I know, it is not a perfect solution, I know there is a window of opportunity between the
device being created and the user space applying the DACL, I know, but what can you do...
it is better than nothing in my opinion, considering that we cannot patch the driver because
we'd lose the signature and Windows doesn't let users load their own code in the kernel
without pissing on the entire OS security by turning on test mode.
This idea was previously employed by Razer, for example, before someone found it as the worst
thing to have happened and insisted for a CVE for it as if it is the worst idea in the world.
It's not, it's a 99% mitigation considering the situation. Ideally, one should write
customized drivers that expose high level primitives to user space, but, again, since the OS
doesn't let you load custom code in the kernel easily, people have resorted to running some
universal solution and working with that and accepting its drawbacks.
More details and binary downloads here:
https://github.com/valinet/ThinkPadLEDControl/issues/25#issuecomment-4526312208
https://github.com/user-attachments/files/28182298/WinRing0Secureish.zip
Compile with:
x64
cl /nologo forwarder.c kernel32.lib advapi32.lib /O1 /GS- /Gs9999999 /GF /kernel /link /DLL /ENTRY:DllMain /NODEFAULTLIB /SUBSYSTEM:windows /NOCOFFGRPINFO /ALIGN:16 /MERGE:.rdata=.text /MERGE:.pdata=.text /OUT:64rnel32.dll
x86
cl /nologo forwarder.c kernel32.lib advapi32.lib /O1 /GS- /Gs9999999 /GF /kernel /link /DLL /ENTRY:DllMain /NODEFAULTLIB /SUBSYSTEM:windows /NOCOFFGRPINFO /ALIGN:16 /MERGE:.rdata=.text /MERGE:.pdata=.text /OUT:32rnel32.dll
License is GPLv2 (please share back any improvements).
*/
#define WIN32_LEAN_AND_MEAN
#include <Windows.h>
#include <sddl.h>
#ifdef _WIN64
#pragma comment(linker, "/export:SetProcessAffinityMask=kernel32.SetProcessAffinityMask")
#pragma comment(linker, "/export:Sleep=kernel32.Sleep")
#pragma comment(linker, "/export:GetModuleFileNameW=kernel32.GetModuleFileNameW")
#pragma comment(linker, "/export:CreateFileW=_CreateFileW")
#pragma comment(linker, "/export:GetVersionExW=kernel32.GetVersionExW")
#pragma comment(linker, "/export:GetProcessAffinityMask=kernel32.GetProcessAffinityMask")
#pragma comment(linker, "/export:FindClose=kernel32.FindClose")
#pragma comment(linker, "/export:GetDriveTypeW=kernel32.GetDriveTypeW")
#pragma comment(linker, "/export:GetCurrentProcess=kernel32.GetCurrentProcess")
#pragma comment(linker, "/export:SetThreadAffinityMask=kernel32.SetThreadAffinityMask")
#pragma comment(linker, "/export:GetCurrentThread=kernel32.GetCurrentThread")
#pragma comment(linker, "/export:DeviceIoControl=kernel32.DeviceIoControl")
#pragma comment(linker, "/export:HeapFree=kernel32.HeapFree")
#pragma comment(linker, "/export:GetProcessHeap=kernel32.GetProcessHeap")
#pragma comment(linker, "/export:HeapAlloc=kernel32.HeapAlloc")
#pragma comment(linker, "/export:GetLastError=kernel32.GetLastError")
#pragma comment(linker, "/export:FindFirstFileW=kernel32.FindFirstFileW")
#pragma comment(linker, "/export:CloseHandle=kernel32.CloseHandle")
#pragma comment(linker, "/export:GetCurrentThreadId=kernel32.GetCurrentThreadId")
#pragma comment(linker, "/export:FlsSetValue=kernel32.FlsSetValue")
#pragma comment(linker, "/export:GetCommandLineA=kernel32.GetCommandLineA")
#pragma comment(linker, "/export:TerminateProcess=kernel32.TerminateProcess")
#pragma comment(linker, "/export:UnhandledExceptionFilter=kernel32.UnhandledExceptionFilter")
#pragma comment(linker, "/export:SetUnhandledExceptionFilter=kernel32.SetUnhandledExceptionFilter")
#pragma comment(linker, "/export:IsDebuggerPresent=kernel32.IsDebuggerPresent")
#pragma comment(linker, "/export:RtlVirtualUnwind=kernel32.RtlVirtualUnwind")
#pragma comment(linker, "/export:RtlLookupFunctionEntry=kernel32.RtlLookupFunctionEntry")
#pragma comment(linker, "/export:RtlCaptureContext=kernel32.RtlCaptureContext")
#pragma comment(linker, "/export:HeapSetInformation=kernel32.HeapSetInformation")
#pragma comment(linker, "/export:HeapCreate=kernel32.HeapCreate")
#pragma comment(linker, "/export:HeapDestroy=kernel32.HeapDestroy")
#pragma comment(linker, "/export:GetModuleHandleW=kernel32.GetModuleHandleW")
#pragma comment(linker, "/export:GetProcAddress=kernel32.GetProcAddress")
#pragma comment(linker, "/export:ExitProcess=kernel32.ExitProcess")
#pragma comment(linker, "/export:WriteFile=kernel32.WriteFile")
#pragma comment(linker, "/export:GetStdHandle=kernel32.GetStdHandle")
#pragma comment(linker, "/export:GetModuleFileNameA=kernel32.GetModuleFileNameA")
#pragma comment(linker, "/export:EncodePointer=kernel32.EncodePointer")
#pragma comment(linker, "/export:DecodePointer=kernel32.DecodePointer")
#pragma comment(linker, "/export:FlsGetValue=kernel32.FlsGetValue")
#pragma comment(linker, "/export:FlsFree=kernel32.FlsFree")
#pragma comment(linker, "/export:SetLastError=kernel32.SetLastError")
#pragma comment(linker, "/export:FlsAlloc=kernel32.FlsAlloc")
#pragma comment(linker, "/export:SetHandleCount=kernel32.SetHandleCount")
#pragma comment(linker, "/export:GetFileType=kernel32.GetFileType")
#pragma comment(linker, "/export:GetStartupInfoA=kernel32.GetStartupInfoA")
#pragma comment(linker, "/export:DeleteCriticalSection=kernel32.DeleteCriticalSection")
#pragma comment(linker, "/export:FreeEnvironmentStringsA=kernel32.FreeEnvironmentStringsA")
#pragma comment(linker, "/export:GetEnvironmentStrings=kernel32.GetEnvironmentStrings")
#pragma comment(linker, "/export:FreeEnvironmentStringsW=kernel32.FreeEnvironmentStringsW")
#pragma comment(linker, "/export:WideCharToMultiByte=kernel32.WideCharToMultiByte")
#pragma comment(linker, "/export:GetEnvironmentStringsW=kernel32.GetEnvironmentStringsW")
#pragma comment(linker, "/export:RtlUnwindEx=kernel32.RtlUnwindEx")
#pragma comment(linker, "/export:QueryPerformanceCounter=kernel32.QueryPerformanceCounter")
#pragma comment(linker, "/export:GetTickCount=kernel32.GetTickCount")
#pragma comment(linker, "/export:GetCurrentProcessId=kernel32.GetCurrentProcessId")
#pragma comment(linker, "/export:GetSystemTimeAsFileTime=kernel32.GetSystemTimeAsFileTime")
#pragma comment(linker, "/export:LeaveCriticalSection=kernel32.LeaveCriticalSection")
#pragma comment(linker, "/export:EnterCriticalSection=kernel32.EnterCriticalSection")
#pragma comment(linker, "/export:LoadLibraryA=kernel32.LoadLibraryA")
#pragma comment(linker, "/export:InitializeCriticalSectionAndSpinCount=kernel32.InitializeCriticalSectionAndSpinCount")
#pragma comment(linker, "/export:GetCPInfo=kernel32.GetCPInfo")
#pragma comment(linker, "/export:GetACP=kernel32.GetACP")
#pragma comment(linker, "/export:GetOEMCP=kernel32.GetOEMCP")
#pragma comment(linker, "/export:IsValidCodePage=kernel32.IsValidCodePage")
#pragma comment(linker, "/export:HeapReAlloc=kernel32.HeapReAlloc")
#pragma comment(linker, "/export:HeapSize=kernel32.HeapSize")
#pragma comment(linker, "/export:GetLocaleInfoA=kernel32.GetLocaleInfoA")
#pragma comment(linker, "/export:GetStringTypeA=kernel32.GetStringTypeA")
#pragma comment(linker, "/export:MultiByteToWideChar=kernel32.MultiByteToWideChar")
#pragma comment(linker, "/export:GetStringTypeW=kernel32.GetStringTypeW")
#pragma comment(linker, "/export:LCMapStringA=kernel32.LCMapStringA")
#pragma comment(linker, "/export:LCMapStringW=kernel32.LCMapStringW")
#else
#pragma comment(linker, "/export:ExitProcess=kernel32.ExitProcess")
#pragma comment(linker, "/export:CloseHandle=kernel32.CloseHandle")
#pragma comment(linker, "/export:GetLastError=kernel32.GetLastError")
#pragma comment(linker, "/export:HeapAlloc=kernel32.HeapAlloc")
#pragma comment(linker, "/export:GetProcessHeap=kernel32.GetProcessHeap")
#pragma comment(linker, "/export:HeapFree=kernel32.HeapFree")
#pragma comment(linker, "/export:GetCurrentThread=kernel32.GetCurrentThread")
#pragma comment(linker, "/export:SetThreadAffinityMask=kernel32.SetThreadAffinityMask")
#pragma comment(linker, "/export:GetCurrentProcess=kernel32.GetCurrentProcess")
#pragma comment(linker, "/export:GetProcessAffinityMask=kernel32.GetProcessAffinityMask")
#pragma comment(linker, "/export:SetProcessAffinityMask=kernel32.SetProcessAffinityMask")
#pragma comment(linker, "/export:DeviceIoControl=kernel32.DeviceIoControl")
#pragma comment(linker, "/export:Sleep=kernel32.Sleep")
#pragma comment(linker, "/export:GetModuleFileNameA=kernel32.GetModuleFileNameA")
#pragma comment(linker, "/export:CreateFileA=__CreateFileA@28")
#pragma comment(linker, "/export:GetVersionExA=kernel32.GetVersionExA")
#pragma comment(linker, "/export:GetProcAddress=kernel32.GetProcAddress")
#pragma comment(linker, "/export:GetModuleHandleA=kernel32.GetModuleHandleA")
#pragma comment(linker, "/export:FindFirstFileA=kernel32.FindFirstFileA")
#pragma comment(linker, "/export:FindClose=kernel32.FindClose")
#pragma comment(linker, "/export:GetDriveTypeA=kernel32.GetDriveTypeA")
#pragma comment(linker, "/export:GetCurrentThreadId=kernel32.GetCurrentThreadId")
#pragma comment(linker, "/export:GetCommandLineA=kernel32.GetCommandLineA")
#pragma comment(linker, "/export:TerminateProcess=kernel32.TerminateProcess")
#pragma comment(linker, "/export:UnhandledExceptionFilter=kernel32.UnhandledExceptionFilter")
#pragma comment(linker, "/export:SetUnhandledExceptionFilter=kernel32.SetUnhandledExceptionFilter")
#pragma comment(linker, "/export:IsDebuggerPresent=kernel32.IsDebuggerPresent")
#pragma comment(linker, "/export:DeleteCriticalSection=kernel32.DeleteCriticalSection")
#pragma comment(linker, "/export:LeaveCriticalSection=kernel32.LeaveCriticalSection")
#pragma comment(linker, "/export:EnterCriticalSection=kernel32.EnterCriticalSection")
#pragma comment(linker, "/export:VirtualFree=kernel32.VirtualFree")
#pragma comment(linker, "/export:VirtualAlloc=kernel32.VirtualAlloc")
#pragma comment(linker, "/export:HeapReAlloc=kernel32.HeapReAlloc")
#pragma comment(linker, "/export:HeapDestroy=kernel32.HeapDestroy")
#pragma comment(linker, "/export:HeapCreate=kernel32.HeapCreate")
#pragma comment(linker, "/export:WriteFile=kernel32.WriteFile")
#pragma comment(linker, "/export:GetStdHandle=kernel32.GetStdHandle")
#pragma comment(linker, "/export:GetCPInfo=kernel32.GetCPInfo")
#pragma comment(linker, "/export:InterlockedIncrement=kernel32.InterlockedIncrement")
#pragma comment(linker, "/export:InterlockedDecrement=kernel32.InterlockedDecrement")
#pragma comment(linker, "/export:GetACP=kernel32.GetACP")
#pragma comment(linker, "/export:GetOEMCP=kernel32.GetOEMCP")
#pragma comment(linker, "/export:IsValidCodePage=kernel32.IsValidCodePage")
#pragma comment(linker, "/export:TlsGetValue=kernel32.TlsGetValue")
#pragma comment(linker, "/export:TlsAlloc=kernel32.TlsAlloc")
#pragma comment(linker, "/export:TlsSetValue=kernel32.TlsSetValue")
#pragma comment(linker, "/export:TlsFree=kernel32.TlsFree")
#pragma comment(linker, "/export:SetLastError=kernel32.SetLastError")
#pragma comment(linker, "/export:SetHandleCount=kernel32.SetHandleCount")
#pragma comment(linker, "/export:GetFileType=kernel32.GetFileType")
#pragma comment(linker, "/export:GetStartupInfoA=kernel32.GetStartupInfoA")
#pragma comment(linker, "/export:FreeEnvironmentStringsA=kernel32.FreeEnvironmentStringsA")
#pragma comment(linker, "/export:GetEnvironmentStrings=kernel32.GetEnvironmentStrings")
#pragma comment(linker, "/export:FreeEnvironmentStringsW=kernel32.FreeEnvironmentStringsW")
#pragma comment(linker, "/export:WideCharToMultiByte=kernel32.WideCharToMultiByte")
#pragma comment(linker, "/export:GetEnvironmentStringsW=kernel32.GetEnvironmentStringsW")
#pragma comment(linker, "/export:QueryPerformanceCounter=kernel32.QueryPerformanceCounter")
#pragma comment(linker, "/export:GetTickCount=kernel32.GetTickCount")
#pragma comment(linker, "/export:GetCurrentProcessId=kernel32.GetCurrentProcessId")
#pragma comment(linker, "/export:GetSystemTimeAsFileTime=kernel32.GetSystemTimeAsFileTime")
#pragma comment(linker, "/export:InitializeCriticalSection=kernel32.InitializeCriticalSection")
#pragma comment(linker, "/export:RtlUnwind=kernel32.RtlUnwind")
#pragma comment(linker, "/export:LoadLibraryA=kernel32.LoadLibraryA")
#pragma comment(linker, "/export:LCMapStringA=kernel32.LCMapStringA")
#pragma comment(linker, "/export:MultiByteToWideChar=kernel32.MultiByteToWideChar")
#pragma comment(linker, "/export:LCMapStringW=kernel32.LCMapStringW")
#pragma comment(linker, "/export:GetStringTypeA=kernel32.GetStringTypeA")
#pragma comment(linker, "/export:GetStringTypeW=kernel32.GetStringTypeW")
#pragma comment(linker, "/export:GetLocaleInfoA=kernel32.GetLocaleInfoA")
#pragma comment(linker, "/export:HeapSize=kernel32.HeapSize")
#endif
#ifdef _WIN64
HANDLE WINAPI _CreateFileW(LPCWSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode,
LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes, HANDLE hTemplateFile) {
HANDLE hFile = CreateFileW(lpFileName, dwDesiredAccess, dwShareMode, lpSecurityAttributes, dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile);
#else
HANDLE WINAPI _CreateFileA(LPCSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode,
LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes, HANDLE hTemplateFile) {
HANDLE hFile = CreateFileA(lpFileName, dwDesiredAccess, dwShareMode, lpSecurityAttributes, dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile);
#endif
if (hFile != INVALID_HANDLE_VALUE && dwCreationDisposition == (CREATE_NEW | CREATE_ALWAYS)) {
PSECURITY_DESCRIPTOR pSD = NULL;
if (ConvertStringSecurityDescriptorToSecurityDescriptorA("O:BAG:SYD:(A;;FA;;;SY)(A;;FA;;;BA)", SDDL_REVISION_1, &pSD, NULL)) {
SetFileSecurityA("\\\\.\\WinRing0_1_2_0", DACL_SECURITY_INFORMATION | OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION, pSD);
LocalFree(pSD);
}
}
return hFile;
}
BOOL WINAPI DllMain(HINSTANCE hModule, DWORD fdwReason, LPVOID lpReserved) {
UNREFERENCED_PARAMETER(lpReserved);
switch (fdwReason) {
case DLL_PROCESS_ATTACH:
DisableThreadLibraryCalls(hModule);
break;
case DLL_PROCESS_DETACH:
break;
default:
break;
}
return TRUE;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment