Created
May 23, 2026 19:51
-
-
Save valinet/ef2ba8f2de4e2017d4f16d394d266bb6 to your computer and use it in GitHub Desktop.
WinRing0 fix
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| /* | |
| 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