vs程序员使用windbg实例

如果使用32位的windbg,windbg加载完dump文件后,窗口会显示wow64cpu,表示是64位进程,需要切换到64位环境:

.load wow64exts
!sw

设置符号表(crtl+s):

srv*D:\DumpAnalysis\ms_symbols*https://msdl.microsoft.com/download/symbols;srv*D:\DumpAnalysis\kis_symbols*

如果堆栈显示rcmdhelper!0x3838,表示rcmdhelper模块加载符号表失败,可以显示符号表全路径寻址,手动把符号表文件放到加载的路径,完成手动加载指定模块:

!lmi rcmdhelper //查找名为rcmdhelper模块的pdb文件是否已经被正确加载了
!sym noisy  //当Windbg加载Symbol文件的时候,显示Symbol的路径,默认情况下是不显示的。
.reload /f xxx.dll  //重新加载指定模块的符号表文件。
.reload /i xxx.dll  //如果确定代码是完全一样的,只是编译时间引起加载符号表加载错误,可以使用此命令行忽略符号表的检查。
lmvm xxx    //这个命令不能带文件后缀。可以查看模块的版本号,文件大小
CheckSum    //这两项信息可以校验文件是否损坏、篡改

建议本地有一份和编译服务器同样目录的源码

这样的话操作符号表文件也方便点,如果符号表不匹配,可以直接从编译产出目录

VS操作习惯的Windbg:

如果符号表齐全并且代码目录和编译服务器的代码目录一致, alt+3(局部变量窗口)、alt+6(当前线程堆栈窗口)、alt+9(线程列表窗口),可以很方便的,和使用vs差不多一样的查看代码、线程、线程堆栈,点击切换栈帧,查看当前栈帧的局部变量。右键这些窗口选择dock(停靠),使用习惯可以更接近vs了。想同时观察多个命令,可以用ctrl+n打开多个命令窗口。如果没有符号表,或者符号表不齐全,或者代码目录和编译服务器的代码目录不一致,很多东西还是得用命令行。

!analyze -v  //最为强大的命令,自动分析dump,并输出错误信息,输出建议命令行

命令执行后,自动分析并显示有问题的堆栈,有错误提示,并且有推荐的命令行的。一般推荐的命令行很给力,可以直接看到出问题的堆栈。例如~41s; .ecxr ; kvn。意思切换到41号线程,修复堆栈,显示堆栈。错误提示也蛮给力的,可以留意一下。

~72s //切换到72号线程(最后记得带s)

k命令显示当前线程调用堆栈、帧数、简单参数值,n表示帧号:

0:037> kvn
 # ChildEBP RetAddr  Args to Child              
