Chrome Hook 去除圆角
我就是想去除,告诉我方法
https://github.com/sfc9982/ChromeDisableRoundedCorners
下载 Release, 参数为 Chrome 位置,附加参数启动即可。
起因
Chrome 在 Windows 11 下的右键菜单和系统菜单会自动启用圆角,由于我使用了 Win11DisableOrRestoreRoundedCorners
,所以这个和系统的又不匹配(Chrome 的菜单不经由 DWM 渲染),所以得另寻他法。
Chromium 代码
自从 https://chromium-review.googlesource.com/c/chromium/src/+/3176190 起, Chromium 监测到 Windows 版本 >= 11 时就会自动开启圆角, 基于 Chromium 内核的浏览器, CEF 与 Electron App 也是如此。在以前可以通过附加参数或 chrome://flags
进行关闭,但是这个功能取消了测试被正式合并,变成了默认开启状态。
void MenuConfig::Init() {
// ...
win11_style_menus = base::win::GetVersion() >= base::win::Version::WIN11;
UMA_HISTOGRAM_BOOLEAN("Windows.Menu.Win11Style", win11_style_menus);
separator_upper_height = 5;
separator_lower_height = 7;
if (win11_style_menus)
corner_radius = 8;
}
可见,只要满足 base::win::GetVersion() >= base::win::Version::WIN11
就会开启圆角。
base::win::GetVersion()
返回的定义在 base/win/windows_version.cc
中,
// static
OSInfo** OSInfo::GetInstanceStorage() {
// Note: we don't use the Singleton class because it depends on AtExitManager,
// and it's convenient for other modules to use this class without it.
static OSInfo* info = []() {
_OSVERSIONINFOEXW version_info = {sizeof(version_info)};
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
// GetVersionEx() is deprecated, and the suggested replacement are
// the IsWindows*OrGreater() functions in VersionHelpers.h. We can't
// use that because:
// - For Windows 10, there's IsWindows10OrGreater(), but nothing more
// granular. We need to be able to detect different Windows 10 releases
// since they sometimes change behavior in ways that matter.
// - There is no IsWindows11OrGreater() function yet.
::GetVersionEx(reinterpret_cast<_OSVERSIONINFOW*>(&version_info));
#pragma clang diagnostic pop
DWORD os_type = 0;
::GetProductInfo(version_info.dwMajorVersion, version_info.dwMinorVersion,
0, 0, &os_type);
return new OSInfo(version_info, GetSystemInfoStorage(), os_type);
}();
return &info;
}
注意代码与注释,这里使用了一个在 Windows 8 后被 deprecated 的函数 (GetVersionEx
),在 Unicode 环境下,被宏定义为 GetVersionExW
https://learn.microsoft.com/en-us/windows/win32/api/sysinfoapi/nf-sysinfoapi-getversionexw
参数
[in, out] lpVersionInformation
接收操作系统信息的 OSVERSIONINFO 或 OSVERSIONINFOEX 结构。
在调用 GetVersionEx 函数之前,请根据需要设置结构的 dwOSVersionInfoSize 成员,以指示要传递给此函数的数据结构。
返回值
如果函数成功,则返回值为非零值。
如果函数失败,则返回值为零。 要获得更多的错误信息,请调用 GetLastError。 如果为 OSVERSIONINFO 或 OSVERSIONINFOEX 结构的 dwOSVersionInfoSize 成员指定无效值,则函数将失败。
这里我想 Hook 这个 API,让它返回一个 Windows 10 的版本信息。事实上我们只要修改版本结构体的成员即可。
typedef struct _OSVERSIONINFOEXA {
DWORD dwOSVersionInfoSize;
DWORD dwMajorVersion;
DWORD dwMinorVersion;
DWORD dwBuildNumber;
DWORD dwPlatformId;
CHAR szCSDVersion[128];
WORD wServicePackMajor;
WORD wServicePackMinor;
WORD wSuiteMask;
BYTE wProductType;
BYTE wReserved;
} OSVERSIONINFOEXA, *POSVERSIONINFOEXA, *LPOSVERSIONINFOEXA;
dwMajorVersion
操作系统的主要版本号。
dwMinorVersion
操作系统的次要版本号。
dwBuildNumber
操作系统的内部版本号。
这三个是我们需要的。
Hook
这里我使用了 Detours 库。Microsoft Detours 是一个开源库,用于在Microsoft Windows上拦截,监视和检测二进制函数。最常用于在Windows应用程序中拦截 Win32 API 调用。可以添加调试工具并将任意DLL附加到任何现有的 Win32 二进制文件。
这里为了方便调试,我写了一个 dummy client,先对它进行 API 劫持。
Dummy Client
#pragma warning(disable : 4996 // GetVersionExW() 是一个 deprecated 函数
#define UNICODE // GetVersionEx() 在 define 了 UNICODE 之后才是 GetVersionExW()
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
int __cdecl main()
{
OSVERSIONINFO osvi;
ZeroMemory(&osvi, sizeof(OSVERSIONINFO));
osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
GetVersionExW(&osvi);
printf("Windows Version: %ld.%ld.%ld\n", osvi.dwMajorVersion, osvi.dwMinorVersion, osvi.dwBuildNumber);
return 0;
}
这里直接编译运行会提示 Windows NT 6.2 (Windows 8).
https://stackoverflow.com/questions/58294262/getversionex-windows-10-detected-as-windows-8
mt /manifest GetVersion.manifest -outputresource:$(BIND)\GetVersion.exe
GetVersion.manifest
<!-- GetVersion.exe.manifest -->
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1" xmlns:asmv3="urn:schemas-microsoft-com:asm.v3">
<assemblyIdentity
type="win32"
name="Contoso.ExampleApplication.ExampleBinary"
version="1.0.0.0"
processorArchitecture="x86"
/>
<description>Contoso Example Application</description>
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
<application>
<!-- Windows 10 and Windows 11 -->
<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}"/>
<!-- Windows 8.1 -->
<supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}"/>
<!-- Windows 8 -->
<supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}"/>
<!-- Windows 7 -->
<supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}"/>
<!-- Windows Vista -->
<supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}"/>
</application>
</compatibility>
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
<security>
<requestedPrivileges>
<!--
UAC settings:
- app should run at same integrity level as calling process
- app does not need to manipulate windows belonging to
higher-integrity-level processes
-->
<requestedExecutionLevel
level="asInvoker"
uiAccess="false"
/>
</requestedPrivileges>
</security>
</trustInfo>
</assembly>
注意 supportedOS
Hook
static BOOL (WINAPI * TrueGetVersionEx)(OSVERSIONINFO *osvi) = GetVersionEx;
BOOL WINAPI W10GetVersionEx(OSVERSIONINFO *osvi)
{
BOOL ret = TrueGetVersionEx(osvi);
if (ret) {
osvi->dwMajorVersion = 10;
osvi->dwMinorVersion = 0;
osvi->dwBuildNumber = 19045;
}
printf("Called W10GetVersionEx().\n");
return ret;
}
注入
但 Chrome 貌似用绝对路径加载,自己的dll还有签名。所以 DLL 劫持路子暂时走不通。
这里使用 Detour 的 withdll
,或者改 IAT。
参考
Chromium 代码
- https://source.chromium.org/chromium/chromium/src/+/main:base/win/windows_version.cc;l=254;drc=632f7d125c559e4d9dadba662558c33b474df1cb?q=22000&ss=chromium%2Fchromium%2Fsrc
- https://source.chromium.org/chromium/chromium/src/+/main:chrome/updater/util/win_util.cc?q=RtlGetVersion&ss=chromium%2Fchromium%2Fsrc
DLL 劫持
PoC 里无法劫持的 UBR (Update Build Revision) 版本号
How can I get a Windows 10 build version, revision number in WINAPI?](https://stackoverflow.com/questions/65315845/how-can-i-get-a-windows-10-build-version-revision-number-in-winapi)