aboutsummaryrefslogtreecommitdiffstats
path: root/capstone/tests/test_winkernel.cpp
blob: 6413b1a2cb72e48cf0a24cf80a35899f8150b52c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
/* Capstone Disassembly Engine */
/* By Satoshi Tanda <tanda.sat@gmail.com>, 2016 */

#include <ntddk.h>

#include <capstone/platform.h>
#include <capstone/capstone.h>

#ifdef __cplusplus
extern "C" {
#endif

#include "../utils.h"   // for cs_snprintf

#ifdef __cplusplus
}
#endif

EXTERN_C DRIVER_INITIALIZE DriverEntry;

#pragma warning(push)
#pragma warning(disable : 4005)   // 'identifier' : macro redefinition
#pragma warning(disable : 4007)   // 'main': must be '__cdecl'

// Drivers must protect floating point hardware state. See use of float.
// Use KeSaveFloatingPointState/KeRestoreFloatingPointState around floating
// point operations. Display Drivers should use the corresponding Eng... routines.
#pragma warning(disable : 28110)  // Suppress this, as it is false positive.

// "Import" existing tests into this file. All code is encaptured into unique
// namespace so that the same name does not conflict. Beware that those code
// is going to be compiled as C++ source file and not C files because this file
// is C++.

namespace basic {
#include "test_basic.c"
}  // namespace basic

namespace detail {
#include "test_detail.c"
}  // namespace detail

namespace skipdata {
#include "test_skipdata.c"
}  // namespace skipdata

namespace iter {
#include "test_iter.c"
}  // namespace iter

namespace customized_mnem_ {
#include "test_customized_mnem.c"
}  // namespace customized_mnem_

namespace arm {
#include "test_arm.c"
}  // namespace arm

namespace arm64 {
#include "test_arm64.c"
}  // namespace arm64

namespace mips {
#include "test_mips.c"
}  // namespace mips

namespace m68k {
#include "test_m68k.c"
}  // namespace m68k

namespace ppc {
#include "test_ppc.c"
}  // namespace ppc

namespace sparc {
#include "test_sparc.c"
}  // namespace sparc

namespace systemz {
#include "test_systemz.c"
}  // namespace systemz

namespace x86 {
#include "test_x86.c"
}  // namespace x86

namespace xcore {
#include "test_xcore.c"
}  // namespace xcore

#pragma warning(pop)

// Exercises all existing regression tests
static void test()
{
	KFLOATING_SAVE float_save;
	NTSTATUS status;

	// Any of Capstone APIs cannot be called at IRQL higher than DISPATCH_LEVEL
	// since our malloc implementation using ExAllocatePoolWithTag() is able to
	// allocate memory only up to the DISPATCH_LEVEL level.
	NT_ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL);

	// On a 32bit driver, KeSaveFloatingPointState() is required before using any
	// Capstone function because Capstone can access to the MMX/x87 registers and
	// 32bit Windows requires drivers to use KeSaveFloatingPointState() before and
	// KeRestoreFloatingPointState() after accessing them. See "Using Floating
	// Point or MMX in a WDM Driver" on MSDN for more details.
	status = KeSaveFloatingPointState(&float_save);
	if (!NT_SUCCESS(status)) {
		printf("ERROR: Failed to save floating point state!\n");
		return;
	}

	basic::test();
	detail::test();
	skipdata::test();
	iter::test();
	customized_mnem_::test();
	arm::test();
	arm64::test();
	mips::test();
	m68k::test();
	ppc::test();
	sparc::test();
	systemz::test();
	x86::test();
	xcore::test();

	// Restores the nonvolatile floating-point context.
	KeRestoreFloatingPointState(&float_save);
}

// Functional test for cs_winkernel_vsnprintf()
static void cs_winkernel_vsnprintf_test()
{
	char buf[10];
	bool ok = true;
	ok = (ok && cs_snprintf(buf, sizeof(buf), "%s", "") == 0 && strcmp(buf, "") == 0);
	ok = (ok && cs_snprintf(buf, sizeof(buf), "%s", "0") == 1 && strcmp(buf, "0") == 0);
	ok = (ok && cs_snprintf(buf, sizeof(buf), "%s", "012345678") == 9 && strcmp(buf, "012345678") == 0);
	ok = (ok && cs_snprintf(buf, sizeof(buf), "%s", "0123456789") == 10 && strcmp(buf, "012345678") == 0);
	ok = (ok && cs_snprintf(buf, sizeof(buf), "%s", "01234567890") == 11 && strcmp(buf, "012345678") == 0);
	ok = (ok && cs_snprintf(buf, sizeof(buf), "%s", "0123456789001234567890") == 22 && strcmp(buf, "012345678") == 0);
	if (!ok) {
		printf("ERROR: cs_winkernel_vsnprintf_test() did not produce expected results!\n");
	}
}

// Driver entry point
EXTERN_C NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath)
{
	UNREFERENCED_PARAMETER(DriverObject);
	UNREFERENCED_PARAMETER(RegistryPath);
	cs_winkernel_vsnprintf_test();
	test();
	return STATUS_CANCELLED;
}

// This functions mimics printf() but does not return the same value as printf()
// would do. printf() is required to exercise regression tests.
_Use_decl_annotations_
int __cdecl printf(const char * format, ...)
{
	NTSTATUS status;
	va_list args;

	va_start(args, format);
	status = vDbgPrintEx(DPFLTR_DEFAULT_ID, DPFLTR_ERROR_LEVEL, format, args);
	va_end(args);
	return NT_SUCCESS(status);
}