回到异常现场
拿到一个dump文件,使用k命令进行栈回溯的时候,可能无法正常显示函数名,产生这样的问题的原因是dump文件显示的上下文信息是写入转储文件时的上下文,我们首先需要想办法切换到发生异常的时候的上下文。
windows系统的用户态转储文件专门定义了一种记录异常信息的数据块。称为异常数据流,数据结构为MINIDUMP_EXCEPTION_STREAM。使用.ecxr命令
可以读取异常数据流,从而回到异常现场。可以看到当前函数为RtlRaiseStatus
。这是一个抛出异常的函数
何人触雷
使用kn
查看是和调用了上述函数,发现01号栈帧无法识别函数。为什么无法识别呢??下一节解释,既然我们无法由栈顶到栈底分析,我们反向分析,也就是说从函数的调用者分析。
我们知道函数的返回地址一个在函数调用处的下5个字节(call一般长5字节)。也就是说函数的返回地址一定在父函数内部。由此,我们利用函数的返回值,去反向反汇编向前反汇编出函数的调用处。利用ub retaddr
命令即可完成。
代码流放
为什么利用kn无法完全识别函数呢?原因在于编译器优化将执行概率高的代码尽可能放在一起,这样可以减少页面置换的发生,而需要移动其他代码才能放置这些高概率发生的代码。这些被移动的代码就是一些异常处理的函数代码,因为他们不经常被使用。优化器移动代码却不移动符号,这样调试器无法识别原本函数。
事出何因
使用uf [funname]
可以反汇编出函数所有代码。通过搜索地址的方式,将问题定位到了ZwSetEvent。如果函数返回失败,经过两次跳转,调用RtlRaiseStatus函数。抛出异常。
那个句柄
查看参数传递的情况,判断问题所在。