Skip to content

Commit e13eada

Browse files
fix: make explorerframe.dll patch universal
1 parent 8021f24 commit e13eada

File tree

1 file changed

+103
-90
lines changed

1 file changed

+103
-90
lines changed

src/shell/fix_win11_menu.cc

Lines changed: 103 additions & 90 deletions
Original file line numberDiff line numberDiff line change
@@ -81,72 +81,83 @@ std::wstring RegQueryKeyPath(HKEY hKey) {
8181
void mb_shell::fix_win11_menu::install() {
8282
auto proc = blook::Process::self();
8383

84-
// approch 1: simulated reg edit
85-
auto advapi32 = proc->module("kernelbase.dll");
86-
87-
auto RegGetValueW = advapi32.value()->exports("RegGetValueW");
88-
static auto RegGetValueHook = RegGetValueW->inline_hook();
89-
90-
// RegGetValueHook->install(
91-
// (void *)+[](HKEY hkey, LPCWSTR lpSubKey, LPCWSTR lpValue, DWORD
92-
// dwFlags,
93-
// LPDWORD pdwType, PVOID pvData, LPDWORD pcbData) {
94-
// // simulate
95-
// // reg.exe add
96-
// //
97-
// //
98-
// //
99-
// "HKCU\Software\Classes\CLSID\{86ca1aa0-34aa-4e8b-a509-50c905bae2a2}\InprocServer32"
100-
// // /f /ve
101-
// auto path = wstring_to_utf8(RegQueryKeyPath(hkey));
102-
// if
103-
// (path.ends_with("\\CLSID\\{86ca1aa0-34aa-4e8b-a509-50c905bae2a2}"
104-
// "\\InprocServer32")) {
105-
// if (pvData != nullptr && pcbData != nullptr) {
106-
// *pcbData = 0;
107-
// }
108-
// if (pdwType != nullptr) {
109-
// *pdwType = REG_SZ;
110-
// }
111-
// return ERROR_SUCCESS;
112-
// } else
113-
// return RegGetValueHook->call_trampoline<long>(
114-
// hkey, lpSubKey, lpValue, dwFlags, pdwType, pvData, pcbData);
115-
// });
116-
117-
// approch 2: patch the shell32.dll to predent the shift key is pressed
84+
// patch the shell32.dll to predent the shift key is pressed
11885
std::thread([=]() {
11986
try {
87+
auto user32 = LoadLibraryA("user32.dll");
88+
auto extraInfo = user32
89+
? GetProcAddress(user32, "SetMessageExtraInfo")
90+
: nullptr;
91+
auto getKeyState =
92+
user32 ? GetProcAddress(user32, "GetKeyState") : nullptr;
93+
auto getAsyncKeyState =
94+
user32 ? GetProcAddress(user32, "GetAsyncKeyState") : nullptr;
95+
if (!extraInfo || !getKeyState) {
96+
spdlog::error(
97+
"Failed to resolve user32 exports for win11 menu fix");
98+
return;
99+
}
100+
101+
auto imported_call_target = [](auto &insn) -> void * {
102+
if (insn->getMnemonic() != zasm::x86::Mnemonic::Call)
103+
return nullptr;
104+
105+
auto xrefs = insn.xrefs();
106+
if (xrefs.empty())
107+
return nullptr;
108+
109+
if (auto ptr = xrefs[0].try_read_pointer())
110+
return ptr->data();
111+
112+
return nullptr;
113+
};
120114

121-
auto patch_area = [&](auto mem) {
115+
auto is_mov_ecx_imm = [](auto &insn, int value) {
116+
return insn->getMnemonic() == zasm::x86::Mnemonic::Mov &&
117+
insn->getOperand(0) == zasm::x86::ecx &&
118+
insn->getOperand(1).template holds<zasm::Imm>() &&
119+
insn->getOperand(1)
120+
.template get<zasm::Imm>()
121+
.template value<int>() == value;
122+
};
123+
124+
auto is_key_state_call = [&](auto &insn) {
125+
auto target = imported_call_target(insn);
126+
return target == getKeyState || target == getAsyncKeyState;
127+
};
128+
129+
auto find_key_state_check = [&](auto mem, int value) -> void * {
122130
for (auto it = mem.begin(); it != mem.end(); ++it) {
131+
auto next = std::next(it);
132+
if (next == mem.end())
133+
break;
134+
123135
auto &insn = *it;
124-
if (insn->getMnemonic() == zasm::x86::Mnemonic::Mov) {
125-
if (insn->getOperand(0) == zasm::x86::ecx &&
126-
insn->getOperand(1).template holds<zasm::Imm>() &&
127-
insn->getOperand(1)
128-
.template get<zasm::Imm>()
129-
.template value<int>() == 0x10) {
130-
auto &next = *std::next(it);
131-
if (next->getMnemonic() ==
132-
zasm::x86::Mnemonic::Call &&
133-
next->getOperand(0)
134-
.template holds<zasm::Mem>()) {
135-
insn.ptr()
136-
.reassembly([](auto a) {
137-
a.mov(zasm::x86::ecx, 0x10);
138-
a.mov(zasm::x86::eax, 0xffff);
139-
a.nop();
140-
a.nop();
141-
})
142-
.patch();
143-
144-
return true;
145-
}
146-
}
136+
if (is_mov_ecx_imm(insn, value) &&
137+
is_key_state_call(*next)) {
138+
return insn.ptr().data();
147139
}
148140
}
149141

142+
return nullptr;
143+
};
144+
145+
auto has_key_state_check = [&](auto mem, int value) {
146+
return find_key_state_check(mem, value) != nullptr;
147+
};
148+
149+
auto patch_key_state_check = [&](auto mem, int value) {
150+
if (auto addr = find_key_state_check(mem, value)) {
151+
spdlog::info("Patching key state check at: {}",
152+
(void *)addr);
153+
blook::Pointer(addr)
154+
.range_next_instr(2)
155+
.reassembly_with_padding(
156+
[](auto a) { a.mov(zasm::x86::rax, 0xffff); })
157+
.patch();
158+
return true;
159+
}
160+
150161
return false;
151162
};
152163

@@ -157,48 +168,50 @@ void mb_shell::fix_win11_menu::install() {
157168

158169
// the function to determine if show win10 menu or win11 menu
159170
// calls SetMessageExtraInfo, so we use it as a hint
160-
auto extraInfo = GetProcAddress(LoadLibraryA("user32.dll"),
161-
"SetMessageExtraInfo");
162171
for (auto &ins : disasm) {
163-
if (ins->getMnemonic() == zasm::x86::Mnemonic::Call) {
164-
auto xrefs = ins.xrefs();
165-
if (xrefs.empty())
166-
continue;
167-
if (auto ptr = xrefs[0].try_read_pointer();
168-
ptr && ptr->data() == extraInfo) {
169-
if (patch_area(ins.ptr()
170-
.find_upwards({0xCC, 0xCC, 0xCC,
171-
0xCC, 0xCC})
172-
->range_size(0xB50)
173-
.disassembly())) {
174-
spdlog::info(
175-
"Patched shell32.dll for win11 menu fix");
176-
break;
177-
}
178-
}
172+
if (imported_call_target(ins) != extraInfo)
173+
continue;
174+
175+
if (patch_key_state_check(
176+
ins.ptr()
177+
.find_upwards({0xCC, 0xCC, 0xCC, 0xCC, 0xCC})
178+
->range_size(0xB50)
179+
.disassembly(),
180+
0x10)) {
181+
spdlog::info("Patched shell32.dll for win11 menu fix");
182+
break;
179183
}
180184
}
181185
}
182186

183187
if (auto explorerframe = proc->module("ExplorerFrame.dll")) {
184-
/*
185-
CNscTree::ShouldShowMiniMenu
186-
187-
1801ca353 b910000000 mov ecx, 0x10
188-
1801ca358 48ff1521cb0700 call qword [rel GetKeyState]
189-
*/
190-
191-
if (auto res =
192-
explorerframe.value()->section(".text")->find_one(
193-
{0xb9, 0x10, 0x00, 0x00, 0x00, 0x48, 0xff, 0x15,
194-
0x21, 0xcb, 0x07, 0x00})) {
195-
if (patch_area(res->range_size(0x20).disassembly()))
188+
auto disasm =
189+
explorerframe.value()->section(".text")->disassembly();
190+
191+
for (auto &ins : disasm) {
192+
if (!is_key_state_call(ins))
193+
continue;
194+
195+
auto function =
196+
ins.ptr()
197+
.find_upwards({0xCC, 0xCC, 0xCC, 0xCC, 0xCC})
198+
->range_size(0x200)
199+
.disassembly();
200+
if (!has_key_state_check(function, 0x10) ||
201+
!has_key_state_check(function, 0x79)) {
202+
continue;
203+
}
204+
205+
if (patch_key_state_check(function, 0x10)) {
196206
spdlog::info(
197-
"Patched explorerframe.dll for win11 menu fix");
207+
"Patched explorerframe.dll for win11 menu fix: {}",
208+
ins.ptr().data());
209+
break;
210+
}
198211
}
199212
}
200213
} catch (...) {
201-
spdlog::error("Failed to patch shell32.dll for win11 menu fix");
214+
spdlog::error("Failed to patch win11 menu fix");
202215
}
203216
}).detach();
204217
}

0 commit comments

Comments
 (0)