SEH
SEH is an exception handling mechanism provided by the Windows operating system, which is realized by using __try, __except, and __finally keywords in the program source code. Mainly used in anti-debugging.
Note:
SEH has a different structure than try.catch exception handling in C++. In terms of time, compared with C++’s try and catch exception handling, Microsoft first created the SEH mechanism, and then carried it into VC++. So SEH is an exception handling mechanism subordinate to VC ++ development tools and Windows operating system.
Exception handling during debugging
If an exception occurs inside the debugged process:
OS will first throw the exception to the debugging process. The debugger has almost all the permissions of the debugged. It can not only run and terminate the debugged, but also has the read and write permissions of the virtual memory and registers of the debugged process. In particular, all exceptions (errors) that occur inside the debuggee are handled by the debugger. Therefore, all exceptions (errors) that occur during debugging must be managed by the debugger first (the SEH of the debugged is pushed to the debugger according to the priority order). Like this, when an exception occurs in the debugged, the debugger will suspend the operation, and some measures must be taken to handle the exception, and continue debugging after completion.
- Several processing methods are often used when encountering exceptions:
- Modify exceptions directly: code, registers, memory
- Throw the exception to the debugee for handling
- OS default exception handling mechanism
Exceptions defined by the operating system
EXCEPTION_DATATYPE_MISALIGNMENT (0X80000002) EXCEPTION_BREAKPOINT (0X80000003) EXCEPTION_SINGLE_STEP (0x80000004) EXCEPTION_ACCESS_VIOLATION (0xC0000005) EXCEPTION_IN_PAGE_ERROR (0xC0000006) EXCEPTION_ILLEGAL_INSTRUCTION (0xC000001D) EXCEPTION_NONCONTINUABLE_EXCEPTION (0xC0000025) EXCEPTION_INVALID_DISPOSITION (0xC0000026) EXCEPTION_ARRAY_BOUNDS_EXCEEDED (0xC000008C) EXCEPTION_FLT_DENORMAL_OPERAND (0xC000008D) EXCEPTION_FLT_DIVIDE_BYZERO (0xC000008E) EXCEPTION_FLT_INEXACT_RESULT (0xC000008F) EXCEPTION_FLT_INVALID_OPERATION (0xC0000090) EXCEPTION_FLT_OVERFLOW (0xC0000091) EXCEPTION_FLT_STACK_CHECK (0xC0000092) EXCEPTION_FLT_UNDERFLOW (0xC0000093) EXCEPTION_INT_DIVIDE_BY_ZERO (0xC0000094) EXCEPTION_INT_OVERFLOW (0xC0000095) EXCEPTION_PRIV_INSTRUCTION (0xC0000096) EXCEPTION_STACK_OVERFLOW (0xC00000FD)
- common exception
EXCEPTION_ACCESS_VIOLATION(C0000005)
: illegal access exception, trying to access a memory area that does not exist or has no access rights.
EXCEPTION_BREAKPOINT(80000003)
: After the running code is set with a breakpoint, when the CPU tries to execute the instruction at the address, an EXCEPTION_BREAKPOINT exception will occur. The principle is that setting a breakpoint will modify the instruction at this place to 0xCC, but Ollydbg will not display the actual instruction of the temporary breakpoint. You can use the PE Tools tool to dump the process memory and open the file with Hex Editor to see It’s really an order.
EXCEPTION_ILLEGAL_INSTRUCTION(C000001D)
: This exception is thrown when the CPU encounters an instruction that cannot be parsed.
EXCEPTION_INT_DIVIDE_BY_ZERO(C0000094)
: If the denominator is zero in the division operation, a division by zero exception will occur. The situation that may occur in the program is that the denominator is a variable, and the variable becomes 0 at a certain moment, and an exception will occur when the division operation is performed.
EXCEPTION_SINGLE_STEP(80000004)
: After setting the eighth bit TF (Trap Flag trap flag) of the EFLAGS register to 1, the CPU will enter the single-step working mode. After each instruction is executed, it will pause and throw an exception.
SEH chain
SEH exists in the form of a chain, a linked list composed of _EXCEPTION_REGISTRATION_RECORD
structure
If the associated exception is not handled by the first exception handler, it is passed to the next exception handler until it is handled.
- SEH structure
typedef struct _EXCEPTION_REGISTRATION_RECORD {<!-- --> // The linked list ends with a structure whose Next member is FFFFFFFF, indicating the last node of the linked list PEXCEPTION_REGISTRATION_RECORD Next; // Handler: exception handling function PEXCEPTION_DISPOSITION Handler; } EXCEPTION_REGISTRATION_RECORD, *PEXCEPTION_REGISTRATION_RECORD; // The exception is passed along the chain until it is handled by an exception handler
Graphic representation
- exception handler
This function is a callback function, which is called by the system, and the system will provide the parameters required by the function
It can be seen from the definition that this function requires four parameters, and the return value is aenum
type
EXCEPTION_DISPOSITION_except_handler ( EXCEPTION_RECORD *pRecord, EXCEPTION_REGISTRATIOIN_RECORD *pFrame, CONTEXT *pContext, PVOID pValue );
The first parameter
typedef struct _EXCEPTION_RECORD {<!-- --> DWORD ExceptionCode; //Exception code, used to indicate the exception type DWORD ExceptionFlags; struct _EXCEPTION_RECORD * ExceptionRecord; PVOID ExceptionAddress; //The code address where the exception occurred DWORD NumberParameters; ULONG_PTR ExceptionInformation[EXCEPTION_AMXIMUM_PARAMETERS];//15 } EXCEPTION_RECORD, *PEXCEPTION_RECORD
The third parameter
struct CONTEXT {<!-- --> DWORD ContextFlags; DWORD Dr0; DWORD Dr1; DWORD Dr2; DWORD Dr3; DWORD Dr6; DWORD Dr7; FLOATING_SAVE_AREA FloatSave; DWORD SegGs; DWORD SegFs; DWORD SegEs; DWORD SegDs; DWORD Edi; DWORD Esi; DWORD Ebx; DWORD Edx; DWORD Ecx; DWORD Eax; DWORD Ebp; DWORD Eip; DWORD SegCs; DWORD EFlags; DWORD Esp; DWORD SegSs; BYTE ExtendedRegisters[MAXIMUM_SUPPORTED_EXTENSION];//512 }
return value
typedef enum_EXCEPTION_DISPOSITION {<!-- --> ExceptionContinueExecution = 0, //Continue to execute exception code ExceptionContinueSearch = 1, //run the next exception handler ExceptionNestedException = 2, //used inside the OS ExceptionCollidedUnwind = 3 //used internally by the OS } EXCEPTION_DISPOSITION;
The exception handler will return ExceptionContinueExecution(0)
after processing the exception, and continue running from the code where the exception occurred. If the exception cannot be handled, return ExceptionContinueSearch(1)
, and send a field to the next exception handler in the SEH chain.
- Methods to access the SEH chain of a process
Through the NtTib member of the TEB structure
TEB.NtTib.ExceptionList = FS:[0]
- Install SEH
In C language, SEH can be added to code by using __try, __except, __finally keywords.
compilation
PUSH @MyHandler PUSH DWORD PTR FS:[0] MOV DWORD PTR FS:[0], ESP
FS:[0]The address of TEB is stored here, the first member of TEB is the _NT_TIB structure, _NT_TIB< /strong> The first member of the structure is a structure pointer of type _EXCEPTION_REGISTRATION_RECORD, which is the first address of the SEH chain
- TEB structure
// Reference given by MSDN typedef struct _TEB {<!-- --> PVOID Reserved1[12]; PPEB ProcessEnvironmentBlock; PVOID Reserved2[399]; BYTE Reserved3[1952]; PVOID TlsSlots[64]; BYTE Reserved4[8]; PVOID Reserved5[26]; PVOID ReservedForOle; PVOID Reserved6[4]; PVOID TlsExpansionSlots; } TEB, *PTEB;
What WinDbg sees
+ 0x000 NtTib : _NT_TIB ... + 0x030 ProcessEnvironmentBlock : Ptr32_PEB
These are two important members, ProcessEnvironmentBlock
is the address of PEB
NtTib
structure:
typedef struct _NT_TIB //sizeof 1ch {<!-- --> 00h struct _EXCEPTION_REGISTRATION_RECORD *ExceptionList; //SEH chain entry 04h PVOID StackBase; //Stack base address 08h PVOID StackLimit; //Stack size 0ch PVOID SubSystemTib; union {<!-- --> PVOID FiberData; 10h DWORD Version; }; 14h PVOID ArbitraryUserPointer; 18h struct _NT_TIB *Self; //The linear address of the NT_TIB structure itself }NT_TIB; typedef NT_TIB *PNT_TIB;
Other
source of learning
- When an exception occurs in the process, if the SEH is not processed or the registered SEH does not exist. At this time, the
kernel32!UnhandledExceptionFIlter()
API of the system will be called. - This API will run the last exception handler of the system – Top Level Exception Filter or Last Exception Filter (the usual behavior is to pop up an error message box and terminate the process).
kernel32!UnhandledExceptionFilter()
calledntdll!QueryInformationProcess(ProcessDebugPort)
. to determine whether the process is being debugged. If debugging is in progress, the exception is passed to the debugger. Otherwise the system exception handler terminates the process.- The last exception handler of the system can be modified by
kernel32!SetUnhandledExceptionFilter()
. The function definition is as follows:
//Returns the address of the previous Top Level Exception Filter for easy recovery LPTOP_LEVEL_EXCEPTION_FILTER WINAPI SetUnhandledExceptionFilter( __in LPTOP_LEVEL_EXCEPTION_FILTER lpTopLevelExceptionFilter );
- The function definition of Top Level Exception Filter:
typedef struct _EXCEPTION_POINTERS{<!-- --> PEXCEPTION_RECORD ExceptionRecord; PCONTEXT ContextRecord; } EXCEPTION_POINTERS, *PEXCEPTION_POINTERS; LONG TopLevelExceptionFilter( PEXCEPTION_POINTER pExcept; );