首页 > 其他分享 >x64 APP栈回溯原理

x64 APP栈回溯原理

时间:2023-02-04 16:26:21浏览次数:57  
标签:ConsoleApplication3 00 UNWIND 00000000 00000001 APP x64 回溯 rsp

[原创]关于X64程序中RUNTIME_FUNCTION,UNWIND_INFO,UNWIND_CODE结构理解   2021-2-3 19:27  4012

X64程序会生成一个Pdata段,用于记录每个函数的栈帧和异常信息,结构如下:
struct RUNTIME_FUNCTION
{
void __ptr32 FunctionStart;
void 
ptr32 FunctionEnd;
void *ptr32 UnwindInfo;
};
FunctionStart起始位置(RVA)
FunctionEnd结束位置(RVA)
UnwindInfo信息描述(RVA)
本人ida反汇编中RUNTIME_FUNCTION的一条信息(以下就用这条信息做介绍)
RUNTIME_FUNCTION <rva sub_180006840, rva loc_180006874, rva stru_1801FADC8>
起始位置
text:0000000180006840 sub_180006840 proc near
.text:0000000180006840 4C 89 44 24 18 mov [rsp+arg_10], r8
.text:0000000180006845 4C 89 4C 24 20 mov [rsp+arg_18], r9
.text:000000018000684A 53 push rbx
.text:000000018000684B 55 push rbp
.text:000000018000684C 56 push rsi
.text:000000018000684D 48 83 EC 40 sub rsp, 40h
.text:0000000180006851 33 DB xor ebx, ebx
结束位置(这里结束并不是函数结束)
loc_180006874: ; DATA XREF:
.text:0000000180006874 ; .rdata:00000001801FADF0↓o ...
.text:0000000180006874 48 89 7C 24 38 mov [rsp+58h+var_20], rdi

 

信息描述数据
stru_1801FADC8 UNWIND_INFO <1, 11h, 4, 0>

 

1801FADCC 11 72 UNWIND_CODE <11h, 72h> ; UWOP_ALLOC_SMALL
1801FADCE 0D 60 UNWIND_CODE <0Dh, 60h> ; UWOP_PUSH_NONVOL
1801FADD0 0C 50 UNWIND_CODE <0Ch, 50h> ; UWOP_PUSH_NONVOL
1801FADD2 0B 30 UNWIND_CODE <0Bh, 30h> ; UWOP_PUSH_NONVOL
信息描述是一个UNWIND_INFO结构体,其中第三个参数4代表有四个UNWIND_CODE 数据,UNWIND_CODE可以理解成伪指令,用于描述这段代码对栈的操作,第一个UNWIND_CODE是在栈上分配内存(sub rsp,*),11代表起始位置偏移,也就是(180006840+11),地址0x180006851这条地址的上一条指令就是sub rsp,40h,第二个UNWIND_CODE的0D是可以理解成伪指令,对应的操作是push rsi,第三条OC代表push rbp,第四条 0B代表push rbx,所以X86没有像X86一样通过ebp来进行栈回溯,而是通过.pdata段中的RUNNING_FUNCTION 直接找到栈中的返回地址,从而实现栈回溯,编译器已经把所有函数的结构生成在PE文件中
以上如有错误希望大佬指出


[招生]科锐逆向工程师培训46期预科班将于 2023年02月09日 正式开班

      收藏 ・3     点赞・1     打赏     分享
最新回复 (1)
  MarkHui 活跃值 2022-7-2 15:58
       2 楼   0
https://docs.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-runtime_function

X64 SEH的展开

于 2017-12-08 01:08:05 发布1603 收藏 分类专栏: 软件调试 版权   软件调试专栏收录该内容 12 篇文章1 订阅 订阅专栏

C++ 代码:

 

#include "stdafx.h"
#include <windows.h>


ULONG WINAPI FilterFunc(DWORD dwExceptionCode)
{
	return (dwExceptionCode == STATUS_INTEGER_DIVIDE_BY_ZERO) ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH;
}

int add1(int a,int b)
{
	int c = 0,d=0;
	__try
	{
		printf("a address=%p\n",&a);
		__try
		{
			printf("b address=%p\n", &b);
			c = a / b;
		}
		__except (FilterFunc(GetExceptionCode()))
		{
			printf("c address=%p\n", &c);
			c = a / (a + b);
		}

	}
	__except (EXCEPTION_EXECUTE_HANDLER)
	{
		printf("d address=%p\n", &d);
		c = c + 1;
	}

	return c;
}

#include <stdio.h> 
#include <Windows.h> 
int main()
{
	DebugBreak();
	add1(0,0);
	return 0;
}

