Eradicate Immersive Menus
Oct 2, 2023 14:18:47 GMT -8
Post by aubymori on Oct 2, 2023 14:18:47 GMT -8
IMPORTANT: This mod has been moved to the official Windhawk repository. As such, this post is likely to be outdated.
This mod I made for Windhawk will get rid of immersive menus system-wide.
Prerequisite mod (2023/10/02)
As of now (2023/10/02), there is a bug in Windhawk's symbol hook system which makes mods that hook symbols crash on x86 (32-bit) programs.
You MUST install this mod, or else EVERY 32-bit application (INCLUDING THE WINDHAWK UI AND THE WINDHAWK ENGINE ITSELF) will CRASH.
// ==WindhawkMod==
// @id -windhawk-load-symbols-self-fix
// @name Windhawk load symbols self fix
// @description Fix Windhawk symbol loading for 32-bit apps
// @version 0.2
// @author m417z
// @include *
// @architecture x86
// ==/WindhawkMod==
// ==WindhawkModReadme==
/*
# Windhawk load symbols self fix
A temporary fix until a new version is released. The name starts with a dash to
make the mod loaded first.
*/
// ==/WindhawkModReadme==
#include <initializer_list>
bool fix() {
HMODULE module = GetModuleHandle(L"windhawk.dll");
if (!module) {
return false;
}
struct {
size_t rva;
std::initializer_list<BYTE> original;
std::initializer_list<BYTE> patched;
} patches[] = {
{0x2A3D2, {0x8B, 0xE5}, {0xEB, 0x3A}},
{0x2A3FD, {0x8B, 0xE5}, {0xEB, 0x0F}},
{0x2A411, {0xC3, 0xCC, 0xCC}, {0xC2, 0x14, 0x00}},
};
for (const auto& patch : patches) {
BYTE* address = (BYTE*)module + patch.rva;
if (memcmp(address, patch.original.begin(), patch.original.size()) != 0) {
return false;
}
}
for (const auto& patch : patches) {
BYTE* address = (BYTE*)module + patch.rva;
DWORD dwOldProtect;
VirtualProtect(address, patch.patched.size(), PAGE_EXECUTE_READWRITE, &dwOldProtect);
memcpy(address, patch.patched.begin(), patch.patched.size());
VirtualProtect(address, patch.patched.size(), dwOldProtect, &dwOldProtect);
}
return true;
}
BOOL Wh_ModInit() {
Wh_Log(L"Init " WH_MOD_ID L" version " WH_MOD_VERSION);
fix();
return TRUE;
}
void Wh_ModUninit() {
Wh_Log(L"Uninit");
}
Mod code
// ==WindhawkMod==
// @id eradicate-immersive-menus
// @name Eradicate Immersive Menus
// @description Gets rid of immersive menus system-wide
// @version 1.0.0
// @author aubymori
// @github https://github.com/aubymori
// @include *
// @exclude windhawk.exe
// @exclude dwm.exe
// @exclude ShellExperienceHost.exe
// @exclude wlanext.exe
// @exclude svchost.exe
// @exclude SearchIndexer.exe
// @exclude consent.exe
// @compilerOptions -luser32
// ==/WindhawkMod==
// ==WindhawkModReadme==
/*
# Eradicate Immersive Menus
Gets rid of immersive menus system-wide.
# Common problems
## Freezing
This mod will take **a while** to load on the first run, and if you disable and then enable it while your system is all
already up and running with many software open.
## Stuck on "Initializing..."
If ever a certain process gets stuck on "Initializing...", and the "Mod tasks in progress" window does not go away,
restart Windhawk. If that does not work, simply add it to the exclusion list in the Advanced tab of this mod.
## Failed to download symbols:
Sometimes, Windhawk may fail to download the symbols for certain system files. This doesn't necessarily mean that your version
of Windows is incompatible, but it means that whatever application had the mod hooked cannot connect to the internet (which is how Windhawk
attempts to download symbols).
You can work around this issue by manually downloading the symbols and dropping them in the Windhawk symbols
folder. In order to do this, use a tool such as [PDB Downloader](https://github.com/rajkumar-rangaraj/PDB-Downloader/releases)
and download the symbols for any of the missing files from the following list.
- `ExplorerFrame.dll` (x86)
- `shell32.dll` (x86)
- `pnidui.dll`
- `SndVolSSO.dll`
- `SecurityHealthSSO.dll`
- `twinui.dll`
- `twinui.pcshell.dll`
The DLLs themselves are located in `%SystemRoot%\System32`. Of these DLLs, the ones with (x86) at the end have a 32-bit
variant in `%SystemRoot%\SysWOW64`, for open/save dialogs in 32-bit applications, so you may need to download symbols for
these as well.
The standard (non-portable) version of Windhawk stores symbols in `C:\ProgramData\Windhawk\Engine\Symbols`.
If you encounter this error, a message box will be displayed warning you of the failure.
*/
// ==/WindhawkModReadme==
// ==WindhawkModSettings==
/*
- explorer: true
$name: Apply to Explorer
$description: Applies to Explorer itself, including desktop, navigation pane, main Explorer view, open/save dialogs, and the main taskbar menu.
- nosettingsicon: true
$name: No "Taskbar settings" icon
$description: Removes the icon from the "Taskbar settings" entry in the taskbar menu
- sound: true
$name: Apply to Volume tray icon
- network: true
$name: Apply to Network tray icon
- defender: true
$name: Apply to Windows Security
*/
// ==/WindhawkModSettings==
#include <windhawk_api.h>
#include <windhawk_utils.h>
struct {
BOOL explorer;
/* Tray icons are always 64-bit */
#ifdef _WIN64
BOOL sound;
BOOL network;
BOOL defender;
BOOL nosettingsicon;
#endif
} settings;
/* ImmersiveContextMenuHelper::CanApplyOwnerDrawToMenu */
typedef bool (*ICMH_CAODTM_t)(HMENU, HWND);
ICMH_CAODTM_t ICMH_CAODTM_orig_shell32;
ICMH_CAODTM_t ICMH_CAODTM_orig_ExplorerFrame;
/* Explorer and tray icons are always 64-bit */
#ifdef _WIN64
ICMH_CAODTM_t ICMH_CAODTM_orig_explorer;
ICMH_CAODTM_t ICMH_CAODTM_orig_twinui;
ICMH_CAODTM_t ICMH_CAODTM_orig_twinui_pcshell;
ICMH_CAODTM_t ICMH_CAODTM_orig_SndVolSSO;
ICMH_CAODTM_t ICMH_CAODTM_orig_pnidui;
ICMH_CAODTM_t ICMH_CAODTM_orig_SecurityHealthSSO;
#endif
/**
* __fastcall is needed, or else stack corruption occurs
* in x86-32 applications.
*/
bool __fastcall ICMH_CAODTM_hook(
HMENU hMenu,
HWND hWnd
)
{
return false;
}
#ifdef _WIN64
using SetMenuItemInfoW_t = decltype(&SetMenuItemInfoW);
SetMenuItemInfoW_t SetMenuItemInfoW_orig;
BOOL SetMenuItemInfoW_hook(
HMENU hMenu,
UINT item,
BOOL fByPosition,
LPCMENUITEMINFOW lpmii
)
{
if ((!fByPosition && item == 413) && settings.nosettingsicon) // LE HOMESTUCK??
{
return TRUE;
}
return SetMenuItemInfoW_orig(
hMenu,
item,
fByPosition,
lpmii
);
}
#endif
LPWSTR strtowcs(const char* string)
{
if (strlen(string) > 0)
{
size_t out;
size_t size = strlen(string) + 1;
wchar_t* wstring = (wchar_t*)malloc(strlen(string) * 2);
mbstowcs_s(&out, wstring, size, string, size - 1);
return (LPWSTR)wstring;
}
return (LPWSTR)L"";
}
/**
* Hooks ImmersiveContextMenuHelper::CanApplyOwnerDrawToMenu for a given DLL.
* There are many DLLs that have this function, so each one needs to be accounted for.
*/
inline BOOL HookICMH_CAODTM(LPCSTR lpDll, void **pOrig)
{
HMODULE hModule;
/* If lpDll is NULL, patch the current process instead */
if (lpDll == NULL)
{
hModule = GetModuleHandle(NULL);
}
else
{
hModule = LoadLibraryA(lpDll);
}
if (!hModule)
{
Wh_Log(L"Failed to load %s", strtowcs(lpDll));
return FALSE;
}
WindhawkUtils::SYMBOL_HOOK symbolHooks[] = {
{
{
L"bool "
#ifdef _WIN64
L"__cdecl"
#else
L"__stdcall"
#endif
L" ImmersiveContextMenuHelper::CanApplyOwnerDrawToMenu(struct HMENU__ *,struct HWND__ *)"
},
pOrig,
(void *)ICMH_CAODTM_hook,
true
}
};
bool bHookSuccess = HookSymbols(
hModule,
symbolHooks,
ARRAYSIZE(symbolHooks)
);
if (bHookSuccess)
{
return TRUE;
}
if (lpDll == NULL)
{
Wh_Log(
L"Failed to hook ImmersiveContextMenuHelper::CanApplyOwnerDrawToMenu in explorer.exe. "
L"This may be a result of symbols failing to download. "
L"Please see the \"Details\" page of the mod for instructions on how to download the symbols manually."
);
}
else
{
WCHAR msg[1024];
Wh_Log(
L"Failed to hook ImmersiveContextMenuHelper::CanApplyOwnerDrawToMenu in %s. "
L"This may be a result of symbols failing to download. "
L"Please see the \"Details\" page of the mod for instructions on how to download the symbols manually.",
strtowcs(lpDll)
);
}
return FALSE;
}
void LoadSettings()
{
settings.explorer = Wh_GetIntSetting(L"explorer", TRUE);
/* Tray icons are always 64-bit */
#ifdef _WIN64
settings.sound = Wh_GetIntSetting(L"sound", TRUE);
settings.network = Wh_GetIntSetting(L"network", TRUE);
settings.defender = Wh_GetIntSetting(L"defender", TRUE);
settings.nosettingsicon = Wh_GetIntSetting(L"nosettingsicon", TRUE);
#endif
}
BOOL Wh_ModInit()
{
LoadSettings();
/* Explorer is always 64-bit */
#ifdef _WIN64
WCHAR szProcessPath[MAX_PATH];
GetModuleFileNameW(NULL, szProcessPath, MAX_PATH);
BOOL bIsExplorer = (wcscmp(wcslwr(szProcessPath), L"c:\\windows\\explorer.exe") == 0);
if (settings.nosettingsicon)
{
Wh_SetFunctionHook(
(void *)SetMenuItemInfoW,
(void *)SetMenuItemInfoW_hook,
(void **)&SetMenuItemInfoW_orig
);
}
#endif
if (settings.explorer
#ifdef _WIN64
&& 0 != wcscmp(wcslwr(szProcessPath), L"c:\\windows\\system32\\securityhealthsystray.exe")
#endif
)
{
if (!HookICMH_CAODTM(
"shell32.dll",
(void **)&ICMH_CAODTM_orig_shell32
))
{
return FALSE;
}
if (!HookICMH_CAODTM(
"ExplorerFrame.dll",
(void **)&ICMH_CAODTM_orig_ExplorerFrame
))
{
return FALSE;
}
/* Explorer itself is always 64-bit */
#ifdef _WIN64
if (bIsExplorer)
{
if (!HookICMH_CAODTM(
NULL,
(void **)&ICMH_CAODTM_orig_explorer
))
{
return FALSE;
}
if (!HookICMH_CAODTM(
"twinui.dll",
(void **)&ICMH_CAODTM_orig_twinui
))
{
return FALSE;
}
if (!HookICMH_CAODTM(
"twinui.pcshell.dll",
(void **)&ICMH_CAODTM_orig_twinui_pcshell
))
{
return FALSE;
}
}
#endif
}
/* Tray icons are always 64-bit */
#ifdef _WIN64
if (bIsExplorer)
{
if (settings.sound)
{
if (!HookICMH_CAODTM(
"SndVolSSO.dll",
(void **)&ICMH_CAODTM_orig_SndVolSSO
))
{
return FALSE;
}
}
if (settings.network)
{
if (!HookICMH_CAODTM(
"pnidui.dll",
(void **)&ICMH_CAODTM_orig_pnidui
))
{
return FALSE;
}
}
}
if (settings.defender
&& 0 == wcscmp(wcslwr(szProcessPath), L"c:\\windows\\system32\\securityhealthsystray.exe"))
{
if (!HookICMH_CAODTM(
"SecurityHealthSSO.dll",
(void **)&ICMH_CAODTM_orig_SecurityHealthSSO
))
{
return FALSE;
}
}
#endif
return TRUE;
}
BOOL Wh_ModSettingsChanged(BOOL *bReload)
{
*bReload = TRUE;
LoadSettings();
return TRUE;
}