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