百度云代码:SEH_Sample.zip

 

 

 

1 X64 的基本概念和结构体

 

相比于X86 在程序运行中动态构建SEH结构,X64-SEH 是静态的,其信息包含在PE文件中。下面我们首先看一下对应的结构,然后看看其提供的信息是否能够满足异常捕获以及异常处理的功能。

为异常处理和调试器支持展开数据


 

执行异常处理和调试支持所需的数据结构

RUNTIME_FUNCTION
typedef struct _RUNTIME_FUNCTION_ { 
    DWORD BeginAddress;                             // 函数起始地址 
    DWORD EndAddress;                                // 函数结束地址 
    DWORD UnwindInfoAddress;               // 展开信息地址看下面的_UNWIND_INFO 结构体    
}RUNTIME_FUNCTION , *_RUNTIME_FUNCTION ;
该结构在内存中必须为DWORD 对齐。所有的地址都是ImageBase 的 RVA 值。这些项已经经过排序了(按照BeginAddress升序排列),放置在PE32+ 的 .pdata节中。对于动态生成的函数,我们暂时不介绍。
UNWIND_INFO
// 
// Define unwind information flags. 
//
#define UNW_FLAG_NHANDLER 0x0 
#define UNW_FLAG_EHANDLER 0x1 
#define UNW_FLAG_UHANDLER 0x2 
#define UNW_FLAG_CHAININFO 0x4
上面四个标志依次代表:
既没有EXCEPT_FILTER也没有EXCEPT_HANDLER
有EXCEPT_FILTER 和 EXCEPT_HANDLER
有 FINALLY_HANDLER
有多个UNWIND_INFO 串联在一起,
typedef struct _UNWIND_INFO { 
    UCHAR Version : 3;                     // 版本信息,当前为1 
    UCHAR Flags : 5;                          // 对应上面的四个标志 
    UCHAR SizeOfProlog;                 // Prolog 的大小,单位是字节 
    UCHAR CountOfCodes;              // UNWIND_INFO 包含多少UNWIND_CODE结构 
    UCHAR FrameRegister : 4;   
    UCHAR FrameOffset : 4;  
    UNWIND_CODE UnwindCode[1];
// 
// unwind codes 数组后面是一个可选的DWROD 对齐的成员。此成员有两种可能,异常处理函数地址或者function table entry(flags中指定了UNW_FALGS_CHAININFO),如果是异常处理函数地址的话,它将为一个语言相关的异常处理数据 
// 
  union { 
      struct { //下面两个组成一个结构体,不是联合体,看清楚
          ULONG ExceptionHandler; 
          ULONG ExceptionData[]; 
      }; 
 
      RUNTIME_FUNCTION FunctionEntry; //如果上面的Flags指定的是 UNW_FLAG_CHAININFO,该联合体为 RUNTIME_FUNCTION
  }; 

} UNWIND_INFO, *PUNWIND_INFO;
UNWIND_INFO 结构体必须是DWORD 对齐的。
FrameRegister
如果不是0 的话,这个函数使用了帧指针,该值表示帧指针使用的非易失性寄存器的数目。与UNWIND_CODE中的成员使用相同的编码。
FrameOffset
如果FrameRegister 不为0,表示在刚建立栈帧时,应用于FP 寄存器的RSP 的缩放偏移量。实际的FP 为RSP+16*当前值,范围是0~240。这样允许将FP 寄存器指向本地动态栈帧的中间位置,然后通过更短的指令来提高代码密度(更多的 指令将可以使用8位带符号偏移形式)。
Unwind code 数组
这一系列的code 代表了prolog 中对于非易失性寄存器和RSP 寄存器的影响。由于对齐, 这个数组始终有偶数个,最后的一个成员可能未被使用。
Exception Handler
ExceptionHandler 该域为一个RVA,指向exception handler的地址,ExceptionData 指向一个类似于scopetable 的地址
如果Flags指定的是 UNW_FLAG_CHAININFO,该域为 RUNTIME_FUNCTION
UNWIND_CODE
typedef enum _UNWIND_OP_CODES {  
    UWOP_PUSH_NONVOL = 0, /* info == register number */  
    UWOP_ALLOC_LARGE,     /* no info, alloc size in next 2 slots */  
    UWOP_ALLOC_SMALL,     /* info == size of allocation / 8 - 1 */  
    UWOP_SET_FPREG,       /* no info, FP = RSP + UNWIND_INFO.FPRegOffset*16 */  
    UWOP_SAVE_NONVOL,     /* info == register number, offset in next slot */  
    UWOP_SAVE_NONVOL_FAR, /* info == register number, offset in next 2 slots */  
    UWOP_SAVE_XMM128,     /* info == XMM reg number, offset in next slot */  
    UWOP_SAVE_XMM128_FAR, /* info == XMM reg number, offset in next 2 slots */  
    UWOP_PUSH_MACHFRAME   /* info == 0: no error-code, 1: error-code */  
} UNWIND_CODE_OPS;  
  
