1 /* Capstone Disassembly Engine */
2 /* By Satoshi Tanda <tanda.sat@gmail.com>, 2016 */
3 
4 #include <ntddk.h>
5 #include <capstone.h>
6 
7 #ifdef __cplusplus
8 extern "C" {
9 #endif
10 
11 #include "../utils.h"   // for cs_snprintf
12 
13 #ifdef __cplusplus
14 }
15 #endif
16 
17 EXTERN_C DRIVER_INITIALIZE DriverEntry;
18 
19 #pragma warning(push)
20 #pragma warning(disable : 4005)   // 'identifier' : macro redefinition
21 #pragma warning(disable : 4007)   // 'main': must be '__cdecl'
22 
23 // Drivers must protect floating point hardware state. See use of float.
24 // Use KeSaveFloatingPointState/KeRestoreFloatingPointState around floating
25 // point operations. Display Drivers should use the corresponding Eng... routines.
26 #pragma warning(disable : 28110)  // Suppress this, as it is false positive.
27 
28 // "Import" existing tests into this file. All code is encaptured into unique
29 // namespace so that the same name does not conflict. Beware that those code
30 // is going to be compiled as C++ source file and not C files because this file
31 // is C++.
32 
33 namespace unnamed {
34 #include "test.c"
35 }  // namespace unnamed
36 
37 namespace detail {
38 #include "test_detail.c"
39 }  // namespace detail
40 
41 namespace skipdata {
42 #include "test_skipdata.c"
43 }  // namespace skipdata
44 
45 namespace iter {
46 #include "test_iter.c"
47 }  // namespace iter
48 
49 namespace arm {
50 #include "test_arm.c"
51 }  // namespace arm
52 
53 namespace arm64 {
54 #include "test_arm64.c"
55 }  // namespace arm64
56 
57 namespace mips {
58 #include "test_mips.c"
59 }  // namespace mips
60 
61 namespace ppc {
62 #include "test_ppc.c"
63 }  // namespace ppc
64 
65 namespace sparc {
66 #include "test_sparc.c"
67 }  // namespace sparc
68 
69 namespace systemz {
70 #include "test_systemz.c"
71 }  // namespace systemz
72 
73 namespace x86 {
74 #include "test_x86.c"
75 }  // namespace x86
76 
77 namespace xcore {
78 #include "test_xcore.c"
79 }  // namespace xcore
80 
81 #pragma warning(pop)
82 
83 // Exercises all existing regression tests
test()84 static void test()
85 {
86 	KFLOATING_SAVE float_save;
87 	NTSTATUS status;
88 
89 	// Any of Capstone APIs cannot be called at IRQL higher than DISPATCH_LEVEL
90 	// since our malloc implementation using ExAllocatePoolWithTag() is able to
91 	// allocate memory only up to the DISPATCH_LEVEL level.
92 	NT_ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL);
93 
94 	// On a 32bit driver, KeSaveFloatingPointState() is required before using any
95 	// Capstone function because Capstone can access to the MMX/x87 registers and
96 	// 32bit Windows requires drivers to use KeSaveFloatingPointState() before and
97 	// KeRestoreFloatingPointState() after accessing them. See "Using Floating
98 	// Point or MMX in a WDM Driver" on MSDN for more details.
99 	status = KeSaveFloatingPointState(&float_save);
100 	if (!NT_SUCCESS(status)) {
101 		printf("ERROR: Failed to save floating point state!\n");
102 		return;
103 	}
104 
105 	unnamed::test();
106 	detail::test();
107 	skipdata::test();
108 	iter::test();
109 	arm::test();
110 	arm64::test();
111 	mips::test();
112 	ppc::test();
113 	sparc::test();
114 	systemz::test();
115 	x86::test();
116 	xcore::test();
117 
118 	// Restores the nonvolatile floating-point context.
119 	KeRestoreFloatingPointState(&float_save);
120 }
121 
122 // Functional test for cs_winkernel_vsnprintf()
cs_winkernel_vsnprintf_test()123 static void cs_winkernel_vsnprintf_test()
124 {
125 	char buf[10];
126 	bool ok = true;
127 	ok = (ok && cs_snprintf(buf, sizeof(buf), "%s", "") == 0 && strcmp(buf, "") == 0);
128 	ok = (ok && cs_snprintf(buf, sizeof(buf), "%s", "0") == 1 && strcmp(buf, "0") == 0);
129 	ok = (ok && cs_snprintf(buf, sizeof(buf), "%s", "012345678") == 9 && strcmp(buf, "012345678") == 0);
130 	ok = (ok && cs_snprintf(buf, sizeof(buf), "%s", "0123456789") == 10 && strcmp(buf, "012345678") == 0);
131 	ok = (ok && cs_snprintf(buf, sizeof(buf), "%s", "01234567890") == 11 && strcmp(buf, "012345678") == 0);
132 	ok = (ok && cs_snprintf(buf, sizeof(buf), "%s", "0123456789001234567890") == 22 && strcmp(buf, "012345678") == 0);
133 	if (!ok) {
134 		printf("ERROR: cs_winkernel_vsnprintf_test() did not produce expected results!\n");
135 	}
136 }
137 
138 // Driver entry point
DriverEntry(PDRIVER_OBJECT DriverObject,PUNICODE_STRING RegistryPath)139 EXTERN_C NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath)
140 {
141 	UNREFERENCED_PARAMETER(DriverObject);
142 	UNREFERENCED_PARAMETER(RegistryPath);
143 	cs_winkernel_vsnprintf_test();
144 	test();
145 	return STATUS_CANCELLED;
146 }
147 
148 // This functions mimics printf() but does not return the same value as printf()
149 // would do. printf() is required to exercise regression tests.
150 _Use_decl_annotations_
printf(const char * format,...)151 int __cdecl printf(const char * format, ...)
152 {
153 	NTSTATUS status;
154 	va_list args;
155 
156 	va_start(args, format);
157 	status = vDbgPrintEx(DPFLTR_DEFAULT_ID, DPFLTR_ERROR_LEVEL, format, args);
158 	va_end(args);
159 	return NT_SUCCESS(status);
160 }
161