Search code examples
debuggingwindbgusermode

Is there a difference in dt nt!_TEB and dt ntdll!_TEB?


I can dump types from an arbitrary module using

dt modulename!type

In some cases I saw e.g.

dt nt!_TEB

(and it works) although the module is called ntdll:

0:001> lm m nt
start             end                 module name
0:001> lm m ntdll
start             end                 module name
00000000`76e00000 00000000`76fa9000   ntdll      (pdb symbols)          d:\...\ntdll.pdb

As you can see above, ntdll cannot always be replaced by nt.

Is there a difference in dt nt!type versus dt ntdll!type or can it always be used in its shortcut form? I'm looking for a credible answer with sources, not just "Yes".

I have tried:

  • reading WinDbg help .hh dt

Bonus questions if you have some background knowledge you'd like to share:

  • are there other commands where nt can be used instead of ntdll or is this dt-specific?
  • are there other modules which have a shortcut form?
  • where does this come from (e.g. is there some historical background for this behavior)?

Solution

  • nt is an automatic alias set by debugger lookup for $ntsym or $ntnsym. Explanation is in WinDbg help "Using aliases" (online version at MSDN). You can use it wherever you would require that alias.

    Suppose you have a script that works in both kernelmode as well as usermode. You can use {nt} to denote either of ntdll, ntkrnlpa, ntkrnlmp, ntoskrnl or ntwowxxxx.

    Not only ntdll and ntXXXXX in kernel mode has this automatic alias as both have functionally equivalent code in common. No other module has common code like these two modules. For example ntdll!NtCreateFile has an equivalent nt!NtCreateFile where the former is a stub that reaches the real implementation in the latter via syscall.

    You can't use nt as is everywhere. For example, autocompleting dt nt!_p in usermode won't autocomplete, but dt ntdll!_p will autocomplete properly. evaluate nt it will err with cannot evaluate but evaluating ? ntdll will work.

    nt is parsed specially in dt command and has a function to assign a proper module value to the string so it can be used in dt as is.

    pseudo code for the function that parses nt is something like this:

    switch(GetToken(wcschr(inputstr ,"!")) == "nt" )
    case usermode nt = "ntdll";
    case kmode    nt = "Nt" using machineinfo.NtModule (ntos .......)
    case wow      nt = "Nt32" using getnt32module()
    

    If you are curious disassemble dbgeng and search around the functions that has the string typedump in it that is x dbgeng!*typedump* one of that functions has a subcall that parses the string nt and assigns it a value.