Closed aubymori closed 9 months ago
I should provide the mod in question. Here:
Since all hooks are placed in Wh_ModInit
, they're placed before the target process (explorer.exe) can resume execution, unless for some reason Windhawk is unable to intercept the process creation, in which case the injection is done asynchronously. See Mod lifetime.
Let's start by finding out whether the injection is done asynchronously. You can find out by adding the following log in Wh_ModInit
:
#ifdef _WIN64
const size_t OFFSET_SAME_TEB_FLAGS = 0x17EE;
#else
const size_t OFFSET_SAME_TEB_FLAGS = 0x0FCA;
#endif
bool isInitialThread = *(USHORT*)((BYTE*)NtCurrentTeb() + OFFSET_SAME_TEB_FLAGS) & 0x0400;
Wh_Log(L"isInitialThread=%d", isInitialThread);
If the output is isInitialThread=0
, the injection is done asynchronously. Otherwise, if the output is isInitialThread=1
, the injection could be done synchronously, or asynchronously if Windhawk was quick enough.
Since all hooks are placed in
Wh_ModInit
, they're placed before the target process (explorer.exe) can resume execution, unless for some reason Windhawk is unable to intercept the process creation, in which case the injection is done asynchronously. See Mod lifetime.Let's start by finding out whether the injection is done asynchronously. You can find out by adding the following log in
Wh_ModInit
:#ifdef _WIN64 const size_t OFFSET_SAME_TEB_FLAGS = 0x17EE; #else const size_t OFFSET_SAME_TEB_FLAGS = 0x0FCA; #endif bool isInitialThread = *(USHORT*)((BYTE*)NtCurrentTeb() + OFFSET_SAME_TEB_FLAGS) & 0x0400; Wh_Log(L"isInitialThread=%d", isInitialThread);
If the output is
isInitialThread=0
, the injection is done asynchronously. Otherwise, if the output isisInitialThread=1
, the injection could be done synchronously, or asynchronously if Windhawk was quick enough.
I'm seeing isInitialThread=0
on both initial injection to the already running explorer process and on the injection to the first instance of Control Panel.
I'm seeing
isInitialThread=0
on both initial injection to the already running explorer process and on the injection to the first instance of Control Panel.
What does "the injection to the first instance of Control Panel" mean? I assume you have the "Launch folder windows in a separate process" option enabled, right? To understand why the injection is done asynchronously, we need to understand:
I assume that the answer to 3 is - nothing special, since it's a regular process (should be nothing exotic like conhost.exe).
Regarding 1 and 2, can you check it out? For 1, you can find it out with procmon by looking at process creation events. For 2, you can use procexp and look for the windhawk.dll module in the process.
I'm seeing
isInitialThread=0
on both initial injection to the already running explorer process and on the injection to the first instance of Control Panel.What does "the injection to the first instance of Control Panel" mean? I assume you have the "Launch folder windows in a separate process" option enabled, right? To understand why the injection is done asynchronously, we need to understand:
1. Which process creates the Control Panel's process 2. Is Windhawk injected into that process 3. How is the process created
I assume that the answer to 3 is - nothing special, since it's a regular process (should be nothing exotic like conhost.exe).
Regarding 1 and 2, can you check it out? For 1, you can find it out with procmon by looking at process creation events. For 2, you can use procexp and look for the windhawk.dll module in the process.
Here's what I mean by "the injection to the first instance of Control Panel". It seems to create another explorer.exe
process. This does not happen on any subsequent instances of Control Panel.
https://github.com/ramensoftware/windhawk/assets/44238627/f08ff77a-ee61-4ce8-991a-c7e84733ab83
explorer.exe
creates control.exe
(Run dialog), and then control.exe
seems to invoke svchost.exe
in some way (it doesn't create the svchost.exe
process itself) to create the new explorer.exe
process for Control Panel. The command line of the new explorer.exe
process is C:\Windows\explorer.exe /factory,{5BD95610-9434-43C2-886C-57852CC8A120) -Embedding
.I should note that -Embedding
command lines actually are really weird and exotic. No command line I have ever seen that has -Embedding
, including this one (I've seen them when trying to port old things such as the Windows 7 Help and Support) ever work straight from the Run box.
I could reproduce it on my Windows 10 VM.
- Yes.
It seems to me that the answer is no, i.e. windhawk.dll isn't injected into that instance of svchost.exe. That explains why it can't intercept the creation of the explorer.exe process.
After enabling the "Inject into critical system processes" option, the injection becomes synchronous.
So that's a known limitation of Windhawk which, in this case, can be worked around.
I could reproduce it on my Windows 10 VM.
- Yes.
It seems to me that the answer is no, i.e. windhawk.dll isn't injected into that instance of svchost.exe. That explains why it can't intercept the creation of the explorer.exe process.
After enabling the "Inject into critical system processes" option, the injection becomes synchronous.
So that's a known limitation of Windhawk which, in this case, can be worked around.
Ah, yes, you're right. After enabling injection into critical system processes, it works just fine on the initial launch.
I suppose I'll close this issue for now and add a notice to my mod telling the user to enable the option.
The first time launching Control Panel after Explorer has started, it will sometimes launch before mods have initialized.
Demonstration
Module:
ExplorerFrame.dll
Hooked functions:CAddressBand::GetBandInfo
,CUniversalSearchBand::GetBandInfo
Initial launch (Windhawk):
The address bar size which the mod is supposed to affect is unaffected.
After updating address bar (clickng on and off of it):
The address bar size is now updated, which shows that the mod was in fact initialized, just after the initial call of the functions hooked.
Initial launch (cold-patched DLL):
The address bar size is adjusted by default.
Initial launch (partially functional):
CAddressBand::GetBandInfo
was hooked before Control Panel opened, butCUniversalSearchBand::GetBandInfo
was not.