00 06abfb7c 7c92df3c 7c93b22b 000008dc 00000000 ntdll!KiFastSystemCallRet (FPO: [0,0,0])
01 06abfb80 7c93b22b 000008dc 00000000 00000000 ntdll!NtWaitForSingleObject+0xc (FPO: [3,0,0])
02 06abfc08 7c921046 00ab61c8 769ad222 76ab61c8 ntdll!RtlpWaitForCriticalSection+0x132 (FPO: [Non-Fpo])
03 06abfc10 769ad222 76ab61c8 0b2cbd98 76ab61c0 ntdll!RtlEnterCriticalSection+0x46 (FPO: [1,0,0])
04 06abfc20 769afb04 0b2cbd98 00000080 00000001 ole32!COleStaticMutexSem::Request+0x59 (FPO: [0,0,0])
05 06abfdcc 769afd56 0b2cbd98 00000080 00000001 ole32!COIDTable::ThreadCleanup+0x32 (FPO: [Non-Fpo])
06 06abfdf8 769afca9 00000000 06abfe44 76ab67e8 ole32!FinishShutdown+0x69 (FPO: [Non-Fpo])
07 06abfe14 769af231 00000000 00000000 0b2cbd98 ole32!ApartmentUninitialize+0x7e (FPO: [Non-Fpo])
08 06abfe2c 769aee98 06abfe44 00000000 00000001 ole32!wCoUninitialize+0x41 (FPO: [Non-Fpo])
09 06abfe48 769dc269 00000001 76990000 769ad1ba ole32!CoUninitialize+0x5b (FPO: [Non-Fpo])
0a 06abfe54 769ad1ba 06abfe7c 769ad159 76990000 ole32!DoThreadSpecificCleanup+0x4f (FPO: [0,0,0])
0b 06abfe5c 769ad159 76990000 00000003 00000000 ole32!ThreadNotification+0x37 (FPO: [Non-Fpo])
0c 06abfe7c 769ad101 76990000 00000003 00000000 ole32!DllMain+0x147 (FPO: [Non-Fpo])
0d 06abfe9c 7c92118a 76990000 00000003 00000000 ole32!_DllMainCRTStartup+0x52 (FPO: [Non-Fpo])
0e 06abfebc 7c933a23 769ad0b9 76990000 00000003 ntdll!LdrpCallInitRoutine+0x14
0f 06abff34 7c80c126 0012f144 7c92e900 0190cd00 ntdll!LdrShutdownThread+0xd7 (FPO: [Non-Fpo])
10 06abff6c 7813299f 00000000 781329c1 00000000 kernel32!ExitThread+0x3e (FPO: [Non-Fpo])
11 06abff74 781329c0 00000000 371c30cd 0012f144 msvcr80!_endthreadex+0x1f (FPO: [1,0,0]) (CONV: cdecl) [f:\sp\vctools\crt_bld\self_x86\crt\src\threadex.c @ 412]
12 06abffac 78132a47 7c92e900 7c80b713 0190cd00 msvcr80!_callthreadstartex+0x20 (FPO: [Non-Fpo]) (CONV: cdecl) [f:\sp\vctools\crt_bld\self_x86\crt\src\threadex.c @ 348]
13 06abffb4 7c80b713 0190cd00 0012f144 7c92e900 msvcr80!_threadstartex+0x66 (FPO: [1,0,4]) (CONV: stdcall) [f:\sp\vctools\crt_bld\self_x86\crt\src\threadex.c @ 326]
14 06abffec 00000000 781329e1 0190cd00 00000000 kernel32!BaseThreadStart+0x37 (FPO: [Non-Fpo])

切换调用帧:

.frame 13

(来到上面堆栈的13帧:13 06abffb4 7c80b713 0190cd00 0012f144 7c92e900 msvcr80!_threadstartex+0x66 (FPO: [1,0,4]) (CONV: stdcall) [f:\sp\vctools\crt_bld\self_x86\crt\src\threadex.c @ 326]) 此命令挺好用的,如果源码在本地(建议本地有一份和编译服务器同样目录的源码),会直接跳转到相关代码。

然后可以用x命令,显示当前帧的局部变量、参数(this指针可以重点关注:dt this地址,局部变量查看窗口有时候查看不了具体内容,dt命令还是很好用的):

x命令:

运行x命令后,可以用dt命令行,显示各种代码级别的内容。例如dt CStringW 082efefc 指定地址转成CStringW来查看值。直接用du命令行查看此地址是不行的。 以上命令行方法,和vs点击堆栈,查看变量效果接近了。

将地址转为指定结构体: dt KHealthProxyImpl 0xfffffffc

切换到源码:

.open C:\Program Files (x86)\Microsoft Visual Studio 8\VC\crt\src\threadex.c

鼠标移到代码上,可以看到当前代码的局部变量、参数等。前提是当前线程当前帧,所以~s、.frame命令很重要。

dd wort、da ansic编码、du unicode编码、dds 根据地址还原堆栈(注意winapi中的context结构,可以用此命令行还原堆栈)

异常捕获的崩溃:

