-
Notifications
You must be signed in to change notification settings - Fork 14
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
5 changed files
with
344 additions
and
0 deletions.
There are no files selected for viewing
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 | ||
|
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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. |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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** | ||
<br><img src="https://i.imgur.com/u2HnnAL.gif"> | ||
|
||
**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). |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,230 @@ | ||
#include <array> | ||
#include <algorithm> | ||
#include <functional> | ||
#include <format> | ||
#include <iostream> | ||
#include <optional> | ||
|
||
#include <cstdio> | ||
#include <cinttypes> | ||
|
||
#include <windows.h> | ||
#include <tlhelp32.h> | ||
|
||
#include <Zydis/Zydis.h> | ||
|
||
#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<DisassembleCallbackT> &callback) noexcept | ||
{ | ||
CALLBACK_ASSERT(address != 0); | ||
|
||
ZydisDecodedInstruction instrn{}; | ||
ZydisDecodedOperand operands[ZYDIS_MAX_OPERAND_COUNT_VISIBLE]; | ||
|
||
while (ZYAN_SUCCESS(ZydisDecoderDecodeFull(&decoder, reinterpret_cast<void const *>(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<std::ptrdiff_t> 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<uint64_t>(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<uint64_t> 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<HANDLE>(-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<void *>(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<void const *>(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_proto *>(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<char const *, 2> 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; | ||
} |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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]) |