From 28b985a783a24eed5ecc907b48c173294b778103 Mon Sep 17 00:00:00 2001
From: Richard Obermayr <6305520+oberrich@users.noreply.github.com>
Date: Fri, 19 Aug 2022 01:11:04 +0200
Subject: [PATCH] RELEASE
---
.gitignore | 38 +++++++++
LICENSE | 21 +++++
README.md | 28 +++++++
main.cpp | 230 ++++++++++++++++++++++++++++++++++++++++++++++++++++
meson.build | 27 ++++++
5 files changed, 344 insertions(+)
create mode 100644 .gitignore
create mode 100644 LICENSE
create mode 100644 README.md
create mode 100644 main.cpp
create mode 100644 meson.build
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..23d10df
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,38 @@
+/.vs
+/.idea
+/build/
+/deps/
+
+# Prerequisites
+*.d
+
+# Compiled Object files
+*.slo
+*.lo
+*.o
+*.obj
+
+# Precompiled Headers
+*.gch
+*.pch
+
+# Compiled Dynamic libraries
+*.so
+*.dylib
+*.dll
+
+# Fortran module files
+*.mod
+*.smod
+
+# Compiled Static libraries
+*.lai
+*.la
+*.a
+*.lib
+
+# Executables
+*.exe
+*.out
+*.app
+
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..f06675d
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2022 oberrich
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..e15e97a
--- /dev/null
+++ b/README.md
@@ -0,0 +1,28 @@
+# win11-toggle-rounded-corners
+A simple utility that does **NOT** patch dwm (uDWM.dll) in order to disable window rounded corners in Windows 11
+
+No system files are being replaced so you **won't** brick your system. All this tool really does is setting a bool inside the heap of the Desktop Window Manager (DWM), to be more precise inside the `udwm.dll`s singleton instance of `CDesktopManager`.
+
+**Demonstration**
+
+
+**Download**
+
+Precompiled binaries are available [**here**](https://github.com/oberrich/win11-toggle-rounded-corners/releases) *(Some Anti-Virus products may block the access to `dwm.exe` in which case you have to disable them temporarily)*.
+
+To permanently disable rounded corners put the app into your auto-start (Task Manager > Startup apps > Run new task > `path/to/win11-toggle-rounded-edges.exe`).
+
+**Build**
+
+First clone the repo **recursive**ly
+```
+git clone --recursive 'https://github.com/oberrich/win11-toggle-rounded-corners.git'
+```
+
+Then simply build it with meson
+```
+meson setup build
+meson compile -C build
+```
+
+If you find any bugs or issues feel free to [open an issue](https://github.com/oberrich/win11-toggle-rounded-corners/issues/new).
diff --git a/main.cpp b/main.cpp
new file mode 100644
index 0000000..1264de6
--- /dev/null
+++ b/main.cpp
@@ -0,0 +1,230 @@
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+
+#include
+#include
+
+#include
+
+#define CALLBACK_ASSERT(cond) \
+ if (!(cond)) \
+ return DisassembleStatus::kFailed;
+
+enum class DisassembleStatus
+{
+ kContinue,
+ kFailed,
+ kSuccess,
+ kFollow,
+ kZydisError
+};
+
+using DisassembleCallbackT = DisassembleStatus(ZydisDecodedInstruction &, ZydisDecodedOperand *, uint64_t &);
+
+ZydisDecoder decoder;
+ZydisFormatter formatter;
+
+void zydis_init()
+{
+ ZydisDecoderInit(&decoder, ZYDIS_MACHINE_MODE_LONG_64, ZYDIS_STACK_WIDTH_64);
+ ZydisFormatterInit(&formatter, ZYDIS_FORMATTER_STYLE_INTEL);
+ ZydisFormatterSetProperty(&formatter, ZYDIS_FORMATTER_PROP_IMM_SIGNEDNESS, ZYDIS_SIGNEDNESS_AUTO);
+}
+
+void zydis_print_instrn(ZydisDecodedInstruction const &instrn, ZydisDecodedOperand const *operands, uint64_t address) noexcept
+{
+ printf(" %016" PRIX64 " ", address);
+ char buffer[256];
+ ZydisFormatterFormatInstruction(&formatter, &instrn, operands, instrn.operand_count_visible, buffer, sizeof(buffer), address, ZYAN_NULL);
+ puts(buffer);
+}
+
+DisassembleStatus zydis_disassemble(uint64_t address, const std::function &callback) noexcept
+{
+ CALLBACK_ASSERT(address != 0);
+
+ ZydisDecodedInstruction instrn{};
+ ZydisDecodedOperand operands[ZYDIS_MAX_OPERAND_COUNT_VISIBLE];
+
+ while (ZYAN_SUCCESS(ZydisDecoderDecodeFull(&decoder, reinterpret_cast(address), 32, &instrn, operands, ZYDIS_MAX_OPERAND_COUNT_VISIBLE, ZYDIS_DFLAG_VISIBLE_OPERANDS_ONLY))) {
+ if (auto status = callback(instrn, operands, address); status != DisassembleStatus::kContinue) {
+ if (status == DisassembleStatus::kFollow) {
+ CALLBACK_ASSERT(ZydisCalcAbsoluteAddress(&instrn, operands, address, &address));
+ continue;
+ }
+ return status;
+ }
+ address += instrn.length;
+ }
+
+ return DisassembleStatus::kZydisError;
+}
+
+struct desktop_manager_proto
+{
+ void *unknown0[3];
+ uint8_t unknown1[2];
+ bool rounded_shadow_enabled;
+ bool enable_sharp_corners;
+ bool enable_rounded_corners;
+};
+
+static_assert(offsetof(desktop_manager_proto, enable_rounded_corners) == 0x1C,
+ "alignment issues (wrong arch)");
+
+std::optional locate_udwm_desktop_manager() noexcept
+{
+ auto const udwm_dll = LoadLibraryExA("udwm.dll", nullptr, DONT_RESOLVE_DLL_REFERENCES);
+ if (!udwm_dll)
+ return {};
+
+ auto const dwm_client_startup = reinterpret_cast(GetProcAddress(udwm_dll, MAKEINTRESOURCE(101)));
+ if (!dwm_client_startup)
+ return {};
+
+ struct Context {
+ uint64_t dm_instance;
+ bool found_dm_create;
+ };
+
+ Context ctx{};
+ auto callback = [&ctx](auto const &instrn, auto const operands, auto &address) noexcept -> DisassembleStatus {
+ CALLBACK_ASSERT(instrn.mnemonic != ZYDIS_MNEMONIC_RET);
+ zydis_print_instrn(instrn, operands, address);
+
+ if (!ctx.found_dm_create && instrn.mnemonic == ZYDIS_MNEMONIC_CALL) {
+ ctx.found_dm_create = true;
+ return DisassembleStatus::kFollow;
+ }
+
+ auto const &lhs = operands[0];
+ if (instrn.mnemonic == ZYDIS_MNEMONIC_MOV && lhs.type == ZYDIS_OPERAND_TYPE_MEMORY && lhs.mem.segment == ZYDIS_REGISTER_DS) {
+ ZydisCalcAbsoluteAddress(&instrn, operands, address, &ctx.dm_instance);
+ return DisassembleStatus::kSuccess;
+ }
+
+ return DisassembleStatus::kContinue;
+ };
+
+ if (zydis_disassemble(dwm_client_startup, callback) != DisassembleStatus::kSuccess || !ctx.dm_instance)
+ return {};
+
+ return { ctx.dm_instance - (uint64_t)udwm_dll };
+}
+
+std::optional find_module_base(DWORD pid, std::string_view module_name) noexcept
+{
+ auto snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE | TH32CS_SNAPMODULE32, pid);
+ if (snapshot != INVALID_HANDLE_VALUE) {
+ auto entry = MODULEENTRY32{ .dwSize = sizeof(MODULEENTRY32) };
+
+ if (Module32First(snapshot, &entry)) {
+ do {
+ if (module_name == entry.szModule) {
+ CloseHandle(snapshot);
+ return { (uint64_t)entry.modBaseAddr };
+ }
+ } while (Module32Next(snapshot, &entry));
+ }
+ }
+ CloseHandle(snapshot);
+ return {};
+}
+
+bool enable_privilege(LPCTSTR name) noexcept
+{
+ TOKEN_PRIVILEGES privilege{};
+ privilege.PrivilegeCount = 1;
+ privilege.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
+
+ if (!LookupPrivilegeValue(nullptr, name, &privilege.Privileges[0].Luid))
+ return false;
+
+ HANDLE token{};
+ if (!OpenProcessToken(reinterpret_cast(-1), TOKEN_ADJUST_PRIVILEGES, &token))
+ return false;
+
+ if (!AdjustTokenPrivileges(token, FALSE, &privilege, sizeof privilege, nullptr, nullptr)) {
+ CloseHandle(token);
+ return false;
+ }
+
+ CloseHandle(token);
+ return true;
+}
+
+int main() try
+{
+ if (!enable_privilege(SE_DEBUG_NAME))
+ throw std::runtime_error(std::format("Failed enable {}!", SE_DEBUG_NAME));
+
+ auto const dwm_hwnd = FindWindowA("Dwm", nullptr);
+ DWORD dwm_pid = 0u;
+ if (!dwm_hwnd || !GetWindowThreadProcessId(dwm_hwnd, &dwm_pid))
+ throw std::runtime_error("Failed to find dwm process.\n");
+
+ std::cout << std::format("Found dwm.exe process [window handle: {}, pid: {}].\n", static_cast(dwm_hwnd), dwm_pid);
+
+ auto const dwm_process = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwm_pid);
+ if (!dwm_process)
+ throw std::runtime_error(std::format("Failed to open dwm.exe process, status: {:#x}!", GetLastError()));
+
+ std::cout << std::format("Opened process handle {:#x} to dwm.exe.\nLocating CDesktopManager *g_pdmInstance:\n", (uint64_t)dwm_process);
+
+ zydis_init();
+
+ auto const desktop_manager_rva = locate_udwm_desktop_manager();
+ if (!desktop_manager_rva)
+ throw std::runtime_error("Failed to locate g_pdmInstance RVA inside udwm.dll.");
+
+ std::cout << std::format("Found g_pdmInstance at RVA {:#x}.\n", desktop_manager_rva.value());
+
+ auto const dwm_base = find_module_base(dwm_pid, std::string_view{"udwm.dll"});
+ if (!dwm_base)
+ throw std::runtime_error("Failed to find udwm.dll module inside dwm.exe process!");
+
+ std::cout << std::format("Found udwm.dll mapped at {:#x}.\n", dwm_base.value());
+
+ auto desktop_manager_ptr = reinterpret_cast(dwm_base.value() + desktop_manager_rva.value());
+ uint64_t desktop_manager_inst{};
+ SIZE_T out_size{};
+ if (!ReadProcessMemory(dwm_process, desktop_manager_ptr, &desktop_manager_inst, sizeof(void *), &out_size) || !desktop_manager_inst)
+ throw std::runtime_error(std::format("Failed to read value of g_pdmInstance from dwm.exe , status: {:#x}.\n", GetLastError()));
+
+ auto desktop_manager = reinterpret_cast(desktop_manager_inst);
+ std::cout << std::format(" g_pdmInstance = (CDesktopManager *){:#x};\n\n", desktop_manager_inst);
+
+ bool enable_sharp_corners = true;
+ out_size = {};
+ if (!ReadProcessMemory(dwm_process, &desktop_manager->enable_sharp_corners, &enable_sharp_corners, 1, &out_size) || out_size != 1)
+ std::cerr << std::format("Failed to read 'enable_sharp_corners' from dwm.exe, status: {:#x}.\n", GetLastError());
+
+ constexpr std::array boolean_values {
+ "disabled",
+ "enabled"
+ };
+
+ std::cout << std::format("Your rounded corners were '{}', they are now being {}...\n", boolean_values[enable_sharp_corners], boolean_values[(!enable_sharp_corners)]);
+ enable_sharp_corners ^= true;
+
+ out_size = {};
+ if (!WriteProcessMemory(dwm_process, &desktop_manager->enable_sharp_corners, &enable_sharp_corners, 1, &out_size) || out_size != 1)
+ throw std::runtime_error(std::format("Failed to write 'enable_sharp_corners' to dwm.exe, status: {:#x}.\n", GetLastError()));
+
+ std::cout << "Success!";
+
+ if (enable_sharp_corners)
+ std::cout << " Your Windows 11 experience is now enhanced!\n";
+
+ return 0;
+} catch (std::exception const &e) {
+ std::cerr << e.what() << '\n';
+ return 1;
+}
\ No newline at end of file
diff --git a/meson.build b/meson.build
new file mode 100644
index 0000000..9dde1d1
--- /dev/null
+++ b/meson.build
@@ -0,0 +1,27 @@
+project('win11-toggle-rounded-corners', ['c', 'cpp'],
+ version : '0.x',
+ default_options : [
+ 'warning_level=3',
+ 'cpp_std=c++latest',
+ 'buildtype=release',
+ 'prefer_static=true',
+ 'default_library=static',
+ 'b_vscrt=static_from_buildtype'
+ ],
+ subproject_dir : 'deps')
+
+cmake = import('cmake')
+zydis_opts = cmake.subproject_options()
+zydis_opts.add_cmake_defines({'ZYDIS_BUILD_TOOLS': false, 'ZYDIS_BUILD_EXAMPLES': false})
+
+
+cc = meson.get_compiler('c')
+if cc.get_id() == 'msvc'
+ zydis_opts.append_compile_args(['c', 'cpp'], ['/MT', '/DEBUG:NONE'])
+ zydis_opts.append_link_args(['c', 'cpp'], ['/EMITPOGOPHASEINFO', '/ASSEMBLYDEBUG:DISABLE'])
+endif
+
+zydis_proj = cmake.subproject('zydis', options : zydis_opts)
+zydis_depends = zydis_proj.dependency('Zydis')
+
+executable('win11-toggle-rounded-corners', 'main.cpp', install : true, dependencies: [zydis_depends])