mirror of
https://github.com/mirkobrombin/raven.git
synced 2026-10-28 21:25:06 +00:00
157 lines
4.2 KiB
C
157 lines
4.2 KiB
C
#define WIN32_LEAN_AND_MEAN
|
|
#include <windows.h>
|
|
#include <excpt.h>
|
|
|
|
#define CHECK(code,condition) do { if(!(condition)) return code; } while(0)
|
|
|
|
// The scope table that the compiler emits for each function using __try; the handler walks it for the faulting pc.
|
|
typedef struct { ULONG begin, end, handler, target; } SCOPE;
|
|
typedef struct { ULONG count; SCOPE scopes[1]; } SCOPE_TABLE;
|
|
|
|
EXCEPTION_DISPOSITION __C_specific_handler(PEXCEPTION_RECORD record,PVOID frame,PCONTEXT context,PDISPATCHER_CONTEXT dispatcher)
|
|
{
|
|
const SCOPE_TABLE *table=(const SCOPE_TABLE *)dispatcher->HandlerData;
|
|
const ULONG64 base=dispatcher->ImageBase;
|
|
const ULONG64 pc=dispatcher->ControlPc-base;
|
|
for(ULONG index=dispatcher->ScopeIndex;index<table->count;++index) {
|
|
const SCOPE *scope=&table->scopes[index];
|
|
if(pc<scope->begin || pc>=scope->end) continue;
|
|
if(record->ExceptionFlags&(EXCEPTION_UNWINDING|EXCEPTION_EXIT_UNWIND)) {
|
|
// Unwinding runs termination handlers (no target) for scopes the exception leaves.
|
|
if(scope->target==0) {
|
|
dispatcher->ScopeIndex=index+1;
|
|
((void (*)(BOOLEAN,PVOID))(base+scope->handler))(TRUE,frame);
|
|
} else if(dispatcher->TargetIp==base+scope->target) {
|
|
return ExceptionContinueSearch;
|
|
}
|
|
continue;
|
|
}
|
|
if(scope->target==0) continue;
|
|
LONG decision=EXCEPTION_EXECUTE_HANDLER;
|
|
if(scope->handler!=1) {
|
|
EXCEPTION_POINTERS pointers={record,context};
|
|
decision=((LONG (*)(PEXCEPTION_POINTERS,PVOID))(base+scope->handler))(&pointers,frame);
|
|
}
|
|
if(decision==EXCEPTION_CONTINUE_EXECUTION) return ExceptionContinueExecution;
|
|
if(decision==EXCEPTION_EXECUTE_HANDLER) {
|
|
RtlUnwindEx(frame,(PVOID)(base+scope->target),record,0,dispatcher->ContextRecord,dispatcher->HistoryTable);
|
|
return ExceptionContinueSearch;
|
|
}
|
|
}
|
|
return ExceptionContinueSearch;
|
|
}
|
|
|
|
static volatile LONG trail[16];
|
|
static volatile LONG trail_count;
|
|
static void note(LONG value) { trail[trail_count++]=value; }
|
|
|
|
static int fault_code;
|
|
static LONG record_code(PEXCEPTION_POINTERS pointers)
|
|
{
|
|
fault_code=(int)pointers->ExceptionRecord->ExceptionCode;
|
|
return EXCEPTION_EXECUTE_HANDLER;
|
|
}
|
|
|
|
static int null_write(void)
|
|
{
|
|
volatile int *pointer=0;
|
|
__try {
|
|
*pointer=1;
|
|
return 0;
|
|
} __except(record_code(GetExceptionInformation())) {
|
|
return fault_code==(int)EXCEPTION_ACCESS_VIOLATION ? 1 : 2;
|
|
}
|
|
}
|
|
|
|
static int divide(volatile int zero)
|
|
{
|
|
__try {
|
|
return 10/zero;
|
|
} __except(EXCEPTION_EXECUTE_HANDLER) {
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
static void cleanup_inner(void)
|
|
{
|
|
__try {
|
|
note(1);
|
|
RaiseException(0xe0001234,EXCEPTION_NONCONTINUABLE,0,0);
|
|
note(99);
|
|
} __finally {
|
|
note(2);
|
|
}
|
|
}
|
|
|
|
static int cleanup_outer(void)
|
|
{
|
|
__try {
|
|
cleanup_inner();
|
|
note(98);
|
|
return 0;
|
|
} __except(GetExceptionCode()==0xe0001234 ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) {
|
|
note(3);
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
static int deep(int depth)
|
|
{
|
|
if(depth==0) {
|
|
RaiseException(0xe0000042,0,1,(const ULONG_PTR []){7});
|
|
return 0;
|
|
}
|
|
volatile char padding[200];
|
|
padding[0]=(char)depth;
|
|
return deep(depth-1)+padding[0];
|
|
}
|
|
|
|
static LONG resume_filter(PEXCEPTION_POINTERS pointers)
|
|
{
|
|
return pointers->ExceptionRecord->ExceptionCode==0xe0000077 ? EXCEPTION_CONTINUE_EXECUTION : EXCEPTION_CONTINUE_SEARCH;
|
|
}
|
|
|
|
static int continuable(void)
|
|
{
|
|
int reached=0;
|
|
__try {
|
|
RaiseException(0xe0000077,0,0,0);
|
|
reached=1;
|
|
} __except(resume_filter(GetExceptionInformation())) {
|
|
return -1;
|
|
}
|
|
return reached;
|
|
}
|
|
|
|
static LONG parameter_filter(PEXCEPTION_POINTERS pointers)
|
|
{
|
|
fault_code=(int)pointers->ExceptionRecord->ExceptionInformation[0];
|
|
return EXCEPTION_EXECUTE_HANDLER;
|
|
}
|
|
|
|
static LONG WINAPI last_resort(PEXCEPTION_POINTERS pointers)
|
|
{
|
|
(void)pointers;
|
|
return EXCEPTION_EXECUTE_HANDLER;
|
|
}
|
|
|
|
int raven_entry(void)
|
|
{
|
|
CHECK(1,null_write()==1);
|
|
CHECK(2,divide(0)==-1 && divide(2)==5);
|
|
CHECK(3,cleanup_outer()==1);
|
|
CHECK(4,trail_count==3 && trail[0]==1 && trail[1]==2 && trail[2]==3);
|
|
int caught=0;
|
|
__try {
|
|
deep(20);
|
|
} __except(parameter_filter(GetExceptionInformation())) {
|
|
caught=1;
|
|
}
|
|
CHECK(5,caught==1 && fault_code==7);
|
|
CHECK(6,continuable()==1);
|
|
// Nothing handles this one: the program's own top-level filter must see it before the process dies.
|
|
CHECK(7,SetUnhandledExceptionFilter(last_resort)==0);
|
|
CHECK(8,SetUnhandledExceptionFilter(0)==last_resort);
|
|
return 0;
|
|
}
|