winseh.h
4.95 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
#pragma once
// winseh.h
// 12/13/2013 jichi
// See: http://code.metager.de/source/xref/WebKit/Source/WebCore/platform/win/makesafeseh.asm
// See: http://jpassing.com/2008/05/20/fun-with-low-level-seh/
#ifdef _MSC_VER
# pragma warning (disable:4733) // C4733: Inline asm assigning to 'FS:0' : handler not registered as safe handler
#endif // _MSC_VER
#define SEH_RAISE (*(int*)0 = 0) // raise C000005, for debugging only
// Maximum number of nested SEH
// Default nested function count is 100, see: http://stackoverflow.com/questions/8656089/solution-for-fatal-error-maximum-function-nesting-level-of-100-reached-abor
#ifndef SEH_CAPACITY
# define SEH_CAPACITY 100
#endif // SEH_CAPACITY
enum { seh_capacity = SEH_CAPACITY };
typedef unsigned long seh_dword_t; // DWORD in <windows.h>
// 12/13/2013 jichi
// The list implementation is not thread-safe
extern seh_dword_t
seh_count // current number of exception handlers
, seh_handler // extern PEXCEPTION_ROUTINE seh_handler;
, seh_esp[seh_capacity] // LPVOID, current stack
, seh_eip[seh_capacity] // LPVOID, current IP address
, seh_eh[seh_capacity] // EXCEPTION_ROUTINE, current exception handler function address
;
/**
* Push SEH handler
* @param _label exception recover label which should be the same as seh_pop_
* @param _eh EXCEPTION_ROUTINE or 0
* @param _r1 scalar register name, such as eax
* @param _r2 counter register name, such as ecx
*
* Note: __asm prefix is needed to allow inlining macro
* I didn't pushad and popad which seems to be not needed
*
* For SEH, see:
* http://www.codeproject.com/Articles/82701/Win32-Exceptions-OS-Level-Point-of-View
* http://sploitfun.blogspot.com/2012/08/seh-exploit-part1.html
* http://sploitfun.blogspot.com/2012/08/seh-exploit-part2.html
*
* fs:0x0 on Windows is the pointer to ExceptionList
* http://stackoverflow.com/questions/4657661/what-lies-at-fs0x0-on-windows
*
* EPB and ESP
* http://stackoverflow.com/questions/1395591/what-is-exactly-the-base-pointer-and-stack-pointer-to-what-do-they-point
*
* TODO: get sizeof dword instead of hardcode 4
*/
#define seh_push_(_label, _eh, _r1, _r2) \
{ \
__asm mov _r1, _eh /* move new handler address */ \
__asm mov _r2, seh_count /* get current seh counter */ \
__asm mov dword ptr seh_eh[_r2*4], _r1 /* set recover exception hander */ \
__asm mov _r1, _label /* move jump label address */ \
__asm mov dword ptr seh_eip[_r2*4], _r1 /* set recover eip as the jump label */ \
__asm push seh_handler /* push new safe seh handler */ \
__asm push fs:[0] /* push old fs:0 */ \
__asm mov dword ptr seh_esp[_r2*4], esp /* safe current stack address */ \
__asm mov fs:[0], esp /* change fs:0 to the current stack */ \
__asm inc seh_count /* increase number of seh */ \
}
/**
* Restore old SEH handler
* @param _label exception recover label which should be the same as seh_push_
*/
#define seh_pop_(_label) \
{ \
__asm _label: /* the exception recover label */ \
__asm pop dword ptr fs:[0] /* restore old fs:0 */ \
__asm add esp, 4 /* pop seh_handler */ \
__asm dec seh_count /* decrease number of seh */ \
}
// Define seh_exit as the shared exit label
#define seh_pop() seh_pop_(seh_exit)
#define seh_push() seh_push_(seh_exit, 0, eax, ecx) // use ecx as counter better than ebx
/**
* @param _eh EXCEPTION_ROUTINE or 0
*/
#define seh_push_eh(_eh) seh_push_(seh_exit, _eh, eax, ecx)
/**
* Wrap the code block with SEH handler
* @param* any code block. The colon for the last expression is optional.
*/
#define seh_with(...) \
{ \
seh_push() \
__VA_ARGS__ \
; /* allow __VA_ARGS__ to be an expression */ \
seh_pop() \
}
/**
* Wrap the code block with SEH handler
* @param _eh EXCEPTION_ROUTINE or 0
* @param* any code block. The colon for the last expression is optional.
*/
#define seh_with_eh(_eh, ...) \
{ \
seh_push_eh(_eh) \
__VA_ARGS__ \
; /* allow __VA_ARGS__ to be an expression */ \
seh_pop() \
}
// EOF
//#define seh_push_front() \
// { \
// __asm mov eax, seh_exit \
// __asm mov seh_eip, eax \
// __asm push seh_handler \
// __asm push fs:[0] \
// __asm mov seh_esp, esp \
// __asm mov fs:[0], esp \
// }
//
//#define seh_pop_front() \
// { \
// __asm seh_exit: \
// __asm mov eax, [esp] \
// __asm mov fs:[0], eax \
// __asm add esp, 8 \
// }
//
//#define seh_push_back() \
// { \
// __asm mov eax, seh_exit \
// __asm mov ecx, seh_capacity - 1 \
// __asm mov DWORD PTR seh_eip[ecx*4], eax \
// __asm push seh_handler \
// __asm push fs:[0] \
// __asm mov DWORD PTR seh_esp[ecx*4], esp \
// __asm mov fs:[0], esp \
// }
//
//#define seh_pop_back() \
// { \
// __asm seh_exit: \
// __asm mov eax, [esp] \
// __asm mov fs:[0], eax \
// __asm add esp, 8 \
// }