From the archives: Windbg conditional breakpoints with string comparisons

2 min readOct 26, 2023

From the archives of my old blog. These days there are probably better ways of doing this, such as using windbg’s Javascript extensions, TTD or other instrumentation tools. Enjoy.

Actually, it’s more a note to self rather, just thought I’d might as well leave the note here. Recently, I’ve had to reverse engineer a program and I wanted to break at the point where the program calls CreateFileW with a path to a certain file. What I’d normally do would be to set a breakpoint on CreateFileW and print the path argument every time that breakpoint is hit. For example:

bp Kernel32!CreateFileW ".printf \"%mu\\n\", poi(esp+4);"

However, this particular program calls CreateFileW multiple times in the course of its execution and it was time consuming to have to do this manually, so I searched for a solution to this problem. Windbg help shows several string comparison functions, such as $scmp, $sicmp, $spat, however they all take in strings as their arguments and not memory pointer to strings — something like $spat(‘hello world’, ‘hello*’) would work but not $spat(‘hello world’, poi(esp+4)).

Searching for a solution to this problem, I found that people have suggested that string aliases be used. Aliases for Unicode strings are created using the following command:

as /mu ${/v:FileName} poi(esp+4);

as is the command for creating aliases. ${/v:FileName} says take the name ‘FileName’ literally and do not substitute that phrase for any existing aliases. poi(esp+4) is the pointer to the Unicode string representing FileName. Combining this with $spat and the breakpoint command would lead to the following command:

bp Kernel32!CreateFileW ".printf \"%mu\\n\", poi(esp+4); as /mu ${/v:FileName} poi(esp+4); .if $spat(\"${FileName}\", \"*target*\") {.echo Hit} .else {.echo Not Yet;g;}"

This did not work as expected however. This breakpoint will only break on the call after the call to CreateFileW with the word ‘target’ in its path. Windbg help mentions that “Note that if the portion of the line after the semicolon requires expansion of the alias, you must enclose that second portion of the line in a new block.” Thus, in order for the new alias value to be evaluated and used in the following command, the following command has to be inside a windbg block, created by .block{}. The full command would be as follows:

bp Kernel32!CreateFileW ".printf \"%mu\\n\", poi(esp+4); as /mu ${/v:FileName} poi(esp+4); .block{.if $spat(\"${FileName}\", \"*target*\") {.echo Hit} .else {.echo Not Yet;g;}}"

One thing to note is that the alias FileName should NOT EXIST before that command is executed, else the alias FileName used as the argument to $spat will be expanded and would lead to unintended results.