How to debug a Windows Search property handler - windows-search

I'm maintainning a Windows Search property handler project, it is loaded by SearchFilterHost.exe. I don’t know when SearchFilterHost.exe will be launched, don’t know the command line arguments usage, and I find SearchFilterHost.exe will exit one or two minutes after started, so it’s difficult to use the debugger to attach the process then debug the DLL it loaded.
How to debug a Windows Search property handler?

Debugging Protocol Handlers in MSDN talks about how to do this. It involves adding registry entries to make SearchIndexer and SearchFilterHost a little more friendly to debug. You probably will need to take ownership of the registry branch(es) to be able to change the values. Just doing the first set may be enough for you to be able to directly attach to SearchFilterHost.
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft
Windows Search
Gathering Manager
DebugFilters = 1
DisableBackOff = 1 may also be helpful
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion
Image File Execution Options
SearchIndexer.exe
Debugger = <path to debugger> <debugger options>
Example using the ntsd debugger
Debugger = C:\debuggers\ntsd.exe -odGx -c: "sxe ld mydll.dll;g"
Option Description
-o Tells ntsd.exe to debug child prcoesses.
-d Pipes ntsd.exe through the kernel debugger to ensure the debugger is lauched on the right desktop (system context).
-g Tells ntsd.exe to exit immediately when the child terminates.
-x Disables first-chance break on access violation exceptions. The second occurrence of an access violation will break into the debugger.
-c Sets the order of commands passed ntsd.exe.
Once you have things set up, restart the WSearch service, tweak your searched file, and things should happen.
Also, here's an old thread of others' experiences. Among other things, it talks about using the MSDN tool IFiltTst in your project's debug settings.
In your Project properties window, open ‘configuration properties’, ‘debugging’; and enter the following settings:
Debugger to launch: Local Windows Debugger
Command: C:\<your path here>\IFiltTst.Exe
Command arguments: /i "D:\<your project test folder>\<good file>.<extention to filter>" /v 3 /t 5 /l /d
Working directory: /i "D:\<your project test folder>
Attach: No
Leave all other settings as default.
Both methods require your DLL to be registered so it will be found by Search.

Related

'.symfix+' is not recognized on cmd terminal

I am trying to follow this WinDBG tutorial, and at some point, it requires the Microsoft public symbol server to be set up. I ran the command:
set _NT_SYMBOL_PATH=srv*DownstreamStore*https://msdl.microsoft.com/download/symbols
followed by
.symfix+ C:\MySymbols
but I get the infamous error message
'.symfix+' is not recognized as an internal or external command, operable program or batch file.
My environment, running the command systeminfo | findstr /B /C:"OS Name" /C:"OS Version" is:
OS Name: Microsoft Windows 10 Home
OS Version: 10.0.19041 N/A Build 19041
I would appreciate it if you could help me know what is the problem and how I can solve it.
The command
set _NT_SYMBOL_PATH=...
sets an environment variable that attempts to tell all debugging programs where to download symbols. This affects WinDbg, Visual Studio, Process Explorer and others.
The command
.symfix
is WinDbg specific and is an equivalent to the above. Setting both is not necessary.
Please note that you should not enter this part
srv*DownstreamStore*https://msdl.microsoft.com/download/symbols
literally. You should replace the part DownstreamStore by a place where you want the downloaded symbols to be stored on your hard disk. So in your case, this should be C:\MySymbols.
The command .symfix just takes DownstreamStore as an argument and puts srv* before and *https://msdl.microsoft.com/download/symbols after that argument. So using
.symfix C:\MySymbols
is equivalent to
.sympath srv*C:\MySymbols*https://msdl.microsoft.com/download/symbols
but much easier to type.
The + in these commands (.sympath+ or .symfix+) will append another symbol path, assuming that you already had one set up before.
Neither set _NT_SYMBOL_PATH nor .symfix nor .sympath will actually download symbols. The symbols will be downloaded on demand. Use ld*; reload /f when being attached to a process for downloading symbols.
Or, as mentioned by yourself, use the command line tool symchk.
As mentioned in the comment above, the .symfix command is a WinDbg one, which needs to be entered at the software's command line, not the Windows terminal cmd!
However, there are certain command-line tools that can do the job, partly! The complete "WinDbg Command-Line Options" documentation can be seen here. Also, there is the symchk tool coming with the "Windows Driver Kit (WDK)". One can download the "Microsoft's public symbol" database using the command:
symchk "path\to\binary" /s srv*DownstreamStore*https://msdl.microsoft.com/download/symbols
P.S. Usefull common WinDbg commands

Unattended WinDbg script for breakpoints and delays