typedef union _UNWIND_CODE {  
    struct {  
        UBYTE CodeOffset;  
        UBYTE UnwindOp : 4;  
        UBYTE OpInfo   : 4;  
    };  
    USHORT FrameOffset;  
} UNWIND_CODE, *PUNWIND_CODE;  
UNWIND_CODE结构体用来记录在proglog 中影响非易失性寄存器和RSP寄存器的序列。每个UNWIND_CODE有上述结构。其中,分别表示本操作在prolog中的offset,Unwind操作码,操作信息。该数组的排列按照prolog中的offset的降序排列。
 
 有些展开操作代码需要本地栈帧的一个无符号偏移。这个偏移是相对于固定栈申请而言的。如果UNWIND_INFO的Frame Register 成员为0,offset 是对RSP而言的,否则,offset 是相对于在建立栈帧的时候RSP 被存储的的地方。此时需要栈帧-栈帧寄存器的偏移(16*缩放帧寄存器在UNWIND_INFO中的偏移)。如果FP 寄存器被使用,所有使用offset的unwind code必须在prolog建立栈帧之后才可以使用。


 

2  查找add1函数的RUNTIME_FUNCTION

 使用windbg 

 

0:000> .fnent ConsoleApplication3!add1
Debugger function entry 00000000`003a0fc0 for:
d:\work\temp\consoleapplication3\consoleapplication3.cpp(14)
(00000001`3f501030)   ConsoleApplication3!add1   |  (00000001`3f5010e0)   ConsoleApplication3!main
Exact matches:
    ConsoleApplication3!add1 (int, int)


BeginAddress      = 00000000`00001030
EndAddress        = 00000000`000010d4
UnwindInfoAddress = 00000000`00002670


Unwind info at 00000001`3f502670, 10 bytes
  version 1, flags 1, prolog c, codes 1
  handler routine: ConsoleApplication3!_C_specific_handler (00000001`3f501e10), data 2
  00: offs c, unwind op 2, op info 8	UWOP_ALLOC_SMALL.

根据上面的信息,结合Study_PE+,从.pdata section中找到对应的信息

 

 

 

2 .pdada Section中寻找add1 UNW_INFO的信息

我们知道add1的UNW_INFO 的RVA是2670,所以我们使用PE工具得到FOA

 

 

3 add1的 UNW_INFO 解析

000000001A70: 09 0C 01 00

09的二进制00001 001 ,Flags:5  = 00001 ,Version:3 = 001 也就是说版本是1 。Flags是1,也就是#define UNW_FLAG_EHANDLER 0x1 。

0C 也就是prelog 占用的大小为0c , 可以用windbg看下,

     

00000001`3f501030 89542410        mov     dword ptr [rsp+10h],edx
00000001`3f501034 894c2408        mov     dword ptr [rsp+8],ecx
00000001`3f501038 4883ec48        sub     rsp,48h
prelog占用C大小

 

01  仅仅包含一个UNWIND_INFO 结构。需要注意的是unwind_info数组通常都是偶数出现,为了对齐,另外unwind_info是2字节的union联合体,所以这个例子应该占用4个字节,后两个字节用00 00 对齐

 

00  

    UCHAR FrameRegister : 4;   
    UCHAR FrameOffset : 4;  

 

000000001A74: 0C 82 00 00 

对应的是UNWIND_CODE结构,可以参考https://msdn.microsoft.com/zh-cn/library/ck9asaa9.aspx

CodeOffset为0C,即偏移为0C

UnwinOp为2 ,即UWOP_ALLOC_SMALL

OpInfo为8,即申请大小为(08+1)*8 = 72 =0h48

 

可以反汇编验证一下

 

0:000> u ConsoleApplication3!add1
ConsoleApplication3!add1 [d:\work\temp\consoleapplication3\consoleapplication3.cpp @ 14]:
00000001`3fc71030 89542410        mov     dword ptr [rsp+10h],edx
00000001`3fc71034 894c2408        mov     dword ptr [rsp+8],ecx
00000001`3fc71038 4883ec48        sub     rsp,48h

 

 此外我们也验证一下main函数的

 

