X64 SEH的展开
来源:互联网 发布:ubuntu 升级python2.7 编辑:程序博客网 时间:2024/06/05 10:52
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_FUNCTIONtypedef 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 HandlerExceptionHandler 该域为一个RVA,指向exception handler的地址,ExceptionData 指向一个类似于scopetable 的地址如果Flags指定的是 UNW_FLAG_CHAININFO,该域为 RUNTIME_FUNCTIONUNWIND_CODEtypedef 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!add1Debugger function entry 00000000`003a0fc0 for:d:\work\temp\consoleapplication3\consoleapplication3.cpp(14)(00000001`3f501030) ConsoleApplication3!add1 | (00000001`3f5010e0) ConsoleApplication3!mainExact matches: ConsoleApplication3!add1 (int, int)BeginAddress = 00000000`00001030EndAddress = 00000000`000010d4UnwindInfoAddress = 00000000`00002670Unwind 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 8UWOP_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],edx00000001`3f501034 894c2408 mov dword ptr [rsp+8],ecx00000001`3f501038 4883ec48 sub rsp,48hprelog占用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!add1ConsoleApplication3!add1 [d:\work\temp\consoleapplication3\consoleapplication3.cpp @ 14]:00000001`3fc71030 89542410 mov dword ptr [rsp+10h],edx00000001`3fc71034 894c2408 mov dword ptr [rsp+8],ecx00000001`3fc71038 4883ec48 sub rsp,48h
(
此外我们也验证一下main函数的
:000> .fnent ConsoleApplication3!mainDebugger 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`000010e0EndAddress = 00000000`000010faUnwindInfoAddress = 00000000`000026a8Unwind info at 00000001`3fc726a8, 6 bytes version 1, flags 0, prolog 4, codes 1 00: offs 4, unwind op 2, op info 4UWOP_ALLOC_SMALL.//栈空间大小为(4+1)*8 =40 =0h280:000> u ConsoleApplication3!mainConsoleApplication3!main [d:\work\temp\consoleapplication3\consoleapplication3.cpp @ 43]:00000001`3fc710e0 4883ec28 sub rsp,28h//栈空间大小为0h2800000001`3fc710e4 ff15160f0000 call qword ptr [ConsoleApplication3!_imp_DebugBreak (00000001`3fc72000)]00000001`3fc710ea 33d2 xor edx,edx00000001`3fc710ec 33c9 xor ecx,ecx00000001`3fc710ee e83dffffff call ConsoleApplication3!add1 (00000001`3fc71030)00000001`3fc710f3 33c0 xor eax,eax00000001`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 ConsoleApplication3Browse full module liststart end module name00000001`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=000000000:000> gBreakpoint 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 Site00 00000000`002deba8 00000000`77c9812d ConsoleApplication3!_C_specific_handler01 00000000`002debb0 00000000`77c8855f ntdll!RtlDecodePointer+0xad02 00000000`002debe0 00000000`77cbbcb8 ntdll!RtlUnwindEx+0xbbf03 00000000`002df2c0 00000001`3fc71074 ntdll!KiUserExceptionDispatcher+0x2e04 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+0xd09 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
_CRTIMP __C_specific_handler( _In_ struct _EXCEPTION_RECORD *ExceptionRecord, _In_ void *EstablisherFrame, _Inout_ struct _CONTEXT *ContextRecord, _Inout_ struct _DISPATCHER_CONTEXT *DispatcherContext);
0:000> rrax=0000000000000000 rbx=00000000002e0000 rcx=00000000002df7b0rdx=00000000002df9c0 rsi=000000013fc7400c rdi=00000000002dd000rip=000000013fc71e10 rsp=00000000002deba8 rbp=00000000002df9c0 r8=00000000002df2c0 r9=00000000002dec70 r10=000000013fc71e10r11=000000013fc74000 r12=000000013fc71074 r13=0000000000000000r14=00000000002df7b0 r15=000000013fc70000iopl=0 nv up ei pl nz na pe nccs=0033 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00000202ConsoleApplication3!_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_RECORDConsoleApplication3!_EXCEPTION_RECORD +0x000 ExceptionCode : 0xc0000094 +0x004 ExceptionFlags : 0 +0x008 ExceptionRecord : (null) +0x010 ExceptionAddress : 0x00000001`3fc71074 Void //异常地址 +0x018 NumberParameters : 0 +0x020 ExceptionInformation : [15] 0x3fb95b0:000> !error 0xc0000094 //好像没有显示成功,查找网络0xC0000094: Integer division by zero
Error code: (NTSTATUS) 0xc0000094 (3221225620) - {
0:000> u 0x00000001`3fc71074ConsoleApplication3!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],eax00000001`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 @r8ConsoleApplication3!_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 L100000000`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+ 1ed00:000> gBreakpoint 1 hitConsoleApplication3!`add1'::`1'::filt$0:00000001`3fc71ed0 4055 push rbp0:000> k # Child-SP RetAddr Call Site00 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+0xa002 00000000`002debb0 00000000`77c8855f ntdll!RtlDecodePointer+0xad03 00000000`002debe0 00000000`77cbbcb8 ntdll!RtlUnwindEx+0xbbf04 00000000`002df2c0 00000001`3fc71074 ntdll!KiUserExceptionDispatcher+0x2e05 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+0xd0a 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],edx00000001`3fc71034 894c2408 mov dword ptr [rsp+8],ecx00000001`3fc71038 4883ec48 sub rsp,48h00000001`3fc7103c c744242000000000 mov dword ptr [rsp+20h],000000001`3fc71044 c744242c00000000 mov dword ptr [rsp+2Ch],000000001`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 nop00000001`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 cdq00000001`3fc71074 f77c2458 idiv eax,dword ptr [rsp+58h]00000001`3fc71078 89442420 mov dword ptr [rsp+20h],eax00000001`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,eax00000001`3fc71099 8bc1 mov eax,ecx00000001`3fc7109b 89442428 mov dword ptr [rsp+28h],eax00000001`3fc7109f 8b442450 mov eax,dword ptr [rsp+50h]00000001`3fc710a3 99 cdq00000001`3fc710a4 8b4c2428 mov ecx,dword ptr [rsp+28h]00000001`3fc710a8 f7f9 idiv eax,ecx00000001`3fc710aa 89442420 mov dword ptr [rsp+20h],eax00000001`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 eax00000001`3fc710c7 89442420 mov dword ptr [rsp+20h],eax00000001`3fc710cb 8b442420 mov eax,dword ptr [rsp+20h]00000001`3fc710cf 4883c448 add rsp,48h00000001`3fc710d3 c3 ret00000001`3fc710d4 cc int 300000001`3fc710d5 cc int 300000001`3fc710d6 cc int 300000001`3fc710d7 cc int 300000001`3fc710d8 cc int 300000001`3fc710d9 cc int 300000001`3fc710da cc int 300000001`3fc710db cc int 300000001`3fc710dc cc int 300000001`3fc710dd cc int 300000001`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
- X64 SEH的展开
- x64的seh
- 关于SEH局部展开的一点思考
- dump x64 seh
- SEH X64(1)
- SEH X64(2)
- SEH X64(3)
- SEH链和展开操作
- SEH分析笔记(X64篇)
- SEH分析笔记(X64篇)
- SEH的综合
- SEH 的工作原理
- SEH
- SEH
- seh
- seh
- Windows异常世界历险记(一)——Windows系统用户级结构化异常处理机制(SEH)的基础知识和Unwind展开操作
- SEH 的机制的实现
- python抽象类、抽象方法的实现
- codeforces 890B. Vlad and Cafes
- 字符串编码解码的一点理解
- knn代码
- node.js那些事
- X64 SEH的展开
- 如何写高质量代码?
- 双向绑定伪代码
- 静态顺序表的一些操作
- Java| Java关键字-static,final比较
- Altium Designer 16学习笔记——原理图和PCB元件对应查找
- data为什么是一个函数
- 进程间通信
- 盒子模型