I want to debug an application running on Windows by setting a breakpoint on a certain address, waiting till the breakpoint is hit, keeping the application paused for a certain period of time and then continuing. All of this should be done in an unattended fashion (e.g. a script).
To do this, I chose to use WinDbg since the scripting support seems promising.
Starting WinDbg and attaching to the process by process name can e.g. be done by invoking the following command:
"C:\Program Files (x86)\Windows Kits\10\Debuggers\x64\windbg.exe" -pn my-executable.exe
Setting the breakpoint is done with the bu command:
bu 0x1337
Continuing works with the g command.
Delaying can be done with the .sleep command:
.sleep milliseconds
For writing WinDbg scripts this PDF might be helpful.
How can I piece it all together? I didn't figure out how delaying after hitting a breakpoint can be done nor do I know how to perform all of those actions (including attaching) from the command line alone without loading up the WinDbg GUI at all.
what for you need to sleep
you can embed the script commands and pass it to and instance of windbg
with -c switch the command below lists the modules and quits the session
windbg -c "lm;q" calc.exe
you can put it inside a batfile and run the batfile
like
cdb -c "bu %2 \".sleep 5000;g\";g" %1.exe
a gif showing how i broke on winmain slept for 5 seconds before allowing the exe to run below

GFlags - command lines

I want to start a process that takes a commandline. Using gflags I want to enable page heap and allow windbg to attach to the process each time it starts.
How can I add the commandline parameter in the gflags UI?
You don't. And you're mixing up pretty unrelated things.
PageHeap
To enable the heap verification ("PageHeap") you set the configuration you want using the GFlags utility, either using the GUI or passing it the approporiate command-line arguments (See GFlags and PageHeap). Either way, this setting it global for all binaries with the name you define.
Debugging
To run the program under the debugger each and every time it starts you'd probably want to use the Debugger setting under Image File Execution Options. You can set it too using GFlags. Tick the Debugger checkbox in the Image File tab (after specifying the EXE name and hitting tab) and enter the path to the debugger.
The way this mechanism works is that (somewhere) inside CreateProcess there's a test whether or not IFEO\Debugger is set for the program you're trying to run, and if it is set, whatever set in the Debugger value is executed **and it is passed the original command line*.
So if you set
HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\foo.exe\Debugger
to be C:\Program Files (x86)\Windows Kits\10\Debuggers\x64\windbg.exe and then try to execute C:\Users\d_blk\Desktop\foo.exe -param 1 -param 2, Windows runs
C:\Program Files (x86)\Windows Kits\10\Debuggers\x64\windbg.exe C:\Users\d_blk\Desktop\foo.exe -param 1 -param 2
and WinDbg passes everything after foo.exe to the target program (as noted here).
So you see, there's no need to set the command-line arguments to the program you're debugging anywhere but wherever you're running it.
The only connection between PageHeap and IFEO\Debugger is that you can control both of them through the GFlags utility.
Caveats
Note all the usual caveats for using IFEO\Debugger. For example:
The caller gets from CreateProcess a handle to WinDbg, not the target process (and process ID, etc.).
Any information in a non-default STARTUPINFO argument applies to WinDbg, not the target process. Same for lpEnvironment I guess.
If that doesn't affect you great. If it does, an alternative might be adding an unhandled exception at the beginning of your program, and setting WinDbg as the post-mortem debugger (AeDebug)

how do I run an msi with SEE_MASK_NOZONECHECKS without restart

