String comparison in Windbg script
Asked Answered
F

3

15

Using Windbg script I want to check the presence of a certain string in an argument of any function.

0:000> g
Breakpoint 0 hit
eax=00000001 ebx=00000000 ecx=00422fc6 edx=00000000 esi=03d574e8 edi=00000005
eip=76d8fd3f esp=000cf7ac ebp=000cf7c8 iopl=0         nv up ei pl nz na po nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000202
USER32!MessageBoxW:
76d8fd3f 8bff            mov     edi,edi

0:000> du poi(esp+8)
03d574e8  "Cannot find "hello""

Here the 2nd parameter passed to MessageBoxW is Cannot find "hello".

So I want to check the presence of string hello inside the 2nd argument.

Based on this MSDN article, I tried the following commands, but it's not working:

0:000> r $t1 = poi(esp+8)
0:000> as /mu $MSG $t1
0:000> .echo ${$MSG}
Cannot find "hello"
0:000> .if ($spat(@"${MSG}","*hello*") == 0) {.echo NotFound} .else {.echo Found}
NotFound

It should return Found I guess!

Thanks.

Frost answered 31/3, 2015 at 15:38 Comment(2)
if you have double quotes inside Double quotes like "cannot find "hello"" then $spat will not work as it requires Quoted strings "${foo}" will become "cannot find " write a simple strcmp extension and pass your search you will be better off iirc i posted a string comparing code hereConversable
I've updated my answer to provide more details about @"${MSG}" and another alternative using built-in WinDbg commands.Dodge
D
11

What's wrong with escaping ${MSG}?

In the .if command you used, ${MSG} does not get replaced due to a missing $. Try searching for MSG as the proof:

0:001> .if ($spat(@"${MSG}","*MSG*") == 0) {.echo NotFound} .else {.echo Found}
Found

It gets replaced in

0:001> .if ($spat(${$MSG},"*hello*") == 0) {.echo NotFound} .else {.echo Found}
Syntax error at '(Cannot find "hello","*hello*") == 0) {.echo NotFound} .else {.echo Found}'

but that is missing has quotation marks before Cannot. It also gets replaced in

0:001> .if ($spat("${$MSG}","*hello*") == 0) {.echo NotFound} .else {.echo Found}
Syntax error at '("Cannot find "hello"","*hello*") == 0) {.echo NotFound} .else {.echo Found}'

but there, the quotation marks are closed by the quotation marks inside the string. Also, the @ symbol does not help:

0:001> .if ($spat(@"${$MSG}","*hello*") == 0) {.echo NotFound} .else {.echo Found}
Syntax error at '(@"Cannot find "hello"","*hello*") == 0) {.echo NotFound} .else {.echo Found}'

So this is one of those cases where IMHO they forgot to consider escape characters in WinDbg. Very frustrating and always a source of errors.

Solution with PyKD extension

Luckily there is PyKD and the code to check for the string is

>>> "hello" in loadWStr(ptrPtr(reg("esp")+8))
True

reg("esp") gets the value of the ESP register. +8 adds 8 of course. ptrPtr() gets a pointer sized value from that address. loadWStr() reads from that value until it hits a NUL character. "hello" in performs a find operation. You could also use .find("hello")>0.

Here's how I tried it:

0:003> .dvalloc 2000
Allocated 2000 bytes starting at 00470000
0:003> eu 00470000 "Cannot find \"hello\""
0:003> du 00470000 
00470000  "Cannot find "hello""
0:003> ep 00470000+1008 00470000 
0:003> r esp=00470000+1000
0:003> .load E:\debug\Extensions\pykd\x86\pykd.dll
0:003> !pycmd
Python 2.7.8 |Anaconda 2.1.0 (32-bit)| (default, Jul  2 2014, 15:13:35) [MSC v.1500 32 bit (Intel)] on win32
Type "help", "copyright", "credits" or "license" for more information.
(InteractiveConsole)
>>> "hello" in loadWStr(ptrPtr(reg("esp")+8))
True
>>> exit()

You can put the following code into a .PY file

from pykd import * 
print "hello" in loadWStr(ptrPtr(reg("esp")+8))

And then run it without the interactive console like this:

0:003> !py e:\debug\hello.py
True

Solution with WinDbg

In WinDbg, you need to get rid of the quotation marks. One way to do that is .foreach:

0:001> .foreach (token {.echo $MSG}){.echo ${token}}
Cannot
find
hello

The output does not contain quotation marks any more. Let's assign this output to another alias:

0:001> as /c NOQ .foreach (token {.echo ${$MSG}}){.echo ${token}}

With this new alias, your command will work:

