Skip to content

Commit

Permalink
Partial SEH support.
Browse files Browse the repository at this point in the history
 * Removed linker script; .edata *and* .pdata required by MingW for SEH.
 * Removed buggy `-fdata-sections` and `-ffunction-sections`.

Signed-off-by: Toni Uhlig <[email protected]>
  • Loading branch information
utoni committed Nov 15, 2023
1 parent 9ae0188 commit 5f31388
Show file tree
Hide file tree
Showing 8 changed files with 116 additions and 405 deletions.
35 changes: 35 additions & 0 deletions CRT/except.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
#ifndef EXCEPT_H
#define EXCEPT_H 1

#ifndef __SEH__
#error "SEH not supported by your toolchain!"
#endif

#ifdef __try1
#undef __try1
#endif

#ifdef __except1
#undef __except1
#endif

#define __dpptry(handler, counter) \
__asm__ goto( \
".seh_handler __C_specific_handler, @except\n\t" \
".seh_handlerdata\n\t" \
".long 1\n\t" \
".rva .l_startw" #counter ", .l_endw" #counter ", " #handler ", .l_exceptw" #counter \
"\n\t" \
".section .text\n" \
".l_startw" #counter ":" :: ::except);

#define __dppexcept(counter) \
goto end; \
except: \
__asm__(".l_exceptw" #counter ":");

#define __dpptryend(counter) \
end: \
__asm__(".l_endw" #counter ":");

#endif
2 changes: 2 additions & 0 deletions CRT/kcrt.c
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@

#include <ntddk.h>

#include "except.h"

#define KCRT_POOL_DEFAULT_TAG 0xDEADBEEF

extern void (*__CTOR_LIST__)();
Expand Down
4 changes: 2 additions & 2 deletions Makefile.deps
Original file line number Diff line number Diff line change
Expand Up @@ -49,12 +49,12 @@ endif

$(LIBCRT_BUILD_DIR)/kcrt$(NAME_SUFFIX).o: $(CC) $(DPP_ROOT)/CRT/kcrt.c
$(Q)test -d '$(LIBCRT_BUILD_DIR)' || mkdir -p '$(LIBCRT_BUILD_DIR)'
$(Q)$(CC) -std=c99 $(CFLAGS) -c CRT/kcrt.c -o $@
$(Q)$(CC) -std=gnu99 $(CFLAGS) -c CRT/kcrt.c -o $@
@echo 'CC $@'

$(LIBCRT_BUILD_DIR)/ntdll_zw_functions$(NAME_SUFFIX).o: $(CC) $(DPP_ROOT)/CRT/ntdll_zw_functions.c
$(Q)test -d '$(LIBCRT_BUILD_DIR)' || mkdir -p '$(LIBCRT_BUILD_DIR)'
$(Q)$(CC) -std=c99 $(CFLAGS) -c CRT/ntdll_zw_functions.c -o $@
$(Q)$(CC) -std=gnu99 $(CFLAGS) -c CRT/ntdll_zw_functions.c -o $@
@echo 'CC $@'

$(LIBCRT_BUILD_DIR)/eastl_compat$(NAME_SUFFIX).opp: $(CXX) $(DPP_ROOT)/CRT/eastl_compat.cpp
Expand Down
7 changes: 3 additions & 4 deletions Makefile.inc
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ RC = $(LOCAL_MINGW64_RC)
DDK_INCLUDE_DIR = $(dir $(CC))../x86_64-w64-mingw32/include/ddk
CFLAGS := -Wall -Wextra -Wno-sign-compare -Wno-strict-aliasing \
-m64 -fPIC -fvisibility=hidden \
-ffunction-sections -fdata-sections -fno-builtin -ffreestanding \
-fno-builtin -ffreestanding \
-fno-stack-protector -mno-stack-arg-probe \
-I$(DPP_ROOT)/CRT -I$(DDK_INCLUDE_DIR) \
-D__INTRINSIC_DEFINED_InterlockedBitTestAndSet \
Expand Down Expand Up @@ -84,8 +84,7 @@ DRIVER_LDFLAGS := -shared \
-Wl,--exclude-all-symbols \
-Wl,--entry,_CRT_DriverEntry \
$(PRINT_LDSCRIPT) \
-nostartfiles -nodefaultlibs -nostdlib \
-T$(DPP_ROOT)/ld-script.txt
-nostartfiles -nodefaultlibs -nostdlib
DRIVER_LIBS := -lntoskrnl -lhal
USER_LDFLAGS := -Wl,--dynamicbase -Wl,--nxcompat -Wl,--gc-sections
USER_LIBS :=
Expand Down Expand Up @@ -139,7 +138,7 @@ define BUILD_C_OBJECT
$(call CHECK_REQUIRED_PATHS)
$(call is_set,$(1),First argument: Source file missing)
$(call is_set,$(2),Second argument: Output object file missing)
$(Q)$(CC) -std=c99 $(CFLAGS) $(CUSTOM_CFLAGS) $(CFLAGS_$(2)) -c $(1) -o $(2)
$(Q)$(CC) -std=gnu99 $(CFLAGS) $(CUSTOM_CFLAGS) $(CFLAGS_$(2)) -c $(1) -o $(2)
@echo 'CC $(2)'
endef

Expand Down
3 changes: 1 addition & 2 deletions Makefile.native.inc
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ CXX = /usr/bin/c++
AR = /usr/bin/ar
CFLAGS := -Wall -Wextra -Wno-sign-compare -Wno-strict-aliasing -Wno-c++20-compat \
-m64 -fPIC -fvisibility=hidden \
-ffunction-sections -fdata-sections \
-I$(DPP_ROOT)/CRT -DNATIVE=1
ifneq ($(WERROR),)
CFLAGS += -Werror
Expand Down Expand Up @@ -68,7 +67,7 @@ define BUILD_C_OBJECT
$(call CHECK_REQUIRED_PATHS)
$(call is_set,$(1),First argument: Source file missing)
$(call is_set,$(2),Second argument: Output object file missing)
$(Q)$(CC) -std=c99 $(CFLAGS) -c $(1) -o $(2)
$(Q)$(CC) -std=gnu99 $(CFLAGS) -c $(1) -o $(2)
@echo 'CC $(2)'
endef

Expand Down
31 changes: 30 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ Instead either use Zeranoe's build script with `make -C [path-to-this-repo] -f M

1. `examples/dpp-template`: plain and stupid ddk C example
2. `examples/dpp-template-cplusplus`: same, but written in C++, including a very complex class and some MT
3. `examples/dpp-template-cplusplus-EASTL`: C++ example w/ (EA)STL integration, basicially everything usable except for SEH, VEH and assertions.
3. `examples/dpp-template-cplusplus-EASTL`: C++ example w/ (EA)STL integration, basicially everything usable except for VEH and assertions.

`examples/dpp-template-cplusplus-EASTL` supports `BUILD_NATIVE`!
You can build and run it on your native Linux either with the other examples e.g. `make examples`, build only native executables `make -C examples DPP_ROOT="$(realpath .)" BUILD_NATIVE=1` in the top-level directory or directly build it from the examples directory with `make DPP_ROOT="$(realpath ..)" BUILD_NATIVE=1`.
Expand Down Expand Up @@ -195,6 +195,35 @@ You may reach a point where system functions, intrinsics or built-ins are requir
For system functions that can be retrieved via `MmGetSystemRoutineAddress`, you may use `CRT/gen_wrapper.sh` to create wrapper modules. These modules retrieve the desired functions during run-time, but will be available during link-time. An example is `ZwTraceControl`, which gets exported by `ntdll.dll`.
Eventually missing intrinsics/built-ins should be placed in `CRT/kcrt.c`.

## Notes on SEH

There are some limitations regarding the use of MingW's SEH implementation in kernel mode.
You can not use it as you might have been known it from MSVC or MingW.

Predefined statements `__try`, `__catch`, `__finally`, `__try1`, `__catch1`, etc. do **not** work!

You need to use something like:

```C
#include <except.h>

int handler(_In_ EXCEPTION_POINTERS * ep)
{
(void)ep;
return EXCEPTION_EXECUTE_HANDLER;
}

// ...

__dpptry(handler, unique_identifier) {
*(int *)0 = 0;
} __dppexcept(unique_identifier) {
DbgPrint("%s\n", "Exception caught!");
} __dpptryend(unique_identifier);
```

SEH needs to be improved. Patches are welcome!

## Known Issues

Unfortunately, `eastl::to_string` does not work. See `CRT/eastl_compat.cpp` for more details.
Expand Down
44 changes: 43 additions & 1 deletion examples/dpp-example.c
Original file line number Diff line number Diff line change
@@ -1,16 +1,58 @@
#include <ntddk.h>

#include <except.h>

DRIVER_INITIALIZE DriverEntry;
DRIVER_UNLOAD DriverUnload;

extern NTSTATUS NTAPI ZwProtectVirtualMemory(_In_ HANDLE ProcessHandle,
_In_ _Out_ PVOID * BaseAddress,
_In_ _Out_ PULONG NumberOfBytesToProtect,
_In_ ULONG NewAccessProtection,
_Out_ PULONG OldAccessProtection);

int example_exception_handler(_In_ EXCEPTION_POINTERS * lpEP)
{
(void)lpEP;
DbgPrint("Exception handler called!\n");
return EXCEPTION_EXECUTE_HANDLER;
}

static void another_seh_test()
{
DbgPrint("Another SEH test..\n");
__dpptry(example_exception_handler, anotherseh)
{
*(int *)0 = 0;
}
__dppexcept(anotherseh)
{
DbgPrint("Success!\n");
}
__dpptryend(anotherseh);
}

NTSTATUS DriverEntry(struct _DRIVER_OBJECT * DriverObject, PUNICODE_STRING RegistryPath)
{
(void)DriverObject;
(void)RegistryPath;

DbgPrint("%s\n", "Hello ring0!");

// This is bad. Please do not call _disable/_enable in the DriverEntry.
DbgPrint("Testing SEH..\n");
__dpptry(example_exception_handler, testseh)
{
*(int *)0 = 0;
DbgPrint("You should never see this text!\n");
}
__dppexcept(testseh)
{
DbgPrint("Success! SEH seems to work.\n");
}
__dpptryend(testseh);

another_seh_test();

DbgPrint("%s\n", "Disable/Enable Interrupts!");
_disable();
_enable();
Expand Down
Loading

0 comments on commit 5f31388

Please sign in to comment.