Wednesday, September 30, 2009

Query the windows event logs via the command line

Today someone told me "You can find if bibblebob happened by looking in the event viewer". I automate things so I went hunting for a CLI tool to accomplish this task. wevtutil is its name-o.

The query language for wevtutil is confusing. I recommend using the eventvwr.exe GUI to build a custom query, and then pass that query to wevtutil.

Here's an example of finding all the times DHCP started:


C:\Windows\System32>wevtutil qe System /rd:true /f:text /q:"*[System[(EventID=50036)]]" |more
Event[0]:
Log Name: System
Source: Microsoft-Windows-Dhcp-Client
Date: 2009-09-22T17:42:54.667
Event ID: 50036
Task: Service State Event
Level: Information
Opcode: ServiceStart
Keyword: N/A
User: S-1-5-19
User Name: NT AUTHORITY\LOCAL SERVICE
Computer: igordm1.redmond.corp.microsoft.com
Description:
DHCPv4 client service is started

Event[1]:
Log Name: System
Source: Microsoft-Windows-Dhcp-Client
Date: 2009-09-17T20:46:36.179
Event ID: 50036
Task: Service State Event
Level: Information
Opcode: ServiceStart
Keyword: N/A
User: S-1-5-19
User Name: NT AUTHORITY\LOCAL SERVICE
Computer: igordm1.redmond.corp.microsoft.com
Description:
DHCPv4 client service is started


Good Hunting!

Friday, September 25, 2009

Use cdb to see what files your application is opening.

In this post I'll show you how to use CDB to intercept CreateFile and see what files your application is opening. For this problem, Process Monitor is often a better tool, but the techniques I demonstrate work for any API you should learn them.

This won't take much time, so if you've never done this before I recommend you follow along.

First Load CDB against cmd:
 

C:\Program Files\Debugging Tools for Windows (x64)>cdb.exe cmd.exe

Microsoft (R) Windows Debugger Version 6.12.0000.526 AMD64
Copyright (c) Microsoft Corporation. All rights reserved.

CommandLine: cmd.exe
Symbol search path is: *** Invalid ***
****************************************************************************
* Symbol loading may be unreliable without a symbol search path. *
* Use .symfix to have the debugger choose a symbol path. *
* After setting your symbol path, use .reload to refresh symbol locations. *
****************************************************************************
Executable search path is:
ModLoad: 00000000`49fc0000 00000000`4a018000 cmd.exe
ModLoad: 00000000`77c10000 00000000`77db8000 ntdll.dll
ModLoad: 00000000`779f0000 00000000`77b0e000 C:\Windows\system32\kernel32.dll
ModLoad: 000007fe`fde90000 000007fe`fdef9000 C:\Windows\system32\KERNELBASE.dll
ModLoad: 000007fe`febd0000 000007fe`fec6f000 C:\Windows\system32\msvcrt.dll
ModLoad: 000007fe`fc850000 000007fe`fc858000 C:\Windows\system32\WINBRAND.dll
ModLoad: 00000000`77b10000 00000000`77c0b000 C:\Windows\system32\USER32.dll
ModLoad: 000007fe`fee70000 000007fe`feed7000 C:\Windows\system32\GDI32.dll
ModLoad: 000007fe`febc0000 000007fe`febce000 C:\Windows\system32\LPK.dll
ModLoad: 000007fe`fe2b0000 000007fe`fe37a000 C:\Windows\system32\USP10.dll
(1268.1dfc): Break instruction exception - code 80000003 (first chance)
*** ERROR: Symbol file could not be found. Defaulted to export symbols for ntdll.dll -
ntdll!CsrSetPriorityClass+0x40:
00000000`77cbb790 cc int 3
0:000> g
ModLoad: 000007fe`fe640000 000007fe`fe66e000 C:\Windows\system32\IMM32.DLL
ModLoad: 000007fe`fe530000 000007fe`fe639000 C:\Windows\system32\MSCTF.dll
Microsoft Windows [Version 6.1.7110]
Copyright (c) 2009 Microsoft Corporation. All rights reserved.

C:\Program Files\Debugging Tools for Windows (x64)>
(1268.1c1c): Control-C exception - code 40010005 (first chance)
First chance exceptions are reported before any exception handling.

Next find something like CreateFile to breakpoint:
 
0:001> x *!*CreateFile*
00000000`779fd6a0 kernel32!CreateFileMappingA ()
00000000`779ffb30 kernel32!CreateFileMappingW ()
00000000`77a02740 kernel32!CreateFileW ()
00000000`77a124b0 kernel32!CreateFileA ()
00000000`77a3b980 kernel32!CreateFileMappingNumaW ()
00000000`77a54d50 kernel32!CreateFileMappingNumaA ()
00000000`77a63740 kernel32!LZCreateFileW ()
00000000`77a66450 kernel32!CreateFileTransactedW ()
00000000`77a665f0 kernel32!CreateFileTransactedA ()
00000000`77c5ea20 ntdll!NtCreateFile ()
00000000`77c5ea20 ntdll!ZwCreateFile ()
000007fe`fde94990 KERNELBASE!CreateFileW ()
000007fe`fde96270 KERNELBASE!CreateFileMappingNumaW ()
000007fe`fdea3120 KERNELBASE!CreateFileMappingW ()
000007fe`fdec9cc0 KERNELBASE!CreateFileA ()

