* Copyright (c) 2014-2022 Google, Inc. All rights reserved.
* Copyright (c) 2003-2010 VMware, Inc. All rights reserved.
* **********************************************************/
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* * Neither the name of VMware, Inc. nor the names of its contributors may be
* used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL VMWARE, INC. OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*/
#include "tools.h"
#include <windows.h>
#include "except.h"
* We used a raw NtCreateThread with associated code borrowed from the core
* that used this stack. But this doesn't work on modern Windows, and at
* least for instrumentation modes we actively support today, there seems to
* be no need for all of that: so we just run the code on the initial stack.
*/
typedef void (*funcptr)();
char *badfunc;
void
run_test()
{
EXCEPTION_RECORD exception;
CONTEXT *context;
* than if in data segment
*/
char badfuncbuf[1000];
badfunc = (char *)ALIGN_FORWARD(badfuncbuf, 256);
badfunc[0] = 0xc3;
__try {
ULONG arguments[] = { 0, 0xabcd };
initialize_registry_context();
RaiseException(EXCEPTION_ACCESS_VIOLATION, 0, 2, arguments);
print("Never after RaiseException\n");
} __except (print("In RaiseException filter\n"),
#ifdef RAISE_EXCEPTION_EIP_NOT_CONSTANT
dump_exception_info((GetExceptionInformation())->ExceptionRecord,
(GetExceptionInformation())->ContextRecord),
#endif
EXCEPTION_EXECUTE_HANDLER) {
print("In RaiseException handler\n");
}
see case 197 and should also cover a direct CTI to bad memory,
the latter not very likely in real apps though */
and we should try to transparently return normal exceptions
[most likely these will remain unhandled]
We want to make sure people get the seriousness of the situation
and every case in which this happens should be taken as a real attack vector.
Usually they would see this as a bug,
but it may also be an attacker probing with AAAA.
Therefore, we should let execution continue only in -detect_mode
(fake) exceptions should be generated as if generated normally
*/
__try {
__try {
__try {
initialize_registry_context();
__asm {
mov eax, 0xbadcdef0
call dword ptr [eax]
}
print("At statement after exception\n");
} __except (context = (GetExceptionInformation())->ContextRecord,
print("Inside first filter eax=%x\n", context->CXT_XAX),
dump_exception_info((GetExceptionInformation())->ExceptionRecord,
context),
context->CXT_XAX = 0xcafebabe,
EXCEPTION_CONTINUE_EXECUTION, EXCEPTION_EXECUTE_HANDLER) {
print("Inside first handler\n");
}
print("At statement after 1st try-except\n");
__try {
initialize_registry_context();
__asm {
mov edx, 0xdeadbeef
call edx
}
print("NEVER Inside 2nd try\n");
} __except (print("Inside 2nd filter\n"), EXCEPTION_CONTINUE_SEARCH) {
print("This should NOT be printed\n");
}
} __finally {
print("Finally!\n");
}
print("NEVER At statement after 2nd try-finally\n");
} __except (print("Inside 3rd filter\n"),
exception = *(GetExceptionInformation())->ExceptionRecord,
context = (GetExceptionInformation())->ContextRecord,
dump_exception_info(&exception, context),
(GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION)
? EXCEPTION_EXECUTE_HANDLER
: EXCEPTION_CONTINUE_SEARCH) {
print("Expected memory access violation, ignoring it!\n");
}
print("After exception handler\n");
because the addresses are normally readable, but now we impose our own policy
-detect_mode should behave normally
no exceptions are triggered
-throw_exception -no_detect_mode
should behave similarly to the handling of unreadable memory above
(fake) exceptions should be generated claiming that badfunc is not executable
*/
print("Attempting execution of badfunc\n");
__try {
__try {
__try {
initialize_registry_context();
((funcptr)badfunc)();
print("DATA: At statement after exception\n");
} __except (
context = (GetExceptionInformation())->ContextRecord,
print("DATA VIOLATION: Inside first filter eax=%x\n", context->CXT_XAX),
dump_exception_info((GetExceptionInformation())->ExceptionRecord,
context),
EXCEPTION_EXECUTE_HANDLER) {
print("DATA VIOLATION: Inside first handler\n");
}
print("DATA: At statement after 1st try-except\n");
__try {
initialize_registry_context();
((funcptr)badfunc)();
print("DATA: Inside 2nd try\n");
} __except (EXCEPTION_CONTINUE_SEARCH) {
print("DATA: This should NOT be printed\n");
}
} __finally {
print("DATA: Finally!\n");
}
print("DATA: At statement after 2nd try-finally\n");
} __except (exception = *(GetExceptionInformation())->ExceptionRecord,
context = (GetExceptionInformation())->ContextRecord,
(GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION)
? EXCEPTION_EXECUTE_HANDLER
: EXCEPTION_CONTINUE_SEARCH) {
print("DATA: Expected execution violation!\n");
dump_exception_info(&exception, context);
}
print("DATA: After exception handler\n");
}
int
thread_func()
{
__try {
run_test();
} __except (EXCEPTION_EXECUTE_HANDLER) {
print("Should never have exception bubble up to thread function\n");
}
ExitThread(0);
return 0;
}
int
main()
{
thread_func();
return 0;
}