用户模拟异常的记录

Posted onetrainee

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了用户模拟异常的记录相关的知识,希望对你有一定的参考价值。

用户模拟异常的记录

  我们现在来分析一下用户模拟异常

 

1. 测试代码

 

 1 #include "pch.h"
 2 #include <iostream>
 3 void exceptiontest() {
 4     throw 1;
 5 
 6 }
 7 int main()
 8 {
 9 
10     exceptiontest();
11 }

 

二、分析过程

1. 使用 visual Studio 在 "throw 1"处下断点启动调试

 throw 1;
  00D91808  mov         dword ptr [ebp-0C8h],1  
  00D91812  push        offset __TI1H (0D99018h)  
  00D91817  lea         eax,[ebp-0C8h]  
  00D9181D  push        eax  
  00D9181E  call        __CxxThrowException@8 (0D9139Dh) 

 可以看到其首先进行了两个步骤:

  1)创建了一个局部变量1。

  2)向__CxxThrowException@8函数传入了一个 偏移地址 offset __TI1H (0D99018h) ,和 局部变量1 的地址。

2. 分析 _CxxThrowException函数传入参数:

  _CxxThrowException(
        void*           pExceptionObject,   // The object thrown
        _ThrowInfo*     pThrowInfo          // Everything we need to know about it
  )

  通过分析参数我们知道:

  1)第一个传入的一个指针pThrowInfo,我们需要知道该异常的有关信息(即 _EXCEPTION_RECORD类似模板)

  2)第二个是异常地址(1)

3. 分析在_CxxThrowException函数创建的一个结构体

 

static const EHExceptionRecord ExceptionTemplate = { // A generic exception record
            EH_EXCEPTION_NUMBER,            // Exception number
            EXCEPTION_NONCONTINUABLE,       // Exception flags (we don‘t do resume)
            nullptr,                           // Additional record (none)
            nullptr,                           // Address of exception (OS fills in)
            EH_EXCEPTION_PARAMETERS,        // Number of parameters
            {   EH_MAGIC_NUMBER1,           // Our version control magic number
                nullptr,                       // pExceptionObject
                nullptr,
#if EH_EXCEPTION_PARAMETERS == 4
                nullptr                        // Image base of thrown object
#endif
            }                      // pThrowInfo
        };
        EHExceptionRecord ThisException = ExceptionTemplate;    // This exception
61409708  mov         ecx,8  
6140970D  mov         esi,offset ExceptionTemplate (61401588h)  
61409712  lea         edi,[ThisException]  
61409715  rep movs    dword ptr es:[edi],dword ptr [esi]  

        //
        // Fill in the blanks:
        //
        ThisException.params.pExceptionObject = pExceptionObject;
61409770  mov         eax,dword ptr [pExceptionObject]  
61409773  mov         dword ptr [ebp-1Ch],eax  
        ThisException.params.pThrowInfo = pTI;
61409776  mov         ecx,dword ptr [pTI]  61409779  mov         dword ptr [ebp-18h],ecx  
#if _EH_RELATIVE_TYPEINFO
        PVOID ThrowImageBase = RtlPcToFileHeader((PVOID)pTI, &ThrowImageBase);
        ThisException.params.pThrowImageBase = ThrowImageBase;
#endif

 

  1)创建结构体的反汇编:如上面反汇编代码,lea edi,[ebp-x],使用 rep movs 一共传入8次(ecx),看上面结构体正好对起来。

  2)之后填写结构体,可以看到有异常号,发生异常时的信息,以及某些异常地址。

4. _CxxThrowException函数的作用

1 RaiseException( 
2     ThisException.ExceptionCode,
3     ThisException.ExceptionFlags,
4     ThisException.NumberParameters,
5     (PULONG_PTR)&ThisException.params );
6 }
  1)通过分析其函数最后进入一个 RaiseException 函数中。
   2)因此我们可以分析出该函数的作用是打包上层异常信息,创建 ThisException 结构,将其成员传递给 RaiseException。
5. RaiseException 函数分析

 

 

 1 .text:7C812A99 ; void __stdcall RaiseException(DWORD dwExceptionCode, DWORD dwExceptionFlags, DWORD nNumberOfArguments, const ULONG_PTR *lpArguments)
 2 .text:7C812A99                 public _RaiseException@16
 3 .text:7C812A99 _RaiseException@16 proc near            ; CODE XREF: OutputDebugStringA(x)+4F↓p
 4 .text:7C812A99                                         ; DATA XREF: .text:off_7C802654↑o ...
 5 .text:7C812A99
 6 .text:7C812A99 ExceptionRecord = EXCEPTION_RECORD ptr -50h
 7 .text:7C812A99 dwExceptionCode = dword ptr  8
 8 .text:7C812A99 dwExceptionFlags= dword ptr  0Ch
 9 .text:7C812A99 nNumberOfArguments= dword ptr  10h