Set the breakpoint on Kernel32!CreateFileW (You can figure that out by looking on MSDN)
 
0:001> bm kernel32!CreateFileW
breakpoint 1 redefined
1: 00000000`77a02740 @!"kernel32!CreateFileW"

Lets open a file and make sure our function is called!
 
0:002> g

C:\Program Files\Debugging Tools for Windows (x64)>type c:\foo.txt
Breakpoint 1 hit
kernel32!CreateFileW:
00000000`77a02740 48895c2408 mov qword ptr [rsp+8],rbx ss:00000000`0024e180=000000000031df00
0:000>


Our breakpoint is hit. Lets figure out the filename being opened. To do this, we lookup the parameter list of CreateFile on MSDN. Filename is the first parameter. Next we look up the calling convention. On AMD64, the first paramater lives in rcx. Lets dump rcx as a unicode string:
 
0:000> du rcx
00000000`0031a310 "c:\foo.txt"
0:000>

Awesome - it worked. Lets make our breakpoint automatically print, and continue execution so it's non-intrusive.
 
0:000> bm kernel32!CreateFileW "du @rcx;g"
breakpoint 1 redefined
1: 00000000`77a02740 @!"kernel32!CreateFileW"
0:000> g

C:\Program Files\Debugging Tools for Windows (x64)>type c:\fo2.txt
00000000`0031a310 "c:\fo2.txt"
The system cannot find the file specified.

C:\Program Files\Debugging Tools for Windows (x64)>type c:\IgorOpenedThisFile.txt
00000000`0031b9e0 "c:\IgorOpenedThisFile.txt"
The system cannot find the file specified.

C:\Program Files\Debugging Tools for Windows (x64)>

Notice the debugger spew intersperesed with cmd output. Anytime we open a file we'll see it in the spew! Use this approach to debug all sorts of I wonder what's going on problems.

Tuesday, September 8, 2009

Copying files across parallel directory structures.

It happens to all of us, you've made a change in branch2, now you need to copy it to branch1. Here's a trick I use to accomplish this task:

C:\src\branch1\mydir\mydir2\mydir3\mydir4>xcopy %cd:branch1=branch2%\foo*
Overwrite C:\src\branch1\mydir\mydir2\mydir3\mydir4\foo.txt (Yes/No/All)? y
C:\src\branch2\mydir\mydir2\mydir3\mydir4\foo.txt
1 File(s) copied


How'd that work? Use echo to find out what happened:

C:\src\branch1\mydir\mydir2\mydir3\mydir4>echo %cd:branch1=branch2%
C:\src\branch2\mydir\mydir2\mydir3\mydir4

For more information run help set.

Thursday, July 30, 2009

Finding CLR exceptions without visual studio

(If you want to understand what exception code 0xe0434352 is, read this post)



Often exceptions are thrown and caught and you don't see them. You probably know how to debug this in Visual Studio, so let me show you how to do it in cdb.

Sample Code:





class Program
{
static void Main(string[] args)
{
foreach (var x in Enumerable.Range(0,2000))
{
Thread.Sleep(TimeSpan.FromSeconds(1));
Console.WriteLine("Hello World");
ThrowAndCatchException();
}

}

private static void ThrowAndCatchException()
{
try
{
throw new NotImplementedException();
}
catch(Exception)
{
}
}
}
Output of the application:

Hello World
Hello World
Hello World
Nothing about an exception, but you're sure it's happening behind the covers -- fire up cdb:

C:\Program Files\Debugging Tools for Windows (x64)>cdb -pn consoleapplication3.exe

<SNIP>

ModLoad: 000007fe`f7e90000 000007fe`f7eb4000 C:\Windows\Microsoft.NET\Framework64\v4.0.20506\culture.dll
(ff8.17a8): Break instruction exception - code 80000003 (first chance)
*** ERROR: Symbol file could not be found. Defaulted to export symbols for C:\Windows\SYSTEM32\ntdll.dll -
ntdll!DbgBreakPoint:
00000000`77b7d7b0 cc int 3
Continue debugging:

