@@ -81,72 +81,83 @@ std::wstring RegQueryKeyPath(HKEY hKey) {
8181void 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