__CxxUnhandledExceptionFilter崩溃点(c、c++抛出异常,堆栈被运行库接管,需要还原堆栈): .cxr dwo(__CxxUnhandledExceptionFilter的第一个参数地址(左边开始第三个参数)+4)
然后kb(或kv、kvn)即可还原异常堆栈。
也可以用跟底层的命令还原堆栈:dt _CONTEXT __CxxUnhandledExceptionFilter的第一个参数地址,上面命令行可以获得ESP的地址,然后再用dds命令行还原ESP堆栈,命令为: dds ESP的地址 l100。
有些命令行是无限行数的,例如dW显示宽字节字符串、dds显示堆栈,记得这种命令行一定要带上l100,表示只显示100行,否则windbg会busy,不容易中断。

windbg断点调试:

可以做一些简单的技术逆向。

bu kernel32!CreateFileW

断点在kernel32.dll的CreateFileW函数,这个是dll的真正导出函数、不能用CreateFile这样的函数名,一定要指定W或A版本api。

触发断点后,kb查看堆栈。api参数顺序从左到右,第三个开始才是真实函数参数。如果像上面断点CreateFileW的例子,需要先f10单步一下,函数参数才入栈,才能看到正确的前三个参数,如果不想单步就查看函数参数,或者要看第3个后面的参数,需要用下面的方法:

poi是解引用,类似C/C++的*解引用指针,windbg里面看到的参数数值都是地址,需要解引用。如果不想单步就查看函数参数,或者查看超过的3个函数参数,可以这样打印当前函数的堆栈,du poi(esp+4)。esp+4是第一个参数、esp+8是第二个参数,依次类推。du是unicode字符串数据格式,如果整数换dd,其他格式类推。查看CreateFileW的7个参数,可以用以下方法一次性查看。类型需要根据参数变化而变化,例如%mu表示Unicode字符串,%ma表示ANSI字符串,%p表示整数。

//以下命令行可以打印前7个函数参数,如果参数数量不一样,可以自行减少、增加
.printf"%mu,%p,%p,%p,%p,%p,%p",poi(esp+4),poi(esp+8),poi(esp+c),poi(esp+10),poi(esp+14),poi(esp+18),poi(esp+1c)
.cls  // 清除屏幕
!gle //getlasterror

死锁:

定位卡死、通常是定位主线程卡死,因为其他线程卡死估计也暴露不了。。。
所以第一关注对象肯定是0号线程。
!locks查看所有的线程占用的锁
~*k
0号线程 wait -> x号线程
x号线程 wait -> y号线程
……
y号线程 wait ->0或x即会造成死锁
https://blog.csdn.net/xxin_w/article/details/8449855

内存:

查看分配的的内存:


!heap -a  
查看内存泄漏方法:  
!heap –s   
查看程序内存状况   
过一段时间再次通过!heap –s 查看程序内存状况。找出增长较快的内存块,如00b70000。  
!!heap -stat -h 00b70000 查看00b70000内存详细情况   
!heap -flt s 查进程中size=ea60的所有内存   
0:000> !heap -flt s ea60   
3.4 !heap -p –a 查看内存堆栈,定位泄露根源。   
0:000> !heap -p -a 71614e38   
0:000> !heap -p -a 721acf68   

https://blog.csdn.net/cuglifangzheng/article/details/50725890
https://blog.csdn.net/worldy/article/details/17888253

进程信息:

!runaway //显示当前进程中线程运行情况 vertarget //查看系统信息、系统运行时长System Uptime、进程启动时间Process Uptime !peb //查看进程信息(进程的ImageBaseAddress,进程的堆(Heap)起始地址, 装载了那些DLL,命令行参数,系统的环境变量,mimidump通常无效,可以查看0号线程堆栈,查看main函数参数) !teb//查看进程信息(栈(stack)的起始地址,Tls Storage的地址,异常处理的地址,LastError的值

 

C++异常栈回溯:

我们没有捕捉这个异常,所以一般是手动抓的dump才会有,一般异常被__scrt_unhandled_exception_filter接管了,用.exptr命令还原其第一个参数即可

