首页
社区
课程
招聘
[原创]如何快速从 32 位转储文件中找到异常发生时的线程上下文
发表于: 2023-10-15 15:27 9590

[原创]如何快速从 32 位转储文件中找到异常发生时的线程上下文

2023-10-15 15:27
9590

在上一篇文章中介绍了如何在 64 位进程的转储文件中查找异常上下文的方法 —— KiUserExceptionDispatcher() 函数对应栈帧的 Child-SP 的值保存了异常发生时的线程上下文。

本文将介绍如何在 32 位进程及 wow64 进程的转储文件中查找异常上下文的方法,并且会先介绍几个跟异常分发相关的函数和结构体。如果忘记了结论,可以根据函数参数手动逆向查找验证。

因为 32 位进程中的函数参数可以通过 ebp 进行定位 —— ebp+8 指向第一个参数,ebp+c 指向第二个参数 ...(对调用约定不是 fastcall 的函数有效,一般系统 API 都是 stdcall),每个函数的 ebp 值可以通过 k 命令列出来。如果知道了关键函数的参数,就可以快速定位到异常上下文了。

在查找前先介绍几个关键结构体及异常分发函数。

ntdll!KiUserExceptionDispatcher

ntdll!RtlDispatchException

kernel32!UnhandledExceptionFilter

CONTEXT

注意:文档中给出的 _CONTEXT64 位的定义,通过 dt 命令列出来的是 32 位的。

下面通过几个实例介绍如何在 32 位进程及 wow64 进程的转储文件中查找异常上下文。

基本上 32 位进程和 wow64 进程查找方法一样,不再单独分析,这里介绍几种典型情况。

下图是某个 32 位进程转储文件发生异常时的调用栈。

view-exception-callstack-32

从上图中可知,RtlDispatchException() 对应的 ebp0x0014f8e8UnhandledExceptionFilter() 对应的 ebp0x0014f7d0。从RtlDispatchException() 入手。

通过 dd 0014f8e8 命令可以得知 EXCEPTION_RECORD 的地址是 0x0014f900ebp+8 处的值),CONTEXT 的地址是 0x0014f91cebp+c 处的值)。

再通过 dt _EXCEPTION_RECORD 0014f900dt _CONTEXT 0014f91c 查看对应结构体的具体内容,可以发现是匹配的,如下图。

verify-exception-info-32

下图是某个 wow64 位进程转储文件发生异常时的调用栈。
view-exception-callstack-wow64

调用栈中只能看到 UnhandledExceptionFilter() ,对应的 ebp0x0097f474ebp+8 位置的值(0x0097f4a4 )存储了

_EXCEPTION_POINTERS* 的值(0x0097f4a4)。使用 dd 0097f4a4 L4 查看 _EXCEPTION_RECORD 的地址(0x0097f5e0 )和 _CONTEXT 的地址(0x0097f630)。然后再验证,发现是匹配的。郑国过程如下图:

verify-exception-info-wow64

32 位进程中的函数参数可以通过 ebp 进行定位。我觉得这是 32 位进程调试时相对于 64 位进程最友好的地方了,不用费劲到栈上找参数了。

可以通过 ntdll!RtlDispatchException()kernel32!UnhandledExceptionFilter() 的参数快速找到异常上下文。

void KiUserExceptionDispatcher(EXCEPTION_RECORD* exceptionRecord, CONTEXT* contextRecord);
void KiUserExceptionDispatcher(EXCEPTION_RECORD* exceptionRecord, CONTEXT* contextRecord);
BOOL RtlDispatchException(EXCEPTION_RECORD* exceptionRecord, CONTEXT* contextRecord);
BOOL RtlDispatchException(EXCEPTION_RECORD* exceptionRecord, CONTEXT* contextRecord);
LONG UnhandledExceptionFilter(_EXCEPTION_POINTERS* ExceptionInfo);
LONG UnhandledExceptionFilter(_EXCEPTION_POINTERS* ExceptionInfo);
typedef struct _EXCEPTION_POINTERS
{
  PEXCEPTION_RECORD ExceptionRecord;
  PCONTEXT          ContextRecord;
} EXCEPTION_POINTERS, *PEXCEPTION_POINTERS;
typedef struct _EXCEPTION_POINTERS
{
  PEXCEPTION_RECORD ExceptionRecord;
  PCONTEXT          ContextRecord;
} EXCEPTION_POINTERS, *PEXCEPTION_POINTERS;
0:000> dt _EXCEPTION_RECORD
ntdll!_EXCEPTION_RECORD
   +0x000 ExceptionCode    : Int4B
   +0x004 ExceptionFlags   : Uint4B
   +0x008 ExceptionRecord  : Ptr32 _EXCEPTION_RECORD
   +0x00c ExceptionAddress : Ptr32 Void
   +0x010 NumberParameters : Uint4B
   +0x014 ExceptionInformation : [15] Uint4B
0:000> dt _EXCEPTION_RECORD
ntdll!_EXCEPTION_RECORD
   +0x000 ExceptionCode    : Int4B
   +0x004 ExceptionFlags   : Uint4B
   +0x008 ExceptionRecord  : Ptr32 _EXCEPTION_RECORD
   +0x00c ExceptionAddress : Ptr32 Void
   +0x010 NumberParameters : Uint4B
   +0x014 ExceptionInformation : [15] Uint4B
0:000> dt _CONTEXT
ntdll!_CONTEXT
   +0x000 ContextFlags     : Uint4B
   +0x004 Dr0              : Uint4B
   +0x008 Dr1              : Uint4B
   +0x00c Dr2              : Uint4B
   +0x010 Dr3              : Uint4B
   +0x014 Dr6              : Uint4B
   +0x018 Dr7              : Uint4B
   +0x01c FloatSave        : _FLOATING_SAVE_AREA
   +0x08c SegGs            : Uint4B
   +0x090 SegFs            : Uint4B
   +0x094 SegEs            : Uint4B
   +0x098 SegDs            : Uint4B
   +0x09c Edi              : Uint4B
   +0x0a0 Esi              : Uint4B
   +0x0a4 Ebx              : Uint4B
   +0x0a8 Edx              : Uint4B
   +0x0ac Ecx              : Uint4B
   +0x0b0 Eax              : Uint4B
   +0x0b4 Ebp              : Uint4B
   +0x0b8 Eip              : Uint4B
   +0x0bc SegCs            : Uint4B
   +0x0c0 EFlags           : Uint4B
   +0x0c4 Esp              : Uint4B
   +0x0c8 SegSs            : Uint4B
   +0x0cc ExtendedRegisters : [512] UChar
0:000> dt _CONTEXT

[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!

收藏
免费 4
支持
分享
最新回复 (2)
雪    币: 940
活跃值: (9936)
能力值: ( LV13,RANK:385 )
在线值:
发帖
回帖
粉丝
2
windbg .help 有针对异常查看的命令.
   .exptr <address> - do .exr and .cxr for EXCEPTION_POINTERS
   .exr <address> - dump exception record at specified address

.exr解析异常记录结构. .exptr可以直接解析UnhandledExceptionFilter的参数.(异常结构体指针).

谢谢楼主分享优质知识.共同进步.
2023-10-17 11:27
1
雪    币: 8519
活跃值: (9122)
能力值: ( LV12,RANK:360 )
在线值:
发帖
回帖
粉丝
3
TkBinary windbg .help 有针对异常查看的命令. .exptr - do .exr and .cxr for EXCEPTION_POINTERS .exr - dump exce ...
感谢大佬,又学到了
2023-10-17 19:05
0
游客
登录 | 注册 方可回帖
返回
//