使用windbg调试程序时,可以使用!logexts系列指令记录windows api的调用情况。使用方法如下
1. !logexts.logi
The !logexts.logi extension initializes logging by injecting Logger into the target application.
将logger注入到目标进程中
2. !logexts.loge [OutputDirectory]
The !logexts.loge extension enables logging. If logging has not been initialized, it will be initialized and enabled
启用记录API,可以忽略!logexts.logi指令而直接使用!logexts.loge
3. !logexts.logo {e|d} {d|t|v}
The !logexts.logo extension sets or displays the Logger output options.
!logexts.logo显示或者设置输出选项,包括调试器、文本文件或者lgv文件。lgv文件包含更多的信息,可以使用logviewer工具查看。查看之前请关闭程序,否则lgv文件会被占用,logviewer无法解析(但是logviewer并不报错,faint)。
4. !logexts.logd
The !logexts.logd extension disables logging.
停止记录api。5. !logexts.logm
The !logexts.logm extension creates or displays a module inclusion list or a module exclusion list.
6. !logexts.logcThe !logexts.logc extension displays all API categories, displays all APIs in a specific category, or enables and disables the logging of APIs in one or more categories.
调试64位应用程序时,发现若使用调试器启动进程方式后,在第一个断点出现后使用!logexts功能,会使进程崩溃,如下
ModLoad: 00000000`4fb50000 00000000`4fbb5000 C:\Program Files\Debugging Tools for Windows (x64)\winext\logexts.dll
(4594.de8): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
ntdll!RtlCaptureContext+0x86:
00000000`771fb145 0fae8100010000 fxsave [rcx+100h] ds:00000000`001cdb28=04
0:000> k
Child-SP RetAddr Call Site
00000000`001cd9e8 00000000`771c88c8 ntdll!RtlCaptureContext+0x86
00000000`001cd9f8 000007fe`fd0fa06d ntdll!RtlRaiseException+0x48
00000000`001ce038 000007fe`fd0f6dcd KERNELBASE!RaiseException+0x39
*** ERROR: Symbol file could not be found. Defaulted to export symbols for C:\Program Files\Debugging Tools for Windows (x64)\winext\logexts.dll -
00000000`001ce108 00000000`4fb68d59 KERNELBASE!OutputDebugStringA+0x6d
00000000`001ce3d8 00000000`4fb6b807 logexts!LogGetInclExclList+0x769
00000000`001ce428 00000000`4fb6e1da logexts!LogGetInclExclList+0x3217
00000000`001ce8b8 00000000`4fb63bbe logexts!LogInitialize+0xfa
00000000`001ce988 00000000`001d00d6 logexts!InjectionCleanup+0x16e
00000000`001cee38 00000000`4fb50000 0x1d00d6
00000000`001cee40 00000000`001d01e0 logexts
00000000`001cee48 00000000`001d06e4 0x1d01e0
00000000`001cee50 00000000`77257801 0x1d06e4
00000000`001cee58 00000000`001d01e0 ntdll!LdrpDoDebuggerBreak+0x31
00000000`001cee98 00000000`001d06e4 0x1d01e0
00000000`001ceea0 00000000`001d0120 0x1d06e4
00000000`001ceea8 00000000`76e50000 0x1d0120
00000000`001ceeb0 00000000`00000246 kernel32!TestResourceDataMatchEntry <PERF> (kernel32+0x0)
00000000`001ceeb8 000007ff`fffd3000 0x246
00000000`001ceec0 00000000`772dd650 0x7ff`fffd3000
00000000`001ceec8 00000000`00000000 ntdll!PebLdr+0x10
从上图可以看出,在进程启动早期,使用RtlCaptureContext产生了异常。后进过测试,使用调试器附加进程或者在执行进程入口点函数时启用api记录功能不会产生问题。调试win32进程时并未发现这样状况。
Api记录的调用者(caller)地址是调用Api后的返回地址,并且记录了Api的返回值。
使用logviewer可以过滤一些api调用,方便查找问题。
题外话,从上面的调用堆栈中可以得知OutputDebugStringA的实现包含了 KERNELBASE!RaiseException的调用,并且OutputDebugString也是一个为数不多的从W转到A去执行的。