I have set up WinDbg for hybrid (user mode to kernel mode) debugging.
In the user mode application, I am calling CreateFile()
with certain parameters. I want to break at the CreateFile()
call in context of the user mode process, and trace its execution from there.
I tried searching for the CreateFile
symbol with the x
command. The issue is that x nt!*CreateFile*
cannot find the respective symbol. Out of the bunch of symbols it lists, the closest I could find was nt!NtCreateFile
, which appears to have a different signature, and presumably an internal API.
Why is the CreateFile()
symbol missing in WinDbg?
You can search for Microsoft Windows API functions using the search terms "MSDN <function>". If you do so, this brings you to CreateFileA()
. That website tells you that the function is defined in fileapi.h
.
Look inside fileapi.h
(find it on your local machine, e.g. using Everything), you'll find these lines:
#ifdef UNICODE
#define CreateFile CreateFileW
#else
#define CreateFile CreateFileA
#endif // !UNICODE
So, CreateFile()
is just an alias for either CreateFileA()
or CreateFileW()
, depending on whether you compile for ANSI or Unicode.
You'll find many functions which are redirected like that and have the ...A()
and ...W()
naming convention. That's outlined by MS on Unicode in the Windows API and they explain the conventions using another example.
On the same website, there's a section called Requirements, which says
Header fileapi.h (include Windows.h)
Library Kernel32.lib
DLL Kernel32.dll
So the breakpoints can be set with
0:001> bp kernel32!CreateFileA
0:001> bp kernel32!CreateFileW
But your x
approach also works, if you search in all modules, like
0:001> x *!CreateFileA
00007ff8`23dc1320 KERNELBASE!CreateFileA (void)
00007ff8`25fa4e90 KERNEL32!CreateFileA (CreateFileA)
With both breakpoints (A and W) set, you should find the function:
0:001> g
Breakpoint 1 hit
KERNEL32!CreateFileW:
00007ff8`25fa4ea0 ff251af40500 jmp qword ptr [KERNEL32!_imp_CreateFileW (00007ff8`260042c0)] ds:00007ff8`260042c0={KERNELBASE!CreateFileW (00007ff8`23dc1410)}
as followed up in comments
When should the kernel!*
functions be available? Very early, typically at the initial breakpoint already. The first 4 modules loaded are your app, ntdll, kernel32 and kernelbase, if you don't debug a so called native DLL, which tries to get rid of as many dependencies as possible.
ModLoad: 00007ff7`bf830000 00007ff7`bf866000 YourApp.exe
ModLoad: 00007ffc`dfdd0000 00007ffc`dffc8000 ntdll.dll
ModLoad: 00007ffc`df8b0000 00007ffc`df971000 C:\Windows\System32\KERNEL32.DLL
ModLoad: 00007ffc`dd970000 00007ffc`ddc6d000 C:\Windows\System32\KERNELBASE.dll
and then, depending on the programming language, e.g. C++
ModLoad: 00007ffc`88280000 00007ffc`8828f000 C:\Windows\SYSTEM32\VCRUNTIME140_1D.dll
ModLoad: 00007ffc`72710000 00007ffc`7273e000 C:\Windows\SYSTEM32\VCRUNTIME140D.dll
ModLoad: 00007ffc`6b2e0000 00007ffc`6b3c2000 C:\Windows\SYSTEM32\MSVCP140D.dll
ModLoad: 00007ffc`00430000 00007ffc`00651000 C:\Windows\SYSTEM32\ucrtbased.dll
ModLoad: 0000020a`14190000 0000020a`143b1000 C:\Windows\SYSTEM32\ucrtbased.dll
(4ac.32c): Break instruction exception - code 80000003 (first chance)
ntdll!LdrpDoDebuggerBreak+0x30:
00007ffc`dfea0820 cc int 3
Windows Internals 7 Part 1 says (chapter "Early process initialization")
In newer versions of Windows, the loader instead builds a dependency map ahead of time, with specific nodes that describe a single DLL and its dependency graph, building out separate nodes that can be loaded in parallel.
So the load order may even vary between runs, but I haven't seen that for these most basic DLLs.
If you really don't see kernelbase
or kernel32
yet, you have the following options:
sxe ld kernel*
(enable exception on load of a module, filtering for kernel)bu