Tracking the Current Directory from the debugger: RtlpCurDirRef

Some rogue code was changing our current directory from under our feet, and we needed to catch it in action. I was looking for a memory location to set a data breakpoint on.

(Note: for the remainder of this post it is assumed that ntdll.dll symbols are loaded.)

The High road

The natural repository for process-wide data is the Process Environment Block and indeed you can get to the current directory from the there. The PEB and its internal structures are almost entirely undocumented, but the venerable Nir Sofer (and others) got around it using MS public debug symbols: the path is PEB->ProcessParameters->CurrentDirectory. After translating the private field locations to offsets, you get a rather horrifying – but functional – expression, that you can paste in a watch window:

(((_CURDIR*)&((((((PTEB)$TIB)->ProcessEnvironmentBlock)->ProcessParameters)->Reserved2)[5]))->DosPath).Buffer

To break execution when your current folder changes, you can set a data breakpoint on:

&(((((PTEB)$TIB)->ProcessEnvironmentBlock)->ProcessParameters)->Reserved2)[5]

An Easier Alternative

Interestingly when inspecting GetCurrentDirectory disassembly it turns out it doesn’t go the TEB/PEB way, but takes a detour:

Ntdll.dll!RtlpCurDirRef is undocumented, but is included in the public ntdll debug symbols and so can be used in the debugger. The Cygwin guys mention it as the backbone of their unix-like cwd command, and their _FAST_CWD_8 type seems to still accurately reflect the windows type (as of July 2017). If you’re willing to modify your source to enable better variable watch go ahead and add –

typedef struct _FAST_CWD_8 {
LONG           ReferenceCount;
HANDLE         DirectoryHandle;
ULONG          OldDismountCount;
UNICODE_STRING Path;
LONG           FSCharacteristics;
WCHAR          Buffer[MAX_PATH];
} FAST_CWD_8, *PFAST_CWD_8;

And inspect in the debugger:

If you can’t or don’t want to modify the source, you can set the watch with a direct offset –

(*(wchar_t**)ntdll.dll!RtlpCurDirRef)+22

SetCurrentDirectory() replaces the contents of RtlpCurDirRef, so you can set a data breakpoint directly on it.

Advertisements
This entry was posted in Debugging, VC++, Win32. Bookmark the permalink.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s