I'm trying to install a driver with a remote framework that lets me run shell commands spawned as children of the remoting/monitoring app on the remote machine, run as cmd /c "command". But the driver refuses to install due to a security feature which thinks the driver may be unsafe.
The driver also has quotes(spaces in path) so its something like
Dim command: command = "\\\\server\\driver\\folder\\Autorun.exe" /passive /norestart";
Set retVal = remote.Shell(command)
which runs
cmd /c " "\\server\driver\folder\Autorun.exe" /passive /norestart"
on the remote machine
I've tried and have had trouble using setx SEE_MASK_NOZONECHECKS 1 /m in a previous statement, I'm guessing that the subprocess don't see new global enviromental variables that weren't around when it's parent started, and won't work without a restart. I'd like to avoid a restart.
I tried running
cmd /c " set SEE_MASK_NOZONECHECKS=1 & "\\server\driver\folder\Autorun.exe" /passive /norestart"
but it doesn't seem to work. Any ideas?
You got a bit lost on the way SEE_MASK_NOZONECHECKS is used. It is not an environment variable and cannot be tinkered with from the command prompt, it is an option for ShellExecuteEx(). A winapi function that you indeed use to start programs. It isn't very clear what programming tools you have access to, using it in a batch file or VBScript isn't going to work. You'd need at least, say, VB.NET and pinvoke the function. You can get the required declarations from the pinvoke.net web site.
Let's talk about what's really going on, you might find a simpler solution. When you download a file from an Internet web site, Windows adds an extra stream to the file that indicates where the file came from. Which basically states "this file did not come from a safe place" and makes the driver installer balky. Which is rather an important feature if you think about it, your user is going to install software that can do a lot, you pretty much have free reign of the machine if you can get a driver installed.
If you right-click the file in Explorer and click Properties then you'll see this at the bottom of the window:
All that's needed is to click that Unblock button. So this is a simple way for your user to solve the problem. You could document the extra step in the install instructions. Also with the advantage that it is now the user that took responsibility of allowing potentially unsafe code to be installed.
Other ways to get the file unblocked is with PowerShell's Unblock-File command and the SysInterals' streams utility, -d option.
And you probably ought to consider the option of writing your own installer. Which will keep the driver packaged in the setup file so it won't be tinkered with by Windows. And the user gets the warning when he starts the installer instead. And it can be signed so the user has some confidence in where the file came from and that it didn't get messed with on its way to his machine. There are many utilities that help you write an installer, like InstallAware, InstallShield, NSIS, etcetera.
I beg to differ to Hans' answer:
Of course, SEE_MASK_NOZONECHECKS is as well a predefined environment variable. Changing it in a process and then starting a child process (e.g. msiexec.exe) which by defaults inherits the environment, has just the same result as using ShellExecuteEx() and providing SEE_MASK_NOZONECHECKS as a parameter to the SHELLEXECUTEINFO structure. The first method is preferred by admins or quick hacks, e.g. if you work with batch or script files which set the environment variable- or when the final call to the .msi file lying on the unsafe network drive is not done by your own code.
For example:
#echo off
set SEE_MASK_NOZONECHECKS=1
call msiexec.exe /i "\\MY_UNC_DRIVE\installs\mysetup.msi /qb /L*v "c:\logs\mysetup.log"
call "\\MY_UNC_DRIVE\installs\Just_another_setup.exe"
If you already use a ShellExecuteEx() in your code, then of course, go with the parameter as Hans mentioned, because this implementation it is more closed. (If you use CreateProcess(), think about using ShellExecuteEx() instead.
Getting back to the environment variable(s). Generally you cannot influence the environment of already started processes. You can set the default environment used by NEW processes by the "setx" command used in the question. But with "setx" you don't change the environment for your current process.This was the problem in question. For this you have to use "set" as shown. So either use both commands after each other or don't use setx at all because for running a setup on foreign machines, it is not clean to make permanent security changes without asking.
For more details on permanent changes/admin point of view, see:
https://superuser.com/questions/595211/removing-the-open-file-security-warning-in-windows-8/934283#934283
Important: As mentioned, there is no general way in Windows to influence processes which already run (only own-defined inter-process-communication maybe), so it is important to set the environment variable before starting the setup to be influenced.
One more thing: Some people think, one must use "SETLOCAL" in a batch file. Normally this is not necessary. Environment changes with "set" are not permanent, and do not incluence "other" processes- they are only inherited to subprocesses and, partly, to superprocesses. But, when the caller on first level ends, the environment is reverted to original state again.
I ended up setting "Launch applications and unsafe files" to enabled for Internet zone in Internet Explorer options under security(custom level) and then exporting the changes from HKCU\Software\Microsoft\Windows\CurrentVersion\Internet Settings\Zones\3 to a registry file and adding it with regedit /s.
After that I can run the installer of the shared drive.
One of these days I'll pare the registry file down to the minimum I guess.
P.S. I believe this causes IE to default to a warning page on startup.
I believe you need to put everything within the same quotation:
cmd /c "set SEE_MASK_NOZONECHECKS=1 & \\server\driver\folder\Autorun.exe /passive /norestart"
You can try these and see the difference in the output:
cmd /c "echo foo & echo bar"
cmd /c "echo foo" & "echo bar"

Use Console2 for Visual Studio debugging?

Is there a way to use the popular Console2 cmd.exe replacement for Visual Studio debugging? In other words, when I debug a console app under VS, I want it to use Console2 instead of cmd.exe.
Interesting question. I looked into it, there are some options but none are pretty.
Console.exe takes arguments, so it's possible to start it with a specific tab and execute an arbitrary process. However, this process will always be run within it's own cmd.exe; for example if your program is c:\my.exe and you launch Console as console.exe -t tabname -r c:\myexe Console2 internally calls CreateProcess( ... cmd.exe c:\my.exe ... ), as a result you can't even see the output of my.exe. This is easily solved though: launch it as console.exe -t tabname -r "/k c:\myexe": the /k switch makes the cmd.exe stay active and you can see your program's standard output. (I looked through the source but couldn't find a way to 'attach' a tab to a currently running Console instance, so launching with arguments will always create a new instance, not sure this is what you are looking for?
You can easily modify the project's debugging properties to reflect the above:
Command: /path/to/console.exe
Command Arguments: -t tabname -r "/k $(TargetPath)"
When starting your exe from within VS, it will launch your exe witin a Console session. However the debugging won't work as VS will try to debug console.exe, not my.exe since that is now a different process. Putting a DebugBreak(); as first line in your exe's main() will sort of solve this, as it will present you the option to debug your exe. All in all, this may a bit too much of a hassle to achieve what you want, but i don't think there's another way: Console always spawns a new process, so the only way to get it debugged is to attach the debugger to it after that process started.
Scott Hanselman blogged about this.
He suggests using this value for Console Settings > tabs > Main > Shell :
%comspec% /k ""C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\vcvarsall.bat"" x86
Sadly for me, This does not appear to work for Visual Studio Express 2010, which lacks a vcvarsall.bat file.

Resources