0:001> .if ($spat("${NOQ}","*hello*") == 0) {.echo NotFound} .else {.echo Found}
Found
Dodge answered 31/3, 2015 at 19:35 Comment(3)
Thanks! No doubt I want similar thing. But even windbg script makes debugging process very slow and pykd makes it more slower :( Let's see if I get any wds based answer.. :)Frost
Nice explanation and example! Do you find, as @Deb.K. mentions, that PyKD is noticeably slower than a windbg script?Algo
@MarcSherman: Sorry, I didn't measure that ans seldom use breakpoints. Of course performance is a point when having a breakpoint that is hit often. I'm thinking of posting this as its own question, but I need to write a scenario (SSCCE, probably in C++) for that.Dodge
D
1

From the comments:

Let's see if I get any WDS based answer.

Hard to believe that you want to go the long tramp. But ok, here it is, the WinDbg built-in solution:

r $t9=1;.foreach /ps fffff (endaddr {s -[1]w 00570000 L1000 0}) {.foreach /ps fffff (findaddr {s -[1]u 00570000 ${endaddr} "hello"}) {r $t9=2} }; .if (@$t9==2) { .echo "Found"} .else {.echo "Not Found"}

What it does? Well, I leave that as an exercise to you, spoilers below.

r $t9=1; sets the T9 pseudo register to a defined value so that it is not accidentally equal to the value used for comparison later.

s -[1]w 00570000 L1000 0 does a memory search for a DWORD (w) of value 0, which is equal to a Unicode end of string. [1] limits the output to the address only.

.foreach /ps fffff (endaddr { ... }) {...}; assigns the address to the endaddr variable. /ps fffff skips other findings if there are many.

s -[1]u 00570000 ${endaddr} "hello" does a memory search, this time for a Unicode string (u), also limiting to address output ([1]).

.foreach /ps fffff (findaddr {...}) {...} takes the output of the search. The findaddr variable is unused here but might be useful in the final command, depending on what you're trying to achieve.

r $t9=2 changes the T9 pseudo register to a value indicating that the search term was found.

.if (@$t9==2) { ... } .else { ... } does something based on the T9 pseudo register.

Dodge answered 1/4, 2015 at 13:5 Comment(1)
Thanks!But I've seen one example with $spat() in MSDN article (mentioned in question)..which seems much easier option to do same, but somehow its not working as intended for me..Do you have any thought about that function?Frost
C
1

wow Thomas that is probably termed as going to the extremes

@deb if finding a match is the main requirement you can try some thing like this

0:000> .printf "%y\n" , @eip
USER32!MessageBoxW (7e466534)
0:000> $ ----------------------------------------------------------------------------------------------------------------------
0:000> du poi(@esp+8)
00408168  "cannot find "hello""
0:000> $ ----------------------------------------------------------------------------------------------------------------------
0:000> .foreach /pS 1 /ps 100 (place { dpu @esp+8 l1 }) { s -u place l100 "\"hello\"" }
00408180  0022 0068 0065 006c 006c 006f 0022 0000  ".h.e.l.l.o."...
0040827a  0022 0068 0065 006c 006c 006f 0022 0020  ".h.e.l.l.o.". .
0:000> $ ----------------------------------------------------------------------------------------------------------------------
0:000> .foreach /pS 1 /ps 100 (place { dpu @esp+8 l1 }) { s -u place l100 "\"z\"" }
0:000> $ ----------------------------------------------------------------------------------------------------------------------
0:000> .foreach /pS 1 /ps 100 (place { dpu @esp+8 l1 }) { s -u place l100 "\"zoop\"" }
0:000> $ ----------------------------------------------------------------------------------------------------------------------
0:000> .foreach /pS 1 /ps 100 (place { dpu @esp+8 l1 }) { s -[l 20]u place l100 "can" }
00408168  0063 0061 006e 006e 006f 0074 0020 0066  c.a.n.n.o.t. .f.
0040819c  0063 0061 006e 006e 006f 0074 0020 0066  c.a.n.n.o.t. .f.
004081d0  0063 0061 006e 006e 006f 0074 0020 0066  c.a.n.n.o.t. .f.
00408204  0063 0061 006e 006e 006f 0074 0020 0066  c.a.n.n.o.t. .f.
00408238  0063 0061 006e 006e 006f 0074 0020 0066  c.a.n.n.o.t. .f.
0:000> $ ----------------------------------------------------------------------------------------------------------------------
0:000> .foreach /pS 1 /ps 100 (place { dpu @esp+8 l1 }) { s -[1]u place l100 "can" }
0x00408168
0x0040819c
0x004081d0
0x00408204
0x00408238
0:000> $ ----------------------------------------------------------------------------------------------------------------------
0:000> .foreach /pS 1 /ps 100 (place { dpu @esp+8 l1 }) { .foreach (vlace { s -[1]u place l100 "can"} ) {du vlace} }
00408168  "cannot find "hello""
0040819c  "cannot find "iello""
004081d0  "cannot find "jello""
00408204  "cannot find "fello""
00408238  "cannot find "kello""
0:000> $ ----------------------------------------------------------------------------------------------------------------------
0:000> .foreach /pS 1 /ps 100 (place { dpu @esp+8 l1 }) { .foreach (vlace { s -[1]u place l100 "ello"} ) {du vlace} } 
00408184  "ello""
004081b8  "ello""
004081ec  "ello""
00408220  "ello""
00408254  "ello""
0040827e  "ello" baby"
0:000> $ ----------------------------------------------------------------------------------------------------------------------
0:000> lsf msgboxw.cpp
msgboxw.cpp
0:000> $ ----------------------------------------------------------------------------------------------------------------------
0:000> ls 0,15
     1: #include <windows.h>
     2: #pragma comment(lib,"user32.lib")
     3: int main (void)
     4: {
     5:     MessageBoxW(0,L"cannot find \"hello\"",L"test",0);
     6:     MessageBoxW(0,L"cannot find \"iello\"",L"test",0);
     7:     MessageBoxW(0,L"cannot find \"jello\"",L"test",0);
     8:     MessageBoxW(0,L"cannot find \"fello\"",L"test",0);
     9:     MessageBoxW(0,L"cannot find \"kello\"",L"test",0);
    10:     MessageBoxW(0,L"saying \"hello\" baby",L"test",0);
    11: return 0;
    12: }
    13: 
    14: 
0:000> $ ----------------------------------------------------------------------------------------------------------------------
Conversable answered 2/4, 2015 at 10:4 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.