|
Post by ephemeralViolette on Nov 20, 2023 13:36:37 GMT -8
Here is the code. Now it only injects mspaint.exe for testing purposes. The function NtOpenSection fails for me in runtime.
// ==WindhawkMod== // @id classic-theme-enable // @name Enable Classic Theme // @description Disables theming by closing the handle // @version 0.1 // @author Anixx // @github https://github.com/nat // @twitter https://twitter.com/jack // @homepage https://your-personal-homepage.example.com/ // @include mspaint.exe // @compilerOptions -lntdll // ==/WindhawkMod==
#include <windows.h> #include <iostream> #include <sddl.h> #include <winternl.h> #include <aclapi.h>
// Define the prototype for the NtOpenSection function. extern "C" NTSTATUS NTAPI NtOpenSection( OUT PHANDLE SectionHandle, IN ACCESS_MASK DesiredAccess, IN POBJECT_ATTRIBUTES ObjectAttributes );
BOOL Wh_ModInit() {
Wh_Log(L"Init"); // Retrieve the current session ID for the process. DWORD sessionId; if (!ProcessIdToSessionId(GetCurrentProcessId(), &sessionId)) { std::wcerr << L"Error getting session ID: " << GetLastError() << std::endl; return 1; }
wchar_t sectionName[256]; swprintf_s(sectionName, _countof(sectionName), L"\\Sessions\\%lu\\BaseNamedObjects\\Windows\\ThemeSection", sessionId);
// Define the name of the section object. UNICODE_STRING sectionObjectName; RtlInitUnicodeString(§ionObjectName, sectionName);
// Define the attributes for the section object. OBJECT_ATTRIBUTES objectAttributes; InitializeObjectAttributes(&objectAttributes, §ionObjectName, OBJ_CASE_INSENSITIVE, NULL, NULL);
HANDLE hSection; NTSTATUS status = NtOpenSection(&hSection, SECTION_ALL_ACCESS, &objectAttributes);
// Define your SDDL string. LPCWSTR sddl = L"O:BAG:SYD:(A;;RC;;;IU)(A;;DCSWRPSDRCWDWO;;;SY)"; PSECURITY_DESCRIPTOR psd = NULL;
// Convert the SDDL string to a security descriptor. if (!ConvertStringSecurityDescriptorToSecurityDescriptorW(sddl, SDDL_REVISION_1, &psd, NULL)) { std::wcerr << L"Error converting SDDL to security descriptor: " << GetLastError() << std::endl; CloseHandle(hSection); return 1; }
// Set the security descriptor for the object. DWORD result = SetSecurityInfo( hSection, SE_KERNEL_OBJECT, DACL_SECURITY_INFORMATION, NULL, NULL, ((SECURITY_DESCRIPTOR*)psd)->Dacl, NULL );
// Cleanup: free allocated security descriptor memory and close the handle. LocalFree(psd); CloseHandle(hSection);
return result == ERROR_SUCCESS ? 0 : 1; }
// The mod is being unloaded, free all allocated resources. void Wh_ModUninit() { Wh_Log(L"Uninit"); }
Any ideas, how to fix it?
It's just a bad approach in general. You're trying to make it close access to the theme section for all programs, when you really just want to block things locally. Here is a fully-local example: /* * NtOpenSection: Used for accessing section objects, which can share memory * between processes. * * UxTheme uses a section to store user-specific global theme state, which can * then be accessed by all programs, which is more efficient than parsing the * theme file each time you go to open a new program. * * The theme section is aptly named "ThemeSection", and is thus really easy to * detect and disable. UxTheme will give up the first time it encounters an * access denied error, so we will just return that. */ typedef NTSTATUS (*NtOpenSection_t)(PHANDLE, ACCESS_MASK, POBJECT_ATTRIBUTES); NtOpenSection_t NtOpenSection_orig; NTSTATUS NtOpenSection_hook(PHANDLE pSectionHandle, ACCESS_MASK desiredAccess, POBJECT_ATTRIBUTES pObjectAttributes) { if (wcsstr(pObjectAttributes->ObjectName->Buffer, L"ThemeSection")) { return 0xc0000022; // NT_STATUS_ACCESS_DENIED } return NtOpenSection_orig(pSectionHandle, desiredAccess, pObjectAttributes); }
// The mod is being initialized, load settings, hook functions, and do other // initialization stuff if required. BOOL Wh_ModInit() { Wh_Log(L"Init " WH_MOD_ID L" version " WH_MOD_VERSION);
HMODULE ntdll = LoadLibrary(L"ntdll.dll"); FARPROC pNtOpenSection = GetProcAddress(ntdll, "NtOpenSection");
if (!Wh_SetFunctionHook( (void *)pNtOpenSection, (void *)NtOpenSection_hook, (void **)&NtOpenSection_orig )) Wh_Log(L"Failed to hook NtOpenSection.");
return TRUE; }
|
|
|
Post by anixx on Nov 21, 2023 0:32:19 GMT -8
Your mod is great. Here is the full version:
// ==WindhawkMod== // @id classic-theme-per-process // @name Classic Theme per process // @description Disables theming per process. It enables classic theme in programs of your choice. // @version 1.0 // @include * // @exclude ApplicationFrameHost.exe // ==/WindhawkMod==
#include <winternl.h>
typedef NTSTATUS (*NtOpenSection_t)(PHANDLE, ACCESS_MASK, POBJECT_ATTRIBUTES); NtOpenSection_t NtOpenSection_orig; NTSTATUS NtOpenSection_hook(PHANDLE pSectionHandle, ACCESS_MASK desiredAccess, POBJECT_ATTRIBUTES pObjectAttributes) { if (wcsstr(pObjectAttributes->ObjectName->Buffer, L"ThemeSection")) { return 0xc0000022; // NT_STATUS_ACCESS_DENIED } return NtOpenSection_orig(pSectionHandle, desiredAccess, pObjectAttributes); }
// The mod is being initialized, load settings, hook functions, and do other // initialization stuff if required. BOOL Wh_ModInit() { Wh_Log(L"Init " WH_MOD_ID L" version " WH_MOD_VERSION);
HMODULE ntdll = LoadLibrary(L"ntdll.dll"); FARPROC pNtOpenSection = GetProcAddress(ntdll, "NtOpenSection");
if (!Wh_SetFunctionHook( (void *)pNtOpenSection, (void *)NtOpenSection_hook, (void **)&NtOpenSection_orig )) Wh_Log(L"Failed to hook NtOpenSection.");
return TRUE; }
It enables classic theme in all programs, or in programs of your choice. It DOES NOT REQUIRE ADMIN RIGHTS!
I think, it is currently the easiest way to enable classic theme. Does not need messing with task scheduler.
Please publish this on Github.
|
|
|
Post by OrthodoxWin32 on Nov 21, 2023 3:07:21 GMT -8
anixx ephemeralVioletteFor some reason, this mod does not support console, nor the login/lock screen in console mode. For the login/lock screen, I don't know if it's a problem with Logonui.exe, or again with the console.
|
|
|
Post by anixx on Nov 21, 2023 3:29:08 GMT -8
anixx ephemeralViolette For some reason, this mod does not support console, nor the login/lock screen in console mode. For the login/lock screen, I don't know if it's a problem with Logonui.exe, or again with the console. Yes, but a workaround is to use Classic Conhost mod.
|
|
|
Post by OrthodoxWin32 on Nov 21, 2023 3:57:59 GMT -8
Yes, but a workaround is to use Classic Conhost mod. It's true ; but I'm still curious why this isn't the case for the mod, while ClassicThemeTray is.
|
|
KotonePopper
Freshman Member
#Sukinanda
Posts: 71
OS: Windows 7 Enterprise
Theme: Windows 7 M2
CPU: Intel Core i5-2400S
RAM: 12 GB
GPU: Nvidia GeForce GT 710
|
Post by KotonePopper on Nov 21, 2023 4:35:30 GMT -8
anixx ephemeralViolette For some reason, this mod does not support console, nor the login/lock screen in console mode. For the login/lock screen, I don't know if it's a problem with Logonui.exe, or again with the console. Yes, but a workaround is to use Classic Conhost mod. I've tried using both the Classic theme enable mod with Windhawk with UAC on and Classic Conhost mod, and it renders as basic theme with cmd.exe/conhost.exe open.
|
|
|
Post by OrthodoxWin32 on Nov 21, 2023 8:38:43 GMT -8
I've tried using both the Classic theme enable mod with Windhawk with UAC on and Classic Conhost mod, and it renders as basic theme with cmd.exe/conhost.exe open. In my case it works, but it is not viable for two reasons: - The console opens themed before quickly switching to the classic theme. - Only the console has the classic theme, but not the console settings or logonUI.exe.
|
|
|
Post by Taniko Yamamoto on Nov 21, 2023 14:36:29 GMT -8
Yes, but a workaround is to use Classic Conhost mod. It's true ; but I'm still curious why this isn't the case for the mod, while ClassicThemeTray is. Windhawk globally observes programs as they open and attempts to inject into them. You can get early injection if CreateProcess can be hooked, which is usually the case.
But since console windows are launched from protected code which Windhawk is unable to inject into, the Windhawk mods will inject after the window is constructed. Since this needs to prevent the uxtheme engine from opening the section before it loads, the mod loads too late to work.
Classic Conhost mod implements a window observer, which is designed to be able to apply the changes later, basically like a mini basicthemer.
ClassicThemeTray closes the ThemeSection section across the entire OS, which means that any opening program cannot access it. This, on the other hand, hooks Windows API functions to force opening the section to fail within the program. They function basically the same, but this is less destructive.
|
|
|
Post by OrthodoxWin32 on Nov 21, 2023 15:13:34 GMT -8
Taniko Yamamoto Thank you for this information. From what I understand, it is not possible to hook conhost.exe before opening it, and therefore it is not possible to obtain a correct Windhawks mod for the classic theme, unless you find a solution to "unprotect" the code from the console.
|
|
|
Post by ephemeralViolette on Nov 21, 2023 16:17:02 GMT -8
Taniko Yamamoto Thank you for this information. From what I understand, it is not possible to hook conhost.exe before opening it, and therefore it is not possible to obtain a correct Windhawks mod for the classic theme, unless you find a solution to "unprotect" the code from the console. There is no way to "unprotect" the console, because there is no issue with the console host itself. The issue is that conhost.exe is launched by the kernel driver condrv.sys, which is impossible to hook with Windhawk, so Windhawk cannot force its own DLL to load at startup.
The best solution would be modifying conhost in some way to load windhawk.dll at startup, like it already does with system DLLs like uxtheme. I looked into doing this with a custom Application Verifier provider, but I couldn't figure out how to get it working.
|
|
|
Post by OrthodoxWin32 on Nov 22, 2023 3:06:35 GMT -8
There is no way to "unprotect" the console, because there is no issue with the console host itself. The issue is that conhost.exe is launched by the kernel driver condrv.sys, which is impossible to hook with Windhawk, so Windhawk cannot force its own DLL to load at startup.
The best solution would be modifying conhost in some way to load windhawk.dll at startup, like it already does with system DLLs like uxtheme. I looked into doing this with a custom Application Verifier provider, but I couldn't figure out how to get it working.
Indeed it will be great to achieve that; I'm not sure, but I imagine that it would also allow you to obtain the logonui console with the classic theme (but DWM activated).
|
|
|
Post by anixx on Nov 22, 2023 5:39:34 GMT -8
It's true ; but I'm still curious why this isn't the case for the mod, while ClassicThemeTray is. Windhawk globally observes programs as they open and attempts to inject into them. You can get early injection if CreateProcess can be hooked, which is usually the case.
But since console windows are launched from protected code which Windhawk is unable to inject into, the Windhawk mods will inject after the window is constructed. Since this needs to prevent the uxtheme engine from opening the section before it loads, the mod loads too late to work.
Classic Conhost mod implements a window observer, which is designed to be able to apply the changes later, basically like a mini basicthemer.
ClassicThemeTray closes the ThemeSection section across the entire OS, which means that any opening program cannot access it. This, on the other hand, hooks Windows API functions to force opening the section to fail within the program. They function basically the same, but this is less destructive.
But can we make a variant of the mod that closes the section?
|
|
|
Post by ephemeralViolette on Nov 22, 2023 13:34:13 GMT -8
Windhawk globally observes programs as they open and attempts to inject into them. You can get early injection if CreateProcess can be hooked, which is usually the case.
But since console windows are launched from protected code which Windhawk is unable to inject into, the Windhawk mods will inject after the window is constructed. Since this needs to prevent the uxtheme engine from opening the section before it loads, the mod loads too late to work.
Classic Conhost mod implements a window observer, which is designed to be able to apply the changes later, basically like a mini basicthemer.
ClassicThemeTray closes the ThemeSection section across the entire OS, which means that any opening program cannot access it. This, on the other hand, hooks Windows API functions to force opening the section to fail within the program. They function basically the same, but this is less destructive.
But can we make a variant of the mod that closes the section? The calling program would need permission to change security permissions on the sections, which wouldn't be guaranteed, since Windhawk can inject into applications both with and without administrator privileges. Additionally, this would have all the drawbacks of, say, ClassicThemeTray, because it's the exact same approach.
By the way, ThemeSection isn't closed, but rather denied read permission globally, which is what causes UxTheme initialisation to fail.
|
|
|
Post by ephemeralViolette on Nov 22, 2023 13:39:22 GMT -8
There is no way to "unprotect" the console, because there is no issue with the console host itself. The issue is that conhost.exe is launched by the kernel driver condrv.sys, which is impossible to hook with Windhawk, so Windhawk cannot force its own DLL to load at startup.
The best solution would be modifying conhost in some way to load windhawk.dll at startup, like it already does with system DLLs like uxtheme. I looked into doing this with a custom Application Verifier provider, but I couldn't figure out how to get it working.
Indeed it will be great to achieve that; I'm not sure, but I imagine that it would also allow you to obtain the logonui console with the classic theme (but DWM activated). Logon screen modification is a bit weirder to do, since services startup after LogonUI is already loaded. I think the only good solution for this is to use a custom Application Verifier provider, which is what SecureUxTheme does. But, as I stated in my above post, it's rather difficult to do that.
I think Windhawk does inject on the logon screen eventually though, just far too late for it to ever be able to apply classic theme frames on a LogonUI window. So, if my assumption is correct here, it would be a very similar issue to what's detailed above.
Of course, forcing conhost to load another library that prevents themes from applying would work, since this would all happen within the application on the startup thread synchronously; no race condition would result.
|
|
|
Post by anixx on Nov 22, 2023 19:05:41 GMT -8
But can we make a variant of the mod that closes the section? The calling program would need permission to change security permissions on the sections, which wouldn't be guaranteed, since Windhawk can inject into applications both with and without administrator privileges. Additionally, this would have all the drawbacks of, say, ClassicThemeTray, because it's the exact same approach.
By the way, ThemeSection isn't closed, but rather denied read permission globally, which is what causes UxTheme initialisation to fail. For me, Casscthemetray has only one drawback - it starts via task scheduler.
|
|
|
Post by anixx on Nov 22, 2023 21:32:12 GMT -8
It seems, this method fails to affect the other parts of the system as well:
I think, we need the changing the perissions mod to cover all fully.
|
|
|
Post by anixx on Nov 23, 2023 8:16:14 GMT -8
Everything beyond the UAC prompt is themed:
|
|
kirta
Freshman Member
Posts: 59
OS: Windows 10 LTSC 2021
|
Post by kirta on Dec 21, 2023 13:55:33 GMT -8
Everything beyond the UAC prompt is themed:
any updates on this mod?
|
|
|
Post by anixx on Aug 18, 2024 1:10:35 GMT -8
It's just a bad approach in general. You're trying to make it close access to the theme section for all programs, when you really just want to block things locally. Here is a fully-local example: /* * NtOpenSection: Used for accessing section objects, which can share memory * between processes. * * UxTheme uses a section to store user-specific global theme state, which can * then be accessed by all programs, which is more efficient than parsing the * theme file each time you go to open a new program. * * The theme section is aptly named "ThemeSection", and is thus really easy to * detect and disable. UxTheme will give up the first time it encounters an * access denied error, so we will just return that. */ typedef NTSTATUS (*NtOpenSection_t)(PHANDLE, ACCESS_MASK, POBJECT_ATTRIBUTES); NtOpenSection_t NtOpenSection_orig; NTSTATUS NtOpenSection_hook(PHANDLE pSectionHandle, ACCESS_MASK desiredAccess, POBJECT_ATTRIBUTES pObjectAttributes) { if (wcsstr(pObjectAttributes->ObjectName->Buffer, L"ThemeSection")) { return 0xc0000022; // NT_STATUS_ACCESS_DENIED } return NtOpenSection_orig(pSectionHandle, desiredAccess, pObjectAttributes); }
// The mod is being initialized, load settings, hook functions, and do other // initialization stuff if required. BOOL Wh_ModInit() { Wh_Log(L"Init " WH_MOD_ID L" version " WH_MOD_VERSION);
HMODULE ntdll = LoadLibrary(L"ntdll.dll"); FARPROC pNtOpenSection = GetProcAddress(ntdll, "NtOpenSection");
if (!Wh_SetFunctionHook( (void *)pNtOpenSection, (void *)NtOpenSection_hook, (void **)&NtOpenSection_orig )) Wh_Log(L"Failed to hook NtOpenSection.");
return TRUE; }
Can you please submit your mod to the windhawk repo?...
|
|
|
Post by ephemeralViolette on Aug 18, 2024 14:05:39 GMT -8
It's just a bad approach in general. You're trying to make it close access to the theme section for all programs, when you really just want to block things locally. Here is a fully-local example: /* * NtOpenSection: Used for accessing section objects, which can share memory * between processes. * * UxTheme uses a section to store user-specific global theme state, which can * then be accessed by all programs, which is more efficient than parsing the * theme file each time you go to open a new program. * * The theme section is aptly named "ThemeSection", and is thus really easy to * detect and disable. UxTheme will give up the first time it encounters an * access denied error, so we will just return that. */ typedef NTSTATUS (*NtOpenSection_t)(PHANDLE, ACCESS_MASK, POBJECT_ATTRIBUTES); NtOpenSection_t NtOpenSection_orig; NTSTATUS NtOpenSection_hook(PHANDLE pSectionHandle, ACCESS_MASK desiredAccess, POBJECT_ATTRIBUTES pObjectAttributes) { if (wcsstr(pObjectAttributes->ObjectName->Buffer, L"ThemeSection")) { return 0xc0000022; // NT_STATUS_ACCESS_DENIED } return NtOpenSection_orig(pSectionHandle, desiredAccess, pObjectAttributes); }
// The mod is being initialized, load settings, hook functions, and do other // initialization stuff if required. BOOL Wh_ModInit() { Wh_Log(L"Init " WH_MOD_ID L" version " WH_MOD_VERSION);
HMODULE ntdll = LoadLibrary(L"ntdll.dll"); FARPROC pNtOpenSection = GetProcAddress(ntdll, "NtOpenSection");
if (!Wh_SetFunctionHook( (void *)pNtOpenSection, (void *)NtOpenSection_hook, (void **)&NtOpenSection_orig )) Wh_Log(L"Failed to hook NtOpenSection.");
return TRUE; }
Can you please submit your mod to the windhawk repo?... No.
|
|