10 .text:7C812A99 lpArguments     = dword ptr  14h
11 .text:7C812A99 arg_14          = word ptr  1Ch
12 .text:7C812A99 arg_18          = dword ptr  20h
13 .text:7C812A99
14 .text:7C812A99 ; FUNCTION CHUNK AT .text:7C8449F0 SIZE 00000008 BYTES
15 .text:7C812A99 ; FUNCTION CHUNK AT .text:7C84B6A4 SIZE 00000037 BYTES
16 .text:7C812A99
17 .text:7C812A99                 mov     edi, edi
18 .text:7C812A9B                 push    ebp
19 .text:7C812A9C                 mov     ebp, esp
20 .text:7C812A9E                 sub     esp, 50h
21 .text:7C812AA1                 mov     eax, [ebp+dwExceptionCode]
22 .text:7C812AA4                 and     [ebp+ExceptionRecord.ExceptionRecord], 0
23 .text:7C812AA8                 mov     [ebp+ExceptionRecord.ExceptionCode], eax
24 .text:7C812AAB                 mov     eax, [ebp+dwExceptionFlags]
25 .text:7C812AAE                 push    esi
26 .text:7C812AAF                 mov     esi, [ebp+lpArguments]
27 .text:7C812AB2                 and     eax, 1
28 .text:7C812AB5                 test    esi, esi
29 .text:7C812AB7                 mov     [ebp+ExceptionRecord.ExceptionFlags], eax
30 .text:7C812ABA                 mov     [ebp+ExceptionRecord.ExceptionAddress], offset _RaiseException@16 ; RaiseException(x,x,x,x)
31 .text:7C812AC1                 jz      loc_7C812B60
32 .text:7C812AC7                 mov     ecx, [ebp+nNumberOfArguments]
33 .text:7C812ACA                 cmp     ecx, 0Fh
34 .text:7C812ACD                 ja      loc_7C8449F0
35 .text:7C812AD3
36 .text:7C812AD3 loc_7C812AD3:                           ; CODE XREF: RaiseException(x,x,x,x)+31F5A↓j
37 .text:7C812AD3                 test    ecx, ecx
38 .text:7C812AD5                 mov     [ebp+ExceptionRecord.NumberParameters], ecx
39 .text:7C812AD8                 jz      short loc_7C812AE1
40 .text:7C812ADA                 push    edi
41 .text:7C812ADB                 lea     edi, [ebp+ExceptionRecord.ExceptionInformation]
42 .text:7C812ADE                 rep movsd
43 .text:7C812AE0                 pop     edi
44 .text:7C812AE1
45 .text:7C812AE1 loc_7C812AE1:                           ; CODE XREF: RaiseException(x,x,x,x)+3F↑j
46 .text:7C812AE1                                         ; RaiseException(x,x,x,x)+CB↓j
47 .text:7C812AE1                 lea     eax, [ebp+ExceptionRecord]
48 .text:7C812AE4                 push    eax             ; ExceptionRecord
49 .text:7C812AE5                 call    ds:__imp__RtlRaiseException@4 ; RtlRaiseException(x)
50 .text:7C812AEB                 pop     esi
51 .text:7C812AEC                 leave
52 .text:7C812AED                 retn    10h

 

  其在 kernel32.dll 中,我们采用IDA静态分析该函数

  1)在这里,我们终于遇见 EXCEPTION_RECORD 这个结构体

  kd> 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

  2)该函数的目的就是 包装好 EXCEPTION_RECORD 结构体,然后调用下一层内核中的函数 RtlRaiseException。

  3)需要注意一点,是用户层触发的异常, ExceptionFlags为1,如果是内核触发的异常, ExceptionFlags为0。

 

    and eax,

    test esi, esi  

    jz      loc_7C812B60   

    1> 当发现为用户层,将参数个数清零,之后直接调用  RtlRaiseException                                                        2>                                                                                                                                                                       

 

以上是关于用户模拟异常的记录的主要内容,如果未能解决你的问题,请参考以下文章

用户异常与模拟异常的派发

Python+Selenium自动化模拟用户登录(备注:记录一次强行卸载rpm依赖包,引发的rpmyum等命令异常,无法远程xftp工具)

片段中的 EditText 上的空指针异常 [重复]

用于从 cloudkit 检索单列的代码模式/片段

华为OD机试模拟题用 C++ 实现 - 异常的打卡记录(2023.Q1)

不立即分离片段