:000> .fnent ConsoleApplication3!main
Debugger function entry 00000000`003a5140 for:
d:\work\temp\consoleapplication3\consoleapplication3.cpp(43)
(00000001`3fc710e0)   ConsoleApplication3!main   |  (00000001`3fc71100)   ConsoleApplication3!__vcrt_va_start_verify_argument_type<char const * __ptr64 const>
Exact matches:
    ConsoleApplication3!main (void)

BeginAddress      = 00000000`000010e0
EndAddress        = 00000000`000010fa
UnwindInfoAddress = 00000000`000026a8

Unwind info at 00000001`3fc726a8, 6 bytes
  version 1, flags 0, prolog 4, codes 1
  00: offs 4, unwind op 2, op info 4	UWOP_ALLOC_SMALL.//栈空间大小为(4+1)*8 =40 =0h28

0:000> u ConsoleApplication3!main
ConsoleApplication3!main [d:\work\temp\consoleapplication3\consoleapplication3.cpp @ 43]:
00000001`3fc710e0 4883ec28        sub     rsp,28h//栈空间大小为0h28
00000001`3fc710e4 ff15160f0000    call    qword ptr [ConsoleApplication3!_imp_DebugBreak (00000001`3fc72000)]
00000001`3fc710ea 33d2            xor     edx,edx
00000001`3fc710ec 33c9            xor     ecx,ecx
00000001`3fc710ee e83dffffff      call    ConsoleApplication3!add1 (00000001`3fc71030)
00000001`3fc710f3 33c0            xor     eax,eax
00000001`3fc710f5 4883c428        add     rsp,28h 
00000001`3fc710f9 c3              ret

 

剩下的00 00是为了对齐

 

unwind_info 和unwind_code主要为了发生异常的时候,SEH可以根据这个信息进行栈回滚。

   这样在x64 中,MSC 为几乎所有的函数都登记了完备的信息,用来在展开过程中完整的回滚函数所做的栈、寄存器操作。登记的信息包括:
       函数是否使用了 SEH、
       函数使用的是什么组合的 SEH(__try/__except?__try/__finally?)、
       函数申请了多少栈空间、
       函数保存了哪些寄存器、
       函数是否建立了栈帧,
       等等,
       同时也记录了这些操作的顺序(以保证回滚的时候不会乱套)。

 

 

000000001A78: 10 1E 00 00

这里是一个异常处理函数的RVA,我们可用windbg断下看下。

步骤 

  

0:000> lmvm ConsoleApplication3
Browse full module list
start             end                 module name
00000001`3fc70000 00000001`3fc78000   ConsoleApplication3 C (private pdb symbols)  D:\work\temp\ConsoleApplication3\x64\Release\ConsoleApplication3.pdb
    Loaded symbol image file: D:\work\temp\ConsoleApplication3\x64\Release\ConsoleApplication3.exe
    Image path: D:\work\temp\ConsoleApplication3\x64\Release\ConsoleApplication3.exe
    Image name: ConsoleApplication3.exe
    Browse all global symbols  functions  data
    Timestamp:        Thu Dec 07 23:40:44 2017 (5A2960FC)
    CheckSum:         00000000
    ImageSize:        00008000
    Translations:     0000.04b0 0000.04e4 0409.04b0 0409.04e4

 

 对RVA异常函数加断点

 

0:000> bp 00000001`3fc70000 + 1e10
当发生异常的时候就会断下

 

 

0:000> g
(1458.210c): Integer divide-by-zero - code c0000094 (first chance)//这是DIV 0的第一次机会
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
ConsoleApplication3!add1+0x44:
00000001`3fc71074 f77c2458        idiv    eax,dword ptr [rsp+58h] ss:00000000`002dfa18=00000000
0:000> g
Breakpoint 0 hit //断点断下
*** ERROR: Symbol file could not be found.  Defaulted to export symbols for C:\Windows\SYSTEM32\ntdll.dll - 
ConsoleApplication3!_C_specific_handler:
*** ERROR: Symbol file could not be found.  Defaulted to export symbols for C:\Windows\system32\VCRUNTIME140.dll - 
00000001`3fc71e10 ff257a020000    jmp     qword ptr [ConsoleApplication3!_imp___C_specific_handler (00000001`3fc72090)] ds:00000001`3fc72090={VCRUNTIME140!_C_specific_handler (000007fe`f076bff0)}

0:000> kn
 # Child-SP          RetAddr           Call Site