0:004> g
Exceptions - lots of them:

(ff8.16dc): CLR exception - code e0434352 (first chance)
(ff8.16dc): CLR exception - code e0434352 (first chance)
(ff8.16dc): CLR exception - code e0434352 (first chance)
(ff8.16dc): CLR exception - code e0434352 (first chance)
(ff8.16dc): CLR exception - code e0434352 (first chance)
(ff8.16dc): CLR exception - code e0434352 (first chance)
(ff8.1860): Break instruction exception - code 80000003 (first chance)
Break on CLR exceptions:

0:004> sxe clr
0:004> g

(ff8.16dc): CLR exception - code e0434352 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
*** ERROR: Symbol file could not be found. Defaulted to export symbols for C:\Windows\system32\KERNELBASE.dll -
KERNELBASE!RaiseException+0x3d:
000007fe`fdb8bb5d 4881c4c8000000 add rsp,0C8h
Load sos ( in .Net 2/3 use use !loadby sos mscorwks):

0:000> !loadby sos clr
View Stack:

0:000> !CLRStack
PDB symbol for clr.dll not loaded
OS Thread Id: 0x16dc (0)
Child SP IP Call Site
000000000096e6a8 000007fefdb8bb5d [HelperMethodFrame: 000000000096e6a8]
000000000096e7c0 000007ff00170360 ConsoleApplication3.Program.ThrowAndCatchException()
000000000096e810 000007ff001701fb ConsoleApplication3.Program.Main(System.String[])
000000000096ec90 000007feef474ca4 [GCFrame: 000000000096ec90]
View Exception:

0:000> !PrintException
Exception object: 0000000002c88c18
Exception type: System.NotImplementedException
Message: The method or operation is not implemented.
InnerException: <none>
StackTrace (generated):
<none>
StackTraceString: <none>
HResult: 80004001
0:000>
Pretty neat - eh?

Saturday, July 18, 2009

Why write programs that don't modify variables?

Slews of bugs happen because variable have values you aren't expecting. To minimize this class of bugs I use a technique a lot of people find surprising. I try to only assign and never modify variables. In C++, I make almost all my variables const.

C++ people are now saying -- Um if all your values are const how do you write a for loop?

In C++ I can't help myself, I'm stuck with a variable modification eg:

for (size_t x=0;x<6;x++) printf("%d",x)
In python the for loop naturally iterates over a sequence so you don't need to modify a value:
for x in range(6): print x
In C#, you can use either the C++ syntax or a more python syntax via foreach:
for (int x=0;x<6;x++) Console.WriteLine(x);
or
foreach (var x in Enumerable.Range(0,6)) Console.WriteLine(x)

I use the foreach syntax which people initially find confusing. But its value starts to shine when using non zero starting values. Assume I need to generate 113 numbers starting at 27. Which statement do you find expresses it better.
for (int x=27;x<=139;x++) Console.WriteLine(x)

or
foreach (var x in Enumerable.Range(27,113)) Console.WriteLine(x)

Saturday, July 4, 2009

How to attach to an already running debugger target using cdb.

For the last year when I wanted to attach to a process using cdb, I'd attach by PID. This meant i'd need to the following dance:
    C:\Program Files\Debugging Tools for Windows (x64)>tlist |findstr firefox
9128 cmd.exe findstr firefox
276 firefox.exe Restore Session - Vimperator

C:\Program Files\Debugging Tools for Windows (x64)>cdb -p 276
It turns out you can just do:

C:\Program Files\Debugging Tools for Windows (x64)>cdb -pn firefox.exe

Microsoft (R) Windows Debugger Version 6.11.0001.404 AMD64
Copyright (c) Microsoft Corporation. All rights reserved.


If there are multiple instances of your process, you'll still need to use tlist
to find the PID you're interested in.

Sunday, December 28, 2008

I can see you -- Google Analytics:

What are the three most important thing in the retail business? Location, Location, Location.

By contrast in the decision making business, the three most important things are:Data, Data, Data.

A great way for websites to gather this kind of data is Google Analytics.

If you've never heard of Google Analytics I highly recommend you learn what gets tracked by watching this video.

To see if the site you're on uses Google Analytics. Download the webpage and search for gaJsHost::
 
C:\TEMP>h:\bin_drop\wget http://ig2600.blogspot.com
--11:38:04-- http://ig2600.blogspot.com/
=> `index.html.3'


11:38:10 (67.29 KB/s) - `index.html.3' saved [20285/20285]

C:\TEMP> findstr /i gaJSHost index.html.3
var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));

From the above you see that ig2600.blogspot.com uses Google Analytics, and thus collects all sorts of interesting data about its viewers.