00 11acd070 75dfe38b dcebcb30 11acd17c 11acd308 ucrtbase!abort+0x4b (FPO: [0,3,4])
01 11acd0a0 003c7c3e 00000000 00000000 11acd14c ucrtbase!terminate+0x3b (FPO: [Non-Fpo])
02 11acd0b0 760acab0 11acd17c 642d268e 00000000 kxecenter!__scrt_unhandled_exception_filter
03 11acd14c 773e2824 11acd17c 773b74c2 11acfa4c KERNELBASE!UnhandledExceptionFilter+0x1a0 (FPO: [Non-Fpo])

0:010> .exptr 11acd17c;kvn
00 11acd840 74338e69 e06d7363 00000001 00000003 KERNELBASE!RaiseException+0x62 (FPO: [4,22,0])
01 11acd878 74340e5d 11acd888 74395764 743770e8 MSVCR80!_CxxThrowException+0x46 (FPO: [Non-Fpo]) (CONV: stdcall) [f:\sp\vctools\crt_bld\self_x86\crt\prebuild\eh\throw.cpp @ 161]
02 11acd894 743b21b3 003aa3a1 00000020 11ace04d MSVCR80!operator new+0x69 (FPO: [Non-Fpo]) (CONV: cdecl) [f:\sp\vctools\crt_bld\self_x86\crt\src\new.cpp @ 63]
03 11acd8ac 743b2ad4 003aa3a1 00000000 6417c9a0 MSVCP80!std::_Allocate<char>+0x15 (FPO: [Non-Fpo]) (CONV: cdecl) [f:\sp\vctools\crt_bld\self_x86\crt\src\xmemory @ 44]
04 11acd8b8 6417c9a0 003aa3a1 00000000 00000000 MSVCP80!std::allocator<char>::allocate+0xb (FPO: [1,0,0]) (CONV: thiscall) [f:\sp\vctools\crt_bld\self_x86\crt\src\xmemory @ 152]
05 11acd8dc 6417c7f6 11ace16c 00000000 00000000 ksreng3!KSDllCanUnloadNow+0xa3af

 

堆破坏:

使用gflags提前暴露问题,gflags /p /enable kxetray.exe

 

 

如图所示,左边为没有使用gflags的情况,堆破坏造成错误的代码无法在发生堆破坏时 被发现;堆破坏所造成的后果往往是在随后的程序执行中显现出来。这种行为使得我们非常难以跟 踪堆破坏的源头。

当对指定进程名启用gflags后,指定进程的堆管理器将自动地使用某个填充模式来初始化所有内存。填充模式的内 容取决于堆块的状态。当堆块最初被返回给调用者时,堆管理器将用填充模式来填充堆块中用户可 访问的部分,其中在填充模式中包含的值就是baadf00do这表示这个堆块虽然被分配成功,但却 没有被初始化。如果有程序(例如我们的程序)在没有初始化这个堆块之前就对其执行解引用操作, 那么就会导致失败。另一方面,如果程序正确地初始化了堆块,那么程序将继续执行。在这个堆块 被释放之后,堆管理器将再次对堆块中用户可访问的部分进行填充,这一次使用的填充值是 feeefeee。调试器将再次通过这个填充模式来跟踪在释放之后的堆块上所发生的访问操作。在使 用内存之前没有对其进行初始化,这就是在程序中发生故障的原因。

 

备注:如果是gflags /p /enable kxetray.exe /full命令,会导致new大内存失败,结合之前看的一些崩溃的经验,真实用户是存在这种情况的,一般都是对大文件(毒霸的环境,很多M为单位的配置文件、数据库文件)读的时候new大内存,感觉这种new大内存是一种安全隐患,建议后续慢慢改成用内存文件映射,也能让我们的内存占用更优秀。

 

没有PDB怎么分析:

1、使用IDA对地址偏移进行分析

2、将代码回滚到对应文件版本号的状态,然后本地构建,强行加载对应的PDB文件

posted @ 2022-09-07 17:56  水云间月掌柜  阅读(473)  评论(0编辑  收藏  举报