00 00000000`002deba8 00000000`77c9812d ConsoleApplication3!_C_specific_handler
01 00000000`002debb0 00000000`77c8855f ntdll!RtlDecodePointer+0xad
02 00000000`002debe0 00000000`77cbbcb8 ntdll!RtlUnwindEx+0xbbf
03 00000000`002df2c0 00000001`3fc71074 ntdll!KiUserExceptionDispatcher+0x2e
04 00000000`002df9c0 00000001`3fc710f3 ConsoleApplication3!add1+0x44 [d:\work\temp\consoleapplication3\consoleapplication3.cpp @ 22]
05 00000000`002dfa10 00000001`3fc71409 ConsoleApplication3!main+0x13 [d:\work\temp\consoleapplication3\consoleapplication3.cpp @ 46]
06 (Inline Function) --------`-------- ConsoleApplication3!invoke_main+0x22 [f:\dd\vctools\crt\vcstartup\src\startup\exe_common.inl @ 64]
07 00000000`002dfa40 00000000`77a659cd ConsoleApplication3!__scrt_common_main_seh+0x11d [f:\dd\vctools\crt\vcstartup\src\startup\exe_common.inl @ 253]
08 00000000`002dfa80 00000000`77c9a561 kernel32!BaseThreadInitThunk+0xd
09 00000000`002dfab0 00000000`00000000 ntdll!RtlUserThreadStart+0x21

 

__C_specific_handler function

 

Called by the compiler to implement structured exception handling extensions.

The relative address of the language specific handler is present in the UNWIND_INFO whenever flags UNW_FLAG_EHANDLER or UNW_FLAG_UHANDLER are set. The language specific handler is called as part of the search for an exception handler or as part of an unwind. For more information see Language Specific Handler.

Syntax

C++  
_CRTIMP  __C_specific_handler(
  _In_    struct _EXCEPTION_RECORD   *ExceptionRecord,
  _In_    void                       *EstablisherFrame,
  _Inout_ struct _CONTEXT            *ContextRecord,
  _Inout_ struct _DISPATCHER_CONTEXT *DispatcherContext
);
 

 

 

0:000> r
rax=0000000000000000 rbx=00000000002e0000 rcx=00000000002df7b0
rdx=00000000002df9c0 rsi=000000013fc7400c rdi=00000000002dd000
rip=000000013fc71e10 rsp=00000000002deba8 rbp=00000000002df9c0
 r8=00000000002df2c0  r9=00000000002dec70 r10=000000013fc71e10
r11=000000013fc74000 r12=000000013fc71074 r13=0000000000000000
r14=00000000002df7b0 r15=000000013fc70000
iopl=0         nv up ei pl nz na pe nc
cs=0033  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000202
ConsoleApplication3!_C_specific_handler:
00000001`3fc71e10 ff257a020000    jmp     qword ptr [ConsoleApplication3!_imp___C_specific_handler (00000001`3fc72090)] ds:00000001`3fc72090={VCRUNTIME140!_C_specific_handler (000007fe`f076bff0)}
0:000> dt 00000000002df7b0 _EXCEPTION_RECORD
ConsoleApplication3!_EXCEPTION_RECORD
   +0x000 ExceptionCode    : 0xc0000094
   +0x004 ExceptionFlags   : 0
   +0x008 ExceptionRecord  : (null) 
   +0x010 ExceptionAddress : 0x00000001`3fc71074 Void //异常地址
   +0x018 NumberParameters : 0
   +0x020 ExceptionInformation : [15] 0x3fb95b
0:000> !error 0xc0000094  //好像没有显示成功,查找网络

0xC0000094: Integer division by zero


Error code: (NTSTATUS) 0xc0000094 (3221225620) - {

0:000> u 0x00000001`3fc71074
ConsoleApplication3!add1+0x44 [d:\work\temp\consoleapplication3\consoleapplication3.cpp @ 22]:
00000001`3fc71074 f77c2458        idiv    eax,dword ptr [rsp+58h] //这里处理问题
00000001`3fc71078 89442420        mov     dword ptr [rsp+20h],eax
00000001`3fc7107c eb30            jmp     ConsoleApplication3!add1+0x7e (00000001`3fc710ae)
00000001`3fc7107e 488d542420      lea     rdx,[rsp+20h]
00000001`3fc71083 488d0da6110000  lea     rcx,[ConsoleApplication3!GS_ExceptionPointers+0x30 (00000001`3fc72230)]
00000001`3fc7108a e8e1000000      call    ConsoleApplication3!printf (00000001`3fc71170)
00000001`3fc7108f 8b442458        mov     eax,dword ptr [rsp+58h]
00000001`3fc71093 8b4c2450        mov     ecx,dword ptr [rsp+50h]


此时我们需要知道此时的寄存器等信息,这个保存在了第三个参数(X64 参数顺序 rcx rdx r8 r9),

 

 

0:000> dt _CONTEXT @r8
ConsoleApplication3!_CONTEXT
   +0x000 P1Home           : 0x2df7b0
   +0x008 P2Home           : 0x2df2c0
   +0x010 P3Home           : 0
   +0x018 P4Home           : 0
   +0x020 P5Home           : 0x000007fe`f3ac55f0
   +0x028 P6Home           : 0x3fb940
   +0x030 ContextFlags     : 0x10005f
   +0x034 MxCsr            : 0x1f80
   +0x038 SegCs            : 0x33
   +0x03a SegDs            : 0x2b
   +0x03c SegEs            : 0x2b
   +0x03e SegFs            : 0x53
   +0x040 SegGs            : 0x2b
   +0x042 SegSs            : 0x2b
   +0x044 EFlags           : 0x10206
   +0x048 Dr0              : 0
   +0x050 Dr1              : 0
   +0x058 Dr2              : 0
   +0x060 Dr3              : 0
   +0x068 Dr6              : 0
   +0x070 Dr7              : 0
   +0x078 Rax              : 0
   +0x080 Rcx              : 0x000007fe`f3ac4198
   +0x088 Rdx              : 0
   +0x090 Rbx              : 0x000007fe`f3ac59f4
   +0x098 Rsp              : 0x2df9c0
   +0x0a0 Rbp              : 0
   +0x0a8 Rsi              : 0
   +0x0b0 Rdi              : 0x000007fe`f3ac5a10
   +0x0b8 R8               : 0x2ddc98
   +0x0c0 R9               : 0x3fb95b
   +0x0c8 R10              : 0
   +0x0d0 R11              : 0x2df890
   +0x0d8 R12              : 0
   +0x0e0 R13              : 0
   +0x0e8 R14              : 0
   +0x0f0 R15              : 0
   +0x0f8 Rip              : 0x00000001`3fc71074
   +0x100 FltSave          : _XSAVE_FORMAT
   +0x100 Header           : [2] _M128A
   +0x120 Legacy           : [8] _M128A
   +0x1a0 Xmm0             : _M128A
   +0x1b0 Xmm1             : _M128A
   +0x1c0 Xmm2             : _M128A
   +0x1d0 Xmm3             : _M128A
   +0x1e0 Xmm4             : _M128A
   +0x1f0 Xmm5             : _M128A
   +0x200 Xmm6             : _M128A
   +0x210 Xmm7             : _M128A
   +0x220 Xmm8             : _M128A
   +0x230 Xmm9             : _M128A
   +0x240 Xmm10            : _M128A
   +0x250 Xmm11            : _M128A
   +0x260 Xmm12            : _M128A
   +0x270 Xmm13            : _M128A
   +0x280 Xmm14            : _M128A
   +0x290 Xmm15            : _M128A
   +0x300 VectorRegister   : [26] _M128A
   +0x4a0 VectorControl    : 0x00000020`00001000
   +0x4a8 DebugControl     : 0x1000000
   +0x4b0 LastBranchToRip  : 0
   +0x4b8 LastBranchFromRip : 0
   +0x4c0 LastExceptionToRip : 0
   +0x4c8 LastExceptionFromRip : 0

+0x078 Rax              : 0
   +0x098 Rsp              : 0x2df9c0

 

 

0:000> dq 0x2df9c0+58 L1
00000000`002dfa18  00000000`00000000

 

 

EAX/0 导致异常。


剩下的是SCOPE_TABLE结构

000000001A7C: 02 00 00 00

表示有两个ScopeRecord,剩下的数据是这两个ScopeRecord数据

 

000000001A80: 5E 10 00 00 7E 10 00 00 D0 1E 00 00 7E 10 00 00

第一个ScopeRecord 的对应关系

 

 

 

我们对Handler下断点

 

0:000> bp 00000001`3fc70000+ 1ed0
0:000> g
Breakpoint 1 hit
ConsoleApplication3!`add1'::`1'::filt$0:
00000001`3fc71ed0 4055            push    rbp
0:000> k
 # Child-SP          RetAddr           Call Site
00 00000000`002deb38 000007fe`f076c090 ConsoleApplication3!`add1'::`1'::filt$0 [d:\work\temp\consoleapplication3\consoleapplication3.cpp @ 24]
01 00000000`002deb40 00000000`77c9812d VCRUNTIME140!_C_specific_handler+0xa0
02 00000000`002debb0 00000000`77c8855f ntdll!RtlDecodePointer+0xad
03 00000000`002debe0 00000000`77cbbcb8 ntdll!RtlUnwindEx+0xbbf
04 00000000`002df2c0 00000001`3fc71074 ntdll!KiUserExceptionDispatcher+0x2e
05 00000000`002df9c0 00000001`3fc710f3 ConsoleApplication3!add1+0x44 [d:\work\temp\consoleapplication3\consoleapplication3.cpp @ 22]
06 00000000`002dfa10 00000001`3fc71409 ConsoleApplication3!main+0x13 [d:\work\temp\consoleapplication3\consoleapplication3.cpp @ 46]
07 (Inline Function) --------`-------- ConsoleApplication3!invoke_main+0x22 [f:\dd\vctools\crt\vcstartup\src\startup\exe_common.inl @ 64]
08 00000000`002dfa40 00000000`77a659cd ConsoleApplication3!__scrt_common_main_seh+0x11d [f:\dd\vctools\crt\vcstartup\src\startup\exe_common.inl @ 253]
09 00000000`002dfa80 00000000`77c9a561 kernel32!BaseThreadInitThunk+0xd
0a 00000000`002dfab0 00000000`00000000 ntdll!RtlUserThreadStart+0x21

发现会跳转到我们的处理函数中

 


 

000000001A90: 4C 10 00 00 B0 10 00 00 FB 1E 00 00 B0 10 00 00

第二个ScopeRecord可以同样分析。

 

C++对应的汇编

 

ConsoleApplication3!add1:
00000001`3fc71030 89542410        mov     dword ptr [rsp+10h],edx
00000001`3fc71034 894c2408        mov     dword ptr [rsp+8],ecx
00000001`3fc71038 4883ec48        sub     rsp,48h
00000001`3fc7103c c744242000000000 mov     dword ptr [rsp+20h],0
00000001`3fc71044 c744242c00000000 mov     dword ptr [rsp+2Ch],0
00000001`3fc7104c 488d542450      lea     rdx,[rsp+50h]
00000001`3fc71051 488d0db8110000  lea     rcx,[ConsoleApplication3!GS_ExceptionPointers+0x10 (00000001`3fc72210)]
00000001`3fc71058 e813010000      call    ConsoleApplication3!printf (00000001`3fc71170)
00000001`3fc7105d 90              nop
00000001`3fc7105e 488d542458      lea     rdx,[rsp+58h]
00000001`3fc71063 488d0db6110000  lea     rcx,[ConsoleApplication3!GS_ExceptionPointers+0x20 (00000001`3fc72220)]
00000001`3fc7106a e801010000      call    ConsoleApplication3!printf (00000001`3fc71170)
00000001`3fc7106f 8b442450        mov     eax,dword ptr [rsp+50h]
00000001`3fc71073 99              cdq
00000001`3fc71074 f77c2458        idiv    eax,dword ptr [rsp+58h]
00000001`3fc71078 89442420        mov     dword ptr [rsp+20h],eax
00000001`3fc7107c eb30            jmp     ConsoleApplication3!add1+0x7e (00000001`3fc710ae)
00000001`3fc7107e 488d542420      lea     rdx,[rsp+20h]
00000001`3fc71083 488d0da6110000  lea     rcx,[ConsoleApplication3!GS_ExceptionPointers+0x30 (00000001`3fc72230)]
00000001`3fc7108a e8e1000000      call    ConsoleApplication3!printf (00000001`3fc71170)
00000001`3fc7108f 8b442458        mov     eax,dword ptr [rsp+58h]
00000001`3fc71093 8b4c2450        mov     ecx,dword ptr [rsp+50h]
00000001`3fc71097 03c8            add     ecx,eax
00000001`3fc71099 8bc1            mov     eax,ecx
00000001`3fc7109b 89442428        mov     dword ptr [rsp+28h],eax
00000001`3fc7109f 8b442450        mov     eax,dword ptr [rsp+50h]
00000001`3fc710a3 99              cdq
00000001`3fc710a4 8b4c2428        mov     ecx,dword ptr [rsp+28h]
00000001`3fc710a8 f7f9            idiv    eax,ecx
00000001`3fc710aa 89442420        mov     dword ptr [rsp+20h],eax
00000001`3fc710ae eb1b            jmp     ConsoleApplication3!add1+0x9b (00000001`3fc710cb)
00000001`3fc710b0 488d54242c      lea     rdx,[rsp+2Ch]
00000001`3fc710b5 488d0d84110000  lea     rcx,[ConsoleApplication3!GS_ExceptionPointers+0x40 (00000001`3fc72240)]
00000001`3fc710bc e8af000000      call    ConsoleApplication3!printf (00000001`3fc71170)
00000001`3fc710c5 ffc0            inc     eax
00000001`3fc710c7 89442420        mov     dword ptr [rsp+20h],eax
00000001`3fc710cb 8b442420        mov     eax,dword ptr [rsp+20h]
00000001`3fc710cf 4883c448        add     rsp,48h
00000001`3fc710d3 c3              ret
00000001`3fc710d4 cc              int     3
00000001`3fc710d5 cc              int     3
00000001`3fc710d6 cc              int     3
00000001`3fc710d7 cc              int     3
00000001`3fc710d8 cc              int     3
00000001`3fc710d9 cc              int     3
00000001`3fc710da cc              int     3
00000001`3fc710db cc              int     3
00000001`3fc710dc cc              int     3
00000001`3fc710dd cc              int     3
00000001`3fc710de cc              int     3


 

扩展话题:

windbg 在X64的栈回溯,也是利用了RUNTIME_FUNCTION的信息

1 得到函数的任意RIP - EXE的基地址的地址差值RVA,然后遍历.pdata找到这个差值所在的RUNTIME_FUNCTION信息,得到本函数的栈空间大小,可以直接使用.fnent @rip

2 根据上面函数的返回地址替代RIP,重复上面的第一个步骤

3 重复上面所有步骤就可以得到X64的栈.

 

 

 

 

 

 

参考:

https://www.cnblogs.com/lanrenxinxin/p/4762858.html

http://blog.csdn.net/qq_18218335/article/details/72722320

 

后补:

C++代码解析SEH

http://blog.csdn.net/Shevacoming/article/details/7826527

标签:ConsoleApplication3,00,UNWIND,00000000,00000001,APP,x64,回溯,rsp
From: https://www.cnblogs.com/ioriwellings/p/17091762.html

相关文章

  • uni-app + .NET 7实现微信小程序订阅消息推送
    微信小程序的订阅消息是小程序的重要能力之一,为实现服务的闭环提供更优的体验。订阅消息我们应该经常见到,比如下单成功之后的服务通知,支付成功后的支付成功通知,都属于小程......
  • 陪诊app开发|陪诊陪护系统功能
    陪诊app开发可以在生活中给大家带来什么帮助呢?大家每一个人都会有比较忙的时间,没时间陪长者或者朋友去看病,但是有时又必须有人照顾,所以陪诊app重要性就凸显出来了,在用户需要......
  • uniapp开发并调试钉钉H5微应用
    首先要在钉钉开放平台上创建出一个企业内部应用,然后配置这个应用的地址,ip之类写在前面:开发时要调试钉钉H5页面,我用到了两种办法 1.直接在服务器上改 2......
  • Axure App 垂直滚动
    拖两个动态面版最外层【动态面板】用来定义显示区域,高度:692(根据实际来)里面的【动态面板】,用来放内容,高度根据实际情况来,示例中是:1920如下图所示里面的【动态面板】添加垂直......
  • 回溯法学习笔记
    回溯法学习笔记目录回溯法学习笔记1,什么是回溯法2,什么时候使用回溯法3,回溯法的套路4,例题1,什么是回溯法回溯法其实是一种使用递归的暴力搜索法2,什么时候使用回溯法在常......
  • Lala Land and Apple Trees
    Description:AmrlivesinLalaLand.LalaLandisaverybeautifulcountrythatislocatedonacoordinateline.LalaLandisfamouswithitsappletreesgrowing......
  • 淘宝天猫商品详情爬取方案app详情sku数据如何获取?
    背景商品详情包含了非常多的数据,如sku、价格、库存、店铺名称、店铺logo、开店时间、旺旺、主图、标题等等,很多行业都有需要,比如电商相关行业、淘客、电商软件等都需要用到......
  • uniapp在微信小程序中图片宽度显示问题
    在uniapp中,如果你的富文本图片显示宽度不正常,你可以通过设置图片的宽高属性来解决这个问题。例如,你可以在富文本中添加以下代码来设置图片的宽度为100%:<imgsrc="your_ima......
  • uniapp时间格式化处理
    应用需求分析:前台页面有时需要展示YYYY-MM-DD格式,但后台却返回给我们YYYY-MM-DDhh:mm:ss、或者是一串字符//格式化处理方式一:dateFormat(time){......
  • app自动化遍历工具appcrawler
    monkey测试的缺点,测试太随机,功能比较深的页面可能点击不到自动遍历可以制定规则,指定页面,指定点击控件元素范围(Textview显示文字,EditText输入框,Button按钮,ImageView图片等),......