summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authortumagonx2017-08-08 10:54:53 +0700
committertumagonx2017-08-08 10:54:53 +0700
commit2acec63b2ed75bf4b71ad257db573c4b8f9639e7 (patch)
treea8bea139ddd26116d44ea182b0b8436f2162e6e3
initial commit
-rw-r--r--MAKEFILE8
-rw-r--r--Sources9
-rw-r--r--TODO122
-rw-r--r--accessmask.c693
-rw-r--r--accessmask.h55
-rw-r--r--atom.c187
-rw-r--r--atom.h78
-rw-r--r--boprot.c173
-rw-r--r--boprot.h33
-rw-r--r--debug.c162
-rw-r--r--debug.h47
-rw-r--r--dirobj.c153
-rw-r--r--dirobj.h78
-rw-r--r--driver.c1237
-rw-r--r--driver.h90
-rw-r--r--driver.sln21
-rw-r--r--driver.vcproj341
-rw-r--r--driverobj.c205
-rw-r--r--driverobj.h68
-rw-r--r--event.c259
-rw-r--r--event.h105
-rw-r--r--file.c665
-rw-r--r--file.h273
-rw-r--r--hookproc.c1799
-rw-r--r--hookproc.h460
-rw-r--r--i386.c178
-rw-r--r--i386.h184
-rw-r--r--job.c157
-rw-r--r--job.h68
-rw-r--r--learn.c1414
-rw-r--r--learn.h43
-rw-r--r--log.c459
-rw-r--r--log.h236
-rw-r--r--media.c444
-rw-r--r--media.h40
-rw-r--r--misc.c943
-rw-r--r--misc.h101
-rw-r--r--mutant.c151
-rw-r--r--mutant.h78
-rw-r--r--network.c715
-rw-r--r--network.h57
-rw-r--r--ntproto.h289
-rw-r--r--pathproc.c1093
-rw-r--r--pathproc.h67
-rw-r--r--policy.c3243
-rw-r--r--policy.h344
-rw-r--r--port.c318
-rw-r--r--port.h162
-rw-r--r--process.c1270
-rw-r--r--process.h215
-rw-r--r--procname.c677
-rw-r--r--procname.h68
-rw-r--r--registry.c402
-rw-r--r--registry.h140
-rw-r--r--resource.h15
-rw-r--r--section.c285
-rw-r--r--section.h112
-rw-r--r--semaphore.c161
-rw-r--r--semaphore.h69
-rw-r--r--symlink.c185
-rw-r--r--symlink.h78
-rw-r--r--sysinfo.c197
-rw-r--r--sysinfo.h190
-rw-r--r--time.c190
-rw-r--r--time.h68
-rw-r--r--timer.c151
-rw-r--r--timer.h78
-rw-r--r--token.c250
-rw-r--r--token.h145
-rw-r--r--userland.c573
-rw-r--r--userland.h133
-rw-r--r--vdm.c227
-rw-r--r--vdm.h72
-rw-r--r--wireless.c338
-rw-r--r--wireless.h40
75 files changed, 24434 insertions, 0 deletions
diff --git a/MAKEFILE b/MAKEFILE
new file mode 100644
index 0000000..d5bedee
--- /dev/null
+++ b/MAKEFILE
@@ -0,0 +1,8 @@
1#
2# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
3# file to this component. This file merely indirects to the real make file
4# that is shared by all the driver components of the Windows NT DDK
5#
6
7!INCLUDE $(NTMAKEENV)\makefile.def
8
diff --git a/Sources b/Sources
new file mode 100644
index 0000000..a6c0fad
--- /dev/null
+++ b/Sources
@@ -0,0 +1,9 @@
1TARGETNAME=ozone
2TARGETTYPE=DRIVER
3
4TARGETPATH=.
5INCLUDES= $(BASEDIR)\inc;.
6
7TARGETLIBS=$(DDK_LIB_PATH)\tdi.lib
8
9SOURCES=driver.c file.c registry.c policy.c process.c pathproc.c hookproc.c learn.c misc.c section.c sysinfo.c event.c semaphore.c time.c network.c accessmask.c log.c job.c mutant.c port.c symlink.c timer.c token.c driverobj.c atom.c vdm.c i386.c procname.c userland.c debug.c media.c boprot.c dirobj.c \ No newline at end of file
diff --git a/TODO b/TODO
new file mode 100644
index 0000000..c618004
--- /dev/null
+++ b/TODO
@@ -0,0 +1,122 @@
1TODO:
2
3append only files can be achieved by making sure that offsets passed to writefile are not less than the total size of the file
4
5disable all non-TCP/IP / netbios protocols by default (with an additional option to enable)
6(connect to \Device\AFD disable non tcp/ip stuff) (\device\netbios)
7
8svchost.exe needs to be jailed by DLLs... each DLL will have its own policy
9
10policy_include: additional.policy
11
12add ability to deny logons to certain users
13
14add a "signature" rule.. LocalSystem execution of different processes (especially cmd.exe) should be logged and possibly denied?
15
16allow occasional rules to go through w/o logging? especially file & registry?
17
18investigate SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\App Paths\\IEXPLORE.EXE
19
20
21disable execution of certain applications based on their version (i.e. vulnerable IE) (from okena)
22add sniffer & non-ip protocol detection (from okena)
23COM/ActiveX interception
24support for application clauses (chapter 6)
25
26when creating an "exception" rule, MC can/should ask for whether the exception rule should be created on
27the selected agent only, all agents of a certain type or all agents of all types
28
29
30block debuggers
31
32non-GUI/system apps cannot use GUI calls?
33
34
35in server paranoid mode, allow only c:\program files\*.exe and c:\windows\*.exe to execute?
36trusted path execution (execution of binaries from non-trusted directories (i.e world-writable))
37(A trusted path is one that is inside is a root owned directory that is not group or world writable.)
38
39explorer option.. "Run process in a sandbox.." brings up a gui that asks whether to allow file, reg, network access?
40
41port to Itanium/AMD64
42
43see if we can take over the job of a buffer overflow security exception handler
44on win2k3 install custom BO exception handler that terminates a process
45
46need to be able to control access to all device drivers (is this already handled by intercepting createfile?) is there another way to obtain a handle to a kernel driver?
47disable modem access, etc
48
49raw devices of all (mounted?) filesystems should be read-only
50
51copy in all unicode strings, check them and then pass the kernel copies to the kernel to avoid race conditions?
52
53disable our driver if loading using LastKnownGood configuration (notify MC?)
54
55restrict reboot capability and certain programs only to interactive sessions?!
56
57add ability to load what programs are allowed to run? (sha1 hashes, signed binaries)
58
59investigate kernel32!CreateHardLink
60
61dll_all: log will also log all section rules since RULE_DLL will be converted to RULE_SECTION
62
63protect crypto keys
64
65use ZwQueryProcessInfo ProcessVmCounters to keep track of amount of allocated process memory (execution time can be limited using job objects?! memory limit too?)
66(or simply hijack malloc & free)
67
68device naming on terminal servers
69
70have a webpage which lists new vulnerabilities and whether our system would automatically protect against it
71
72deallocate allocated virtual memory that was used by AS randomization once the process is loaded and initialized (what about dynamically loaded DLLs)?
73
74create a policy check tool.. one of the things to lookout for is using "eq" and then specifying regex chars like * or ? in the filename
75
76interactive learning mode
77
78policy_ask user app should not run as an interative service but rather as a separate app running as a particular user
79
80IIS install should scan the registry for any known virtual roots and automatically add them to the policy.. same for other apps
81
82make sure that file-system protection cannot be subverted by accessing files by other means (\\127.0.0.1\share\file)
83
84per-group policy, per-user global policy
85
86
87network connect should be able to specify ports and not just ip addresses
88address eq "127.0.0.1:443" then permit
89address eq "0:443" then deny
90address eq "\\UNCpath\blah" then log
91address eq "www.porn.com:80" then deny
92
93
94new product idea: Solaris BSM-like auditing (http://www.securityfocus.com/infocus/1362) for Windows
95(compare to what audit logs native Windows Group/Security Policies can already generate)
96posix 1003e
97
98
99layers:
100
101desktop
102web server (iis, apache, netscape)
103database server (oracle, MS SQL / access, Sybase, DB2, Informix, Interbase, MySQL)
104terminal server
105mail server
106VPN server / remote access server
107
108dns server
109dhcp server
110wins server
111streaming media server
112domain controller
113file and print server
114(application server – websphere, BEA websphere)
115(collaboration server – IBM Lotus Domino)
116
117
118client policies:
119 email (outlook, outlook express, eudora, netscape)
120 browsers (IE, netscape, opera)
121 IM (aol, yahoo!, msn, icq)
122 others (ms office, napster)
diff --git a/accessmask.c b/accessmask.c
new file mode 100644
index 0000000..e91129f
--- /dev/null
+++ b/accessmask.c
@@ -0,0 +1,693 @@
1/*
2 * Copyright (c) 2004 Security Architects Corporation. All rights reserved.
3 *
4 * Module Name:
5 *
6 * accessmask.c
7 *
8 * Abstract:
9 *
10 * This module implements various ACCESS_MASK decoding routines.
11 *
12 * Author:
13 *
14 * Eugene Tsyrklevich 18-Mar-2004
15 *
16 * Revision History:
17 *
18 * None.
19 */
20
21
22#include "accessmask.h"
23
24
25
26/*
27 * Get_FILE_OperationType()
28 *
29 * Description:
30 * This function decodes file operation types such as GENERIC_READ and DELETE and converts them to
31 * 3 internal operations: OP_READ, OP_WRITE and OP_EXECUTE.
32 *
33 * Parameters:
34 * DesiredAccess - ACCESS_MASK structure (a doubleword value containing standard, specific, and generic rights).
35 *
36 * Returns:
37 * A combination of OP_READ, OP_WRITE & OP_EXECUTE flags set depending on the DesiredAccess argument.
38 */
39
40UCHAR
41Get_FILE_OperationType(ACCESS_MASK DesiredAccess)
42{
43 UCHAR OperationType = 0;
44// int FileAll = MAXIMUM_ALLOWED | GENERIC_ALL | STANDARD_RIGHTS_REQUIRED |
45// STANDARD_RIGHTS_ALL | SPECIFIC_RIGHTS_ALL | ACCESS_SYSTEM_SECURITY; //FILE_ALL_ACCESS
46
47
48 if ( IS_BIT_SET(DesiredAccess, GENERIC_READ) ||
49 IS_BIT_SET(DesiredAccess, GENERIC_ALL) ||
50 IS_BIT_SET(DesiredAccess, FILE_READ_DATA) ||
51// IS_BIT_SET(DesiredAccess, FILE_READ_ACCESS) ||
52// IS_BIT_SET(DesiredAccess, FILE_LIST_DIRECTORY) ||
53 IS_BIT_SET(DesiredAccess, FILE_READ_ATTRIBUTES) ||
54 IS_BIT_SET(DesiredAccess, FILE_READ_EA) ||
55 IS_BIT_SET(DesiredAccess, SYNCHRONIZE) ||
56 IS_BIT_SET(DesiredAccess, STANDARD_RIGHTS_READ) ||
57 IS_BIT_SET(DesiredAccess, FILE_ALL_ACCESS) ||
58 DesiredAccess == 0)
59
60 OperationType |= OP_READ;
61
62
63 if ( IS_BIT_SET(DesiredAccess, GENERIC_WRITE) ||
64 IS_BIT_SET(DesiredAccess, GENERIC_ALL) ||
65 IS_BIT_SET(DesiredAccess, FILE_WRITE_DATA) ||
66// IS_BIT_SET(DesiredAccess, FILE_WRITE_ACCESS) ||
67// IS_BIT_SET(DesiredAccess, FILE_ADD_FILE) ||
68 IS_BIT_SET(DesiredAccess, FILE_WRITE_ATTRIBUTES) ||
69 IS_BIT_SET(DesiredAccess, FILE_WRITE_EA) ||
70 IS_BIT_SET(DesiredAccess, FILE_APPEND_DATA) ||
71// IS_BIT_SET(DesiredAccess, FILE_ADD_SUBDIRECTORY) ||
72// IS_BIT_SET(DesiredAccess, FILE_CREATE_PIPE_INSTANCE) ||
73 IS_BIT_SET(DesiredAccess, FILE_DELETE_CHILD) ||
74 IS_BIT_SET(DesiredAccess, DELETE) || //XXX it's own category now?
75 IS_BIT_SET(DesiredAccess, WRITE_DAC) ||
76 IS_BIT_SET(DesiredAccess, WRITE_OWNER) ||
77 IS_BIT_SET(DesiredAccess, FILE_ALL_ACCESS) )
78
79 OperationType |= OP_WRITE;
80
81
82 if ( IS_BIT_SET(DesiredAccess, GENERIC_EXECUTE) ||
83 IS_BIT_SET(DesiredAccess, GENERIC_ALL) ||
84 IS_BIT_SET(DesiredAccess, FILE_EXECUTE) ||
85// IS_BIT_SET(DesiredAccess, FILE_TRAVERSE) ||
86 IS_BIT_SET(DesiredAccess, FILE_ALL_ACCESS) )
87
88 OperationType |= OP_EXECUTE;
89
90 if (OperationType == 0)
91// OperationType = OP_READ | OP_WRITE | OP_EXECUTE;
92 LOG(LOG_SS_MISC, LOG_PRIORITY_DEBUG, ("Get_FILE_OperationType: Unknown desired access mask %x\n", DesiredAccess));
93
94
95 return OperationType;
96}
97
98
99
100/*
101 * DecodeFileOperationType()
102 *
103 * Description:
104 * This function decodes file operation types such as GENERIC_READ and DELETE and prints them out (for debugging)
105 *
106 * Parameters:
107 * DesiredAccess - ACCESS_MASK structure (a doubleword value containing standard, specific, and generic rights).
108 *
109 * Returns:
110 * Nothing.
111 */
112
113void
114DecodeFileOperationType(ACCESS_MASK DesiredAccess)
115{
116 UCHAR OperationType = 0;
117 int FileAll = MAXIMUM_ALLOWED | GENERIC_ALL | STANDARD_RIGHTS_REQUIRED |
118 STANDARD_RIGHTS_ALL | SPECIFIC_RIGHTS_ALL | ACCESS_SYSTEM_SECURITY;
119
120
121 if ( (DesiredAccess & GENERIC_READ) == GENERIC_READ)
122 LOG(LOG_SS_MISC, LOG_PRIORITY_DEBUG, ("GENERIC_READ %x\n", GENERIC_READ));
123
124 if ( (DesiredAccess & GENERIC_WRITE) == GENERIC_WRITE)
125 LOG(LOG_SS_MISC, LOG_PRIORITY_DEBUG, ("GENERIC_WRITE %x\n", GENERIC_WRITE));
126
127 if ( (DesiredAccess & GENERIC_EXECUTE) == GENERIC_EXECUTE)
128 LOG(LOG_SS_MISC, LOG_PRIORITY_DEBUG, ("GENERIC_EXECUTE %x\n", GENERIC_EXECUTE));
129
130 if ( (DesiredAccess & STANDARD_RIGHTS_READ) == STANDARD_RIGHTS_READ)
131 LOG(LOG_SS_MISC, LOG_PRIORITY_DEBUG, ("STANDARD_RIGHTS_READ %x\n", STANDARD_RIGHTS_READ));
132
133 if ( (DesiredAccess & SYNCHRONIZE) == SYNCHRONIZE)
134 LOG(LOG_SS_MISC, LOG_PRIORITY_DEBUG, ("SYNCHRONIZE %x\n", SYNCHRONIZE));
135
136 if ( (DesiredAccess & MAXIMUM_ALLOWED) == MAXIMUM_ALLOWED)
137 LOG(LOG_SS_MISC, LOG_PRIORITY_DEBUG, ("MAXIMUM_ALLOWED %x\n", MAXIMUM_ALLOWED));
138
139 if ( (DesiredAccess & GENERIC_ALL) == GENERIC_ALL)
140 LOG(LOG_SS_MISC, LOG_PRIORITY_DEBUG, ("GENERIC_ALL %x\n", GENERIC_ALL));
141
142 if ( (DesiredAccess & STANDARD_RIGHTS_REQUIRED) == STANDARD_RIGHTS_REQUIRED)
143 LOG(LOG_SS_MISC, LOG_PRIORITY_DEBUG, ("STANDARD_RIGHTS_REQUIRED %x\n", STANDARD_RIGHTS_REQUIRED));
144
145 if ( (DesiredAccess & STANDARD_RIGHTS_ALL) == STANDARD_RIGHTS_ALL)
146 LOG(LOG_SS_MISC, LOG_PRIORITY_DEBUG, ("STANDARD_RIGHTS_ALL %x\n", STANDARD_RIGHTS_ALL));
147
148 if ( (DesiredAccess & SPECIFIC_RIGHTS_ALL) == SPECIFIC_RIGHTS_ALL)
149 LOG(LOG_SS_MISC, LOG_PRIORITY_DEBUG, ("SPECIFIC_RIGHTS_ALL %x\n", SPECIFIC_RIGHTS_ALL));
150
151 if ( (DesiredAccess & ACCESS_SYSTEM_SECURITY) == ACCESS_SYSTEM_SECURITY)
152 LOG(LOG_SS_MISC, LOG_PRIORITY_DEBUG, ("ACCESS_SYSTEM_SECURITY %x\n", ACCESS_SYSTEM_SECURITY));
153
154 if ( (DesiredAccess & WRITE_OWNER) == WRITE_OWNER)
155 LOG(LOG_SS_MISC, LOG_PRIORITY_DEBUG, ("WRITE_OWNER %x\n", WRITE_OWNER));
156
157 if ( (DesiredAccess & WRITE_DAC) == WRITE_DAC)
158 LOG(LOG_SS_MISC, LOG_PRIORITY_DEBUG, ("WRITE_DAC %x\n", WRITE_DAC));
159
160 if ( (DesiredAccess & DELETE) == DELETE)
161 LOG(LOG_SS_MISC, LOG_PRIORITY_DEBUG, ("DELETE %x\n", DELETE));
162
163
164 if ( IS_BIT_SET(DesiredAccess, GENERIC_READ) ||
165 IS_BIT_SET(DesiredAccess, (STANDARD_RIGHTS_READ | SYNCHRONIZE )) ||
166 IS_BIT_SET(DesiredAccess, FileAll) )
167
168 LOG(LOG_SS_MISC, LOG_PRIORITY_DEBUG, ("OP_READ\n"));
169
170
171 if ( IS_BIT_SET(DesiredAccess, GENERIC_WRITE) ||
172 IS_BIT_SET(DesiredAccess, (DELETE | WRITE_DAC | WRITE_OWNER)) ||
173 IS_BIT_SET(DesiredAccess, FileAll) )
174
175 LOG(LOG_SS_MISC, LOG_PRIORITY_DEBUG, ("OP_WRITE\n"));
176
177
178 if ( IS_BIT_SET(DesiredAccess, GENERIC_EXECUTE) ||
179 IS_BIT_SET(DesiredAccess, FileAll) )
180
181 LOG(LOG_SS_MISC, LOG_PRIORITY_DEBUG, ("OP_EXECUTE\n"));
182}
183
184
185
186/*
187 * Get_NAMEDPIPE_OperationType()
188 *
189 * Description:
190 * This function decodes named pipe operation types such as GENERIC_READ and DELETE and converts them to
191 * 3 internal operations: OP_READ, OP_WRITE and OP_EXECUTE.
192 *
193 * Parameters:
194 * DesiredAccess - ACCESS_MASK structure (a doubleword value containing standard, specific, and generic rights).
195 *
196 * Returns:
197 * A combination of OP_READ, OP_WRITE & OP_EXECUTE flags set depending on the DesiredAccess argument.
198 */
199
200UCHAR
201Get_NAMEDPIPE_OperationType(ACCESS_MASK DesiredAccess)
202{
203 return Get_FILE_OperationType(DesiredAccess);
204}
205
206
207
208/*
209 * Get_MAILSLOT_OperationType()
210 *
211 * Description:
212 * This function decodes mailslot operation types such as GENERIC_READ and DELETE and converts them to
213 * 3 internal operations: OP_READ, OP_WRITE and OP_EXECUTE.
214 *
215 * Parameters:
216 * DesiredAccess - ACCESS_MASK structure (a doubleword value containing standard, specific, and generic rights).
217 *
218 * Returns:
219 * A combination of OP_READ, OP_WRITE & OP_EXECUTE flags set depending on the DesiredAccess argument.
220 */
221
222UCHAR
223Get_MAILSLOT_OperationType(ACCESS_MASK DesiredAccess)
224{
225 return Get_FILE_OperationType(DesiredAccess);
226}
227
228
229
230/*
231 * Get_REGISTRY_OperationType()
232 *
233 * Description:
234 * This function decodes registry operation types such as KEY_QUERY_VALUE and DELETE and converts them to
235 * 3 internal operations: OP_READ, OP_WRITE and OP_EXECUTE.
236 *
237 * Parameters:
238 * DesiredAccess - ACCESS_MASK structure (a doubleword value containing standard, specific, and generic rights).
239 *
240 * Returns:
241 * A combination of OP_READ, OP_WRITE & OP_EXECUTE flags set depending on the DesiredAccess argument.
242 */
243
244UCHAR
245Get_REGISTRY_OperationType(ACCESS_MASK DesiredAccess)
246{
247 UCHAR OperationType = 0;
248
249
250 if ( IS_BIT_SET(DesiredAccess, GENERIC_READ) ||
251 IS_BIT_SET(DesiredAccess, KEY_QUERY_VALUE) ||
252 IS_BIT_SET(DesiredAccess, KEY_ENUMERATE_SUB_KEYS) ||
253 IS_BIT_SET(DesiredAccess, MAXIMUM_ALLOWED) ||
254 IS_BIT_SET(DesiredAccess, SYNCHRONIZE) ||
255 IS_BIT_SET(DesiredAccess, ACCESS_SYSTEM_SECURITY) ||
256 IS_BIT_SET(DesiredAccess, GENERIC_ALL) ||
257 IS_BIT_SET(DesiredAccess, KEY_ALL_ACCESS) ||
258 DesiredAccess == 0)
259
260 OperationType |= OP_READ;
261
262
263 if ( IS_BIT_SET(DesiredAccess, GENERIC_WRITE) ||
264 IS_BIT_SET(DesiredAccess, KEY_SET_VALUE) ||
265 IS_BIT_SET(DesiredAccess, KEY_CREATE_SUB_KEY) ||
266 IS_BIT_SET(DesiredAccess, KEY_CREATE_LINK) ||
267 IS_BIT_SET(DesiredAccess, WRITE_OWNER) ||
268 IS_BIT_SET(DesiredAccess, WRITE_DAC) ||
269 IS_BIT_SET(DesiredAccess, DELETE) ||
270 IS_BIT_SET(DesiredAccess, MAXIMUM_ALLOWED) ||
271 IS_BIT_SET(DesiredAccess, GENERIC_ALL) ||
272 IS_BIT_SET(DesiredAccess, KEY_ALL_ACCESS) )
273
274 OperationType |= OP_WRITE;
275
276
277 if ( IS_BIT_SET(DesiredAccess, GENERIC_EXECUTE) ||
278 IS_BIT_SET(DesiredAccess, KEY_NOTIFY) ||
279 IS_BIT_SET(DesiredAccess, MAXIMUM_ALLOWED) ||
280 IS_BIT_SET(DesiredAccess, GENERIC_ALL) ||
281 IS_BIT_SET(DesiredAccess, KEY_ALL_ACCESS) )
282
283 OperationType |= OP_EXECUTE;
284
285
286 if (OperationType == 0)
287// OperationType = OP_READ | OP_WRITE | OP_EXECUTE;
288 LOG(LOG_SS_MISC, LOG_PRIORITY_DEBUG, ("Get_REGISTRY_OperationType: Unknown desired access mask %x\n", DesiredAccess));
289
290
291 return OperationType;
292}
293
294
295
296/*
297 * Get_EVENT_OperationType()
298 *
299 * Description:
300 * This function decodes event operation types such as EVENT_QUERY_STATE and GENERIC_WRITE and converts them to
301 * 3 internal operations: OP_READ, OP_WRITE and OP_EXECUTE.
302 *
303 * Parameters:
304 * DesiredAccess - ACCESS_MASK structure (a doubleword value containing standard, specific, and generic rights).
305 *
306 * Returns:
307 * A combination of OP_READ, OP_WRITE & OP_EXECUTE flags set depending on the DesiredAccess argument.
308 */
309
310UCHAR
311Get_EVENT_OperationType(ACCESS_MASK DesiredAccess)
312{
313 UCHAR OperationType = 0;
314
315
316 if ( IS_BIT_SET(DesiredAccess, EVENT_QUERY_STATE) ||
317 IS_BIT_SET(DesiredAccess, GENERIC_READ) ||
318 IS_BIT_SET(DesiredAccess, STANDARD_RIGHTS_READ) ||
319 IS_BIT_SET(DesiredAccess, SYNCHRONIZE) ||
320 IS_BIT_SET(DesiredAccess, EVENT_ALL_ACCESS) )
321
322 OperationType |= OP_READ;
323
324
325 if ( IS_BIT_SET(DesiredAccess, EVENT_MODIFY_STATE) ||
326 IS_BIT_SET(DesiredAccess, GENERIC_WRITE) ||
327 IS_BIT_SET(DesiredAccess, WRITE_DAC) ||
328 IS_BIT_SET(DesiredAccess, WRITE_OWNER) ||
329 IS_BIT_SET(DesiredAccess, EVENT_ALL_ACCESS) )
330
331 OperationType |= OP_WRITE;
332
333
334 if (OperationType == 0)
335// OperationType = OP_READ | OP_WRITE | OP_EXECUTE;
336 LOG(LOG_SS_MISC, LOG_PRIORITY_DEBUG, ("Get_EVENT_OperationType: Unknown desired access mask %x\n", DesiredAccess));
337
338
339 return OperationType;
340}
341
342
343
344/*
345 * Get_SEMAPHORE_OperationType()
346 *
347 * Description:
348 * This function decodes semaphore operation types such as SEMAPHORE_QUERY_STATE and converts them to
349 * 3 internal operations: OP_READ, OP_WRITE and OP_EXECUTE.
350 *
351 * Parameters:
352 * DesiredAccess - ACCESS_MASK structure (a doubleword value containing standard, specific, and generic rights).
353 *
354 * Returns:
355 * A combination of OP_READ, OP_WRITE & OP_EXECUTE flags set depending on the DesiredAccess argument.
356 */
357
358UCHAR
359Get_SEMAPHORE_OperationType(ACCESS_MASK DesiredAccess)
360{
361 UCHAR OperationType = 0;
362
363
364 if ( IS_BIT_SET(DesiredAccess, SEMAPHORE_QUERY_STATE) ||
365 IS_BIT_SET(DesiredAccess, GENERIC_READ) ||
366 IS_BIT_SET(DesiredAccess, READ_CONTROL) ||
367 IS_BIT_SET(DesiredAccess, SEMAPHORE_ALL_ACCESS) )
368
369 OperationType |= OP_READ;
370
371
372 if ( IS_BIT_SET(DesiredAccess, SEMAPHORE_MODIFY_STATE) ||
373 IS_BIT_SET(DesiredAccess, GENERIC_WRITE) ||
374 IS_BIT_SET(DesiredAccess, GENERIC_ALL) ||
375 IS_BIT_SET(DesiredAccess, WRITE_DAC) ||
376 IS_BIT_SET(DesiredAccess, SEMAPHORE_ALL_ACCESS) )
377
378 OperationType |= OP_WRITE;
379
380
381 if (OperationType == 0)
382// OperationType = OP_READ | OP_WRITE | OP_EXECUTE;
383 LOG(LOG_SS_MISC, LOG_PRIORITY_DEBUG, ("Get_SEMAPHORE_OperationType: Unknown desired access mask %x\n", DesiredAccess));
384
385
386 return OperationType;
387}
388
389
390
391/*
392 * Get_SECTION_OperationType()
393 *
394 * Description:
395 * This function decodes section operation types such as SECTION_QUERY and converts them to
396 * 3 internal operations: OP_READ, OP_WRITE and OP_EXECUTE.
397 *
398 * Parameters:
399 * DesiredAccess - ACCESS_MASK structure (a doubleword value containing standard, specific, and generic rights).
400 *
401 * Returns:
402 * A combination of OP_READ, OP_WRITE & OP_EXECUTE flags set depending on the DesiredAccess argument.
403 */
404
405UCHAR
406Get_SECTION_OperationType(ACCESS_MASK DesiredAccess)
407{
408 UCHAR OperationType = 0;
409
410
411 if ( IS_BIT_SET(DesiredAccess, SECTION_QUERY) ||
412 IS_BIT_SET(DesiredAccess, GENERIC_READ) ||
413 IS_BIT_SET(DesiredAccess, READ_CONTROL) ||
414 IS_BIT_SET(DesiredAccess, SECTION_MAP_READ) ||
415 IS_BIT_SET(DesiredAccess, SECTION_ALL_ACCESS) )
416
417 OperationType |= OP_READ;
418
419
420 if ( IS_BIT_SET(DesiredAccess, SECTION_EXTEND_SIZE) ||
421 IS_BIT_SET(DesiredAccess, GENERIC_WRITE) ||
422 IS_BIT_SET(DesiredAccess, WRITE_DAC) ||
423 IS_BIT_SET(DesiredAccess, GENERIC_ALL) ||
424 IS_BIT_SET(DesiredAccess, SECTION_MAP_WRITE) ||
425 IS_BIT_SET(DesiredAccess, SECTION_ALL_ACCESS) )
426
427 OperationType |= OP_WRITE;
428
429
430 if ( IS_BIT_SET(DesiredAccess, SECTION_MAP_EXECUTE) ||
431 IS_BIT_SET(DesiredAccess, GENERIC_ALL) ||
432 IS_BIT_SET(DesiredAccess, SECTION_ALL_ACCESS) )
433
434 OperationType |= OP_EXECUTE;
435
436
437 if (OperationType == 0)
438// OperationType = OP_READ | OP_WRITE | OP_EXECUTE;
439 LOG(LOG_SS_MISC, LOG_PRIORITY_DEBUG, ("Get_SECTION_OperationType: Unknown desired access mask %x\n", DesiredAccess));
440
441
442 return OperationType;
443}
444
445
446
447/*
448 * Get_JOB_OperationType()
449 *
450 * Description:
451 * This function decodes job object operation types such as JOB_OBJECT_QUERY and converts them to
452 * 3 internal operations: OP_READ, OP_WRITE and OP_EXECUTE.
453 *
454 * Parameters:
455 * DesiredAccess - ACCESS_MASK structure (a doubleword value containing standard, specific, and generic rights).
456 *
457 * Returns:
458 * A combination of OP_READ, OP_WRITE & OP_EXECUTE flags set depending on the DesiredAccess argument.
459 */
460
461UCHAR
462Get_JOB_OperationType(ACCESS_MASK DesiredAccess)
463{
464 UCHAR OperationType = 0;
465
466
467 if ( IS_BIT_SET(DesiredAccess, JOB_OBJECT_QUERY) ||
468 IS_BIT_SET(DesiredAccess, JOB_OBJECT_ALL_ACCESS) )
469
470 OperationType |= OP_READ;
471
472
473 if ( IS_BIT_SET(DesiredAccess, JOB_OBJECT_ASSIGN_PROCESS) ||
474 IS_BIT_SET(DesiredAccess, JOB_OBJECT_SET_ATTRIBUTES) ||
475 IS_BIT_SET(DesiredAccess, JOB_OBJECT_TERMINATE) ||
476 IS_BIT_SET(DesiredAccess, JOB_OBJECT_SET_SECURITY_ATTRIBUTES) ||
477 IS_BIT_SET(DesiredAccess, JOB_OBJECT_ALL_ACCESS) )
478
479 OperationType |= OP_WRITE;
480
481
482 if (OperationType == 0)
483// OperationType = OP_READ | OP_WRITE | OP_EXECUTE;
484 LOG(LOG_SS_MISC, LOG_PRIORITY_DEBUG, ("Get_JOB_OperationType: Unknown desired access mask %x\n", DesiredAccess));
485
486
487 return OperationType;
488}
489
490
491
492/*
493 * Get_MUTANT_OperationType()
494 *
495 * Description:
496 * This function decodes mutant operation types such as JOB_OBJECT_QUERY and converts them to
497 * 3 internal operations: OP_READ, OP_WRITE and OP_EXECUTE.
498 *
499 * Parameters:
500 * DesiredAccess - ACCESS_MASK structure (a doubleword value containing standard, specific, and generic rights).
501 *
502 * Returns:
503 * A combination of OP_READ, OP_WRITE & OP_EXECUTE flags set depending on the DesiredAccess argument.
504 */
505
506UCHAR
507Get_MUTANT_OperationType(ACCESS_MASK DesiredAccess)
508{
509 UCHAR OperationType = 0;
510
511
512 if ( IS_BIT_SET(DesiredAccess, MUTANT_QUERY_STATE) ||
513 IS_BIT_SET(DesiredAccess, GENERIC_READ) ||
514 IS_BIT_SET(DesiredAccess, GENERIC_ALL) ||
515 IS_BIT_SET(DesiredAccess, READ_CONTROL) ||
516 IS_BIT_SET(DesiredAccess, SYNCHRONIZE) ||
517 IS_BIT_SET(DesiredAccess, MUTANT_ALL_ACCESS) )
518
519 OperationType |= OP_READ;
520
521
522 if ( IS_BIT_SET(DesiredAccess, MUTANT_ALL_ACCESS) ||
523 IS_BIT_SET(DesiredAccess, WRITE_OWNER) ||
524 IS_BIT_SET(DesiredAccess, GENERIC_WRITE) ||
525 IS_BIT_SET(DesiredAccess, WRITE_DAC) ||
526 IS_BIT_SET(DesiredAccess, GENERIC_ALL) )
527
528 OperationType |= OP_WRITE;
529
530
531 if (OperationType == 0)
532// OperationType = OP_READ | OP_WRITE | OP_EXECUTE;
533 LOG(LOG_SS_MISC, LOG_PRIORITY_DEBUG, ("Get_MUTANT_OperationType: Unknown desired access mask %x\n", DesiredAccess));
534
535
536 return OperationType;
537}
538
539
540
541/*
542 * Get_SYMLINK_OperationType()
543 *
544 * Description:
545 * This function decodes symbolic link operation types such as SYMBOLIC_LINK_QUERY and converts them to
546 * 3 internal operations: OP_READ, OP_WRITE and OP_EXECUTE.
547 *
548 * Parameters:
549 * DesiredAccess - ACCESS_MASK structure (a doubleword value containing standard, specific, and generic rights).
550 *
551 * Returns:
552 * A combination of OP_READ, OP_WRITE & OP_EXECUTE flags set depending on the DesiredAccess argument.
553 */
554
555UCHAR
556Get_SYMLINK_OperationType(ACCESS_MASK DesiredAccess)
557{
558 UCHAR OperationType = 0;
559
560
561 if ( IS_BIT_SET(DesiredAccess, SYMBOLIC_LINK_QUERY) ||
562 IS_BIT_SET(DesiredAccess, GENERIC_READ) ||
563 IS_BIT_SET(DesiredAccess, SYNCHRONIZE) ||
564 IS_BIT_SET(DesiredAccess, SYMBOLIC_LINK_ALL_ACCESS) )
565
566 OperationType |= OP_READ;
567
568
569 if ( IS_BIT_SET(DesiredAccess, DELETE) ||
570 IS_BIT_SET(DesiredAccess, MAXIMUM_ALLOWED) ||
571 IS_BIT_SET(DesiredAccess, SYMBOLIC_LINK_ALL_ACCESS) )
572
573 OperationType |= OP_WRITE;
574
575
576 if (OperationType == 0)
577// OperationType = OP_READ | OP_WRITE | OP_EXECUTE;
578 LOG(LOG_SS_MISC, LOG_PRIORITY_DEBUG, ("Get_SYMLINK_OperationType: Unknown desired access mask %x\n", DesiredAccess));
579
580
581 return OperationType;
582}
583
584
585
586/*
587 * Get_TIMER_OperationType()
588 *
589 * Description:
590 * This function decodes timer operation types such as JOB_OBJECT_QUERY and converts them to
591 * 3 internal operations: OP_READ, OP_WRITE and OP_EXECUTE.
592 *
593 * Parameters:
594 * DesiredAccess - ACCESS_MASK structure (a doubleword value containing standard, specific, and generic rights).
595 *
596 * Returns:
597 * A combination of OP_READ, OP_WRITE & OP_EXECUTE flags set depending on the DesiredAccess argument.
598 */
599
600UCHAR
601Get_TIMER_OperationType(ACCESS_MASK DesiredAccess)
602{
603 UCHAR OperationType = 0;
604
605
606 if ( IS_BIT_SET(DesiredAccess, TIMER_QUERY_STATE) ||
607 IS_BIT_SET(DesiredAccess, TIMER_ALL_ACCESS) )
608
609 OperationType |= OP_READ;
610
611
612 if ( IS_BIT_SET(DesiredAccess, TIMER_MODIFY_STATE) ||
613 IS_BIT_SET(DesiredAccess, TIMER_ALL_ACCESS) )
614
615 OperationType |= OP_WRITE;
616
617
618 if (OperationType == 0)
619// OperationType = OP_READ | OP_WRITE | OP_EXECUTE;
620 LOG(LOG_SS_MISC, LOG_PRIORITY_DEBUG, ("Get_TIMER_OperationType: Unknown desired access mask %x\n", DesiredAccess));
621
622
623 return OperationType;
624}
625
626
627
628/*
629 * Get_PORT_OperationType()
630 *
631 * Description:
632 * This function decodes port operation types and converts them to
633 * 3 internal operations: OP_READ, OP_WRITE and OP_EXECUTE.
634 *
635 * Parameters:
636 * DesiredAccess - ACCESS_MASK structure (a doubleword value containing standard, specific, and generic rights).
637 *
638 * Returns:
639 * OP_WRITE.
640 */
641
642UCHAR
643Get_PORT_OperationType(ACCESS_MASK DesiredAccess)
644{
645 return OP_WRITE;
646}
647
648
649
650/*
651 * Get_DIROBJ_OperationType()
652 *
653 * Description:
654 * This function decodes directory operation types such as DIRECTORY_QUERY and converts them to
655 * 3 internal operations: OP_READ, OP_WRITE and OP_EXECUTE.
656 *
657 * Parameters:
658 * DesiredAccess - ACCESS_MASK structure (a doubleword value containing standard, specific, and generic rights).
659 *
660 * Returns:
661 * A combination of OP_READ, OP_WRITE & OP_EXECUTE flags set depending on the DesiredAccess argument.
662 */
663
664UCHAR
665Get_DIROBJ_OperationType(ACCESS_MASK DesiredAccess)
666{
667 UCHAR OperationType = 0;
668
669
670 if ( IS_BIT_SET(DesiredAccess, DIRECTORY_QUERY) ||
671 IS_BIT_SET(DesiredAccess, DIRECTORY_TRAVERSE) ||
672 IS_BIT_SET(DesiredAccess, DIRECTORY_ALL_ACCESS) )
673
674 OperationType |= OP_READ;
675
676
677 if ( IS_BIT_SET(DesiredAccess, DIRECTORY_CREATE_OBJECT) ||
678 IS_BIT_SET(DesiredAccess, DIRECTORY_CREATE_SUBDIRECTORY) ||
679 IS_BIT_SET(DesiredAccess, DIRECTORY_ALL_ACCESS) )
680
681 OperationType |= OP_WRITE;
682
683
684 if (OperationType == 0)
685// OperationType = OP_READ | OP_WRITE | OP_EXECUTE;
686 LOG(LOG_SS_MISC, LOG_PRIORITY_DEBUG, ("Get_DIROBJ_OperationType: Unknown desired access mask %x\n", DesiredAccess));
687
688
689 return OperationType;
690}
691
692
693
diff --git a/accessmask.h b/accessmask.h
new file mode 100644
index 0000000..7ff4a49
--- /dev/null
+++ b/accessmask.h
@@ -0,0 +1,55 @@
1/*
2 * Copyright (c) 2004 Security Architects Corporation. All rights reserved.
3 *
4 * Module Name:
5 *
6 * accessmask.h
7 *
8 * Abstract:
9 *
10 * This module implements various ACCESS_MASK decoding routines.
11 *
12 * Author:
13 *
14 * Eugene Tsyrklevich 18-Mar-2004
15 *
16 * Revision History:
17 *
18 * None.
19 */
20
21
22#ifndef __ACCESSMASK_H__
23#define __ACCESSMASK_H__
24
25
26#include <NTDDK.h>
27#include "policy.h"
28#include "ntproto.h"
29#include "log.h"
30
31
32// IBS = Is Bit Set?
33
34#define IS_BIT_SET(da, mask) (((da) & (mask)) == (mask))
35
36
37UCHAR Get_FILE_OperationType(ACCESS_MASK DesiredAccess);
38UCHAR Get_NAMEDPIPE_OperationType(ACCESS_MASK DesiredAccess);
39UCHAR Get_MAILSLOT_OperationType(ACCESS_MASK DesiredAccess);
40UCHAR Get_REGISTRY_OperationType(ACCESS_MASK DesiredAccess);
41UCHAR Get_EVENT_OperationType(ACCESS_MASK DesiredAccess);
42UCHAR Get_SEMAPHORE_OperationType(ACCESS_MASK DesiredAccess);
43UCHAR Get_SECTION_OperationType(ACCESS_MASK DesiredAccess);
44UCHAR Get_JOB_OperationType(ACCESS_MASK DesiredAccess);
45UCHAR Get_MUTANT_OperationType(ACCESS_MASK DesiredAccess);
46UCHAR Get_SYMLINK_OperationType(ACCESS_MASK DesiredAccess);
47UCHAR Get_TIMER_OperationType(ACCESS_MASK DesiredAccess);
48UCHAR Get_PORT_OperationType(ACCESS_MASK DesiredAccess);
49UCHAR Get_DIROBJ_OperationType(ACCESS_MASK DesiredAccess);
50
51void DecodeFileOperationType(ACCESS_MASK DesiredAccess);
52
53
54
55#endif /* __ACCESSMASK_H__ */ \ No newline at end of file
diff --git a/atom.c b/atom.c
new file mode 100644
index 0000000..91ecc98
--- /dev/null
+++ b/atom.c
@@ -0,0 +1,187 @@
1/*
2 * Copyright (c) 2004 Security Architects Corporation. All rights reserved.
3 *
4 * Module Name:
5 *
6 * atom.c
7 *
8 * Abstract:
9 *
10 * This module implements various atom hooking routines.
11 *
12 * Author:
13 *
14 * Eugene Tsyrklevich 25-Mar-2004
15 *
16 * Revision History:
17 *
18 * None.
19 */
20
21
22#include "atom.h"
23
24
25#ifdef ALLOC_PRAGMA
26#pragma alloc_text (INIT, InitAtomHooks)
27#endif
28
29
30fpZwAddAtom OriginalNtAddAtom = NULL;
31fpZwFindAtom OriginalNtFindAtom = NULL;
32
33
34
35/*
36 * HookedNtCreateAtom()
37 *
38 * Description:
39 * This function mediates the NtAddAtom() system service and checks the
40 * provided atom name against the global and current process security policies.
41 *
42 * NOTE: ZwAddAtom adds an atom to the global atom table. [NAR]
43 *
44 * Parameters:
45 * Those of NtAddAtom().
46 *
47 * Returns:
48 * STATUS_ACCESS_DENIED if the call does not pass the security policy check.
49 * Otherwise, NTSTATUS returned by NtAddAtom().
50 */
51
52NTSTATUS
53NTAPI
54HookedNtAddAtom
55(
56 IN PWSTR String,
57 IN ULONG StringLength,
58 OUT PUSHORT Atom
59)
60{
61 PCHAR FunctionName = "HookedNtAddAtom";
62 CHAR ATOMNAME[MAX_PATH];
63
64
65 HOOK_ROUTINE_ENTER();
66
67
68 if (!VerifyPwstr(String, StringLength))
69 {
70 LOG(LOG_SS_ATOM, LOG_PRIORITY_DEBUG, ("HookedNtAddAtom: VerifyPwstr(%x) failed\n", String));
71 HOOK_ROUTINE_EXIT( STATUS_ACCESS_DENIED );
72 }
73
74
75 _snprintf(ATOMNAME, MAX_PATH, "%S", String);
76 ATOMNAME[ MAX_PATH - 1 ] = 0;
77
78
79 if (LearningMode == FALSE)
80 {
81 POLICY_CHECK_OPTYPE_NAME(ATOM, OP_WRITE);
82 }
83
84
85 ASSERT(OriginalNtAddAtom);
86
87 rc = OriginalNtAddAtom(String, StringLength, Atom);
88
89
90 HOOK_ROUTINE_FINISH_OBJECTNAME_OPTYPE(ATOM, ATOMNAME, OP_WRITE);
91}
92
93
94
95/*
96 * HookedNtFindAtom()
97 *
98 * Description:
99 * This function mediates the NtFindAtom() system service and checks the
100 * provided atom name against the global and current process security policies.
101 *
102 * NOTE: ZwFindAtom searches for an atom in the global atom table. [NAR]
103 *
104 * Parameters:
105 * Those of NtFindAtom().
106 *
107 * Returns:
108 * STATUS_ACCESS_DENIED if the call does not pass the security policy check.
109 * Otherwise, NTSTATUS returned by NtFindAtom().
110 */
111
112NTSTATUS
113NTAPI
114HookedNtFindAtom
115(
116 IN PWSTR String,
117 IN ULONG StringLength,
118 OUT PUSHORT Atom
119)
120{
121 PCHAR FunctionName = "HookedNtFindAtom";
122 CHAR ATOMNAME[MAX_PATH];
123
124
125 HOOK_ROUTINE_ENTER();
126
127
128 if (!VerifyPwstr(String, StringLength))
129 {
130 LOG(LOG_SS_ATOM, LOG_PRIORITY_DEBUG, ("HookedNtFindAtom: VerifyPwstr(%x) failed\n", String));
131 HOOK_ROUTINE_EXIT( STATUS_ACCESS_DENIED );
132 }
133
134
135 _snprintf(ATOMNAME, MAX_PATH, "%S", String);
136 ATOMNAME[ MAX_PATH - 1 ] = 0;
137
138
139 if (LearningMode == FALSE)
140 {
141 POLICY_CHECK_OPTYPE_NAME(ATOM, OP_READ);
142 }
143
144
145 ASSERT(OriginalNtFindAtom);
146
147 rc = OriginalNtFindAtom(String, StringLength, Atom);
148
149
150 HOOK_ROUTINE_FINISH_OBJECTNAME_OPTYPE(ATOM, ATOMNAME, OP_READ);
151}
152
153
154
155/*
156 * InitAtomHooks()
157 *
158 * Description:
159 * Initializes all the mediated atom operation pointers. The "OriginalFunction" pointers
160 * are initialized by InstallSyscallsHooks() that must be called prior to this function.
161 *
162 * NOTE: Called once during driver initialization (DriverEntry()).
163 *
164 * Parameters:
165 * None.
166 *
167 * Returns:
168 * TRUE to indicate success, FALSE if failed.
169 */
170
171BOOLEAN
172InitAtomHooks()
173{
174 if ( (OriginalNtAddAtom = (fpZwAddAtom) ZwCalls[ZW_ADD_ATOM_INDEX].OriginalFunction) == NULL)
175 {
176 LOG(LOG_SS_ATOM, LOG_PRIORITY_DEBUG, ("InitAtomHooks: OriginalNtAddAtom is NULL\n"));
177 return FALSE;
178 }
179
180 if ( (OriginalNtFindAtom = (fpZwFindAtom) ZwCalls[ZW_FIND_ATOM_INDEX].OriginalFunction) == NULL)
181 {
182 LOG(LOG_SS_ATOM, LOG_PRIORITY_DEBUG, ("InitAtomHooks: OriginalNtFindAtom is NULL\n"));
183 return FALSE;
184 }
185
186 return TRUE;
187}
diff --git a/atom.h b/atom.h
new file mode 100644
index 0000000..68af7f8
--- /dev/null
+++ b/atom.h
@@ -0,0 +1,78 @@
1/*
2 * Copyright (c) 2004 Security Architects Corporation. All rights reserved.
3 *
4 * Module Name:
5 *
6 * atom.h
7 *
8 * Abstract:
9 *
10 * This module defines various types used by atom object hooking routines.
11 *
12 * Author:
13 *
14 * Eugene Tsyrklevich 06-Apr-2004
15 *
16 * Revision History:
17 *
18 * None.
19 */
20
21
22#ifndef __ATOM_H__
23#define __ATOM_H__
24
25
26#include <NTDDK.h>
27#include "policy.h"
28#include "pathproc.h"
29#include "hookproc.h"
30#include "accessmask.h"
31#include "learn.h"
32#include "log.h"
33
34
35/*
36 * ZwAddAtom adds an atom to the global atom table. [NAR]
37 */
38
39typedef NTSTATUS (*fpZwAddAtom) (
40 IN PWSTR String,
41 IN ULONG StringLength,
42 OUT PUSHORT Atom
43 );
44
45NTSTATUS
46NTAPI
47HookedNtAddAtom(
48 IN PWSTR String,
49 IN ULONG StringLength,
50 OUT PUSHORT Atom
51 );
52
53
54
55/*
56 * ZwFindAtom searches for an atom in the global atom table. [NAR]
57 */
58
59
60typedef NTSTATUS (*fpZwFindAtom) (
61 IN PWSTR String,
62 IN ULONG StringLength,
63 OUT PUSHORT Atom
64 );
65
66NTSTATUS
67NTAPI
68HookedNtFindAtom(
69 IN PWSTR String,
70 IN ULONG StringLength,
71 OUT PUSHORT Atom
72 );
73
74
75BOOLEAN InitAtomHooks();
76
77
78#endif /* __ATOM_H__ */
diff --git a/boprot.c b/boprot.c
new file mode 100644
index 0000000..b490012
--- /dev/null
+++ b/boprot.c
@@ -0,0 +1,173 @@
1/*
2 * Copyright (c) 2004 Security Architects Corporation. All rights reserved.
3 *
4 * Module Name:
5 *
6 * boport.c
7 *
8 * Abstract:
9 *
10 * This module implements buffer overflow protection related routines.
11 * Specifically, kernel32.dll randomization. The rest of buffer overflow
12 * code is in process.c
13 *
14 * Author:
15 *
16 * Eugene Tsyrklevich 08-Jun-2004
17 *
18 * Revision History:
19 *
20 * None.
21 */
22
23
24#include "boprot.h"
25#include "hookproc.h"
26#include "i386.h"
27
28
29#ifdef ALLOC_PRAGMA
30#pragma alloc_text (INIT, InitBufferOverflowProtection)
31#endif
32
33
34ULONG Kernel32Offset = 0, User32Offset = 0;
35
36
37/*
38 * InitBufferOverflowProtection()
39 *
40 * Description:
41 * .
42 *
43 * NOTE: Called once during driver initialization (DriverEntry()).
44 *
45 * Parameters:
46 * None.
47 *
48 * Returns:
49 * TRUE to indicate success, FALSE if failed.
50 */
51
52BOOLEAN
53InitBufferOverflowProtection()
54{
55 ULONG addr;
56
57
58 if (NTDLL_Base == NULL)
59 return FALSE;
60
61
62 __try
63 {
64 LOG(LOG_SS_MISC, LOG_PRIORITY_DEBUG, ("searching for kernel32.dll (%x)\n", NTDLL_Base));
65 for (addr = (ULONG) NTDLL_Base; addr < 0x77ff9fff; addr++)
66 {
67 if (_wcsnicmp((PWSTR) addr, L"kernel32.dll", 12) == 0)
68 {
69 LOG(LOG_SS_MISC, LOG_PRIORITY_DEBUG, ("InitBufferOverflowProtection: found kernel32.dll string at offset %x\n", addr));
70 Kernel32Offset = addr;
71 if (User32Offset)
72 break;
73 }
74
75 if (_wcsnicmp((PWSTR) addr, L"user32.dll", 12) == 0)
76 {
77 LOG(LOG_SS_MISC, LOG_PRIORITY_DEBUG, ("InitBufferOverflowProtection: found user32.dll string at offset %x\n", addr));
78 User32Offset = addr;
79 if (Kernel32Offset)
80 break;
81 }
82 }
83
84 /* kernel32.dll and user32.dll strings are supposed to follow each other */
85 if (!Kernel32Offset || !User32Offset || (abs(User32Offset - Kernel32Offset) > 32))
86 {
87 LOG(LOG_SS_MISC, LOG_PRIORITY_WARNING, ("InitBufferOverflowProtection: incorrect kernel32.dll (%x) and user32.dll (%x) offsets\n", Kernel32Offset, User32Offset));
88 Kernel32Offset = 0;
89 User32Offset = 0;
90 return FALSE;
91 }
92
93 if (Kernel32Offset)
94 {
95//XXX convert to use Mdl routines
96 INTERRUPTS_OFF();
97 MEMORY_PROTECTION_OFF();
98
99 /* overwrite the first WCHAR of L"kernel32.dll" string with a zero */
100 * (PWCHAR) Kernel32Offset = 0;
101
102 MEMORY_PROTECTION_ON();
103 INTERRUPTS_ON();
104 }
105#if 0
106 if (User32Offset)
107 {
108 INTERRUPTS_OFF();
109 MEMORY_PROTECTION_OFF();
110
111 * (PWCHAR) User32Offset = 0;
112
113 MEMORY_PROTECTION_ON();
114 INTERRUPTS_ON();
115 }
116#endif
117
118 } // __try
119
120 __except(EXCEPTION_EXECUTE_HANDLER)
121 {
122 NTSTATUS status = GetExceptionCode();
123 LOG(LOG_SS_MISC, LOG_PRIORITY_WARNING, ("InitBufferOverflowProtection: caught an exception. status = 0x%x\n", status));
124
125 return FALSE;
126 }
127
128
129 return TRUE;
130}
131
132
133
134/*
135 * ShutdownBufferOverflowProtection()
136 *
137 * Description:
138 * .
139 *
140 * Parameters:
141 * None.
142 *
143 * Returns:
144 * Nothing.
145 */
146
147VOID
148ShutdownBufferOverflowProtection()
149{
150 if (Kernel32Offset)
151 {
152 INTERRUPTS_OFF();
153 MEMORY_PROTECTION_OFF();
154
155 /* restore the first WCHAR of L"kernel32.dll" string */
156 * (PWCHAR) Kernel32Offset = L'k';
157
158 MEMORY_PROTECTION_ON();
159 INTERRUPTS_ON();
160 }
161#if 0
162 if (User32Offset)
163 {
164 INTERRUPTS_OFF();
165 MEMORY_PROTECTION_OFF();
166
167 * (PWCHAR) User32Offset = L'u';
168
169 MEMORY_PROTECTION_ON();
170 INTERRUPTS_ON();
171 }
172#endif
173}
diff --git a/boprot.h b/boprot.h
new file mode 100644
index 0000000..3c106a6
--- /dev/null
+++ b/boprot.h
@@ -0,0 +1,33 @@
1/*
2 * Copyright (c) 2004 Security Architects Corporation. All rights reserved.
3 *
4 * Module Name:
5 *
6 * boBOPROT.c
7 *
8 * Abstract:
9 *
10 * This module implements buffer overflow protection related routines.
11 *
12 * Author:
13 *
14 * Eugene Tsyrklevich 08-Jun-2004
15 *
16 * Revision History:
17 *
18 * None.
19 */
20
21
22#ifndef __BOPROT_H__
23#define __BOPROT_H__
24
25
26#include <NTDDK.h>
27
28
29BOOLEAN InitBufferOverflowProtection();
30VOID ShutdownBufferOverflowProtection();
31
32
33#endif /* __BOPROT_H__ */
diff --git a/debug.c b/debug.c
new file mode 100644
index 0000000..e48a9eb
--- /dev/null
+++ b/debug.c
@@ -0,0 +1,162 @@
1/*
2 * Copyright (c) 2004 Security Architects Corporation. All rights reserved.
3 *
4 * Module Name:
5 *
6 * debug.c
7 *
8 * Abstract:
9 *
10 * This module implements various debug hooking routines.
11 *
12 * Author:
13 *
14 * Eugene Tsyrklevich 23-Apr-2004
15 *
16 * Revision History:
17 *
18 * None.
19 */
20
21
22#include <NTDDK.h>
23#include "debug.h"
24#include "hookproc.h"
25#include "procname.h"
26#include "learn.h"
27#include "log.h"
28
29
30#ifdef ALLOC_PRAGMA
31#pragma alloc_text (INIT, InitDebugHooks)
32#endif
33
34
35fpZwDebugActiveProcess OriginalNtDebugActiveProcess = NULL;
36
37
38//XXX http://www.nsfocus.net/index.php?act=magazine&do=view&mid=2108
39
40
41/*
42 * IsDebuggingAllowed()
43 *
44 * Description:
45 * Check whether the current process is allowed to use debugging functionality.
46 *
47 * Parameters:
48 * None.
49 *
50 * Returns:
51 * FALSE if debugging is disabled. TRUE otherwise.
52 */
53
54BOOLEAN
55IsDebuggingAllowed()
56{
57 PIMAGE_PID_ENTRY CurrentProcess;
58 BOOLEAN DebuggingAllowed = FALSE;
59
60
61 /* check the global policy first */
62 if (! IS_DEBUGGING_PROTECTION_ON(gSecPolicy))
63 return TRUE;
64
65
66 /* now check the process specific policy */
67 CurrentProcess = FindImagePidEntry(CURRENT_PROCESS_PID, 0);
68
69 if (CurrentProcess != NULL)
70 {
71 DebuggingAllowed = ! IS_DEBUGGING_PROTECTION_ON(CurrentProcess->SecPolicy);
72 }
73 else
74 {
75 LOG(LOG_SS_DEBUG, LOG_PRIORITY_DEBUG, ("%d IsDebuggingAllowed: CurrentProcess = NULL!\n", CURRENT_PROCESS_PID));
76 }
77
78
79 return DebuggingAllowed;
80}
81
82
83
84/*
85 * HookedNtDebugActiveProcess()
86 *
87 * Description:
88 * This function mediates the NtDebugActiveProcess() system service and disallows
89 * debugging.
90 *
91 * Parameters:
92 * Those of NtDebugActiveProcess().
93 *
94 * Returns:
95 * STATUS_ACCESS_DENIED if the call does not pass the security policy check.
96 * Otherwise, NTSTATUS returned by NtDebugActiveProcess().
97 */
98
99NTSTATUS
100NTAPI
101HookedNtDebugActiveProcess
102(
103 UINT32 Unknown1,
104 UINT32 Unknown2
105)
106{
107 HOOK_ROUTINE_ENTER();
108
109
110 LOG(LOG_SS_DEBUG, LOG_PRIORITY_DEBUG, ("HookedNtDebugActiveProcess(%x %x)\n", Unknown1, Unknown2));
111
112 if (LearningMode == FALSE && IsDebuggingAllowed() == FALSE)
113 {
114 LOG(LOG_SS_DEBUG, LOG_PRIORITY_DEBUG, ("%d (%S) HookedNtDebugActiveProcess: disallowing debugging\n", (ULONG) PsGetCurrentProcessId(), GetCurrentProcessName()));
115
116 LogAlert(ALERT_SS_DEBUG, OP_DEBUG, ALERT_RULE_NONE, ACTION_DENY, ALERT_PRIORITY_MEDIUM, NULL, 0, NULL);
117
118 HOOK_ROUTINE_EXIT( STATUS_ACCESS_DENIED );
119 }
120
121
122 ASSERT(OriginalNtDebugActiveProcess);
123
124 rc = OriginalNtDebugActiveProcess(Unknown1, Unknown2);
125
126
127 if (LearningMode == TRUE)
128 TURN_DEBUGGING_PROTECTION_OFF(NewPolicy);
129
130
131 HOOK_ROUTINE_EXIT(rc);
132}
133
134
135
136/*
137 * InitDebugHooks()
138 *
139 * Description:
140 * Initializes all the mediated debug operation pointers. The "OriginalFunction" pointers
141 * are initialized by InstallSyscallsHooks() that must be called prior to this function.
142 *
143 * NOTE: Called once during driver initialization (DriverEntry()).
144 *
145 * Parameters:
146 * None.
147 *
148 * Returns:
149 * TRUE to indicate success, FALSE if failed.
150 */
151
152BOOLEAN
153InitDebugHooks()
154{
155 if ( (OriginalNtDebugActiveProcess = (fpZwDebugActiveProcess) ZwCalls[ZW_DEBUG_ACTIVEPROCESS_INDEX].OriginalFunction) == NULL)
156 {
157 /* does not exist on Win2K */
158 LOG(LOG_SS_DEBUG, LOG_PRIORITY_DEBUG, ("InitDebugHooks: OriginalNtDebugActiveProcess is NULL\n"));
159 }
160
161 return TRUE;
162}
diff --git a/debug.h b/debug.h
new file mode 100644
index 0000000..b2f9077
--- /dev/null
+++ b/debug.h
@@ -0,0 +1,47 @@
1/*
2 * Copyright (c) 2004 Security Architects Corporation. All rights reserved.
3 *
4 * Module Name:
5 *
6 * debug.h
7 *
8 * Abstract:
9 *
10 * This module implements various debug hooking routines.
11 *
12 * Author:
13 *
14 * Eugene Tsyrklevich 23-Apr-2004
15 *
16 * Revision History:
17 *
18 * None.
19 */
20
21
22#ifndef __DEBUG_H__
23#define __DEBUG_H__
24
25
26
27/*
28 * ZwDebugActiveProcess.
29 */
30
31typedef NTSTATUS (*fpZwDebugActiveProcess) (
32 UINT32 Unknown1,
33 UINT32 Unknown2
34 );
35
36NTSTATUS
37NTAPI
38HookedNtDebugActiveProcess(
39 UINT32 Unknown1,
40 UINT32 Unknown2
41 );
42
43
44BOOLEAN InitDebugHooks();
45
46
47#endif /* __DEBUG_H__ */
diff --git a/dirobj.c b/dirobj.c
new file mode 100644
index 0000000..b925e42
--- /dev/null
+++ b/dirobj.c
@@ -0,0 +1,153 @@
1/*
2 * Copyright (c) 2004 Security Architects Corporation. All rights reserved.
3 *
4 * Module Name:
5 *
6 * dirobj.c
7 *
8 * Abstract:
9 *
10 * This module implements various object directory hooking routines.
11 * These are not file system directories (see file.c) but rather containers
12 * for other objects.
13 *
14 * Author:
15 *
16 * Eugene Tsyrklevich 03-Sep-2004
17 *
18 * Revision History:
19 *
20 * None.
21 */
22
23
24#include "dirobj.h"
25
26
27#ifdef ALLOC_PRAGMA
28#pragma alloc_text (INIT, InitDirobjHooks)
29#endif
30
31
32fpZwOpenDirectoryObject OriginalNtOpenDirectoryObject = NULL;
33fpZwCreateDirectoryObject OriginalNtCreateDirectoryObject = NULL;
34
35
36
37/*
38 * HookedNtCreateDirectoryObject()
39 *
40 * Description:
41 * This function mediates the NtCreateDirectoryObject() system service and checks the
42 * provided directory object name against the global and current process security policies.
43 *
44 * NOTE: ZwCreateDirectoryObject creates or opens an object directory. [NAR]
45 *
46 * Parameters:
47 * Those of NtCreateDirectoryObject().
48 *
49 * Returns:
50 * STATUS_ACCESS_DENIED if the call does not pass the security policy check.
51 * Otherwise, NTSTATUS returned by NtCreateDirectoryObject().
52 */
53
54NTSTATUS
55NTAPI
56HookedNtCreateDirectoryObject
57(
58 OUT PHANDLE DirectoryHandle,
59 IN ACCESS_MASK DesiredAccess,
60 IN POBJECT_ATTRIBUTES ObjectAttributes
61)
62{
63 PCHAR FunctionName = "HookedNtCreateDirectoryObject";
64
65
66 HOOK_ROUTINE_START(DIROBJ);
67
68
69 ASSERT(OriginalNtCreateDirectoryObject);
70
71 rc = OriginalNtCreateDirectoryObject(DirectoryHandle, DesiredAccess, ObjectAttributes);
72
73
74 HOOK_ROUTINE_FINISH(DIROBJ);
75}
76
77
78
79/*
80 * HookedNtOpenDirectoryObject()
81 *
82 * Description:
83 * This function mediates the NtOpenDirectoryObject() system service and checks the
84 * provided directory object name against the global and current process security policies.
85 *
86 * NOTE: ZwOpenDirectoryObject opens an object directory. [NAR]
87 *
88 * Parameters:
89 * Those of NtOpenDirectoryObject().
90 *
91 * Returns:
92 * STATUS_ACCESS_DENIED if the call does not pass the security policy check.
93 * Otherwise, NTSTATUS returned by NtOpenDirectoryObject().
94 */
95
96NTSTATUS
97NTAPI
98HookedNtOpenDirectoryObject
99(
100 OUT PHANDLE DirectoryHandle,
101 IN ACCESS_MASK DesiredAccess,
102 IN POBJECT_ATTRIBUTES ObjectAttributes
103)
104{
105 PCHAR FunctionName = "HookedNtOpenDirectoryObject";
106
107
108 HOOK_ROUTINE_START(DIROBJ);
109
110
111 ASSERT(OriginalNtOpenDirectoryObject);
112
113 rc = OriginalNtOpenDirectoryObject(DirectoryHandle, DesiredAccess, ObjectAttributes);
114
115
116 HOOK_ROUTINE_FINISH(DIROBJ);
117}
118
119
120
121/*
122 * InitDirobjHooks()
123 *
124 * Description:
125 * Initializes all the mediated driver object operation pointers. The "OriginalFunction" pointers
126 * are initialized by InstallSyscallsHooks() that must be called prior to this function.
127 *
128 * NOTE: Called once during driver initialization (DriverEntry()).
129 *
130 * Parameters:
131 * None.
132 *
133 * Returns:
134 * TRUE to indicate success, FALSE if failed.
135 */
136
137BOOLEAN
138InitDirobjHooks()
139{
140 if ( (OriginalNtOpenDirectoryObject = (fpZwOpenDirectoryObject) ZwCalls[ZW_OPEN_DIRECTORYOBJECT_INDEX].OriginalFunction) == NULL)
141 {
142 LOG(LOG_SS_FILE, LOG_PRIORITY_DEBUG, ("InitDirobjHooks: OriginalNtOpenDirectoryObject is NULL\n"));
143 return FALSE;
144 }
145
146 if ( (OriginalNtCreateDirectoryObject = (fpZwCreateDirectoryObject) ZwCalls[ZW_CREATE_DIRECTORYOBJECT_INDEX].OriginalFunction) == NULL)
147 {
148 LOG(LOG_SS_FILE, LOG_PRIORITY_DEBUG, ("InitDirobjHooks: OriginalNtCreateDirectoryObject is NULL\n"));
149 return FALSE;
150 }
151
152 return TRUE;
153}
diff --git a/dirobj.h b/dirobj.h
new file mode 100644
index 0000000..311402e
--- /dev/null
+++ b/dirobj.h
@@ -0,0 +1,78 @@
1/*
2 * Copyright (c) 2004 Security Architects Corporation. All rights reserved.
3 *
4 * Module Name:
5 *
6 * dirobj.h
7 *
8 * Abstract:
9 *
10 * This module defines various types used by object directory hooking routines.
11 * These are not file system directories (see file.c) but rather containers
12 * for other objects.
13 *
14 * Author:
15 *
16 * Eugene Tsyrklevich 03-Sep-2004
17 *
18 * Revision History:
19 *
20 * None.
21 */
22
23
24#ifndef __DIROBJ_H__
25#define __DIROBJ_H__
26
27
28#include <NTDDK.h>
29#include "policy.h"
30#include "pathproc.h"
31#include "hookproc.h"
32#include "accessmask.h"
33#include "learn.h"
34#include "log.h"
35
36
37/*
38 * ZwCreateDirectoryObject creates or opens an object directory. [NAR]
39 */
40
41typedef NTSTATUS (*fpZwCreateDirectoryObject) (
42 OUT PHANDLE DirectoryHandle,
43 IN ACCESS_MASK DesiredAccess,
44 IN POBJECT_ATTRIBUTES ObjectAttributes
45 );
46
47NTSTATUS
48NTAPI
49HookedNtCreateDirectoryObject(
50 OUT PHANDLE DirectoryHandle,
51 IN ACCESS_MASK DesiredAccess,
52 IN POBJECT_ATTRIBUTES ObjectAttributes
53 );
54
55
56/*
57 * ZwOpenDirectoryObject opens an object directory. [NAR]
58 */
59
60typedef NTSTATUS (*fpZwOpenDirectoryObject) (
61 OUT PHANDLE DirectoryHandle,
62 IN ACCESS_MASK DesiredAccess,
63 IN POBJECT_ATTRIBUTES ObjectAttributes
64 );
65
66NTSTATUS
67NTAPI
68HookedNtOpenDirectoryObject(
69 OUT PHANDLE DirectoryHandle,
70 IN ACCESS_MASK DesiredAccess,
71 IN POBJECT_ATTRIBUTES ObjectAttributes
72 );
73
74
75BOOLEAN InitDirobjHooks();
76
77
78#endif /* __DIROBJ_H__ */
diff --git a/driver.c b/driver.c
new file mode 100644
index 0000000..09f66ad
--- /dev/null
+++ b/driver.c
@@ -0,0 +1,1237 @@
1/*
2 * Copyright (c) 2004 Security Architects Corporation. All rights reserved.
3 *
4 * Module Name:
5 *
6 * driver.c
7 *
8 * Abstract:
9 *
10 * This module implements all the device driver "plumbing" (DriverEntry, etc).
11 *
12 * Author:
13 *
14 * Eugene Tsyrklevich 9-Feb-2004
15 *
16 * Revision History:
17 *
18 * None.
19 */
20
21
22#include <NTDDK.h>
23#include <devioctl.h>
24
25#include "driver.h"
26//#include "eugene.h"
27#include "file.h"
28#include "registry.h"
29#include "sysinfo.h"
30#include "policy.h"
31#include "process.h"
32#include "learn.h"
33#include "event.h"
34#include "semaphore.h"
35#include "dirobj.h"
36#include "symlink.h"
37#include "mutant.h"
38#include "port.h"
39#include "timer.h"
40#include "token.h"
41#include "job.h"
42#include "driverobj.h"
43#include "network.h"
44#include "section.h"
45#include "atom.h"
46#include "time.h"
47#include "vdm.h"
48#include "procname.h"
49#include "userland.h"
50#include "media.h"
51#include "boprot.h"
52#include "debug.h"
53#include "i386.h"
54#include "misc.h"
55#include "log.h"
56
57
58LONG SysenterEip = 0;
59
60
61__declspec(naked)
62VOID
63SysenterHandler()
64{
65 _asm and ecx, 0x000000FF
66 _asm sub esp, ecx
67 _asm jmp [SysenterEip]
68}
69
70
71VOID
72blah()
73{
74 LONG c, s;
75
76#define SYSENTER_CS_MSR 0x174
77#define SYSENTER_ESP_MSR 0x175
78#define SYSENTER_EIP_MSR 0x176
79
80 _asm
81 {
82 mov ecx, SYSENTER_CS_MSR
83 rdmsr
84
85 mov c, eax
86
87
88 mov ecx, SYSENTER_ESP_MSR
89 rdmsr
90
91 mov s, eax
92
93
94 mov ecx, SYSENTER_EIP_MSR
95 rdmsr
96
97 mov SysenterEip, eax
98
99 mov eax, SysenterHandler
100
101 wrmsr
102 }
103
104 KdPrint(("old eip=%x:%x (%x), new eip=%x\n", c, SysenterEip, s, SysenterHandler));
105}
106
107
108
109/*
110 * DriverEntry()
111 *
112 * Description:
113 * Driver entry point.
114 *
115 * Parameters:
116 * pDriverObject - pointer to an initialized driver object that represents our driver
117 * pRegistryPath - name of the service key in the registry
118 *
119 * Returns:
120 * STATUS_SUCCESS to indicate success or an error code to indicate an error.
121 */
122
123/* macro shortcut for bailing out of DriverEntry in case of an error */
124
125#define ABORT_DriverEntry(msg) \
126 { \
127 LOG(LOG_SS_DRIVER_INTERNAL, LOG_PRIORITY_CRITICAL, (msg)); \
128 if (irql != PASSIVE_LEVEL) KeLowerIrql(irql); \
129 DriverUnload(pDriverObject); \
130 return status; \
131 }
132/*
133PVOID Find_Kernel32_Base();
134NTSTATUS
135NTAPI
136ZwCreateSymbolicLinkObject(
137 OUT PHANDLE SymbolicLinkHandle,
138 IN ACCESS_MASK DesiredAccess,
139 IN POBJECT_ATTRIBUTES ObjectAttributes,
140 IN PUNICODE_STRING TargetName
141 );
142 HANDLE h;
143*/
144NTSTATUS
145DriverEntry(IN PDRIVER_OBJECT pDriverObject, IN PUNICODE_STRING pRegistryPath)
146{
147 UNICODE_STRING usDeviceName, usSymLinkName;
148 PDEVICE_OBJECT pDeviceObject;
149 PDEVICE_EXTENSION pDeviceExtension;
150 NTSTATUS status;
151 KIRQL irql = KeGetCurrentIrql();
152 int i;
153
154/*
155 {
156 OBJECT_ATTRIBUTES ObjectAttributes;
157 UNICODE_STRING dest, target;
158 NTSTATUS status;
159
160 RtlInitUnicodeString(&dest, L"\\??\\MyRegistryMachine");
161 RtlInitUnicodeString(&target, L"\\Registry\\Machine");
162
163 InitializeObjectAttributes(&ObjectAttributes, &dest, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL);
164
165 status = ZwCreateSymbolicLinkObject(&h, SYMBOLIC_LINK_ALL_ACCESS, &ObjectAttributes, &target);
166 if (! NT_SUCCESS(status))
167 {
168 KdPrint(("failed, status %x\n", status));
169 }
170 else
171 {
172 KdPrint(("link ok\n"));
173 }
174
175// return STATUS_UNSUCCESSFUL;
176 }
177*/
178 //XXX add pRegistryPath to deny registry access rule?!
179
180 __try
181 {
182 LOG(LOG_SS_DRIVER_INTERNAL, LOG_PRIORITY_DEBUG, ("DriverEntry: Entered (%x %S)\n", pDriverObject, pRegistryPath->Buffer));
183
184
185// blah();
186// KdPrint(("after blah\n"));
187
188
189 /*
190 * Verify we are running on x86 & everything is in order
191 */
192
193 if (!InitI386())
194 {
195 LOG(LOG_SS_DRIVER_INTERNAL, LOG_PRIORITY_CRITICAL, ("InitI386 failed. Aborting.\n"));
196 return STATUS_UNSUCCESSFUL;
197 }
198
199
200 /*
201 * Initialize all the driver object related data and create a device representing our device
202 */
203
204 // set to NULL to disable unload by admins
205// pDriverObject->DriverUnload = NULL;
206 pDriverObject->DriverUnload = DriverUnload;
207
208//XXX need to intercept DriverObject->FastIoDispatch = &VTrcFSFastIoDispatchTable;
209
210 for (i = 0; i < IRP_MJ_MAXIMUM_FUNCTION; i++)
211 //XXX don't intercept IRP_MJ_POWER & IRP_MJ_PNP
212 pDriverObject->MajorFunction[i] = DriverDeviceControl;
213
214 pDriverObject->MajorFunction[ IRP_MJ_CREATE ] = DriverCreate;
215 pDriverObject->MajorFunction[ IRP_MJ_CLEANUP ] = DriverCleanup;
216 pDriverObject->MajorFunction[ IRP_MJ_CLOSE ] = DriverClose;
217 pDriverObject->MajorFunction[ IRP_MJ_DEVICE_CONTROL ] = DriverDeviceControl;
218/*
219 pDriverObject->MajorFunction[ IRP_MJ_READ ] = DriverRead;
220 pDriverObject->MajorFunction[ IRP_MJ_WRITE ] = DriverWrite;
221 */
222 RtlInitUnicodeString(&usDeviceName, DEVICE_NAME);
223
224 status = IoCreateDevice(pDriverObject, sizeof(DEVICE_EXTENSION),
225 &usDeviceName, FILE_DEVICE_UNKNOWN,
226 FILE_DEVICE_SECURE_OPEN, FALSE,//FALSE (Exclusive - Reserved for system use. Drivers set this parameter to FALSE.)
227// 0, TRUE,
228 &pDeviceObject);
229
230 if (!NT_SUCCESS(status))
231 {
232 LOG(LOG_SS_DRIVER_INTERNAL, LOG_PRIORITY_DEBUG, ("DriverEntry: IoCreateDevice failed with status %x\n", status));
233
234 return status;
235 }
236
237
238 pDeviceObject->Flags |= DO_BUFFERED_IO;
239
240 pDeviceExtension = (PDEVICE_EXTENSION) pDeviceObject->DeviceExtension;
241 pDeviceExtension->pDeviceObject = pDeviceObject;
242
243
244 RtlInitUnicodeString(&pDeviceExtension->usSymLink, DEVICE_SYMLINK_NAME);
245
246 status = IoCreateSymbolicLink(&pDeviceExtension->usSymLink, &usDeviceName);
247 if (!NT_SUCCESS(status))
248 {
249 LOG(LOG_SS_DRIVER_INTERNAL, LOG_PRIORITY_DEBUG, ("DriverEntry: IoCreateSymbolicLink failed with status %x\n", status));
250
251 IoDeleteDevice(pDeviceObject);
252
253 return status;
254 }
255
256
257 /*
258 * Now, mediate all the necessary calls
259 */
260
261#if HOOK_NETWORK
262 status = InstallNetworkHooks(pDriverObject);
263 if (! NT_SUCCESS(status))
264 ABORT_DriverEntry("InstallNetworkHooks() failed");
265#endif
266
267
268 /* all consequitive calls that fail will cause the following error to be returned */
269
270 status = STATUS_DRIVER_INTERNAL_ERROR;
271
272 if (!InitSyscallsHooks())
273 ABORT_DriverEntry("InitSyscallsHooks() failed\n");
274
275
276 /*
277 * raise irql to DPC level to avoid any spurious system calls taking place before we
278 * manage to initialize appropriate hooked function pointers
279 */
280
281 irql = KeRaiseIrqlToDpcLevel();
282
283
284 if (!InstallSyscallsHooks())
285 ABORT_DriverEntry("InstallSyscallsHooks() failed\n");
286
287
288#if HOOK_FILE
289 if (!InitFileHooks())
290 ABORT_DriverEntry("InitFileHooks() failed\n");
291
292 LOG(LOG_SS_DRIVER_INTERNAL, LOG_PRIORITY_VERBOSE, ("DriverEntry: Past InitFileHooks\n"));
293#endif
294
295#if HOOK_REGISTRY
296 if (!InitRegistryHooks())
297 ABORT_DriverEntry("InitRegistryHooks() failed\n");
298
299 LOG(LOG_SS_DRIVER_INTERNAL, LOG_PRIORITY_VERBOSE, ("DriverEntry: Past InitRegistryHooks\n"));
300#endif
301
302#if HOOK_SECTION
303 if (!InitSectionHooks())
304 ABORT_DriverEntry("InitSectionHooks() failed\n");
305
306 LOG(LOG_SS_DRIVER_INTERNAL, LOG_PRIORITY_VERBOSE, ("DriverEntry: Past InitSectionHooks\n"));
307#endif
308
309#if HOOK_SYSINFO
310 if (!InitSysInfoHooks())
311 ABORT_DriverEntry("InitSysInfoHooks() failed\n");
312
313 LOG(LOG_SS_DRIVER_INTERNAL, LOG_PRIORITY_VERBOSE, ("DriverEntry: Past InitSysInfoHooks\n"));
314#endif
315
316#if HOOK_EVENT
317 if (!InitEventHooks())
318 ABORT_DriverEntry("InitEventHooks() failed\n");
319
320 LOG(LOG_SS_DRIVER_INTERNAL, LOG_PRIORITY_VERBOSE, ("DriverEntry: Past InitEventHooks\n"));
321#endif
322
323#if HOOK_SEMAPHORE
324 if (!InitSemaphoreHooks())
325 ABORT_DriverEntry("InitSemaphoreHooks() failed\n");
326
327 LOG(LOG_SS_DRIVER_INTERNAL, LOG_PRIORITY_VERBOSE, ("DriverEntry: Past InitSemaphoreHooks\n"));
328#endif
329
330#if HOOK_JOB
331 if (!InitJobHooks())
332 ABORT_DriverEntry("InitJobHooks() failed\n");
333
334 LOG(LOG_SS_DRIVER_INTERNAL, LOG_PRIORITY_VERBOSE, ("DriverEntry: Past InitJobHooks\n"));
335#endif
336
337#if HOOK_MUTANT
338 if (!InitMutantHooks())
339 ABORT_DriverEntry("InitMutantHooks() failed\n");
340
341 LOG(LOG_SS_DRIVER_INTERNAL, LOG_PRIORITY_VERBOSE, ("DriverEntry: Past InitMutantHooks\n"));
342#endif
343
344#if HOOK_DIROBJ
345 if (!InitDirobjHooks())
346 ABORT_DriverEntry("InitDirobjHooks() failed\n");
347
348 LOG(LOG_SS_DRIVER_INTERNAL, LOG_PRIORITY_VERBOSE, ("DriverEntry: Past InitDirobjHooks\n"));
349#endif
350
351#if HOOK_PORT
352 if (!InitPortHooks())
353 ABORT_DriverEntry("InitPortHooks() failed\n");
354
355 LOG(LOG_SS_DRIVER_INTERNAL, LOG_PRIORITY_VERBOSE, ("DriverEntry: Past InitPortHooks\n"));
356#endif
357
358#if HOOK_SYMLINK
359 if (!InitSymlinkHooks())
360 ABORT_DriverEntry("InitSymlinkHooks() failed\n");
361
362 LOG(LOG_SS_DRIVER_INTERNAL, LOG_PRIORITY_VERBOSE, ("DriverEntry: Past InitSymlinkHooks\n"));
363#endif
364
365#if HOOK_TIMER
366 if (!InitTimerHooks())
367 ABORT_DriverEntry("InitTimerHooks() failed\n");
368
369 LOG(LOG_SS_DRIVER_INTERNAL, LOG_PRIORITY_VERBOSE, ("DriverEntry: Past InitTimerHooks\n"));
370#endif
371
372#if HOOK_TOKEN
373 if (!InitTokenHooks())
374 ABORT_DriverEntry("InitTokenHooks() failed\n");
375
376 LOG(LOG_SS_DRIVER_INTERNAL, LOG_PRIORITY_VERBOSE, ("DriverEntry: Past InitTokenHooks\n"));
377#endif
378
379#if HOOK_TIME
380 if (!InitTimeHooks())
381 ABORT_DriverEntry("InitTimeHooks() failed\n");
382
383 LOG(LOG_SS_DRIVER_INTERNAL, LOG_PRIORITY_VERBOSE, ("DriverEntry: Past InitTimeHooks\n"));
384#endif
385
386#if HOOK_DRIVEROBJ
387 if (!InitDriverObjectHooks())
388 ABORT_DriverEntry("InitDriverObjectHooks() failed\n");
389
390 LOG(LOG_SS_DRIVER_INTERNAL, LOG_PRIORITY_VERBOSE, ("DriverEntry: Past InitDriverObjectHooks\n"));
391#endif
392
393#if HOOK_ATOM
394 if (!InitAtomHooks())
395 ABORT_DriverEntry("InitAtomHooks() failed\n");
396
397 LOG(LOG_SS_DRIVER_INTERNAL, LOG_PRIORITY_VERBOSE, ("DriverEntry: Past InitAtomHooks\n"));
398#endif
399
400#if HOOK_VDM
401 if (!InitVdmHooks())
402 ABORT_DriverEntry("InitVdmHooks() failed\n");
403
404 LOG(LOG_SS_DRIVER_INTERNAL, LOG_PRIORITY_VERBOSE, ("DriverEntry: Past InitVdmHooks\n"));
405#endif
406
407
408#if HOOK_DEBUG
409 if (!InitDebugHooks())
410 ABORT_DriverEntry("InitDebugHooks() failed\n");
411
412 LOG(LOG_SS_DRIVER_INTERNAL, LOG_PRIORITY_VERBOSE, ("DriverEntry: Past InitDebugHooks\n"));
413#endif
414
415
416 KeLowerIrql(irql);
417
418
419 /*
420 * The order of the following calls is important:
421 *
422 * InitProcessEntries() initializes OzoneInstallPath
423 * InitPolicy() initiailizes policy related variables
424 * InitProcessNameEntries() then uses policy vars & OzoneInstallPath to load policies
425 */
426
427#if HOOK_PROCESS
428 if (!InitProcessEntries())
429 ABORT_DriverEntry("InitProcessEntries() failed\n");
430
431 LOG(LOG_SS_DRIVER_INTERNAL, LOG_PRIORITY_VERBOSE, ("DriverEntry: Past InitProcessEntries\n"));
432#endif
433
434
435 if (!InitProcessNameEntries())
436 ABORT_DriverEntry("InitProcessNameEntries() failed\n");
437
438 LOG(LOG_SS_DRIVER_INTERNAL, LOG_PRIORITY_VERBOSE, ("DriverEntry: Past InitProcessNameEntries\n"));
439
440
441 if (!InitPolicy())
442 ABORT_DriverEntry("InitPolicy() failed\n");
443
444 LOG(LOG_SS_DRIVER_INTERNAL, LOG_PRIORITY_VERBOSE, ("DriverEntry: Past InitPolicy\n"));
445
446
447 EnumerateExistingProcesses();
448
449 LOG(LOG_SS_DRIVER_INTERNAL, LOG_PRIORITY_VERBOSE, ("DriverEntry: Past EnumerateExistingProcesses\n"));
450
451
452
453 if (LearningMode == TRUE)
454 {
455 if (!InitLearningMode())
456 ABORT_DriverEntry("InitLearningMode() failed\n");
457
458 LOG(LOG_SS_DRIVER_INTERNAL, LOG_PRIORITY_VERBOSE, ("DriverEntry: Past InitLearningMode\n"));
459 }
460
461
462#if HOOK_MEDIA
463 if (!InitRemovableMediaHooks(pDriverObject, pDeviceObject))
464 ABORT_DriverEntry("InitRemovableMedia() failed\n");
465
466 LOG(LOG_SS_DRIVER_INTERNAL, LOG_PRIORITY_VERBOSE, ("DriverEntry: Past InitRemovableMediaHooks\n"));
467#endif
468
469
470#if HOOK_BOPROT
471 if (!InitBufferOverflowProtection())
472 ABORT_DriverEntry("InitBufferOverflowProtection() failed\n");
473
474 LOG(LOG_SS_DRIVER_INTERNAL, LOG_PRIORITY_VERBOSE, ("DriverEntry: Past InitBufferOverflowProtection\n"));
475#endif
476
477
478 if (!InitLog())
479 ABORT_DriverEntry("InitLog() failed\n");
480
481 LOG(LOG_SS_DRIVER_INTERNAL, LOG_PRIORITY_VERBOSE, ("DriverEntry: Past InitLog\n"));
482
483
484 if (!InitUserland())
485 ABORT_DriverEntry("InitUserland() failed\n");
486
487 LOG(LOG_SS_DRIVER_INTERNAL, LOG_PRIORITY_VERBOSE, ("DriverEntry: Past InitUserland\n"));
488
489 } // __try
490
491 __except(EXCEPTION_EXECUTE_HANDLER)
492 {
493 NTSTATUS status = GetExceptionCode();
494 LOG(LOG_SS_DRIVER_INTERNAL, LOG_PRIORITY_CRITICAL, ("DriverEntry: caught an exception. status = 0x%x\n", status));
495
496 return STATUS_DRIVER_INTERNAL_ERROR;
497 }
498
499
500 LOG(LOG_SS_DRIVER_INTERNAL, LOG_PRIORITY_DEBUG, ("DriverEntry: Done\n"));
501
502
503 return STATUS_SUCCESS;
504}
505
506
507
508/*
509 * DriverUnload()
510 *
511 * Description:
512 * Clean up and unload the driver.
513 *
514 * NOTE: Since this driver mediates system calls and other devices, it is not safe to
515 * unload the driver since there might remain outstanding references to our driver code and data
516 * segments once the driver is unloaded.
517 *
518 * NOTE2: In release builds, unload functionality should be disabled for security reasons.
519 *
520 * Parameters:
521 * pDriverObject - pointer to a driver object that represents this driver.
522 *
523 * Returns:
524 * Nothing.
525 */
526
527VOID
528DriverUnload(IN PDRIVER_OBJECT pDriverObject)
529{
530 PDEVICE_OBJECT pDeviceObject, pNextDeviceObject;
531 PDEVICE_EXTENSION pDeviceExtension;
532 LARGE_INTEGER delay;
533
534
535#if DBG
536 LOG(LOG_SS_DRIVER_INTERNAL, LOG_PRIORITY_DEBUG, ("DriverUnload: irql = %d %d\n", KeGetCurrentIrql(), HookedTDIRunning));
537#endif
538
539
540 if (SysenterEip)
541 _asm
542 {
543 mov ecx, SYSENTER_EIP_MSR
544 mov eax, SysenterEip
545 xor edx, edx
546 wrmsr
547 }
548
549#if HOOK_BOPROT
550 ShutdownBufferOverflowProtection();
551 LOG(LOG_SS_DRIVER_INTERNAL, LOG_PRIORITY_VERBOSE, ("DriverUnload: Past ShutdownBufferOverflowProtection\n"));
552#endif
553
554
555 RemoveRemovableMediaHooks();
556 LOG(LOG_SS_DRIVER_INTERNAL, LOG_PRIORITY_VERBOSE, ("DriverUnload: Past RemoveRemovableMediaHooks\n"));
557
558 RemoveNetworkHooks(pDriverObject);
559 LOG(LOG_SS_DRIVER_INTERNAL, LOG_PRIORITY_VERBOSE, ("DriverUnload: Past RemoveNetworkHooks\n"));
560
561 RemoveSyscallsHooks();
562 LOG(LOG_SS_DRIVER_INTERNAL, LOG_PRIORITY_VERBOSE, ("DriverUnload: Past RemoveSyscallsHooks\n"));
563
564 RemoveProcessNameEntries();
565 LOG(LOG_SS_DRIVER_INTERNAL, LOG_PRIORITY_VERBOSE, ("DriverUnload: Past RemoveProcessNameEntries\n"));
566
567
568 if (LearningMode)
569 ShutdownLearningMode();
570 else
571 PolicyRemove();
572
573 LOG(LOG_SS_DRIVER_INTERNAL, LOG_PRIORITY_VERBOSE, ("DriverUnload: Past LearningMode\n"));
574
575
576 ShutdownLog();
577 LOG(LOG_SS_DRIVER_INTERNAL, LOG_PRIORITY_VERBOSE, ("DriverUnload: Past ShutdownLog\n"));
578
579
580 ShutdownUserland();
581 LOG(LOG_SS_DRIVER_INTERNAL, LOG_PRIORITY_VERBOSE, ("DriverUnload: Past UserlandShutdown\n"));
582
583
584 pDeviceObject = pNextDeviceObject = pDriverObject->DeviceObject;
585
586 while (pNextDeviceObject != NULL)
587 {
588 pNextDeviceObject = pDeviceObject->NextDevice;
589 pDeviceExtension = (PDEVICE_EXTENSION) pDeviceObject->DeviceExtension;
590
591 if (pDeviceExtension)
592 {
593 NTSTATUS status;
594
595 LOG(LOG_SS_DRIVER_INTERNAL, LOG_PRIORITY_DEBUG, ("DriverUnload: IoDeleteSymbolicLink(%S)\n", pDeviceExtension->usSymLink.Buffer));
596
597 status = IoDeleteSymbolicLink(&pDeviceExtension->usSymLink);
598 if (! NT_SUCCESS(status))
599 LOG(LOG_SS_DRIVER_INTERNAL, LOG_PRIORITY_DEBUG, ("DriverUnload: IoDeleteSymbolicLink failed: %x\n", status));
600 }
601 else
602 LOG(LOG_SS_DRIVER_INTERNAL, LOG_PRIORITY_DEBUG, ("DriverUnload: pDeviceExtension = NULL\n"));
603
604 IoDeleteDevice(pDeviceObject);
605 pDeviceObject = pNextDeviceObject;
606 }
607
608
609 /* wait for 1 second for all timers/callbacks to complete */
610 delay.QuadPart = SECONDS(1);
611
612 KeDelayExecutionThread(KernelMode, FALSE, &delay);
613
614
615#if DBG
616 LOG(LOG_SS_DRIVER_INTERNAL, LOG_PRIORITY_DEBUG, ("DriverUnload: HookedRoutineRunning = %d\n", HookedRoutineRunning));
617#endif
618
619
620 return;
621}
622
623
624
625/*
626 * DriverDeviceControl()
627 *
628 * Description:
629 * Dispatch routine. Process network (TDI) and our driver requests.
630 *
631 * Parameters:
632 * pDeviceObject - pointer to a device object that a request is being sent to.
633 * pIrp - IRP (I/O Request Packet) request.
634 *
635 * Returns:
636 * Nothing.
637 */
638
639#define COMPLETE_REQUEST(irp, status) \
640 pIrp->IoStatus.Status = (status); \
641 IoCompleteRequest((irp), IO_NO_INCREMENT); \
642 return((status));
643
644NTSTATUS
645DriverDeviceControl(IN PDEVICE_OBJECT pDeviceObject, IN PIRP pIrp)
646{
647 PIO_STACK_LOCATION pIrpStack;
648 ULONG ControlCode;
649 NTSTATUS status;
650 ULONG InSize, OutSize;
651 KIRQL irql;
652
653
654 if (pDeviceObject == NULL || pIrp == NULL)
655 {
656 LOG(LOG_SS_DRIVER_INTERNAL, LOG_PRIORITY_DEBUG, ("DriverDeviceControl: NULL value %x %x\n", pDeviceObject, pIrp));
657
658 COMPLETE_REQUEST(pIrp, STATUS_UNSUCCESSFUL);
659 }
660
661
662#if HOOK_NETWORK
663 if (TDIDispatch(pDeviceObject, pIrp, &status) == TRUE)
664 {
665 LOG(LOG_SS_DRIVER_INTERNAL, LOG_PRIORITY_VERBOSE, ("DriverDeviceControl(%x, %x): TDIDispatch\n", pDeviceObject, pIrp));
666 return status;
667 }
668#endif
669
670
671 pIrpStack = IoGetCurrentIrpStackLocation(pIrp);
672
673 pIrp->IoStatus.Information = 0;
674
675
676 ControlCode = pIrpStack->Parameters.DeviceIoControl.IoControlCode;
677 InSize = pIrpStack->Parameters.DeviceIoControl.InputBufferLength;
678 OutSize = pIrpStack->Parameters.DeviceIoControl.OutputBufferLength;
679
680 switch (ControlCode)
681 {
682 /*
683 * When userland agent service starts up, it registers with the driver using IOCTL_REGISTER_AGENT_SERVICE.
684 * Expects back 1 ULONG - version of the driver
685 */
686
687 // XXX save agent pid and version?
688 case IOCTL_REGISTER_AGENT_SERVICE:
689 {
690 ULONG DriverVersion = DRIVER_VERSION;
691
692
693 LOG(LOG_SS_DRIVER_INTERNAL, LOG_PRIORITY_DEBUG, ("DriverDeviceControl: IOCTL_REGISTER_AGENT_SERVICE ControlCode=%x InBufferSize=%x OutBufferSize=%x\n", ControlCode, InSize, OutSize));
694
695
696 if (OutSize < sizeof(ULONG))
697 {
698 status = STATUS_INVALID_BUFFER_SIZE;
699 break;
700 }
701
702
703 RtlCopyMemory(pIrp->AssociatedIrp.SystemBuffer, &DriverVersion, sizeof(ULONG));
704
705 ActiveUserAgent = TRUE;
706
707
708 pIrp->IoStatus.Information = sizeof(ULONG);
709
710 status = STATUS_SUCCESS;
711
712
713 break;
714 }
715
716
717 /*
718 * Userland agent service retrieves log alerts using IOCTL_GET_ALERT
719 */
720
721 case IOCTL_GET_ALERT:
722 {
723 PSECURITY_ALERT TmpAlert;
724
725
726 LOG(LOG_SS_DRIVER_INTERNAL, LOG_PRIORITY_DEBUG, ("DriverDeviceControl: IOCTL_GET_ALERT ControlCode=%x InBufferSize=%x OutBufferSize=%x\n", ControlCode, InSize, OutSize));
727
728
729// if (UserAgentRegistered == FALSE)
730// XXX;
731
732 KeAcquireSpinLock(&gLogSpinLock, &irql);
733 {
734 if (LogList == NULL)
735 {
736 LOG(LOG_SS_DRIVER_INTERNAL, LOG_PRIORITY_DEBUG, ("DriverDeviceControl: IOCTL_GET_ALERT No More Alerts\n"));
737
738 status = STATUS_NO_MORE_ENTRIES;
739
740 KeReleaseSpinLock(&gLogSpinLock, irql);
741
742 break;
743 }
744
745 /* don't count the size of the Next pointer */
746 LogList->Size -= sizeof(struct _SECURITY_ALERT *);
747
748 if (OutSize < LogList->Size)
749 {
750 LOG(LOG_SS_DRIVER_INTERNAL, LOG_PRIORITY_DEBUG, ("DriverDeviceControl: IOCTL_GET_ALERT %d < %d\n", OutSize, LogList->Size));
751 status = STATUS_INVALID_BUFFER_SIZE;
752 KeReleaseSpinLock(&gLogSpinLock, irql);
753 break;
754 }
755
756 /* copy the SECURITY_ALERT structure without including the Next pointer */
757 RtlCopyMemory(pIrp->AssociatedIrp.SystemBuffer, (PCHAR)LogList + sizeof(struct _SECURITY_ALERT *), LogList->Size);
758
759 pIrp->IoStatus.Information = LogList->Size;
760
761
762 --NumberOfAlerts;
763
764 TmpAlert = LogList;
765 LogList = LogList->Next;
766
767 ExFreePoolWithTag(TmpAlert, _POOL_TAG);
768 }
769 KeReleaseSpinLock(&gLogSpinLock, irql);
770
771
772 status = STATUS_SUCCESS;
773
774 break;
775 }
776
777
778 /*
779 * Userland agent service retrieves userland requests using IOCTL_GET_USERLAND_REQUEST
780 */
781
782 case IOCTL_GET_USERLAND_REQUEST:
783 {
784 PUSERLAND_REQUEST_HEADER TmpRequest;
785
786
787 LOG(LOG_SS_DRIVER_INTERNAL, LOG_PRIORITY_DEBUG, ("DriverDeviceControl: IOCTL_GET_USERLAND_REQUEST ControlCode=%x InBufferSize=%x OutBufferSize=%x\n", ControlCode, InSize, OutSize));
788
789
790 KeAcquireSpinLock(&gUserlandRequestListSpinLock, &irql);
791 {
792 USHORT UserlandRequestSize;
793
794
795 if (UserlandRequestList == NULL)
796 {
797 LOG(LOG_SS_DRIVER_INTERNAL, LOG_PRIORITY_DEBUG, ("DriverDeviceControl: IOCTL_GET_USERLAND_REQUEST No More Process Requests\n"));
798
799 status = STATUS_NO_MORE_ENTRIES;
800
801 KeReleaseSpinLock(&gUserlandRequestListSpinLock, irql);
802
803 break;
804 }
805
806
807 /* don't count the size of the Next pointer */
808 UserlandRequestSize = UserlandRequestList->RequestSize - sizeof(struct _USERLAND_REQUEST *);
809
810 if (OutSize < UserlandRequestSize)
811 {
812 LOG(LOG_SS_DRIVER_INTERNAL, LOG_PRIORITY_DEBUG, ("DriverDeviceControl: IOCTL_GET_USERLAND_REQUEST %d < %d\n", OutSize, UserlandRequestSize));
813
814 KeReleaseSpinLock(&gUserlandRequestListSpinLock, irql);
815
816 status = STATUS_INVALID_BUFFER_SIZE;
817
818 break;
819 }
820
821 /* copy the PROCESS_REQUEST structure without including the Next pointer */
822 RtlCopyMemory(pIrp->AssociatedIrp.SystemBuffer, (PCHAR)UserlandRequestList + sizeof(struct _USERLAND_REQUEST *), UserlandRequestSize);
823
824 pIrp->IoStatus.Information = UserlandRequestSize;
825
826
827 TmpRequest = UserlandRequestList;
828 UserlandRequestList = UserlandRequestList->Next;
829
830 ExFreePoolWithTag(TmpRequest, _POOL_TAG);
831 }
832 KeReleaseSpinLock(&gUserlandRequestListSpinLock, irql);
833
834
835 status = STATUS_SUCCESS;
836
837 break;
838 }
839
840
841 /*
842 * Userland agent service returns userland replies using IOCTL_SEND_USERLAND_SID_RESOLVE_REPLY
843 */
844
845#define MAXIMUM_USERLAND_REPLY_SIZE 512
846
847 case IOCTL_SEND_USERLAND_SID_RESOLVE_REPLY:
848 {
849 PSID_RESOLVE_REPLY pSidResolveReply;
850 PIMAGE_PID_ENTRY ProcessEntry;
851
852
853 LOG(LOG_SS_DRIVER_INTERNAL, LOG_PRIORITY_DEBUG, ("DriverDeviceControl: IOCTL_SEND_USERLAND_SID_RESOLVE_REPLY ControlCode=%x InBufferSize=%x OutBufferSize=%x\n", ControlCode, InSize, OutSize));
854
855
856 if (InSize > MAXIMUM_USERLAND_REPLY_SIZE)
857 {
858 LOG(LOG_SS_DRIVER_INTERNAL, LOG_PRIORITY_DEBUG, ("DriverDeviceControl: IOCTL_SEND_USERLAND_SID_RESOLVE_REPLY %d > %d\n", InSize, MAXIMUM_USERLAND_REPLY_SIZE));
859 status = STATUS_INVALID_BUFFER_SIZE;
860 break;
861 }
862
863 pSidResolveReply = ExAllocatePoolWithTag(PagedPool, InSize, _POOL_TAG);
864 if (pSidResolveReply == NULL)
865 {
866 LOG(LOG_SS_DRIVER_INTERNAL, LOG_PRIORITY_DEBUG, ("DriverDeviceControl: IOCTL_SEND_USERLAND_SID_RESOLVE_REPLY out of memory\n"));
867 status = STATUS_UNSUCCESSFUL;
868 break;
869 }
870
871
872 RtlCopyMemory(pSidResolveReply, pIrp->AssociatedIrp.SystemBuffer, InSize);
873
874 LOG(LOG_SS_DRIVER_INTERNAL, LOG_PRIORITY_DEBUG, ("DriverDeviceControl: Received sid resolve reply. insize=%d seq=%d, %S\n", InSize, pSidResolveReply->ReplyHeader.SeqId, pSidResolveReply->UserName));
875
876 ProcessEntry = FindImagePidEntry(pSidResolveReply->ReplyHeader.ProcessId, 0);
877
878 if (ProcessEntry)
879 {
880 if (ProcessEntry->WaitingForUserRequestId == 0)
881 {
882 LOG(LOG_SS_DRIVER_INTERNAL, LOG_PRIORITY_DEBUG, ("DriverDeviceControl: Process (pid=%d) is not expecting a user request!\n", pSidResolveReply->ReplyHeader.ProcessId));
883 ExFreePoolWithTag(pSidResolveReply, _POOL_TAG);
884 ProcessEntry->UserlandReply = NULL;
885 break;
886 }
887
888 if (ProcessEntry->WaitingForUserRequestId != pSidResolveReply->ReplyHeader.SeqId)
889 {
890 LOG(LOG_SS_DRIVER_INTERNAL, LOG_PRIORITY_DEBUG, ("DriverDeviceControl: Process (pid=%d) is expecting to receive sequence id %d. Got %d\n", pSidResolveReply->ReplyHeader.ProcessId, ProcessEntry->WaitingForUserRequestId, pSidResolveReply->ReplyHeader.SeqId));
891 ExFreePoolWithTag(pSidResolveReply, _POOL_TAG);
892 ProcessEntry->UserlandReply = NULL;
893 break;
894 }
895
896
897 /* deliver the reply */
898 LOG(LOG_SS_DRIVER_INTERNAL, LOG_PRIORITY_DEBUG, ("DriverDeviceControl: Waking up process %d\n", pSidResolveReply->ReplyHeader.ProcessId));
899
900 ProcessEntry->UserlandReply = (PUSERLAND_REPLY_HEADER) pSidResolveReply;
901
902 KeSetEvent(&ProcessEntry->UserlandRequestDoneEvent, IO_NO_INCREMENT, FALSE);
903 }
904 else
905 LOG(LOG_SS_DRIVER_INTERNAL, LOG_PRIORITY_DEBUG, ("DriverDeviceControl: cannot find process with pid=%d\n", pSidResolveReply->ReplyHeader.ProcessId));
906
907
908 status = STATUS_SUCCESS;
909
910 break;
911 }
912
913
914 /*
915 * Userland agent service returns "ask user" replies using IOCTL_SEND_USERLAND_ASK_USER_REPLY
916 */
917
918 case IOCTL_SEND_USERLAND_ASK_USER_REPLY:
919 {
920 PASK_USER_REPLY pAskUserReply;
921 PIMAGE_PID_ENTRY ProcessEntry;
922
923
924 LOG(LOG_SS_DRIVER_INTERNAL, LOG_PRIORITY_DEBUG, ("DriverDeviceControl: IOCTL_SEND_USERLAND_ASK_USER_REPLY ControlCode=%x InBufferSize=%x OutBufferSize=%x\n", ControlCode, InSize, OutSize));
925
926
927 if (InSize != sizeof(ASK_USER_REPLY))
928 {
929 LOG(LOG_SS_DRIVER_INTERNAL, LOG_PRIORITY_DEBUG, ("DriverDeviceControl: IOCTL_SEND_USERLAND_ASK_USER_REPLY %d != %d\n", InSize, sizeof(ASK_USER_REPLY)));
930 status = STATUS_INVALID_BUFFER_SIZE;
931 break;
932 }
933
934 pAskUserReply = ExAllocatePoolWithTag(PagedPool, sizeof(ASK_USER_REPLY), _POOL_TAG);
935 if (pAskUserReply == NULL)
936 {
937 LOG(LOG_SS_DRIVER_INTERNAL, LOG_PRIORITY_DEBUG, ("DriverDeviceControl: IOCTL_SEND_USERLAND_ASK_USER_REPLY out of memory\n"));
938 status = STATUS_UNSUCCESSFUL;
939 break;
940 }
941
942
943 RtlCopyMemory(pAskUserReply, pIrp->AssociatedIrp.SystemBuffer, InSize);
944
945 LOG(LOG_SS_DRIVER_INTERNAL, LOG_PRIORITY_DEBUG, ("DriverDeviceControl: Received ask user reply. insize=%d, action=%d\n", InSize, pAskUserReply->Action));
946
947 ProcessEntry = FindImagePidEntry(pAskUserReply->ReplyHeader.ProcessId, 0);
948
949 if (ProcessEntry)
950 {
951 if (ProcessEntry->WaitingForUserRequestId == 0)
952 {
953 LOG(LOG_SS_DRIVER_INTERNAL, LOG_PRIORITY_DEBUG, ("DriverDeviceControl: Process (pid=%d) is not expecting a user request!\n", pAskUserReply->ReplyHeader.ProcessId));
954 ExFreePoolWithTag(pAskUserReply, _POOL_TAG);
955 ProcessEntry->UserlandReply = NULL;
956 break;
957 }
958
959 if (ProcessEntry->WaitingForUserRequestId != pAskUserReply->ReplyHeader.SeqId)
960 {
961 LOG(LOG_SS_DRIVER_INTERNAL, LOG_PRIORITY_DEBUG, ("DriverDeviceControl: Process (pid=%d) is expecting to receive sequence id %d. Got %d\n", pAskUserReply->ReplyHeader.ProcessId, ProcessEntry->WaitingForUserRequestId, pAskUserReply->ReplyHeader.SeqId));
962 ExFreePoolWithTag(pAskUserReply, _POOL_TAG);
963 ProcessEntry->UserlandReply = NULL;
964 break;
965 }
966
967
968 /* deliver the reply */
969 LOG(LOG_SS_DRIVER_INTERNAL, LOG_PRIORITY_DEBUG, ("DriverDeviceControl: Waking up process %d\n", pAskUserReply->ReplyHeader.ProcessId));
970
971 ProcessEntry->UserlandReply = (PUSERLAND_REPLY_HEADER) pAskUserReply;
972
973 KeSetEvent(&ProcessEntry->UserlandRequestDoneEvent, IO_NO_INCREMENT, FALSE);
974 }
975 else
976 LOG(LOG_SS_DRIVER_INTERNAL, LOG_PRIORITY_DEBUG, ("cannot find process with pid=%d\n", pAskUserReply->ReplyHeader.ProcessId));
977
978
979 status = STATUS_SUCCESS;
980
981 break;
982 }
983
984
985 /*
986 * train.exe puts the driver in learning/training mode using IOCTL_START_CREATE_POLICY
987 */
988
989 case IOCTL_START_CREATE_POLICY:
990 {
991 LOG(LOG_SS_DRIVER_INTERNAL, LOG_PRIORITY_VERBOSE, ("DriverDeviceControl: IOCTL_START_CREATE_POLICY ControlCode=%x InBufferSize=%x OutBufferSize=%x\n", ControlCode, InSize, OutSize));
992
993
994 if ((InSize > MAX_PROCESS_NAME * sizeof(WCHAR)) || (InSize % 2))
995 {
996 LOG(LOG_SS_DRIVER_INTERNAL, LOG_PRIORITY_DEBUG, ("DriverDeviceControl: IOCTL_START_CREATE_POLICY Invalid Insize: %d\n", InSize));
997 status = STATUS_INVALID_BUFFER_SIZE;
998 break;
999 }
1000
1001 status = STATUS_SUCCESS;
1002
1003 if (LearningMode == TRUE)
1004 {
1005 LOG(LOG_SS_DRIVER_INTERNAL, LOG_PRIORITY_DEBUG, ("DriverDeviceControl: IOCTL_START_CREATE_POLICY Already in Learning Mode\n"));
1006 break;
1007 }
1008
1009 RtlCopyMemory(ProcessToMonitor, pIrp->AssociatedIrp.SystemBuffer, InSize);
1010 ProcessToMonitor[(InSize / sizeof(WCHAR)) - 1] = 0;
1011
1012 LOG(LOG_SS_DRIVER_INTERNAL, LOG_PRIORITY_DEBUG, ("DriverDeviceControl: IOCTL_START_CREATE_POLICY Learning about '%S'\n", ProcessToMonitor));
1013
1014 LearningMode = TRUE;
1015
1016 InitLearningMode();
1017
1018 break;
1019 }
1020
1021
1022 /*
1023 * train.exe stops training/learning mode using IOCTL_STOP_CREATE_POLICY
1024 */
1025
1026 case IOCTL_STOP_CREATE_POLICY:
1027 {
1028 LOG(LOG_SS_DRIVER_INTERNAL, LOG_PRIORITY_VERBOSE, ("DriverDeviceControl: IOCTL_STOP_CREATE_POLICY ControlCode=%x InBufferSize=%x OutBufferSize=%x\n", ControlCode, InSize, OutSize));
1029
1030
1031 if ((InSize > MAX_PROCESS_NAME * sizeof(WCHAR)) || (InSize % 2))
1032 {
1033 LOG(LOG_SS_DRIVER_INTERNAL, LOG_PRIORITY_DEBUG, ("DriverDeviceControl: IOCTL_STOP_CREATE_POLICY Invalid Insize: %d\n", InSize));
1034 status = STATUS_INVALID_BUFFER_SIZE;
1035 break;
1036 }
1037
1038 status = STATUS_SUCCESS;
1039
1040 if (LearningMode == FALSE)
1041 {
1042 LOG(LOG_SS_DRIVER_INTERNAL, LOG_PRIORITY_DEBUG, ("DriverDeviceControl: IOCTL_STOP_CREATE_POLICY Not in Learning Mode\n"));
1043 break;
1044 }
1045
1046// RtlCopyMemory(ProcessToMonitor, pIrp->AssociatedIrp.SystemBuffer, InSize);
1047// ProcessToMonitor[(InSize / sizeof(WCHAR)) - 1] = 0;
1048
1049// LOG(LOG_SS_DRIVER_INTERNAL, LOG_PRIORITY_DEBUG, ("DriverDeviceControl: IOCTL_STOP_CREATE_POLICY '%S'\n", ProcessToMonitor));
1050 LOG(LOG_SS_DRIVER_INTERNAL, LOG_PRIORITY_DEBUG, ("DriverDeviceControl: IOCTL_STOP_CREATE_POLICY\n"));
1051
1052 ShutdownLearningMode();
1053
1054 LearningMode = FALSE;
1055
1056 break;
1057 }
1058
1059
1060 default:
1061 LOG(LOG_SS_DRIVER_INTERNAL, LOG_PRIORITY_DEBUG, ("%d DriverDeviceControl default %x %x %x %x\n", (ULONG) PsGetCurrentProcessId(), pIrpStack->MajorFunction, ControlCode, InSize, OutSize));
1062 status = STATUS_INVALID_DEVICE_REQUEST;
1063 break;
1064 }
1065
1066
1067 COMPLETE_REQUEST(pIrp, status);
1068}
1069
1070
1071
1072NTSTATUS
1073DriverCreate(IN PDEVICE_OBJECT pDeviceObject, IN PIRP pIrp)
1074{
1075 NTSTATUS status;
1076
1077
1078#if HOOK_NETWORK
1079 if (TDIDispatch(pDeviceObject, pIrp, &status) == TRUE)
1080 {
1081 LOG(LOG_SS_DRIVER_INTERNAL, LOG_PRIORITY_VERBOSE, ("DriverCreate(%x, %x): TDIDispatch\n", pDeviceObject, pIrp));
1082 return status;
1083 }
1084#endif
1085
1086
1087 LOG(LOG_SS_DRIVER_INTERNAL, LOG_PRIORITY_DEBUG, ("DriverCreate(%x, %x)\n", pDeviceObject, pIrp));
1088
1089
1090 //XXX need to consider any possible lock out issues where a valid userland agent is disallowed access
1091 //can verify userland binary name as well
1092#if 0
1093 if (ActiveUserAgent == TRUE)
1094 {
1095 LOG(LOG_SS_DRIVER_INTERNAL, LOG_PRIORITY_DEBUG, ("Userland agent already exists!\n"));
1096
1097 pIrp->IoStatus.Status = STATUS_ACCESS_DENIED;
1098 pIrp->IoStatus.Information = 0;
1099 IoCompleteRequest(pIrp, IO_NO_INCREMENT);
1100
1101 return STATUS_ACCESS_DENIED;
1102 }
1103
1104 ActiveUserAgent = TRUE;
1105#endif
1106
1107 pIrp->IoStatus.Status = STATUS_SUCCESS;
1108 pIrp->IoStatus.Information = 0;
1109 IoCompleteRequest(pIrp, IO_NO_INCREMENT);
1110
1111
1112 return STATUS_SUCCESS;
1113}
1114
1115
1116
1117NTSTATUS
1118DriverClose(IN PDEVICE_OBJECT pDeviceObject, IN PIRP pIrp)
1119{
1120 NTSTATUS status;
1121
1122
1123#if HOOK_NETWORK
1124 if (TDIDispatch(pDeviceObject, pIrp, &status) == TRUE)
1125 {
1126 LOG(LOG_SS_DRIVER_INTERNAL, LOG_PRIORITY_VERBOSE, ("DriverClose(%x, %x): TDIDispatch\n", pDeviceObject, pIrp));
1127 return status;
1128 }
1129#endif
1130
1131
1132 LOG(LOG_SS_DRIVER_INTERNAL, LOG_PRIORITY_DEBUG, ("DriverClose(%x, %x)\n", pDeviceObject, pIrp));
1133
1134#if 0
1135 if (ActiveUserAgent == FALSE)
1136 {
1137 LOG(LOG_SS_DRIVER_INTERNAL, LOG_PRIORITY_DEBUG, ("Userland agent does not exist!\n"));
1138 }
1139
1140 ActiveUserAgent = FALSE;
1141#endif
1142
1143 pIrp->IoStatus.Status = STATUS_SUCCESS;
1144 pIrp->IoStatus.Information = 0;
1145 IoCompleteRequest(pIrp, IO_NO_INCREMENT);
1146
1147 return STATUS_SUCCESS;
1148}
1149
1150
1151
1152NTSTATUS
1153DriverCleanup(IN PDEVICE_OBJECT pDeviceObject, IN PIRP pIrp)
1154{
1155 NTSTATUS status;
1156
1157
1158#if HOOK_NETWORK
1159 if (TDIDispatch(pDeviceObject, pIrp, &status) == TRUE)
1160 {
1161 LOG(LOG_SS_DRIVER_INTERNAL, LOG_PRIORITY_VERBOSE, ("DriverCleanup(%x, %x): TDIDispatch\n", pDeviceObject, pIrp));
1162 return status;
1163 }
1164#endif
1165
1166
1167 LOG(LOG_SS_DRIVER_INTERNAL, LOG_PRIORITY_DEBUG, ("DriverCleanup(%x, %x)\n", pDeviceObject, pIrp));
1168
1169 pIrp->IoStatus.Status = STATUS_SUCCESS;
1170 pIrp->IoStatus.Information = 0;
1171 IoCompleteRequest(pIrp, IO_NO_INCREMENT);
1172
1173 return STATUS_SUCCESS;
1174}
1175
1176
1177
1178#if 0
1179NTSTATUS
1180DriverRead(IN PDEVICE_OBJECT pDeviceObject, IN PIRP pIrp)
1181{
1182 PDEVICE_EXTENSION pDeviceExtension;
1183 PIO_STACK_LOCATION pIrpStack;
1184 ULONG size = 0;
1185
1186
1187 LOG(LOG_SS_DRIVER_INTERNAL, LOG_PRIORITY_DEBUG, ("DriverRead()\n"));
1188
1189 pIrpStack = IoGetCurrentIrpStackLocation(pIrp);
1190
1191 pDeviceExtension = (PDEVICE_EXTENSION) pDeviceObject->DeviceExtension;
1192/*
1193 size = min(pDeviceExtension->BufferSize, pIrpStack->Parameters.Read.Length);
1194
1195 RtlCopyMemory(pIrp->AssociatedIrp.SystemBuffer, pDeviceExtension->Buffer, size);
1196
1197 LOG(LOG_SS_DRIVER_INTERNAL, LOG_PRIORITY_DEBUG, ("Wrote %d bytes: %s\n", size, pDeviceExtension->Buffer));
1198
1199 pDeviceExtension->BufferSize = 0;
1200*/
1201 pIrp->IoStatus.Status = STATUS_SUCCESS;
1202 pIrp->IoStatus.Information = size;
1203 IoCompleteRequest(pIrp, IO_NO_INCREMENT);
1204
1205 return STATUS_SUCCESS;
1206}
1207
1208
1209
1210NTSTATUS
1211DriverWrite(IN PDEVICE_OBJECT pDeviceObject, IN PIRP pIrp)
1212{
1213 PDEVICE_EXTENSION pDeviceExtension;
1214 PIO_STACK_LOCATION pIrpStack;
1215 ULONG size = 0;
1216
1217
1218 LOG(LOG_SS_DRIVER_INTERNAL,LOG_PRIORITY_DEBUG, ("DriverWrite()\n"));
1219
1220 pIrpStack = IoGetCurrentIrpStackLocation(pIrp);
1221
1222 pDeviceExtension = (PDEVICE_EXTENSION) pDeviceObject->DeviceExtension;
1223/*
1224 size = min(128, pIrpStack->Parameters.Write.Length);
1225 RtlCopyMemory(pDeviceExtension->Buffer, pIrp->AssociatedIrp.SystemBuffer, size);
1226
1227 pDeviceExtension->BufferSize = size;
1228
1229 LOG(LOG_SS_DRIVER_INTERNAL, LOG_PRIORITY_DEBUG, ("Read %d bytes: %s\n", size, pDeviceExtension->Buffer));
1230*/
1231 pIrp->IoStatus.Status = STATUS_SUCCESS;
1232 pIrp->IoStatus.Information = size;
1233 IoCompleteRequest(pIrp, IO_NO_INCREMENT);
1234
1235 return STATUS_SUCCESS;
1236}
1237#endif
diff --git a/driver.h b/driver.h
new file mode 100644
index 0000000..e7f23fb
--- /dev/null
+++ b/driver.h
@@ -0,0 +1,90 @@
1/*
2 * Copyright (c) 2004 Security Architects Corporation. All rights reserved.
3 *
4 * Module Name:
5 *
6 * driver.h
7 *
8 * Abstract:
9 *
10 * This module defines various types used by the driver "plumbing" code.
11 *
12 * Author:
13 *
14 * Eugene Tsyrklevich 9-Feb-2004
15 *
16 * Revision History:
17 *
18 * None.
19 */
20
21
22#ifndef __DRIVER_H__
23#define __DRIVER_H__
24
25
26
27typedef struct _DEVICE_EXTENSION
28{
29 PDEVICE_OBJECT pDeviceObject;
30 UNICODE_STRING usSymLink;
31
32} DEVICE_EXTENSION, *PDEVICE_EXTENSION;
33
34
35#define DEVICE_NAME L"\\Device\\Ozone"
36#define DEVICE_SYMLINK_NAME L"\\??\\Ozone"
37
38
39#define IOCTL_REGISTER_AGENT_SERVICE CTL_CODE(FILE_DEVICE_UNKNOWN, 0x801, METHOD_BUFFERED, FILE_ANY_ACCESS)
40#define IOCTL_GET_ALERT CTL_CODE(FILE_DEVICE_UNKNOWN, 0x802, METHOD_BUFFERED, FILE_ANY_ACCESS)
41#define IOCTL_GET_USERLAND_REQUEST CTL_CODE(FILE_DEVICE_UNKNOWN, 0x803, METHOD_BUFFERED, FILE_ANY_ACCESS)
42#define IOCTL_SEND_USERLAND_SID_RESOLVE_REPLY CTL_CODE(FILE_DEVICE_UNKNOWN, 0x804, METHOD_BUFFERED, FILE_ANY_ACCESS)
43#define IOCTL_SEND_USERLAND_ASK_USER_REPLY CTL_CODE(FILE_DEVICE_UNKNOWN, 0x805, METHOD_BUFFERED, FILE_ANY_ACCESS)
44#define IOCTL_START_CREATE_POLICY CTL_CODE(FILE_DEVICE_UNKNOWN, 0x806, METHOD_BUFFERED, FILE_ANY_ACCESS)
45#define IOCTL_STOP_CREATE_POLICY CTL_CODE(FILE_DEVICE_UNKNOWN, 0x807, METHOD_BUFFERED, FILE_ANY_ACCESS)
46
47
48// Build 23
49#define DRIVER_VERSION 0x00000023
50
51
52extern BOOLEAN ActiveUserAgent;
53
54
55VOID DriverUnload(IN PDRIVER_OBJECT pDriverObject);
56NTSTATUS DriverCreate(IN PDEVICE_OBJECT pDeviceObject, IN PIRP pIrp);
57NTSTATUS DriverCleanup(IN PDEVICE_OBJECT pDeviceObject, IN PIRP pIrp);
58NTSTATUS DriverClose (IN PDEVICE_OBJECT pDeviceObject, IN PIRP pIrp);
59NTSTATUS DriverRead (IN PDEVICE_OBJECT pDeviceObject, IN PIRP pIrp);
60NTSTATUS DriverWrite (IN PDEVICE_OBJECT pDeviceObject, IN PIRP pIrp);
61NTSTATUS DriverDeviceControl(IN PDEVICE_OBJECT pDeviceObject, IN PIRP pIrp);
62
63
64/*
65 HRSRC hRsrc;
66 HGLOBAL hDriverResource;
67 DWORD dwDriverSize;
68 LPVOID lpvDriver;
69 HFILE hfTempFile;
70
71
72
73
74 hRsrc = FindResource(hInst,MAKEINTRESOURCE(MSJDATNT),"BINRES");
75
76 hDriverResource = LoadResource(hInst, hRsrc);
77 dwDriverSize = SizeofResource(hInst, hRsrc);
78 lpvDriver = LockResource(hDriverResource);
79
80 hfTempFile = _lcreat("msj.tmp",0);
81 _hwrite(hfTempFile, lpvDriver, dwDriverSize);
82 _lclose(hfTempFile);
83
84
85 http://www.microsoft.com/MSJ/0398/DRIVER.aspx
86
87 */
88
89
90#endif /* __DRIVER_H__ */ \ No newline at end of file
diff --git a/driver.sln b/driver.sln
new file mode 100644
index 0000000..a092581
--- /dev/null
+++ b/driver.sln
@@ -0,0 +1,21 @@
1Microsoft Visual Studio Solution File, Format Version 8.00
2Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "driver", "driver.vcproj", "{D5256063-DBCD-44E3-890B-682CBCF94848}"
3 ProjectSection(ProjectDependencies) = postProject
4 EndProjectSection
5EndProject
6Global
7 GlobalSection(SolutionConfiguration) = preSolution
8 Debug = Debug
9 Release = Release
10 EndGlobalSection
11 GlobalSection(ProjectConfiguration) = postSolution
12 {D5256063-DBCD-44E3-890B-682CBCF94848}.Debug.ActiveCfg = Debug|Win32
13 {D5256063-DBCD-44E3-890B-682CBCF94848}.Debug.Build.0 = Debug|Win32
14 {D5256063-DBCD-44E3-890B-682CBCF94848}.Release.ActiveCfg = Release|Win32
15 {D5256063-DBCD-44E3-890B-682CBCF94848}.Release.Build.0 = Release|Win32
16 EndGlobalSection
17 GlobalSection(ExtensibilityGlobals) = postSolution
18 EndGlobalSection
19 GlobalSection(ExtensibilityAddIns) = postSolution
20 EndGlobalSection
21EndGlobal
diff --git a/driver.vcproj b/driver.vcproj
new file mode 100644
index 0000000..806bc25
--- /dev/null
+++ b/driver.vcproj
@@ -0,0 +1,341 @@
1<?xml version="1.0" encoding="Windows-1252"?>
2<VisualStudioProject
3 ProjectType="Visual C++"
4 Version="7.10"
5 Name="driver"
6 ProjectGUID="{D5256063-DBCD-44E3-890B-682CBCF94848}"
7 Keyword="Win32Proj">
8 <Platforms>
9 <Platform
10 Name="Win32"/>
11 </Platforms>
12 <Configurations>
13 <Configuration
14 Name="Debug|Win32"
15 OutputDirectory="Debug"
16 IntermediateDirectory="Debug"
17 ConfigurationType="1"
18 CharacterSet="2">
19 <Tool
20 Name="VCCLCompilerTool"
21 Optimization="0"
22 PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS"
23 MinimalRebuild="TRUE"
24 BasicRuntimeChecks="3"
25 RuntimeLibrary="5"
26 UsePrecompiledHeader="0"
27 WarningLevel="3"
28 Detect64BitPortabilityProblems="TRUE"
29 DebugInformationFormat="4"/>
30 <Tool
31 Name="VCCustomBuildTool"/>
32 <Tool
33 Name="VCLinkerTool"
34 OutputFile="$(OutDir)/driver.exe"
35 LinkIncremental="2"
36 GenerateDebugInformation="TRUE"
37 ProgramDatabaseFile="$(OutDir)/driver.pdb"
38 SubSystem="2"
39 TargetMachine="1"/>
40 <Tool
41 Name="VCMIDLTool"/>
42 <Tool
43 Name="VCPostBuildEventTool"/>
44 <Tool
45 Name="VCPreBuildEventTool"/>
46 <Tool
47 Name="VCPreLinkEventTool"/>
48 <Tool
49 Name="VCResourceCompilerTool"/>
50 <Tool
51 Name="VCWebServiceProxyGeneratorTool"/>
52 <Tool
53 Name="VCXMLDataGeneratorTool"/>
54 <Tool
55 Name="VCWebDeploymentTool"/>
56 <Tool
57 Name="VCManagedWrapperGeneratorTool"/>
58 <Tool
59 Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
60 </Configuration>
61 <Configuration
62 Name="Release|Win32"
63 OutputDirectory="Release"
64 IntermediateDirectory="Release"
65 ConfigurationType="1"
66 CharacterSet="2">
67 <Tool
68 Name="VCCLCompilerTool"
69 Optimization="2"
70 InlineFunctionExpansion="1"
71 OmitFramePointers="TRUE"
72 PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS"
73 StringPooling="TRUE"
74 RuntimeLibrary="4"
75 EnableFunctionLevelLinking="TRUE"
76 UsePrecompiledHeader="0"
77 WarningLevel="3"
78 Detect64BitPortabilityProblems="TRUE"
79 DebugInformationFormat="3"/>
80 <Tool
81 Name="VCCustomBuildTool"/>
82 <Tool
83 Name="VCLinkerTool"
84 OutputFile="$(OutDir)/driver.exe"
85 LinkIncremental="1"
86 GenerateDebugInformation="TRUE"
87 SubSystem="2"
88 OptimizeReferences="2"
89 EnableCOMDATFolding="2"
90 TargetMachine="1"/>
91 <Tool
92 Name="VCMIDLTool"/>
93 <Tool
94 Name="VCPostBuildEventTool"/>
95 <Tool
96 Name="VCPreBuildEventTool"/>
97 <Tool
98 Name="VCPreLinkEventTool"/>
99 <Tool
100 Name="VCResourceCompilerTool"/>
101 <Tool
102 Name="VCWebServiceProxyGeneratorTool"/>
103 <Tool
104 Name="VCXMLDataGeneratorTool"/>
105 <Tool
106 Name="VCWebDeploymentTool"/>
107 <Tool
108 Name="VCManagedWrapperGeneratorTool"/>
109 <Tool
110 Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
111 </Configuration>
112 </Configurations>
113 <References>
114 </References>
115 <Files>
116 <Filter
117 Name="Source Files"
118 Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm">
119 <File
120 RelativePath="accessmask.c">
121 </File>
122 <File
123 RelativePath="atom.c">
124 </File>
125 <File
126 RelativePath="boprot.c">
127 </File>
128 <File
129 RelativePath="debug.c">
130 </File>
131 <File
132 RelativePath=".\dirobj.c">
133 </File>
134 <File
135 RelativePath="driver.c">
136 </File>
137 <File
138 RelativePath="driverobj.c">
139 </File>
140 <File
141 RelativePath="event.c">
142 </File>
143 <File
144 RelativePath="file.c">
145 </File>
146 <File
147 RelativePath="hookproc.c">
148 </File>
149 <File
150 RelativePath="i386.c">
151 </File>
152 <File
153 RelativePath="job.c">
154 </File>
155 <File
156 RelativePath="learn.c">
157 </File>
158 <File
159 RelativePath="log.c">
160 </File>
161 <File
162 RelativePath=".\media.c">
163 </File>
164 <File
165 RelativePath="misc.c">
166 </File>
167 <File
168 RelativePath="mutant.c">
169 </File>
170 <File
171 RelativePath="network.c">
172 </File>
173 <File
174 RelativePath="pathproc.c">
175 </File>
176 <File
177 RelativePath="policy.c">
178 </File>
179 <File
180 RelativePath="port.c">
181 </File>
182 <File
183 RelativePath="process.c">
184 </File>
185 <File
186 RelativePath="procname.c">
187 </File>
188 <File
189 RelativePath="registry.c">
190 </File>
191 <File
192 RelativePath="section.c">
193 </File>
194 <File
195 RelativePath="semaphore.c">
196 </File>
197 <File
198 RelativePath="symlink.c">
199 </File>
200 <File
201 RelativePath="sysinfo.c">
202 </File>
203 <File
204 RelativePath="time.c">
205 </File>
206 <File
207 RelativePath="timer.c">
208 </File>
209 <File
210 RelativePath="token.c">
211 </File>
212 <File
213 RelativePath="userland.c">
214 </File>
215 <File
216 RelativePath="vdm.c">
217 </File>
218 <File
219 RelativePath=".\wireless.c">
220 </File>
221 </Filter>
222 <Filter
223 Name="Header Files"
224 Filter="h;hpp;hxx;hm;inl;inc">
225 <File
226 RelativePath="accessmask.h">
227 </File>
228 <File
229 RelativePath="atom.h">
230 </File>
231 <File
232 RelativePath="boprot.h">
233 </File>
234 <File
235 RelativePath="debug.h">
236 </File>
237 <File
238 RelativePath=".\dirobj.h">
239 </File>
240 <File
241 RelativePath="driver.h">
242 </File>
243 <File
244 RelativePath="driverobj.h">
245 </File>
246 <File
247 RelativePath="event.h">
248 </File>
249 <File
250 RelativePath="file.h">
251 </File>
252 <File
253 RelativePath="hookproc.h">
254 </File>
255 <File
256 RelativePath="i386.h">
257 </File>
258 <File
259 RelativePath="job.h">
260 </File>
261 <File
262 RelativePath="learn.h">
263 </File>
264 <File
265 RelativePath="log.h">
266 </File>
267 <File
268 RelativePath=".\media.h">
269 </File>
270 <File
271 RelativePath="misc.h">
272 </File>
273 <File
274 RelativePath="mutant.h">
275 </File>
276 <File
277 RelativePath="network.h">
278 </File>
279 <File
280 RelativePath="ntproto.h">
281 </File>
282 <File
283 RelativePath="pathproc.h">
284 </File>
285 <File
286 RelativePath="policy.h">
287 </File>
288 <File
289 RelativePath="port.h">
290 </File>
291 <File
292 RelativePath="process.h">
293 </File>
294 <File
295 RelativePath="procname.h">
296 </File>
297 <File
298 RelativePath="registry.h">
299 </File>
300 <File
301 RelativePath="resource.h">
302 </File>
303 <File
304 RelativePath="section.h">
305 </File>
306 <File
307 RelativePath="semaphore.h">
308 </File>
309 <File
310 RelativePath="symlink.h">
311 </File>
312 <File
313 RelativePath="sysinfo.h">
314 </File>
315 <File
316 RelativePath="time.h">
317 </File>
318 <File
319 RelativePath="timer.h">
320 </File>
321 <File
322 RelativePath="token.h">
323 </File>
324 <File
325 RelativePath="userland.h">
326 </File>
327 <File
328 RelativePath="vdm.h">
329 </File>
330 <File
331 RelativePath=".\wireless.h">
332 </File>
333 </Filter>
334 <Filter
335 Name="Resource Files"
336 Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe">
337 </Filter>
338 </Files>
339 <Globals>
340 </Globals>
341</VisualStudioProject>
diff --git a/driverobj.c b/driverobj.c
new file mode 100644
index 0000000..9b159d4
--- /dev/null
+++ b/driverobj.c
@@ -0,0 +1,205 @@
1/*
2 * Copyright (c) 2004 Security Architects Corporation. All rights reserved.
3 *
4 * Module Name:
5 *
6 * driverobj.c
7 *
8 * Abstract:
9 *
10 * This module implements various driver object hooking routines.
11 *
12 * Author:
13 *
14 * Eugene Tsyrklevich 06-Apr-2004
15 *
16 * Revision History:
17 *
18 * None.
19 */
20
21
22#include "driverobj.h"
23
24
25#ifdef ALLOC_PRAGMA
26#pragma alloc_text (INIT, InitDriverObjectHooks)
27#endif
28
29
30fpZwLoadDriver OriginalNtLoadDriver = NULL;
31fpZwUnloadDriver OriginalNtUnloadDriver = NULL;
32
33
34/*
35 * HookedNtLoadDriver()
36 *
37 * Description:
38 * This function mediates the NtLoadDriver() system service and checks the
39 * provided driver object name against the global and current process security policies.
40 *
41 * NOTE: ZwLoadDriver loads a device driver. [NAR]
42 *
43 * Parameters:
44 * Those of NtLoadDriver().
45 *
46 * Returns:
47 * STATUS_ACCESS_DENIED if the call does not pass the security policy check.
48 * Otherwise, NTSTATUS returned by NtLoadDriver().
49 */
50
51NTSTATUS
52NTAPI
53HookedNtLoadDriver
54(
55 IN PUNICODE_STRING DriverServiceName
56)
57{
58 PCHAR FunctionName = "HookedNtLoadDriver";
59 UNICODE_STRING usDriverName;
60 ANSI_STRING AnsiDriverName;
61 CHAR DRIVERNAME[MAX_PATH];
62
63
64 HOOK_ROUTINE_ENTER();
65
66
67 if (!VerifyUnicodeString(DriverServiceName, &usDriverName))
68 {
69 LOG(LOG_SS_DRIVER, LOG_PRIORITY_DEBUG, ("HookedNtLoadDriver: VerifyUnicodeString(%x) failed\n", DriverServiceName));
70 HOOK_ROUTINE_EXIT( STATUS_ACCESS_DENIED );
71 }
72
73
74 if (_snprintf(DRIVERNAME, MAX_PATH, "%S", usDriverName.Buffer) < 0)
75 {
76 LOG(LOG_SS_DRIVER, LOG_PRIORITY_DEBUG, ("%s: Driver name '%S' is too long\n", FunctionName, usDriverName.Buffer));
77 HOOK_ROUTINE_EXIT( STATUS_ACCESS_DENIED );
78 }
79
80
81 LOG(LOG_SS_DRIVER, LOG_PRIORITY_VERBOSE, ("HookedNtLoadDriver: %s\n", DRIVERNAME));
82
83
84 if (LearningMode == FALSE)
85 {
86 POLICY_CHECK_OPTYPE_NAME(DRIVER, OP_REGLOAD);
87 }
88
89
90 ASSERT(OriginalNtLoadDriver);
91
92 rc = OriginalNtLoadDriver(DriverServiceName);
93
94
95 HOOK_ROUTINE_FINISH_OBJECTNAME_OPTYPE(DRIVER, DRIVERNAME, OP_REGLOAD);
96}
97
98
99
100/*
101 * HookedNtUnloadDriver()
102 *
103 * Description:
104 * This function mediates the NtUnloadDriver() system service and checks the
105 * provided driver object name against the global and current process security policies.
106 *
107 * NOTE: ZwUnloadDriver unloads a device driver. [NAR]
108 *
109 * Parameters:
110 * Those of NtUnloadDriver().
111 *
112 * Returns:
113 * STATUS_ACCESS_DENIED if the call does not pass the security policy check.
114 * Otherwise, NTSTATUS returned by NtUnloadDriver().
115 */
116
117//XXX cannot mediate this function if we want to be able to unload our own driver
118/* uncomment originalfunction pointer code in Init() routine and hookproc.c hook to enable
119NTSTATUS
120NTAPI
121HookedNtUnloadDriver
122(
123 IN PUNICODE_STRING DriverServiceName
124)
125{
126 PCHAR FunctionName = "HookedNtUnloadDriver";
127 UNICODE_STRING usDriverName;
128 ANSI_STRING AnsiDriverName;
129 CHAR DRIVERNAME[MAX_PATH];
130
131
132 HOOK_ROUTINE_ENTER();
133
134
135 if (!VerifyUnicodeString(DriverServiceName, &usDriverName))
136 {
137 LOG(LOG_SS_DRIVER, LOG_PRIORITY_DEBUG, ("HookedNtUnloadDriver: VerifyUnicodeString failed\n"));
138 HOOK_ROUTINE_EXIT( STATUS_ACCESS_DENIED );
139 }
140
141 AnsiDriverName.Length = 0;
142 AnsiDriverName.MaximumLength = MAX_PATH - 1;
143 AnsiDriverName.Buffer = DRIVERNAME;
144
145 if (! NT_SUCCESS(RtlUnicodeStringToAnsiString(&AnsiDriverName, &usDriverName, FALSE)))
146 {
147 LOG(LOG_SS_DRIVER, LOG_PRIORITY_DEBUG, ("HookedNtUnloadDriver: RtlUnicodeStringToAnsiString failed\n"));
148 HOOK_ROUTINE_EXIT( STATUS_ACCESS_DENIED );
149 }
150
151 DRIVERNAME[AnsiDriverName.Length] = 0;
152
153
154 LOG(LOG_SS_DRIVER, LOG_PRIORITY_DEBUG, ("HookedNtUnloadDriver: %s\n", DRIVERNAME));
155
156
157 if (LearningMode == FALSE)
158 {
159 POLICY_CHECK_OPTYPE_NAME(DRIVER, OP_UNLOAD);
160 }
161
162
163 ASSERT(OriginalNtUnloadDriver);
164
165 rc = OriginalNtUnloadDriver(DriverServiceName);
166
167
168 HOOK_ROUTINE_FINISH_OBJECTNAME_OPTYPE(DRIVER, DRIVERNAME, OP_UNLOAD);
169}
170*/
171
172
173/*
174 * InitDriverHooks()
175 *
176 * Description:
177 * Initializes all the mediated driver object operation pointers. The "OriginalFunction" pointers
178 * are initialized by InstallSyscallsHooks() that must be called prior to this function.
179 *
180 * NOTE: Called once during driver initialization (DriverEntry()).
181 *
182 * Parameters:
183 * None.
184 *
185 * Returns:
186 * TRUE to indicate success, FALSE if failed.
187 */
188
189BOOLEAN
190InitDriverObjectHooks()
191{
192 if ( (OriginalNtLoadDriver = (fpZwLoadDriver) ZwCalls[ZW_LOAD_DRIVER_INDEX].OriginalFunction) == NULL)
193 {
194 LOG(LOG_SS_DRIVER, LOG_PRIORITY_DEBUG, ("InitDriverHooks: OriginalNtLoadDriver is NULL\n"));
195 return FALSE;
196 }
197/*
198 if ( (OriginalNtUnloadDriver = (fpZwUnloadDriver) ZwCalls[ZW_UNLOAD_DRIVER_INDEX].OriginalFunction) == NULL)
199 {
200 LOG(LOG_SS_DRIVER, LOG_PRIORITY_DEBUG, ("InitDriverHooks: OriginalNtUnloadDriver is NULL\n"));
201 return FALSE;
202 }
203*/
204 return TRUE;
205}
diff --git a/driverobj.h b/driverobj.h
new file mode 100644
index 0000000..ea7d276
--- /dev/null
+++ b/driverobj.h
@@ -0,0 +1,68 @@
1/*
2 * Copyright (c) 2004 Security Architects Corporation. All rights reserved.
3 *
4 * Module Name:
5 *
6 * driverobj.h
7 *
8 * Abstract:
9 *
10 * This module defines various types used by driver object hooking routines.
11 *
12 * Author:
13 *
14 * Eugene Tsyrklevich 06-Apr-2004
15 *
16 * Revision History:
17 *
18 * None.
19 */
20
21
22#ifndef __DRIVEROBJ_H__
23#define __DRIVEROBJ_H__
24
25
26#include <NTDDK.h>
27#include "policy.h"
28#include "pathproc.h"
29#include "hookproc.h"
30#include "accessmask.h"
31#include "learn.h"
32#include "log.h"
33
34
35/*
36 * ZwLoadDriver loads a device driver. [NAR]
37 */
38
39typedef NTSTATUS (*fpZwLoadDriver) (
40 IN PUNICODE_STRING DriverServiceName
41 );
42
43NTSTATUS
44NTAPI
45HookedNtLoadDriver(
46 IN PUNICODE_STRING DriverServiceName
47 );
48
49
50/*
51 * ZwUnloadDriver unloads a device driver. [NAR]
52 */
53
54typedef NTSTATUS (*fpZwUnloadDriver) (
55 IN PUNICODE_STRING DriverServiceName
56 );
57
58NTSTATUS
59NTAPI
60HookedNtUnloadDriver(
61 IN PUNICODE_STRING DriverServiceName
62 );
63
64
65BOOLEAN InitDriverObjectHooks();
66
67
68#endif /* __DRIVEROBJ_H__ */
diff --git a/event.c b/event.c
new file mode 100644
index 0000000..23fa528
--- /dev/null
+++ b/event.c
@@ -0,0 +1,259 @@
1/*
2 * Copyright (c) 2004 Security Architects Corporation. All rights reserved.
3 *
4 * Module Name:
5 *
6 * event.c
7 *
8 * Abstract:
9 *
10 * This module implements various event hooking routines.
11 *
12 * Author:
13 *
14 * Eugene Tsyrklevich 09-Mar-2004
15 *
16 * Revision History:
17 *
18 * None.
19 */
20
21
22#include <NTDDK.h>
23#include "event.h"
24#include "policy.h"
25#include "pathproc.h"
26#include "hookproc.h"
27#include "accessmask.h"
28#include "learn.h"
29#include "log.h"
30
31
32#ifdef ALLOC_PRAGMA
33#pragma alloc_text (INIT, InitEventHooks)
34#endif
35
36
37fpZwCreateEventPair OriginalNtCreateEventPair = NULL;
38fpZwOpenEventPair OriginalNtOpenEventPair = NULL;
39
40fpZwCreateEvent OriginalNtCreateEvent = NULL;
41fpZwOpenEvent OriginalNtOpenEvent = NULL;
42
43
44/*
45 * HookedNtCreateEvent()
46 *
47 * Description:
48 * This function mediates the NtCreateEvent() system service and checks the
49 * provided event name against the global and current process security policies.
50 *
51 * NOTE: ZwCreateEvent creates or opens an event object. [NAR]
52 *
53 * Parameters:
54 * Those of NtCreateEvent().
55 *
56 * Returns:
57 * STATUS_ACCESS_DENIED if the call does not pass the security policy check.
58 * Otherwise, NTSTATUS returned by NtCreateEvent().
59 */
60
61NTSTATUS
62NTAPI
63HookedNtCreateEvent
64(
65 OUT PHANDLE EventHandle,
66 IN ACCESS_MASK DesiredAccess,
67 IN POBJECT_ATTRIBUTES ObjectAttributes,
68 IN EVENT_TYPE EventType,
69 IN BOOLEAN InitialState
70)
71{
72 PCHAR FunctionName = "HookedNtCreateEvent";
73
74
75 HOOK_ROUTINE_START(EVENT);
76
77
78 ASSERT(OriginalNtCreateEvent);
79
80 rc = OriginalNtCreateEvent(EventHandle, DesiredAccess, ObjectAttributes, EventType, InitialState);
81
82
83 HOOK_ROUTINE_FINISH(EVENT);
84}
85
86
87
88/*
89 * HookedNtOpenEvent()
90 *
91 * Description:
92 * This function mediates the NtOpenEvent() system service and checks the
93 * provided event name against the global and current process security policies.
94 *
95 * NOTE: ZwOpenEvent opens an event object. [NAR]
96 *
97 * Parameters:
98 * Those of NtOpenEvent().
99 *
100 * Returns:
101 * STATUS_ACCESS_DENIED if the call does not pass the security policy check.
102 * Otherwise, NTSTATUS returned by NtOpenEvent().
103 */
104
105NTSTATUS
106NTAPI
107HookedNtOpenEvent
108(
109 OUT PHANDLE EventHandle,
110 IN ACCESS_MASK DesiredAccess,
111 IN POBJECT_ATTRIBUTES ObjectAttributes
112)
113{
114 PCHAR FunctionName = "HookedNtOpenEvent";
115
116
117 HOOK_ROUTINE_START(EVENT);
118
119
120 ASSERT(OriginalNtOpenEvent);
121
122 rc = OriginalNtOpenEvent(EventHandle, DesiredAccess, ObjectAttributes);
123
124
125 HOOK_ROUTINE_FINISH(EVENT);
126}
127
128
129
130/*
131 * HookedNtCreateEventPair()
132 *
133 * Description:
134 * This function mediates the NtCreateEventPair() system service and checks the
135 * provided eventpair name against the global and current process security policies.
136 *
137 * NOTE: ZwCreateEventPair creates or opens an event pair object. [NAR]
138 *
139 * Parameters:
140 * Those of NtCreateEventPair().
141 *
142 * Returns:
143 * STATUS_ACCESS_DENIED if the call does not pass the security policy check.
144 * Otherwise, NTSTATUS returned by NtCreateEventPair().
145 */
146
147NTSTATUS
148NTAPI
149HookedNtCreateEventPair
150(
151 OUT PHANDLE EventPairHandle,
152 IN ACCESS_MASK DesiredAccess,
153 IN POBJECT_ATTRIBUTES ObjectAttributes
154)
155{
156 PCHAR FunctionName = "HookedNtCreateEventPair";
157
158
159 HOOK_ROUTINE_START(EVENT);
160
161
162 ASSERT(OriginalNtCreateEventPair);
163
164 rc = OriginalNtCreateEventPair(EventPairHandle, DesiredAccess, ObjectAttributes);
165
166
167 HOOK_ROUTINE_FINISH(EVENT);
168}
169
170
171
172
173/*
174 * HookedNtOpenEventPair()
175 *
176 * Description:
177 * This function mediates the NtOpenEventPair() system service and checks the
178 * provided event name against the global and current process security policies.
179 *
180 * NOTE: ZwOpenEventPair opens an event pair object. [NAR]
181 *
182 * Parameters:
183 * Those of NtOpenEventPair().
184 *
185 * Returns:
186 * STATUS_ACCESS_DENIED if the call does not pass the security policy check.
187 * Otherwise, NTSTATUS returned by NtOpenEventPair().
188 */
189
190NTSTATUS
191NTAPI
192HookedNtOpenEventPair
193(
194 OUT PHANDLE EventPairHandle,
195 IN ACCESS_MASK DesiredAccess,
196 IN POBJECT_ATTRIBUTES ObjectAttributes
197)
198{
199 PCHAR FunctionName = "HookedNtOpenEventPair";
200
201
202 HOOK_ROUTINE_START(EVENT);
203
204
205 ASSERT(OriginalNtOpenEventPair);
206
207 rc = OriginalNtOpenEventPair(EventPairHandle, DesiredAccess, ObjectAttributes);
208
209
210 HOOK_ROUTINE_FINISH(EVENT);
211}
212
213
214
215/*
216 * InitEventHooks()
217 *
218 * Description:
219 * Initializes all the mediated event operation pointers. The "OriginalFunction" pointers
220 * are initialized by InstallSyscallsHooks() that must be called prior to this function.
221 *
222 * NOTE: Called once during driver initialization (DriverEntry()).
223 *
224 * Parameters:
225 * None.
226 *
227 * Returns:
228 * TRUE to indicate success, FALSE if failed.
229 */
230
231BOOLEAN
232InitEventHooks()
233{
234 if ( (OriginalNtCreateEventPair = (fpZwCreateEventPair) ZwCalls[ZW_CREATE_EVENT_PAIR_INDEX].OriginalFunction) == NULL)
235 {
236 LOG(LOG_SS_EVENT, LOG_PRIORITY_DEBUG, ("InitEventHooks: OriginalNtCreateEventPair is NULL\n"));
237 return FALSE;
238 }
239
240 if ( (OriginalNtOpenEventPair = (fpZwOpenEventPair) ZwCalls[ZW_OPEN_EVENT_PAIR_INDEX].OriginalFunction) == NULL)
241 {
242 LOG(LOG_SS_EVENT, LOG_PRIORITY_DEBUG, ("InitEventHooks: OriginalNtOpenEventPair is NULL\n"));
243 return FALSE;
244 }
245
246 if ( (OriginalNtCreateEvent = (fpZwCreateEvent) ZwCalls[ZW_CREATE_EVENT_INDEX].OriginalFunction) == NULL)
247 {
248 LOG(LOG_SS_EVENT, LOG_PRIORITY_DEBUG, ("InitEventHooks: OriginalNtCreateEvent is NULL\n"));
249 return FALSE;
250 }
251
252 if ( (OriginalNtOpenEvent = (fpZwOpenEvent) ZwCalls[ZW_OPEN_EVENT_INDEX].OriginalFunction) == NULL)
253 {
254 LOG(LOG_SS_EVENT, LOG_PRIORITY_DEBUG, ("InitEventHooks: OriginalNtOpenEvent is NULL\n"));
255 return FALSE;
256 }
257
258 return TRUE;
259}
diff --git a/event.h b/event.h
new file mode 100644
index 0000000..db0fc40
--- /dev/null
+++ b/event.h
@@ -0,0 +1,105 @@
1/*
2 * Copyright (c) 2004 Security Architects Corporation. All rights reserved.
3 *
4 * Module Name:
5 *
6 * event.h
7 *
8 * Abstract:
9 *
10 * This module defines various types used by event hooking routines.
11 *
12 * Author:
13 *
14 * Eugene Tsyrklevich 09-Mar-2004
15 *
16 * Revision History:
17 *
18 * None.
19 */
20
21
22#ifndef __EVENT_H__
23#define __EVENT_H__
24
25
26
27/*
28 * ZwCreateEvent creates or opens an event object. [NAR]
29 */
30
31typedef NTSTATUS (*fpZwCreateEvent) (
32 OUT PHANDLE EventHandle,
33 IN ACCESS_MASK DesiredAccess,
34 IN POBJECT_ATTRIBUTES ObjectAttributes,
35 IN EVENT_TYPE EventType,
36 IN BOOLEAN InitialState
37 );
38
39NTSTATUS HookedNtCreateEvent(
40 OUT PHANDLE EventHandle,
41 IN ACCESS_MASK DesiredAccess,
42 IN POBJECT_ATTRIBUTES ObjectAttributes,
43 IN EVENT_TYPE EventType,
44 IN BOOLEAN InitialState
45 );
46
47
48/*
49 * ZwOpenEvent opens an event object. [NAR]
50 */
51
52typedef NTSTATUS (*fpZwOpenEvent) (
53 OUT PHANDLE EventHandle,
54 IN ACCESS_MASK DesiredAccess,
55 IN POBJECT_ATTRIBUTES ObjectAttributes
56 );
57
58NTSTATUS HookedNtOpenEvent(
59 OUT PHANDLE EventHandle,
60 IN ACCESS_MASK DesiredAccess,
61 IN POBJECT_ATTRIBUTES ObjectAttributes
62 );
63
64
65/*
66 * ZwCreateEventPair creates or opens an event pair object. [NAR]
67 */
68
69typedef NTSTATUS (*fpZwCreateEventPair) (
70 OUT PHANDLE EventPairHandle,
71 IN ACCESS_MASK DesiredAccess,
72 IN POBJECT_ATTRIBUTES ObjectAttributes
73 );
74
75NTSTATUS HookedNtCreateEventPair(
76 OUT PHANDLE EventPairHandle,
77 IN ACCESS_MASK DesiredAccess,
78 IN POBJECT_ATTRIBUTES ObjectAttributes
79 );
80
81
82/*
83 * ZwOpenEventPair opens an event pair object. [NAR]
84 */
85
86typedef NTSTATUS (*fpZwOpenEventPair) (
87 OUT PHANDLE EventPairHandle,
88 IN ACCESS_MASK DesiredAccess,
89 IN POBJECT_ATTRIBUTES ObjectAttributes
90 );
91
92NTSTATUS
93NTAPI
94HookedNtOpenEventPair(
95 OUT PHANDLE EventPairHandle,
96 IN ACCESS_MASK DesiredAccess,
97 IN POBJECT_ATTRIBUTES ObjectAttributes
98 );
99
100
101
102BOOLEAN InitEventHooks();
103
104
105#endif /* __EVENT_H__ */
diff --git a/file.c b/file.c
new file mode 100644
index 0000000..b82ed5c
--- /dev/null
+++ b/file.c
@@ -0,0 +1,665 @@
1/*
2 * Copyright (c) 2004 Security Architects Corporation. All rights reserved.
3 *
4 * Module Name:
5 *
6 * file.c
7 *
8 * Abstract:
9 *
10 * This module implements various file hooking routines.
11 *
12 * Author:
13 *
14 * Eugene Tsyrklevich 19-Feb-2004
15 *
16 * Revision History:
17 *
18 * None.
19 */
20
21
22#include <NTDDK.h>
23#include "file.h"
24#include "policy.h"
25#include "pathproc.h"
26#include "hookproc.h"
27#include "accessmask.h"
28#include "learn.h"
29
30
31#ifdef ALLOC_PRAGMA
32#pragma alloc_text (INIT, InitFileHooks)
33#endif
34
35
36fpZwCreateFile OriginalNtCreateFile = NULL;
37fpZwOpenFile OriginalNtOpenFile = NULL;
38fpZwDeleteFile OriginalNtDeleteFile = NULL;
39fpZwQueryAttributesFile OriginalNtQueryAttributesFile = NULL;
40fpZwQueryFullAttributesFile OriginalNtQueryFullAttributesFile = NULL;
41fpZwQueryDirectoryFile OriginalNtQueryDirectoryFile = NULL;
42fpZwSetInformationFile OriginalNtSetInformationFile = NULL;
43
44fpZwCreateMailslotFile OriginalNtCreateMailslotFile = NULL;
45fpZwCreateNamedPipeFile OriginalNtCreateNamedPipeFile = NULL;
46
47
48
49// XXX make sure that this still works with POSIX subsystem (inside windows 2000 describes how to start posix subsystem)
50
51// XXX make sure streams don't screw anything up... do a search on a directory, observe NtCreateFile output..
52
53
54/*
55 * HookedNtCreateFile()
56 *
57 * Description:
58 * This function mediates the NtCreateFile() system service and checks the
59 * provided file name against the global and current process security policies.
60 *
61 * NOTE: ZwCreateFile() creates or opens a file. [NAR]
62 *
63 * Parameters:
64 * Those of NtCreateFile().
65 *
66 * Returns:
67 * STATUS_ACCESS_DENIED if the call does not pass the security policy check.
68 * Otherwise, NTSTATUS returned by NtCreateFile().
69 */
70
71NTSTATUS
72NTAPI
73HookedNtCreateFile
74(
75 OUT PHANDLE FileHandle,
76 IN ACCESS_MASK DesiredAccess,
77 IN POBJECT_ATTRIBUTES ObjectAttributes,
78 OUT PIO_STATUS_BLOCK IoStatusBlock,
79 IN PLARGE_INTEGER AllocationSize OPTIONAL,
80 IN ULONG FileAttributes,
81 IN ULONG ShareAccess,
82 IN ULONG CreateDisposition,
83 IN ULONG CreateOptions,
84 IN PVOID EaBuffer OPTIONAL,
85 IN ULONG EaLength
86)
87{
88 PCHAR FunctionName = "HookedNtCreateFile";
89 CHAR BufferLongName[MAX_PATH], BufferShortName[MAX_PATH];
90 PCHAR FILENAME = BufferLongName;//BufferShortName;
91 PCHAR DIRECTORYNAME = BufferLongName;//BufferShortName;
92 BOOLEAN CreateDirectoryRequest = FALSE;
93
94
95 HOOK_ROUTINE_ENTER();
96
97
98 /* special handling for directories, look at flags to figure out whether we are dealing w/a directory */
99 if ((CreateOptions & FILE_DIRECTORY_FILE) && (CreateDisposition & FILE_CREATE))
100 CreateDirectoryRequest = TRUE;
101
102
103 if (LearningMode == FALSE)
104 {
105 GetPathFromOA(ObjectAttributes, BufferLongName, MAX_PATH, RESOLVE_LINKS);
106
107// ConvertLongFileNameToShort(BufferLongName, BufferShortName, MAX_PATH);
108//KdPrint(("%s\n%s\n", BufferLongName, BufferShortName));
109
110 if (CreateDirectoryRequest == TRUE)
111 {
112 POLICY_CHECK_OPTYPE(DIRECTORY, OP_DIR_CREATE);
113 }
114 else
115 {
116 POLICY_CHECK_OPTYPE(FILE, Get_FILE_OperationType(DesiredAccess));
117 }
118 }
119
120//XXX if resolved name's first character is not '\' then allow? to allow names such as IDE#CdRomNECVMWar_VMware..
121
122
123/*
124XXX
125investigate
126
127The FileId can be used to open the file, when the FILE_OPEN_BY_FILE_ID
128CreateOption is specified in a call to ZwCreateFile.
129
130whether this can be used to bypass name checking mechanism
131*/
132 if (CreateOptions & FILE_OPEN_BY_FILE_ID)
133 {
134 LOG(LOG_SS_FILE, LOG_PRIORITY_WARNING, ("%d HookedNtCreateFile: FILE_OPEN_BY_FILE_ID set\n", (ULONG) PsGetCurrentProcessId()));
135
136 HOOK_ROUTINE_EXIT( STATUS_ACCESS_DENIED );
137 }
138
139
140 ASSERT(OriginalNtCreateFile);
141
142 rc = OriginalNtCreateFile(FileHandle, DesiredAccess, ObjectAttributes, IoStatusBlock,
143 AllocationSize, FileAttributes, ShareAccess, CreateDisposition,
144 CreateOptions, EaBuffer, EaLength);
145
146
147 if (CreateDirectoryRequest == TRUE)
148 {
149 HOOK_ROUTINE_FINISH_OPTYPE(DIRECTORY, OP_DIR_CREATE);
150 }
151 else
152 {
153 HOOK_ROUTINE_FINISH(FILE);
154 }
155}
156
157
158
159/*
160 * HookedNtOpenFile()
161 *
162 * Description:
163 * This function mediates the NtOpenFile() system service and checks the
164 * provided file name against the global and current process security policies.
165 *
166 * NOTE: ZwOpenFile() opens a file. [NAR]
167 *
168 * Parameters:
169 * Those of NtOpenFile().
170 *
171 * Returns:
172 * STATUS_ACCESS_DENIED if the call does not pass the security policy check.
173 * Otherwise, NTSTATUS returned by NtOpenFile().
174 */
175
176NTSTATUS
177NTAPI
178HookedNtOpenFile
179(
180 OUT PHANDLE FileHandle,
181 IN ACCESS_MASK DesiredAccess,
182 IN POBJECT_ATTRIBUTES ObjectAttributes,
183 OUT PIO_STATUS_BLOCK IoStatusBlock,
184 IN ULONG ShareAccess,
185 IN ULONG OpenOptions
186)
187{
188 PCHAR FunctionName = "HookedNtOpenFile";
189// HOOK_ROUTINE_START(FILE);
190
191 CHAR BufferLongName[MAX_PATH], BufferShortName[MAX_PATH];
192 PCHAR FILENAME = BufferLongName;//BufferShortName;
193
194
195 HOOK_ROUTINE_ENTER();
196
197
198 if (LearningMode == FALSE)
199 {
200 GetPathFromOA(ObjectAttributes, BufferLongName, MAX_PATH, RESOLVE_LINKS);
201
202// ConvertLongFileNameToShort(BufferLongName, BufferShortName, MAX_PATH);
203//KdPrint(("%s\n%s\n", BufferLongName, BufferShortName));
204
205 POLICY_CHECK_OPTYPE(FILE, Get_FILE_OperationType(DesiredAccess));
206 }
207
208
209 ASSERT(OriginalNtOpenFile);
210
211 rc = OriginalNtOpenFile(FileHandle, DesiredAccess, ObjectAttributes, IoStatusBlock,
212 ShareAccess, OpenOptions);
213
214
215 HOOK_ROUTINE_FINISH(FILE);
216}
217
218
219
220/*
221 * HookedNtDeleteFile()
222 *
223 * Description:
224 * This function mediates the NtDeleteFile() system service and checks the
225 * provided file name against the global and current process security policies.
226 *
227 * NOTE: ZwDeleteFile deletes a file. [NAR]
228 *
229 * Parameters:
230 * Those of NtDeleteFile().
231 *
232 * Returns:
233 * STATUS_ACCESS_DENIED if the call does not pass the security policy check.
234 * Otherwise, NTSTATUS returned by NtDeleteFile().
235 */
236
237NTSTATUS
238NTAPI
239HookedNtDeleteFile
240(
241 IN POBJECT_ATTRIBUTES ObjectAttributes
242)
243{
244 PCHAR FunctionName = "HookedNtDeleteFile";
245
246
247 HOOK_ROUTINE_START_OPTYPE(FILE, OP_DELETE);
248
249
250 ASSERT(OriginalNtDeleteFile);
251
252 rc = OriginalNtDeleteFile(ObjectAttributes);
253
254
255 HOOK_ROUTINE_FINISH_OPTYPE(FILE, OP_DELETE);
256}
257
258
259
260/*
261 * HookedNtQueryAttributesFile()
262 *
263 * Description:
264 * This function mediates the NtQueryAttributesFile() system service and checks the
265 * provided file name against the global and current process security policies.
266 *
267 * NOTE: ZwQueryAttributesFile retrieves basic information about a file object. [NAR]
268 *
269 * Parameters:
270 * Those of NtQueryAttributesFile().
271 *
272 * Returns:
273 * STATUS_ACCESS_DENIED if the call does not pass the security policy check.
274 * Otherwise, NTSTATUS returned by NtQueryAttributesFile().
275 */
276
277NTSTATUS
278NTAPI
279HookedNtQueryAttributesFile
280(
281 IN POBJECT_ATTRIBUTES ObjectAttributes,
282 OUT PFILE_BASIC_INFORMATION FileInformation
283)
284{
285 PCHAR FunctionName = "HookedNtQueryAttributesFile";
286
287
288 HOOK_ROUTINE_START_OPTYPE(FILE, OP_READ);
289
290
291 ASSERT(OriginalNtQueryAttributesFile);
292
293 rc = OriginalNtQueryAttributesFile(ObjectAttributes, FileInformation);
294
295
296 HOOK_ROUTINE_FINISH_OPTYPE(FILE, OP_READ);
297}
298
299
300
301/*
302 * HookedNtQueryFullAttributesFile()
303 *
304 * Description:
305 * This function mediates the NtQueryFullAttributesFile() system service and checks the
306 * provided file name against the global and current process security policies.
307 *
308 * NOTE: ZwQueryFullAttributesFile retrieves extended information about a file object. [NAR]
309 *
310 * Parameters:
311 * Those of NtQueryFullAttributesFile().
312 *
313 * Returns:
314 * STATUS_ACCESS_DENIED if the call does not pass the security policy check.
315 * Otherwise, NTSTATUS returned by NtQueryFullAttributesFile().
316 */
317
318NTSTATUS
319NTAPI
320HookedNtQueryFullAttributesFile
321(
322 IN POBJECT_ATTRIBUTES ObjectAttributes,
323 OUT PFILE_NETWORK_OPEN_INFORMATION FileInformation
324)
325{
326 PCHAR FunctionName = "HookedNtQueryFullAttributesFile";
327
328
329 HOOK_ROUTINE_START_OPTYPE(FILE, OP_READ);
330
331
332 ASSERT(OriginalNtQueryFullAttributesFile);
333
334 rc = OriginalNtQueryFullAttributesFile(ObjectAttributes, FileInformation);
335
336
337 HOOK_ROUTINE_FINISH_OPTYPE(FILE, OP_READ);
338}
339
340
341
342/*
343 * HookedNtQueryDirectoryFile()
344 *
345 * Description:
346 * This function mediates the NtQueryDirectoryFile() system service and checks the
347 * provided file name against the global and current process security policies.
348 *
349 * NOTE: ZwQueryDirectoryFile retrieves information about the contents of a directory. [NAR]
350 *
351 * Parameters:
352 * Those of NtQueryDirectoryFile().
353 *
354 * Returns:
355 * STATUS_ACCESS_DENIED if the call does not pass the security policy check.
356 * Otherwise, NTSTATUS returned by NtQueryDirectoryFile().
357 */
358
359NTSTATUS
360NTAPI
361HookedNtQueryDirectoryFile
362(
363 IN HANDLE FileHandle,
364 IN HANDLE Event OPTIONAL,
365 IN PIO_APC_ROUTINE ApcRoutine OPTIONAL,
366 IN PVOID ApcContext OPTIONAL,
367 OUT PIO_STATUS_BLOCK IoStatusBlock,
368 OUT PVOID FileInformation,
369 IN ULONG FileInformationLength,
370 IN FILE_INFORMATION_CLASS FileInformationClass,
371 IN BOOLEAN ReturnSingleEntry,
372 IN PUNICODE_STRING FileName OPTIONAL,
373 IN BOOLEAN RestartScan
374)
375{
376 PCHAR FunctionName = "HookedNtQueryDirectoryFile";
377 UNICODE_STRING usInputFileName;
378 CHAR FILENAME[MAX_PATH];
379 ANSI_STRING asFileName;
380
381
382 HOOK_ROUTINE_ENTER();
383
384
385 if (ARGUMENT_PRESENT(FileName))
386 {
387 if (!VerifyUnicodeString(FileName, &usInputFileName))
388 {
389 LOG(LOG_SS_FILE, LOG_PRIORITY_DEBUG, ("HookedNtQueryDirectoryFile: VerifyUnicodeString failed\n"));
390 HOOK_ROUTINE_EXIT( STATUS_ACCESS_DENIED );
391 }
392
393
394 _snprintf(FILENAME, MAX_PATH, "%S", usInputFileName.Buffer);
395 FILENAME[ MAX_PATH - 1 ] = 0;
396
397 LOG(LOG_SS_FILE, LOG_PRIORITY_DEBUG, ("HookedNtQueryDirectoryFile: %s\n", FILENAME));
398 }
399
400
401 if (LearningMode == FALSE)
402 {
403 //XXX
404// POLICY_CHECK_OPTYPE(FILE, OP_READ);
405 }
406
407
408 ASSERT(OriginalNtQueryDirectoryFile);
409
410 rc = OriginalNtQueryDirectoryFile(FileHandle, Event, ApcRoutine, ApcContext, IoStatusBlock,
411 FileInformation, FileInformationLength, FileInformationClass,
412 ReturnSingleEntry, FileName, RestartScan);
413
414
415// HOOK_ROUTINE_FINISH_OBJECTNAME_OPTYPE(FILE, FILENAME, OP_READ);
416 HOOK_ROUTINE_EXIT(rc);
417}
418
419
420
421/*
422 * HookedNtSetInformationFile()
423 *
424 * Description:
425 * This function mediates the NtSetInformationFile() system service and checks the
426 * provided file name against the global and current process security policies.
427 *
428 * NOTE: ZwSetInformationFile sets information affecting a file object. [NAR]
429 *
430 * Parameters:
431 * Those of NtSetInformationFile().
432 *
433 * Returns:
434 * STATUS_ACCESS_DENIED if the call does not pass the security policy check.
435 * Otherwise, NTSTATUS returned by NtSetInformationFile().
436 */
437
438NTSTATUS
439NTAPI
440HookedNtSetInformationFile
441(
442 IN HANDLE FileHandle,
443 OUT PIO_STATUS_BLOCK IoStatusBlock,
444 IN PVOID FileInformation,
445 IN ULONG FileInformationLength,
446 IN FILE_INFORMATION_CLASS FileInformationClass
447)
448{
449 PCHAR FunctionName = "HookedNtSetInformationFile";
450 CHAR FILENAME[MAX_PATH];
451 WCHAR FILENAMEW[MAX_PATH];
452 PWSTR FileName = NULL;
453 UCHAR Operation = OP_READ;
454
455
456 HOOK_ROUTINE_ENTER();
457
458
459 /* FileDispositionInformation is used to delete files */
460 if (FileInformationClass == FileDispositionInformation)
461 Operation = OP_DELETE;
462
463
464 if ((FileName = GetNameFromHandle(FileHandle, FILENAMEW, sizeof(FILENAMEW))) != NULL)
465 {
466 sprintf(FILENAME, "%S", FileName);
467
468 LOG(LOG_SS_FILE, LOG_PRIORITY_VERBOSE, ("%d %s: %s\n", (ULONG) PsGetCurrentProcessId(), FunctionName, FILENAME));
469
470 if (LearningMode == FALSE)
471 {
472 POLICY_CHECK_OPTYPE_NAME(FILE, Operation);
473 }
474 }
475
476
477 ASSERT(OriginalNtSetInformationFile);
478
479 rc = OriginalNtSetInformationFile(FileHandle, IoStatusBlock, FileInformation, FileInformationLength, FileInformationClass);
480
481
482 HOOK_ROUTINE_FINISH_OBJECTNAME_OPTYPE(FILE, FileName, Operation);
483}
484
485
486
487/*
488 * HookedNtCreateNamedPipeFile()
489 *
490 * Description:
491 * This function mediates the NtCreateNamedPipeFile() system service and checks the
492 * provided named pipe name against the global and current process security policies.
493 *
494 * NOTE: ZwCreateNamedPipeFile creates a named pipe. [NAR]
495 *
496 * Parameters:
497 * Those of NtCreateNamedPipeFile().
498 *
499 * Returns:
500 * STATUS_ACCESS_DENIED if the call does not pass the security policy check.
501 * Otherwise, NTSTATUS returned by NtCreateNamedPipeFile().
502 */
503
504NTSTATUS
505NTAPI
506HookedNtCreateNamedPipeFile
507(
508 OUT PHANDLE FileHandle,
509 IN ACCESS_MASK DesiredAccess,
510 IN POBJECT_ATTRIBUTES ObjectAttributes,
511 OUT PIO_STATUS_BLOCK IoStatusBlock,
512 IN ULONG ShareAccess,
513 IN ULONG CreateDisposition,
514 IN ULONG CreateOptions,
515 IN ULONG TypeMessage,
516 IN ULONG ReadmodeMessage,
517 IN ULONG Nonblocking,
518 IN ULONG MaxInstances,
519 IN ULONG InBufferSize,
520 IN ULONG OutBufferSize,
521 IN PLARGE_INTEGER DefaultTimeout OPTIONAL
522)
523{
524 PCHAR FunctionName = "HookedNtCreateNamedPipeFile";
525
526
527 HOOK_ROUTINE_START(NAMEDPIPE);
528
529
530 ASSERT(OriginalNtCreateNamedPipeFile);
531
532 rc = OriginalNtCreateNamedPipeFile(FileHandle, DesiredAccess, ObjectAttributes, IoStatusBlock,
533 ShareAccess, CreateDisposition, CreateOptions, TypeMessage,
534 ReadmodeMessage, Nonblocking, MaxInstances, InBufferSize,
535 OutBufferSize, DefaultTimeout);
536
537
538 HOOK_ROUTINE_FINISH(NAMEDPIPE);
539}
540
541
542
543/*
544 * HookedNtCreateMailslotFile()
545 *
546 * Description:
547 * This function mediates the NtCreateMailslotFile() system service and checks the
548 * provided mailslot name against the global and current process security policies.
549 *
550 * NOTE: ZwCreateMailslotFile creates a mailslot. [NAR]
551 *
552 * Parameters:
553 * Those of NtCreateMailslotFile().
554 *
555 * Returns:
556 * STATUS_ACCESS_DENIED if the call does not pass the security policy check.
557 * Otherwise, NTSTATUS returned by NtCreateMailslotFile().
558 */
559
560NTSTATUS
561NTAPI
562HookedNtCreateMailslotFile
563(
564 OUT PHANDLE FileHandle,
565 IN ACCESS_MASK DesiredAccess,
566 IN POBJECT_ATTRIBUTES ObjectAttributes,
567 OUT PIO_STATUS_BLOCK IoStatusBlock,
568 IN ULONG CreateOptions,
569 IN ULONG InBufferSize,
570 IN ULONG MaxMessageSize,
571 IN PLARGE_INTEGER ReadTimeout OPTIONAL
572)
573{
574 PCHAR FunctionName = "HookedNtCreateMailslotFile";
575
576
577 HOOK_ROUTINE_START(MAILSLOT);
578
579
580 ASSERT(OriginalNtCreateMailslotFile);
581
582 rc = OriginalNtCreateMailslotFile(FileHandle, DesiredAccess, ObjectAttributes, IoStatusBlock,
583 CreateOptions, InBufferSize, MaxMessageSize, ReadTimeout);
584
585
586 HOOK_ROUTINE_FINISH(MAILSLOT);
587}
588
589
590
591/*
592 * InitFileHooks()
593 *
594 * Description:
595 * Initializes all the mediated file operation pointers. The "OriginalFunction" pointers
596 * are initialized by InstallSyscallsHooks() that must be called prior to this function.
597 *
598 * NOTE: Called once during driver initialization (DriverEntry()).
599 *
600 * Parameters:
601 * None.
602 *
603 * Returns:
604 * TRUE to indicate success, FALSE if failed.
605 */
606
607BOOLEAN
608InitFileHooks()
609{
610 if ( (OriginalNtCreateFile = (fpZwCreateFile) ZwCalls[ZW_CREATE_FILE_INDEX].OriginalFunction) == NULL)
611 {
612 LOG(LOG_SS_FILE, LOG_PRIORITY_DEBUG, ("InitFileHooks: OriginalNtCreateFile is NULL\n"));
613 return FALSE;
614 }
615
616 if ( (OriginalNtOpenFile = (fpZwOpenFile) ZwCalls[ZW_OPEN_FILE_INDEX].OriginalFunction) == NULL)
617 {
618 LOG(LOG_SS_FILE, LOG_PRIORITY_DEBUG, ("InitFileHooks: OriginalNtOpenFile is NULL\n"));
619 return FALSE;
620 }
621
622 if ( (OriginalNtDeleteFile = (fpZwDeleteFile) ZwCalls[ZW_DELETE_FILE_INDEX].OriginalFunction) == NULL)
623 {
624 LOG(LOG_SS_FILE, LOG_PRIORITY_DEBUG, ("InitFileHooks: OriginalNtDeleteFile is NULL\n"));
625 return FALSE;
626 }
627
628 if ( (OriginalNtQueryAttributesFile = (fpZwQueryAttributesFile) ZwCalls[ZW_QUERY_ATTRIBUTES_FILE_INDEX].OriginalFunction) == NULL)
629 {
630 LOG(LOG_SS_FILE, LOG_PRIORITY_DEBUG, ("InitFileHooks: OriginalNtQueryAttributesFile is NULL\n"));
631 return FALSE;
632 }
633
634 if ( (OriginalNtQueryFullAttributesFile = (fpZwQueryFullAttributesFile) ZwCalls[ZW_QUERY_FULLATTR_FILE_INDEX].OriginalFunction) == NULL)
635 {
636 LOG(LOG_SS_FILE, LOG_PRIORITY_DEBUG, ("InitFileHooks: OriginalNtQueryFullAttributesFile is NULL\n"));
637 return FALSE;
638 }
639/*
640 if ( (OriginalNtQueryDirectoryFile = (fpZwQueryDirectoryFile) ZwCalls[ZW_QUERY_DIRECTORYFILE_INDEX].OriginalFunction) == NULL)
641 {
642 LOG(LOG_SS_FILE, LOG_PRIORITY_DEBUG, ("InitFileHooks: OriginalNtQueryDirectoryFile is NULL\n"));
643 return FALSE;
644 }
645*/
646 if ( (OriginalNtSetInformationFile = (fpZwSetInformationFile) ZwCalls[ZW_SET_INFO_FILE_INDEX].OriginalFunction) == NULL)
647 {
648 LOG(LOG_SS_FILE, LOG_PRIORITY_DEBUG, ("InitFileHooks: OriginalNtSetInformationFile is NULL\n"));
649 return FALSE;
650 }
651
652 if ( (OriginalNtCreateNamedPipeFile = (fpZwCreateNamedPipeFile) ZwCalls[ZW_CREATE_NAMEDPIPEFILE_INDEX].OriginalFunction) == NULL)
653 {
654 LOG(LOG_SS_FILE, LOG_PRIORITY_DEBUG, ("InitFileHooks: OriginalNtCreateNamedPipeFile is NULL\n"));
655 return FALSE;
656 }
657
658 if ( (OriginalNtCreateMailslotFile = (fpZwCreateMailslotFile) ZwCalls[ZW_CREATE_MAILSLOTFILE_INDEX].OriginalFunction) == NULL)
659 {
660 LOG(LOG_SS_FILE, LOG_PRIORITY_DEBUG, ("InitFileHooks: OriginalNtCreateMailslotFile is NULL\n"));
661 return FALSE;
662 }
663
664 return TRUE;
665}
diff --git a/file.h b/file.h
new file mode 100644
index 0000000..792a707
--- /dev/null
+++ b/file.h
@@ -0,0 +1,273 @@
1/*
2 * Copyright (c) 2004 Security Architects Corporation. All rights reserved.
3 *
4 * Module Name:
5 *
6 * file.h
7 *
8 * Abstract:
9 *
10 * This module defines various types used by file hooking routines.
11 *
12 * Author:
13 *
14 * Eugene Tsyrklevich 19-Feb-2004
15 *
16 * Revision History:
17 *
18 * None.
19 */
20
21
22#ifndef __FILE_H__
23#define __FILE_H__
24
25
26/*
27 * ZwCreateFile creates or opens a file. [NAR]
28 */
29
30typedef NTSTATUS (*fpZwCreateFile) (
31 OUT PHANDLE FileHandle,
32 IN ACCESS_MASK DesiredAccess,
33 IN POBJECT_ATTRIBUTES ObjectAttributes,
34 OUT PIO_STATUS_BLOCK IoStatusBlock,
35 IN PLARGE_INTEGER AllocationSize OPTIONAL,
36 IN ULONG FileAttributes,
37 IN ULONG ShareAccess,
38 IN ULONG CreateDisposition,
39 IN ULONG CreateOptions,
40 IN PVOID EaBuffer OPTIONAL,
41 IN ULONG EaLength
42 );
43
44NTSTATUS
45NTAPI
46HookedNtCreateFile(
47 OUT PHANDLE FileHandle,
48 IN ACCESS_MASK DesiredAccess,
49 IN POBJECT_ATTRIBUTES ObjectAttributes,
50 OUT PIO_STATUS_BLOCK IoStatusBlock,
51 IN PLARGE_INTEGER AllocationSize OPTIONAL,
52 IN ULONG FileAttributes,
53 IN ULONG ShareAccess,
54 IN ULONG CreateDisposition,
55 IN ULONG CreateOptions,
56 IN PVOID EaBuffer OPTIONAL,
57 IN ULONG EaLength
58 );
59
60
61/*
62 * ZwOpenFile opens a file. [NAR]
63 */
64
65typedef NTSTATUS (*fpZwOpenFile) (
66 OUT PHANDLE FileHandle,
67 IN ACCESS_MASK DesiredAccess,
68 IN POBJECT_ATTRIBUTES ObjectAttributes,
69 OUT PIO_STATUS_BLOCK IoStatusBlock,
70 IN ULONG ShareAccess,
71 IN ULONG OpenOptions
72 );
73
74NTSTATUS
75NTAPI
76HookedNtOpenFile(
77 OUT PHANDLE FileHandle,
78 IN ACCESS_MASK DesiredAccess,
79 IN POBJECT_ATTRIBUTES ObjectAttributes,
80 OUT PIO_STATUS_BLOCK IoStatusBlock,
81 IN ULONG ShareAccess,
82 IN ULONG OpenOptions
83 );
84
85
86/*
87 * ZwDeleteFile deletes a file. [NAR]
88 */
89
90typedef NTSTATUS (*fpZwDeleteFile) (
91 IN POBJECT_ATTRIBUTES ObjectAttributes
92 );
93
94NTSTATUS
95NTAPI
96HookedNtDeleteFile(
97 IN POBJECT_ATTRIBUTES ObjectAttributes
98 );
99
100
101/*
102 * ZwQueryDirectoryFile retrieves information about the contents of a directory. [NAR]
103 */
104
105typedef NTSTATUS (*fpZwQueryDirectoryFile) (
106 IN HANDLE FileHandle,
107 IN HANDLE Event OPTIONAL,
108 IN PIO_APC_ROUTINE ApcRoutine OPTIONAL,
109 IN PVOID ApcContext OPTIONAL,
110 OUT PIO_STATUS_BLOCK IoStatusBlock,
111 OUT PVOID FileInformation,
112 IN ULONG FileInformationLength,
113 IN FILE_INFORMATION_CLASS FileInformationClass,
114 IN BOOLEAN ReturnSingleEntry,
115 IN PUNICODE_STRING FileName OPTIONAL,
116 IN BOOLEAN RestartScan
117 );
118
119NTSTATUS
120NTAPI
121HookedNtQueryDirectoryFile(
122 IN HANDLE FileHandle,
123 IN HANDLE Event OPTIONAL,
124 IN PIO_APC_ROUTINE ApcRoutine OPTIONAL,
125 IN PVOID ApcContext OPTIONAL,
126 OUT PIO_STATUS_BLOCK IoStatusBlock,
127 OUT PVOID FileInformation,
128 IN ULONG FileInformationLength,
129 IN FILE_INFORMATION_CLASS FileInformationClass,
130 IN BOOLEAN ReturnSingleEntry,
131 IN PUNICODE_STRING FileName OPTIONAL,
132 IN BOOLEAN RestartScan
133 );
134
135
136/*
137 * ZwQueryAttributesFile retrieves basic information about a file object. [NAR]
138 */
139
140typedef NTSTATUS (*fpZwQueryAttributesFile) (
141 IN POBJECT_ATTRIBUTES ObjectAttributes,
142 OUT PFILE_BASIC_INFORMATION FileInformation
143 );
144
145NTSTATUS
146NTAPI
147HookedNtQueryAttributesFile(
148 IN POBJECT_ATTRIBUTES ObjectAttributes,
149 OUT PFILE_BASIC_INFORMATION FileInformation
150 );
151
152
153/*
154 * ZwQueryFullAttributesFile retrieves extended information about a file object. [NAR]
155 */
156
157typedef NTSTATUS (*fpZwQueryFullAttributesFile) (
158 IN POBJECT_ATTRIBUTES ObjectAttributes,
159 OUT PFILE_NETWORK_OPEN_INFORMATION FileInformation
160 );
161
162NTSTATUS
163NTAPI
164HookedNtQueryFullAttributesFile(
165 IN POBJECT_ATTRIBUTES ObjectAttributes,
166 OUT PFILE_NETWORK_OPEN_INFORMATION FileInformation
167 );
168
169
170/*
171 * ZwSetInformationFile sets information affecting a file object. [NAR]
172 */
173
174typedef NTSTATUS (*fpZwSetInformationFile) (
175 IN HANDLE FileHandle,
176 OUT PIO_STATUS_BLOCK IoStatusBlock,
177 IN PVOID FileInformation,
178 IN ULONG FileInformationLength,
179 IN FILE_INFORMATION_CLASS FileInformationClass
180 );
181
182NTSTATUS
183NTAPI
184HookedNtSetInformationFile(
185 IN HANDLE FileHandle,
186 OUT PIO_STATUS_BLOCK IoStatusBlock,
187 IN PVOID FileInformation,
188 IN ULONG FileInformationLength,
189 IN FILE_INFORMATION_CLASS FileInformationClass
190 );
191
192
193
194/*
195 * ZwCreateNamedPipeFile creates a named pipe. [NAR]
196 */
197
198typedef NTSTATUS (*fpZwCreateNamedPipeFile) (
199 OUT PHANDLE FileHandle,
200 IN ACCESS_MASK DesiredAccess,
201 IN POBJECT_ATTRIBUTES ObjectAttributes,
202 OUT PIO_STATUS_BLOCK IoStatusBlock,
203 IN ULONG ShareAccess,
204 IN ULONG CreateDisposition,
205 IN ULONG CreateOptions,
206/* The following 3 parameters listed in NAR are wrong
207 IN BOOLEAN TypeMessage,
208 IN BOOLEAN ReadmodeMessage,
209 IN BOOLEAN Nonblocking,
210*/
211 IN ULONG TypeMessage,
212 IN ULONG ReadmodeMessage,
213 IN ULONG Nonblocking,
214 IN ULONG MaxInstances,
215 IN ULONG InBufferSize,
216 IN ULONG OutBufferSize,
217 IN PLARGE_INTEGER DefaultTimeout OPTIONAL
218 );
219
220NTSTATUS
221NTAPI
222HookedNtCreateNamedPipeFile(
223 OUT PHANDLE FileHandle,
224 IN ACCESS_MASK DesiredAccess,
225 IN POBJECT_ATTRIBUTES ObjectAttributes,
226 OUT PIO_STATUS_BLOCK IoStatusBlock,
227 IN ULONG ShareAccess,
228 IN ULONG CreateDisposition,
229 IN ULONG CreateOptions,
230 IN ULONG TypeMessage,
231 IN ULONG ReadmodeMessage,
232 IN ULONG Nonblocking,
233 IN ULONG MaxInstances,
234 IN ULONG InBufferSize,
235 IN ULONG OutBufferSize,
236 IN PLARGE_INTEGER DefaultTimeout OPTIONAL
237 );
238
239
240
241/*
242 * ZwCreateMailslotFile creates a mailslot. [NAR]
243 */
244
245typedef NTSTATUS (*fpZwCreateMailslotFile) (
246 OUT PHANDLE FileHandle,
247 IN ACCESS_MASK DesiredAccess,
248 IN POBJECT_ATTRIBUTES ObjectAttributes,
249 OUT PIO_STATUS_BLOCK IoStatusBlock,
250 IN ULONG CreateOptions,
251 IN ULONG InBufferSize,
252 IN ULONG MaxMessageSize,
253 IN PLARGE_INTEGER ReadTimeout OPTIONAL
254 );
255
256NTSTATUS
257NTAPI
258HookedNtCreateMailslotFile(
259 OUT PHANDLE FileHandle,
260 IN ACCESS_MASK DesiredAccess,
261 IN POBJECT_ATTRIBUTES ObjectAttributes,
262 OUT PIO_STATUS_BLOCK IoStatusBlock,
263 IN ULONG CreateOptions,
264 IN ULONG InBufferSize,
265 IN ULONG MaxMessageSize,
266 IN PLARGE_INTEGER ReadTimeout OPTIONAL
267 );
268
269
270BOOLEAN InitFileHooks();
271
272
273#endif /* __FILE_H__ */
diff --git a/hookproc.c b/hookproc.c
new file mode 100644
index 0000000..cba59d5
--- /dev/null
+++ b/hookproc.c
@@ -0,0 +1,1799 @@
1/*
2 * Copyright (c) 2004 Security Architects Corporation. All rights reserved.
3 *
4 * Module Name:
5 *
6 * hookproc.c
7 *
8 * Abstract:
9 *
10 * This module implements various service operation (system call) hooking routines.
11 *
12 * Since not all the Zw* services are exported, we use a hack to find the required information.
13 * ntdll.dll contains stubs for calling all the system services. All stubs start with
14 * "mov eax, function_index" instruction where function_index is an index into a global
15 * system call table. By parsing ntdll.dll and extracting all the function indeces
16 * we can map all the Zw* names to their appropriate system call table indeces.
17 *
18 * Author:
19 *
20 * Eugene Tsyrklevich 16-Feb-2004
21 *
22 * Revision History:
23 *
24 * None.
25 */
26
27#include <NTDDK.h>
28#include "hookproc.h"
29#include "sysinfo.h"
30#include "ntproto.h"
31#include "learn.h"
32#include "file.h"
33#include "registry.h"
34#include "section.h"
35#include "sysinfo.h"
36#include "semaphore.h"
37#include "dirobj.h"
38#include "symlink.h"
39#include "mutant.h"
40#include "event.h"
41#include "port.h"
42#include "job.h"
43#include "token.h"
44#include "timer.h"
45#include "driverobj.h"
46#include "process.h"
47#include "procname.h"
48#include "time.h"
49#include "atom.h"
50#include "vdm.h"
51#include "debug.h"
52#include "i386.h"
53#include "misc.h"
54#include "log.h"
55
56
57#ifdef ALLOC_PRAGMA
58#pragma alloc_text (INIT, InitSyscallsHooks)
59#pragma alloc_text (INIT, InstallSyscallsHooks)
60#pragma alloc_text (PAGE, RemoveSyscallsHooks)
61#endif
62
63
64#if DBG
65int HookedRoutineRunning = 0;
66#endif
67
68PCHAR NTDLL_Base;
69
70int ZwCallsNumber = 0;
71
72
73
74/*
75 * FindFunctionOffset()
76 *
77 * Description:
78 * Finds a Zw* system call offset in a system service table.
79 *
80 * Implementation of all the Zw* system services (such as ZwOpenFile or ZwCreateProcess())
81 * start with a "mov eax, function_offset" instruction. Function offset is extracted from
82 * the first instruction.
83 *
84 * Parameters:
85 * Function - Pointer to the function code.
86 *
87 * Returns:
88 * Integer function offset (-1 in case of a failure).
89 */
90
91/* "MOV EAX,IMM32" opcode */
92#define OPCODE_MOV 0xB8
93
94/* macro shortcut for bailing out of FindFunctionOffset in case of an error */
95
96#define ABORT_FindFunctionOffset(msg) { \
97 LOG(LOG_SS_HOOKPROC, LOG_PRIORITY_DEBUG, ("Error occured in FindFunctionOffset():")); \
98 LOG(LOG_SS_HOOKPROC, LOG_PRIORITY_DEBUG, msg); \
99 return -1; \
100 }
101
102int
103FindFunctionOffset(PULONG_PTR Function)
104{
105 PUCHAR Instruction;
106 ULONG num, ServiceIDNumber, ServiceTableIndex;
107
108
109 /*
110 * Make sure that the service code starts with a MOV EAX,IMM32 instruction:
111 *
112 * lkd> u ZwCreateFile
113 * nt!ZwCreateFile:
114 * 804f86f4 b825000000 mov eax,0x25
115 */
116
117 Instruction = (PUCHAR) Function;
118
119 if (*Instruction != OPCODE_MOV)
120
121 ABORT_FindFunctionOffset(("Invalid opcode %x\n", *Instruction));
122
123
124 /*
125 * Extract the Service Descriptor Table index (4 bytes following the mov opcode)
126 *
127 * The index format is as follows:
128 *
129 * Leading 18 bits are all zeroes
130 * Following 2 bits are system service table index (3 bits on Win64)
131 * Following 12 bits are service number
132 */
133
134 num = * (PULONG) ++Instruction;
135
136
137 /* only SERVICE_TABLE_INDEX_BITS LSB bits should be set */
138
139 ServiceTableIndex = num >> SERVICE_ID_NUMBER_BITS;
140
141 if (ServiceTableIndex >= NUMBER_SERVICE_TABLES)
142
143 ABORT_FindFunctionOffset(("Invalid SSDT index: %x (%x)\n", ServiceTableIndex, num));
144
145
146 /* XXX temporary? There exist 4 (8 on IA64) service tables. All the Zw* system services are in table 0 */
147 if (ServiceTableIndex != 0)
148
149 ABORT_FindFunctionOffset(("Invalid SSDT index2: %x (%x)\n", ServiceTableIndex, num));
150
151
152 /* Verify Service ID Number is in range */
153
154 ServiceIDNumber = num & SERVICE_ID_NUMBER_MASK;
155
156//XXX shouldn't we be using the shadow table instead??
157//shadow table Zw* base address is the same in addition to GUI table
158 if (ServiceIDNumber > KeServiceDescriptorTable[ServiceTableIndex].NumberOfServices)
159
160 ABORT_FindFunctionOffset(("Invalid service id number %d (max is %d)\n", ServiceIDNumber, KeServiceDescriptorTable[ServiceTableIndex].NumberOfServices));
161
162
163 return ServiceIDNumber;
164}
165
166
167
168#if 0
169
170/*
171 * HookSystemService()
172 *
173 * Description:
174 * Replaces an existing sytem service pointer (n a global system service table) with another function pointer.
175 *
176 * Parameters:
177 * OldService - Pointer to the service code to mediate.
178 * NewService - Pointer to the new function code.
179 *
180 * Returns:
181 * Current OldService indexed system service function pointer.
182 */
183
184/* macro shortcut for bailing out of HookSystemService in case of an error */
185
186#define ABORT_HookSystemService(msg) { \
187 LOG(LOG_SS_HOOKPROC, LOG_PRIORITY_DEBUG, ("Error occured in HookSystemService():")); \
188 LOG(LOG_SS_HOOKPROC, LOG_PRIORITY_DEBUG, (msg)); \
189 return NULL; \
190 }
191
192PVOID
193HookSystemService(PVOID OldService, PVOID NewService)
194{
195 PULONG_PTR ssdt;
196 PULONG_PTR retptr = NULL;
197 ULONG ServiceIDNumber;
198
199
200 if (OldService == NULL || NewService == NULL)
201
202 ABORT_HookSystemService(("NULL detected. OldService=%x NewService=%x", OldService, NewService));
203
204
205 ServiceIDNumber = FindFunctionOffset(OldService);
206
207 if (ServiceIDNumber == -1)
208
209 ABORT_HookSystemService(("FindFunctionOffset(%x) failed", OldService));
210
211
212 ssdt = KeServiceDescriptorTable[0].ServiceTableBase;
213
214
215 retptr = (PULONG_PTR) ssdt[ServiceIDNumber];
216
217 if (retptr == NULL)
218
219 ABORT_HookSystemService(("ssdt[index] = NULL\n"));
220
221
222 if (((ULONG) retptr & SystemAddressStart) == 0)
223
224 ABORT_HookSystemService(("invalid code instruction specified\n"));
225
226
227 retptr = ExchangeReadOnlyMemoryPointer((PVOID *) &ssdt[ServiceIDNumber], NewService);
228
229
230 return retptr;
231}
232
233#endif
234
235
236
237/*
238 * HookSystemServiceByIndex()
239 *
240 * Description:
241 * Replaces an existing sytem service (n a global system service table) with another function pointer.
242 *
243 * Parameters:
244 * ServiceIDNumber - Index of a system service to mediate.
245 * NewService - Pointer to the new function code.
246 *
247 * Returns:
248 * Current ServiceIDNumber indexed system service function pointer.
249 */
250
251/* macro shortcut for bailing out of HookSystemServiceByIndex in case of an error */
252
253#define ABORT_HookSystemServiceByIndex(msg) { \
254 LOG(LOG_SS_HOOKPROC, LOG_PRIORITY_DEBUG, ("Error occured in HookSystemServiceByIndex():")); \
255 LOG(LOG_SS_HOOKPROC, LOG_PRIORITY_DEBUG, msg); \
256 return NULL; \
257 }
258
259PVOID
260HookSystemServiceByIndex(ULONG ServiceIDNumber, PVOID NewService)
261{
262 PULONG_PTR ssdt;
263 PULONG_PTR retptr = NULL;
264 ULONG ServiceTableIndex = 0;
265
266
267 ssdt = KeServiceDescriptorTable[ServiceTableIndex].ServiceTableBase;
268
269
270 /* Verify Service ID Number is in range */
271
272//XXX shouldn't we be using the shadow table instead??
273 if (ServiceIDNumber > KeServiceDescriptorTable[ServiceTableIndex].NumberOfServices)
274
275 ABORT_HookSystemServiceByIndex(("Invalid service id number %d (max is %d)\n", ServiceIDNumber, KeServiceDescriptorTable[ServiceTableIndex].NumberOfServices));
276
277
278 retptr = (PULONG_PTR) ssdt[ServiceIDNumber];
279
280 if (retptr == NULL)
281
282 ABORT_HookSystemServiceByIndex(("ssdt[index] = NULL\n"));
283
284
285 if (((ULONG) retptr & SystemAddressStart) == 0)
286
287 ABORT_HookSystemServiceByIndex(("invalid code instruction specified\n"));
288
289
290 retptr = ExchangeReadOnlyMemoryPointer((PVOID *) &ssdt[ServiceIDNumber], NewService);
291
292
293 return retptr;
294}
295
296
297#if 0
298/*
299 * FindSystemServiceByIndex()
300 *
301 * Description:XXX
302 * Replaces an existing sytem service (n a global system service table) with another function pointer.
303 *
304 * Parameters:
305 * ServiceIDNumber - Index of a system service to mediate.
306 * NewService - Pointer to the new function code.
307 *
308 * Returns:
309 * Current ServiceIDNumber indexed system service function pointer.
310 */
311
312/* macro shortcut for bailing out of HookSystemServiceByIndex in case of an error */
313
314#define ABORT_FindSystemServiceByIndex(msg) { LOG(LOG_SS_HOOKPROC, LOG_PRIORITY_DEBUG, ("Error occured in FindSystemServiceByIndex():")); LOG(LOG_SS_HOOKPROC, LOG_PRIORITY_DEBUG, msg); return NULL; }
315
316PULONG
317FindSystemServiceByIndex(ULONG ServiceIDNumber)
318{
319 PULONG_PTR ssdt;
320 PULONG_PTR retptr = NULL;
321 ULONG ServiceTableIndex = 0;
322
323
324 ssdt = KeServiceDescriptorTable[ServiceTableIndex].ServiceTableBase;
325
326
327 /* Verify Service ID Number is in range */
328
329//XXX shouldn't we be using the shadow table instead??
330 if (ServiceIDNumber > KeServiceDescriptorTable[ServiceTableIndex].NumberOfServices)
331
332 ABORT_FindSystemServiceByIndex(("Invalid service id number %d (max is %d)\n", ServiceIDNumber, KeServiceDescriptorTable[ServiceTableIndex].NumberOfServices));
333
334
335 retptr = (PULONG_PTR) ssdt[ServiceIDNumber];
336
337 if (retptr == NULL)
338
339 ABORT_FindSystemServiceByIndex(("ssdt[index] = NULL\n"));
340
341
342 if (((ULONG) retptr & SystemAddressStart) == 0)
343
344 ABORT_FindSystemServiceByIndex(("invalid code instruction specified\n"));
345
346
347 return (PULONG) ssdt[ServiceIDNumber];
348}
349#endif
350
351
352/*
353 * HookSystemServiceByName()
354 *
355 * Description:
356 * Replaces an existing sytem service (n a global system service table) with another function pointer.
357 *
358 * Parameters:
359 * ServiceName - Name of a Zw* system service to mediate.
360 * HookFunction - Pointer to the mediator function code.
361 *
362 * Returns:
363 * TRUE to indicate success, FALSE if failed.
364 */
365
366BOOLEAN
367HookSystemServiceByName(PCHAR ServiceName, PULONG_PTR HookFunction)
368{
369 int i;
370
371
372 for (i = 0; i < ZwCallsNumber; i++)
373 {
374 if (strlen(ServiceName) == ZwCalls[i].ZwNameLength && _stricmp(ServiceName, ZwCalls[i].ZwName + 2) == 0)
375 {
376// LOG(LOG_SS_HOOKPROC, LOG_PRIORITY_DEBUG, ("HookSystemServiceByName: Matched rule: %x\n", ZwCalls[i].ServiceIDNumber));
377
378 // hijack the syscall if not hijacked already
379 if (ZwCalls[i].Hijacked == FALSE && ZwCalls[i].ServiceIDNumber != -1)
380 {
381 if ((ZwCalls[i].OriginalFunction = HookSystemServiceByIndex(ZwCalls[i].ServiceIDNumber,
382 HookFunction ? HookFunction : ZwCalls[i].HookFunction)) != NULL)
383 {
384 ZwCalls[i].Hijacked = TRUE;
385 }
386 }
387
388 return TRUE;
389 }
390 }
391
392
393 return FALSE;
394}
395
396
397
398#if 0
399/*
400 * FindSystemServiceIndex()
401 *
402 * Description:
403 * Find a system service index for a specified service name.
404 *
405 * Parameters:
406 * ServiceName - Name of a Zw* system service to find.
407 *
408 * Returns:
409 * System service index if found, -1 otherwise.
410 */
411
412ULONG
413FindSystemServiceIndex(PCHAR ServiceName)
414{
415 int i;
416
417
418 for (i = 0; i < ZwCallsNumber; i++)
419 {
420 if (strlen(ServiceName) == ZwCalls[i].ZwNameLength && _stricmp(ServiceName, ZwCalls[i].ZwName + 2) == 0)
421 {
422// LOG(LOG_SS_HOOKPROC, LOG_PRIORITY_DEBUG, ("FindSystemServiceByName: Matched rule: %x\n", ZwCalls[i].ServiceIDNumber));
423
424 return ZwCalls[i].ServiceIDNumber;
425 }
426 }
427
428
429 return -1;
430}
431#endif
432
433
434/*
435 * FindSystemServiceNumber()
436 *
437 * Description:
438 * Find a system service number for a specified service name.
439 *
440 * Parameters:
441 * ServiceName - Name of a Zw* system service to find.
442 *
443 * Returns:
444 * System service number if found, -1 otherwise.
445 */
446
447ULONG
448FindSystemServiceNumber(PCHAR ServiceName)
449{
450 int i;
451
452
453 for (i = 0; i < ZwCallsNumber; i++)
454 {
455 if (strlen(ServiceName) == ZwCalls[i].ZwNameLength && _stricmp(ServiceName, ZwCalls[i].ZwName + 2) == 0)
456 {
457// LOG(LOG_SS_HOOKPROC, LOG_PRIORITY_DEBUG, ("FindSystemServiceByName: Matched rule: %x\n", ZwCalls[i].ServiceIDNumber));
458
459 return i;
460 }
461 }
462
463
464 return -1;
465}
466
467
468
469/*
470 * Find_NTDLL_Base()
471 *
472 * Description:
473 * Returns the base address of mapped ntdll.dll in a "System" process context.
474 *
475 * NOTE: Based on "Windows NT/2000 Native API Reference" implementation.
476 *
477 * Parameters:
478 * None.
479 *
480 * Returns:
481 * ntdll.dll base address (NULL if not found).
482 */
483
484PVOID
485Find_NTDLL_Base()
486{
487 ULONG size, i;
488 PVOID ntdll = NULL;
489 PULONG SystemInfo;
490 PSYSTEM_MODULE_INFORMATION pSMI;
491 NTSTATUS status;
492
493
494 /*
495 * The data returned to the SystemInformation buffer is a ULONG count of the number of
496 * modules followed immediately by an array of SYSTEM_MODULE_INFORMATION.
497 *
498 * The system modules are the Portable Executable (PE) format files loaded into the
499 * kernel address space (ntoskrnl.exe, hal.dll, device drivers, and so on) and ntdll.dll.
500 */
501
502
503 /* first, find out the total amount of module information to be returned */
504
505 status = ZwQuerySystemInformation(SystemModuleInformation, &size, 0, &size);
506 if (size == 0 || size > 1024*1024)
507 {
508 LOG(LOG_SS_HOOKPROC, LOG_PRIORITY_DEBUG, ("Find_NTDLL_Base: ZwQuerySystemInformation failed. status=%x size=%d\n", status, size));
509 return NULL;
510 }
511
512
513 /* second, allocate the required amount of memory */
514
515 SystemInfo = ExAllocatePoolWithTag(PagedPool, size + 4, _POOL_TAG);
516 if (SystemInfo == NULL)
517 {
518 LOG(LOG_SS_HOOKPROC, LOG_PRIORITY_DEBUG, ("Find_NTDLL_Base: out of memory (requested %d bytes)\n", size + 4));
519 return NULL;
520 }
521
522
523 /* third, request the module information */
524
525 ZwQuerySystemInformation(SystemModuleInformation, SystemInfo, size, &i);
526
527 if (size != ((*SystemInfo * sizeof(SYSTEM_MODULE_INFORMATION)) + 4))
528 {
529 LOG(LOG_SS_HOOKPROC, LOG_PRIORITY_DEBUG, ("Find_NTDLL_Base: inconsistent size (%d != %d * %d + 4)\n", size, *SystemInfo, sizeof(SYSTEM_MODULE_INFORMATION)));
530 return NULL;
531 }
532
533
534
535 pSMI = (PSYSTEM_MODULE_INFORMATION) (SystemInfo + 1);
536
537 for (i = 0; i < *SystemInfo; i++)
538 {
539// LOG(LOG_SS_HOOKPROC, LOG_PRIORITY_DEBUG, ("comparing '%s' (base 0x%x)\n", pSMI[i].ImageName + pSMI[i].ModuleNameOffset, pSMI[i].Base));
540
541 if (_stricmp(pSMI[i].ImageName + pSMI[i].ModuleNameOffset, "ntdll.dll") == 0)
542 {
543 LOG(LOG_SS_HOOKPROC, LOG_PRIORITY_VERBOSE, ("Find_NTDLL_Base: ntdll.dll base address is %x\n", pSMI[i].Base));
544 ntdll = pSMI[i].Base;
545 break;
546 }
547 }
548
549 ExFreePoolWithTag(SystemInfo, _POOL_TAG);
550
551
552 return ntdll;
553}
554
555
556#if 0
557PVOID
558Find_Kernel32_Base2()
559{
560 PVOID Kernel32 = NULL;
561 NTSTATUS status;
562 OBJECT_ATTRIBUTES ObjectAttributes;
563 IO_STATUS_BLOCK isb;
564 HANDLE FileHandle;
565 UNICODE_STRING usName;
566 PVOID BaseAddress = NULL;
567 SIZE_T Size;
568 CHAR buffer[256];
569
570
571// RtlInitUnicodeString(&usName, L"\\SystemRoot\\System32\\kernel32.dll");
572 RtlInitUnicodeString(&usName, L"\\??\\c:\\windows\\system32\\kernel32.dll");
573 InitializeObjectAttributes(&ObjectAttributes, &usName, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL);
574
575 status = ZwCreateFile(&FileHandle, GENERIC_READ, &ObjectAttributes, &isb, NULL, 0, 0, 0, 0, NULL, 0);
576 if (!NT_SUCCESS(status))
577 {
578 LOG(LOG_SS_MISC, LOG_PRIORITY_DEBUG, ("Find_Kernel32_Base: Failed to open file %S (%x)\n", usName.Buffer, status));
579 return FALSE;
580 }
581
582
583 status = ZwReadFile(FileHandle, NULL, NULL, NULL, &isb, (PVOID) buffer, sizeof(buffer) - 1, 0, NULL);
584
585 if (! NT_SUCCESS(status))
586 {
587 if (status != STATUS_END_OF_FILE)
588 {
589 LOG(LOG_SS_POLICY, LOG_PRIORITY_DEBUG, ("LoadSecurityPolicy: ZwReadFile failed rc=%x\n", status));
590 }
591 }
592
593 ZwClose(FileHandle);
594
595
596 return Kernel32;
597}
598
599
600
601PVOID
602Find_Kernel32_Base()
603{
604 PVOID Kernel32 = NULL;
605 NTSTATUS status;
606 OBJECT_ATTRIBUTES ObjectAttributes;
607 HANDLE SectionHandle;
608 UNICODE_STRING usName;
609 PVOID BaseAddress = NULL;
610 SIZE_T Size;
611 NTSTATUS q;
612
613
614 RtlInitUnicodeString(&usName, L"\\KnownDlls\\kernel32.dll");
615 InitializeObjectAttributes(&ObjectAttributes, &usName, OBJ_KERNEL_HANDLE, NULL, NULL);
616
617 if (NT_SUCCESS( ZwOpenSection(&SectionHandle, SECTION_MAP_READ, &ObjectAttributes) ))
618 {
619 q = ZwMapViewOfSection(SectionHandle, NtCurrentProcess(), &BaseAddress, 0, 0, NULL, &Size, ViewShare, MEM_RESERVE, PAGE_READWRITE);
620 if (NT_SUCCESS(q))
621 {
622 KdPrint(("XXX mapped kernel32.dll at BaseAddress %x\n", BaseAddress));
623
624 if (!NT_SUCCESS( ZwUnmapViewOfSection(NtCurrentProcess(), BaseAddress) ))
625 {
626 KdPrint(("ZwUnmapViewOfSection failed"));
627 }
628
629 ZwClose(SectionHandle);
630 }
631 else
632 {
633 KdPrint(("ZwMapViewOfSection failed with status %x", q));
634 }
635 }
636 else
637 {
638 KdPrint(("ZwOpenSection failed"));
639 }
640
641 return Kernel32;
642}
643#endif
644
645
646/*
647 * FindFunctionBase()
648 *
649 * Description:
650 * Finds the address where a function is mapped at.
651 *
652 * NOTE: Based on "Windows NT/2000 Native API Reference" implementation.
653 *
654 * Parameters:
655 * Base - Mapped address of a DLL exporting the function.
656 * Name - Function name.
657 *
658 * Returns:
659 * Address where a function is mapped at (NULL if not found).
660 */
661
662/* macro shortcut for bailing out of FindFunctionBase in case of an error */
663
664#define ABORT_FindFunctionBase(msg) { \
665 LOG(LOG_SS_HOOKPROC, LOG_PRIORITY_DEBUG, ("Error occured in FindFunctionBase():")); \
666 LOG(LOG_SS_HOOKPROC, LOG_PRIORITY_DEBUG, msg); \
667 return NULL; \
668 }
669
670PVOID
671FindFunctionBase(PCHAR ImageBase, PCSTR Name)
672{
673 PIMAGE_DOS_HEADER DosHeader;
674 PIMAGE_NT_HEADERS PeHeader;
675 PIMAGE_DATA_DIRECTORY ImageExportDirectoryEntry;
676 ULONG ExportDirectorySize, ExportDirectoryOffset, i;
677 PIMAGE_EXPORT_DIRECTORY ExportDirectory;
678 PULONG ExportAddressTable;
679 PSHORT ExportOrdinalTable;
680 PULONG ExportNameTable;
681
682
683 if ( (DosHeader = (PIMAGE_DOS_HEADER) ImageBase) == NULL)
684
685 ABORT_FindFunctionBase(("Base pointer is NULL (name = %s)\n", Name));
686
687
688 if (DosHeader->e_magic != IMAGE_DOS_SIGNATURE)
689
690 ABORT_FindFunctionBase(("DOS Signature not found! (%x %x)\n", DosHeader, DosHeader->e_magic));
691
692
693 if (DosHeader->e_lfanew > 1024*1024)
694
695 ABORT_FindFunctionBase(("Invalid e_lfanew value %x\n", DosHeader->e_lfanew));
696
697
698 if ( (PeHeader = (PIMAGE_NT_HEADERS) (ImageBase + DosHeader->e_lfanew)) == NULL)
699
700 ABORT_FindFunctionBase(("NT header pointer is NULL (name = %s)\n", Name));
701
702
703 if (PeHeader->Signature != IMAGE_PE_SIGNATURE)
704
705 ABORT_FindFunctionBase(("PE Signature not found! (%x %x)\n", PeHeader, PeHeader->Signature));
706
707
708 if ( (ImageExportDirectoryEntry = PeHeader->OptionalHeader.DataDirectory + IMAGE_DIRECTORY_ENTRY_EXPORT) == NULL)
709
710 ABORT_FindFunctionBase(("Export directory pointer is NULL (name = %s)\n", Name));
711
712
713 ExportDirectorySize = ImageExportDirectoryEntry->Size;
714 ExportDirectoryOffset = ImageExportDirectoryEntry->VirtualAddress;
715
716 if ( (ExportDirectory = (PIMAGE_EXPORT_DIRECTORY) (ImageBase + ExportDirectoryOffset)) == NULL)
717
718 ABORT_FindFunctionBase(("Exports pointer is NULL (name = %s)\n", Name));
719
720
721 ExportAddressTable = (PULONG) (ImageBase + ExportDirectory->AddressOfFunctions);
722 ExportOrdinalTable = (PSHORT) (ImageBase + ExportDirectory->AddressOfNameOrdinals);
723 ExportNameTable = (PULONG) (ImageBase + ExportDirectory->AddressOfNames);
724
725//XXX "AcceptConnectPort\0" \0 necessary to make sure ZwCreateProcess does not match ZwCreateProcessEx ?
726
727 for (i = 0; i < ExportDirectory->NumberOfNames; i++)
728 {
729 ULONG ord = ExportOrdinalTable[i];
730
731 if (ExportAddressTable[ord] < ExportDirectoryOffset ||
732 ExportAddressTable[ord] >= ExportDirectoryOffset + ExportDirectorySize)
733 {
734 //XXX windows loader uses binary search?
735 if (strcmp(ImageBase + ExportNameTable[i], Name) == 0)
736 {
737 return ImageBase + ExportAddressTable[ord];
738 }
739 }
740 }
741
742 return NULL;
743}
744
745
746
747/*
748 * FindZwFunctionIndex()
749 *
750 * Description:
751 * Finds a system service table index of a Zw* system service.
752 *
753 * NOTE: Based on "Windows NT/2000 Native API Reference" implementation.
754 *
755 * Parameters:
756 * Name - Zw* service name.
757 *
758 * Returns:
759 * Zw* service index in a system service table (-1 if not found).
760 */
761
762int
763FindZwFunctionIndex(PCSTR Name)
764{
765 PULONG_PTR FunctionBase;
766
767
768 if (NTDLL_Base == NULL)
769 if ( (NTDLL_Base = Find_NTDLL_Base()) == NULL)
770 return -1;
771
772
773 if ( (FunctionBase = FindFunctionBase(NTDLL_Base, Name)) == NULL)
774 {
775// LOG(LOG_SS_HOOKPROC, LOG_PRIORITY_DEBUG, ("FindZwFunctionIndex: FindZwFunctionBase(%s) returned NULL", Name));
776 return -1;
777 }
778
779
780 return FindFunctionOffset(FunctionBase);
781}
782
783
784
785/*
786 * ZwCalls structure describes all known system services.
787 * Part of the structure (i.e. system call table offset and system call address)
788 * is filled in at runtime.
789 *
790 * Automatically generated with
791 * dumpbin /exports c:\windows2003\system32\ntdll.dll|grep Zw|
792 * perl -wnle "print qq{\t{ \"$1\", NULL, (PULONG_PTR) SystemCallHandler$i, NULL, FALSE },} if /(Zw.*)/; ++$i" > win2k3_syscalls
793 *
794 * perl -wne "if (/\"Zw(.*?)\"/) { $q=length $1; s/\"Zw(.*?)\"/\"Zw$1\", $q/} print" q.txt > q2.txt
795 */
796
797struct _ZwCalls /* {
798 PCHAR ZwName; // System call name
799 USHORT ZwNameLength; // System call name length
800 USHORT ServiceIDNumber; // System call index (filled in at runtime)
801 PULONG_PTR HookFunction; // Address of the hijacking function (function that will be called instead of the original system call)
802 PULONG_PTR OriginalFunction; // PlaceHolder for the address of the original syscall address
803 BOOLEAN Hijacked; // Flag indicating whether we already hijacked this system call
804 // or whether this is a special system service that needs to be hijacked initially
805} */ ZwCalls[] =
806{
807 { "ZwAcceptConnectPort", 17, -1, (PULONG_PTR) SystemCallHandler0, NULL, FALSE },
808 { "ZwAccessCheck", 11, -1, (PULONG_PTR) SystemCallHandler1, NULL, FALSE },
809 { "ZwAccessCheckAndAuditAlarm", 24, -1, (PULONG_PTR) SystemCallHandler2, NULL, FALSE },
810 { "ZwAccessCheckByType", 17, -1, (PULONG_PTR) SystemCallHandler3, NULL, FALSE },
811 { "ZwAccessCheckByTypeAndAuditAlarm", 30, -1, (PULONG_PTR) SystemCallHandler4, NULL, FALSE },
812 { "ZwAccessCheckByTypeResultList", 27, -1, (PULONG_PTR) SystemCallHandler5, NULL, FALSE },
813 { "ZwAccessCheckByTypeResultListAndAuditAlarm", 40, -1, (PULONG_PTR) SystemCallHandler6, NULL, FALSE },
814 { "ZwAccessCheckByTypeResultListAndAuditAlarmByHandle", 48, -1, (PULONG_PTR) SystemCallHandler7, NULL, FALSE },
815
816
817#if HOOK_ATOM
818 { "ZwAddAtom", 7, -1, (PULONG_PTR) HookedNtAddAtom, NULL, TRUE },
819#else
820 { "ZwAddAtom", 7, -1, (PULONG_PTR) SystemCallHandler8, NULL, FALSE },
821#endif
822
823
824//XXX
825 { "ZwAddBootEntry", 12, -1, (PULONG_PTR) SystemCallHandler9, NULL, FALSE },
826 { "ZwAddDriverEntry", 14, -1, (PULONG_PTR) SystemCallHandler10, NULL, FALSE },
827
828
829#if HOOK_TOKEN_ZZZ
830 { "ZwAdjustGroupsToken", 17, -1, (PULONG_PTR) HookedNtAdjustGroupsToken, NULL, TRUE },
831#else
832 { "ZwAdjustGroupsToken", 17, -1, (PULONG_PTR) SystemCallHandler11, NULL, FALSE },
833#endif
834
835#if HOOK_TOKEN
836 { "ZwAdjustPrivilegesToken", 21, -1, (PULONG_PTR) HookedNtAdjustPrivilegesToken, NULL, TRUE },
837#else
838 { "ZwAdjustPrivilegesToken", 21, -1, (PULONG_PTR) SystemCallHandler12, NULL, FALSE },
839#endif
840
841
842 { "ZwAlertResumeThread", 17, -1, (PULONG_PTR) SystemCallHandler13, NULL, FALSE },
843 { "ZwAlertThread", 11, -1, (PULONG_PTR) SystemCallHandler14, NULL, FALSE },
844 { "ZwAllocateLocallyUniqueId", 23, -1, (PULONG_PTR) SystemCallHandler15, NULL, FALSE },
845 { "ZwAllocateUserPhysicalPages", 25, -1, (PULONG_PTR) SystemCallHandler16, NULL, FALSE },
846 { "ZwAllocateUuids", 13, -1, (PULONG_PTR) SystemCallHandler17, NULL, FALSE },
847 { "ZwAllocateVirtualMemory", 21, -1, (PULONG_PTR) SystemCallHandler18, NULL, FALSE },
848 { "ZwApphelpCacheControl", 19, -1, (PULONG_PTR) SystemCallHandler19, NULL, FALSE },
849 { "ZwAreMappedFilesTheSame", 21, -1, (PULONG_PTR) SystemCallHandler20, NULL, FALSE },
850 { "ZwAssignProcessToJobObject", 24, -1, (PULONG_PTR) SystemCallHandler21, NULL, FALSE },
851 { "ZwCallbackReturn", 14, -1, (PULONG_PTR) SystemCallHandler22, NULL, FALSE },
852 { "ZwCancelDeviceWakeupRequest", 25, -1, (PULONG_PTR) SystemCallHandler23, NULL, FALSE },
853 { "ZwCancelIoFile", 12, -1, (PULONG_PTR) SystemCallHandler24, NULL, FALSE },
854 { "ZwCancelTimer", 11, -1, (PULONG_PTR) SystemCallHandler25, NULL, FALSE },
855 { "ZwClearEvent", 10, -1, (PULONG_PTR) SystemCallHandler26, NULL, FALSE },
856
857 /* don't mediate for performance reasons, requires a valid handle anyway */
858 { "ZwClose", 5, -1, NULL, NULL, FALSE },
859
860 { "ZwCloseObjectAuditAlarm", 21, -1, (PULONG_PTR) SystemCallHandler28, NULL, FALSE },
861 { "ZwCompactKeys", 11, -1, (PULONG_PTR) SystemCallHandler29, NULL, FALSE },
862 { "ZwCompareTokens", 13, -1, (PULONG_PTR) SystemCallHandler30, NULL, FALSE },
863 { "ZwCompleteConnectPort", 19, -1, (PULONG_PTR) SystemCallHandler31, NULL, FALSE },
864 { "ZwCompressKey", 11, -1, (PULONG_PTR) SystemCallHandler32, NULL, FALSE },
865
866
867#if HOOK_PORT
868 { "ZwConnectPort", 11, -1, (PULONG_PTR) HookedNtConnectPort, NULL, TRUE },
869#else
870 { "ZwConnectPort", 11, -1, (PULONG_PTR) SystemCallHandler33, NULL, FALSE },
871#endif
872
873
874 { "ZwContinue", 8, -1, (PULONG_PTR) SystemCallHandler34, NULL, FALSE },
875
876
877#if HOOK_DEBUG_ZZZ
878 { "ZwCreateDebugObject", 17, -1, (PULONG_PTR) HookedNtCreateDebugObject, NULL, TRUE },
879#else
880 { "ZwCreateDebugObject", 17, -1, (PULONG_PTR) SystemCallHandler35, NULL, FALSE },
881#endif
882
883
884#if HOOK_DIROBJ
885 { "ZwCreateDirectoryObject", 21, -1, (PULONG_PTR) HookedNtCreateDirectoryObject, NULL, TRUE },
886#else
887 { "ZwCreateDirectoryObject", 21, -1, (PULONG_PTR) SystemCallHandler36, NULL, FALSE },
888#endif
889
890
891#if HOOK_EVENT
892 { "ZwCreateEvent", 11, -1, (PULONG_PTR) HookedNtCreateEvent, NULL, TRUE },
893 { "ZwCreateEventPair", 15, -1, (PULONG_PTR) HookedNtCreateEventPair, NULL, TRUE },
894#else
895 { "ZwCreateEvent", 11, -1, (PULONG_PTR) SystemCallHandler37, NULL, FALSE },
896 { "ZwCreateEventPair", 15, -1, (PULONG_PTR) SystemCallHandler38, NULL, FALSE },
897#endif
898
899
900#if HOOK_FILE
901 { "ZwCreateFile", 10, -1, (PULONG_PTR) HookedNtCreateFile, NULL, TRUE },
902#else
903 { "ZwCreateFile", 10, -1, (PULONG_PTR) SystemCallHandler39, NULL, FALSE },
904#endif
905
906
907 { "ZwCreateIoCompletion", 18, -1, (PULONG_PTR) SystemCallHandler40, NULL, FALSE },
908
909
910#if HOOK_JOB
911 { "ZwCreateJobObject", 15, -1, (PULONG_PTR) HookedNtCreateJobObject, NULL, TRUE },
912#else
913 { "ZwCreateJobObject", 15, -1, (PULONG_PTR) SystemCallHandler41, NULL, FALSE },
914#endif
915
916
917//XXX ???
918 { "ZwCreateJobSet", 12, -1, (PULONG_PTR) SystemCallHandler42, NULL, FALSE },
919
920
921#if HOOK_REGISTRY
922 { "ZwCreateKey", 9, -1, (PULONG_PTR) HookedNtCreateKey, NULL, TRUE },
923#else
924 { "ZwCreateKey", 9, -1, (PULONG_PTR) SystemCallHandler43, NULL, FALSE },
925#endif
926
927
928 { "ZwCreateKeyedEvent", 16, -1, (PULONG_PTR) SystemCallHandler44, NULL, FALSE },
929
930
931#if HOOK_FILE
932 { "ZwCreateMailslotFile", 18, -1, (PULONG_PTR) HookedNtCreateMailslotFile, NULL, TRUE },
933#else
934 { "ZwCreateMailslotFile", 18, -1, (PULONG_PTR) SystemCallHandler45, NULL, FALSE },
935#endif
936
937
938#if HOOK_MUTANT
939 { "ZwCreateMutant", 12, -1, (PULONG_PTR) HookedNtCreateMutant, NULL, TRUE },
940#else
941 { "ZwCreateMutant", 12, -1, (PULONG_PTR) SystemCallHandler46, NULL, FALSE },
942#endif
943
944
945#if HOOK_FILE
946 { "ZwCreateNamedPipeFile", 19, -1, (PULONG_PTR) HookedNtCreateNamedPipeFile, NULL, TRUE },
947#else
948 { "ZwCreateNamedPipeFile", 19, -1, (PULONG_PTR) SystemCallHandler47, NULL, FALSE },
949#endif
950
951
952 { "ZwCreatePagingFile", 16, -1, (PULONG_PTR) SystemCallHandler48, NULL, FALSE },
953
954
955#if HOOK_PORT
956 { "ZwCreatePort", 10, -1, (PULONG_PTR) HookedNtCreatePort, NULL, TRUE },
957#else
958 { "ZwCreatePort", 10, -1, (PULONG_PTR) SystemCallHandler49, NULL, FALSE },
959#endif
960
961
962#if HOOK_PROCESS
963 { "ZwCreateProcess", 13, -1, (PULONG_PTR) HookedNtCreateProcess, NULL, TRUE },
964 { "ZwCreateProcessEx", 15, -1, (PULONG_PTR) HookedNtCreateProcessEx, NULL, TRUE },
965#else
966 { "ZwCreateProcess", 13, -1, (PULONG_PTR) SystemCallHandler50, NULL, FALSE },
967 { "ZwCreateProcessEx", 15, -1, (PULONG_PTR) SystemCallHandler51, NULL, FALSE },
968#endif
969
970
971 { "ZwCreateProfile", 13, -1, (PULONG_PTR) SystemCallHandler52, NULL, FALSE },
972
973
974#if HOOK_SECTION
975 { "ZwCreateSection", 13, -1, (PULONG_PTR) HookedNtCreateSection, NULL, TRUE },
976#else
977 { "ZwCreateSection", 13, -1, (PULONG_PTR) SystemCallHandler53, NULL, FALSE },
978#endif
979
980
981#if HOOK_SEMAPHORE
982 { "ZwCreateSemaphore", 15, -1, (PULONG_PTR) HookedNtCreateSemaphore, NULL, TRUE },
983#else
984 { "ZwCreateSemaphore", 15, -1, (PULONG_PTR) SystemCallHandler54, NULL, FALSE },
985#endif
986
987
988#if HOOK_SYMLINK
989 { "ZwCreateSymbolicLinkObject", 24, -1, (PULONG_PTR) HookedNtCreateSymbolicLinkObject, NULL, TRUE },
990#else
991 { "ZwCreateSymbolicLinkObject", 24, -1, (PULONG_PTR) SystemCallHandler55, NULL, FALSE },
992#endif
993
994
995#if HOOK_PROCESS
996 { "ZwCreateThread", 12, -1, (PULONG_PTR) HookedNtCreateThread, NULL, TRUE },
997#else
998 { "ZwCreateThread", 12, -1, (PULONG_PTR) SystemCallHandler56, NULL, FALSE },
999#endif
1000
1001
1002#if HOOK_TIMER
1003 { "ZwCreateTimer", 11, -1, (PULONG_PTR) HookedNtCreateTimer, NULL, TRUE },
1004#else
1005 { "ZwCreateTimer", 11, -1, (PULONG_PTR) SystemCallHandler57, NULL, FALSE },
1006#endif
1007
1008
1009#if HOOK_TOKEN_ZZZ
1010 { "ZwCreateToken", 11, -1, (PULONG_PTR) HookedNtCreateToken, NULL, TRUE },
1011#else
1012 { "ZwCreateToken", 11, -1, (PULONG_PTR) SystemCallHandler58, NULL, FALSE },
1013#endif
1014
1015
1016#if HOOK_PORT
1017 { "ZwCreateWaitablePort", 18, -1, (PULONG_PTR) HookedNtCreateWaitablePort, NULL, TRUE },
1018#else
1019 { "ZwCreateWaitablePort", 18, -1, (PULONG_PTR) SystemCallHandler59, NULL, FALSE },
1020#endif
1021
1022
1023#if HOOK_DEBUG
1024 { "ZwDebugActiveProcess", 18, -1, (PULONG_PTR) HookedNtDebugActiveProcess, NULL, TRUE },
1025#else
1026 { "ZwDebugActiveProcess", 18, -1, (PULONG_PTR) SystemCallHandler60, NULL, FALSE },
1027#endif
1028
1029
1030 { "ZwDebugContinue", 13, -1, (PULONG_PTR) SystemCallHandler61, NULL, FALSE },
1031 { "ZwDelayExecution", 14, -1, (PULONG_PTR) SystemCallHandler62, NULL, FALSE },
1032 { "ZwDeleteAtom", 10, -1, (PULONG_PTR) SystemCallHandler63, NULL, FALSE },
1033 { "ZwDeleteBootEntry", 15, -1, (PULONG_PTR) SystemCallHandler64, NULL, FALSE },
1034 { "ZwDeleteDriverEntry", 17, -1, (PULONG_PTR) SystemCallHandler65, NULL, FALSE },
1035
1036
1037#if HOOK_FILE
1038 { "ZwDeleteFile", 10, -1, (PULONG_PTR) HookedNtDeleteFile, NULL, TRUE },
1039#else
1040 { "ZwDeleteFile", 10, -1, (PULONG_PTR) SystemCallHandler66, NULL, FALSE },
1041#endif
1042
1043
1044#if HOOK_REGISTRY
1045 { "ZwDeleteKey", 9, -1, (PULONG_PTR) HookedNtDeleteKey, NULL, TRUE },
1046#else
1047 { "ZwDeleteKey", 9, -1, (PULONG_PTR) SystemCallHandler67, NULL, FALSE },
1048#endif
1049
1050 { "ZwDeleteObjectAuditAlarm", 22, -1, (PULONG_PTR) SystemCallHandler68, NULL, FALSE },
1051 { "ZwDeleteValueKey", 14, -1, (PULONG_PTR) SystemCallHandler69, NULL, FALSE },
1052//XXX
1053
1054 { "ZwDeviceIoControlFile", 19, -1, NULL, NULL, FALSE },
1055 { "ZwDisplayString", 13, -1, (PULONG_PTR) SystemCallHandler71, NULL, FALSE },
1056 { "ZwDuplicateObject", 15, -1, (PULONG_PTR) SystemCallHandler72, NULL, FALSE },
1057 { "ZwDuplicateToken", 14, -1, (PULONG_PTR) SystemCallHandler73, NULL, FALSE },
1058 { "ZwEnumerateBootEntries", 20, -1, (PULONG_PTR) SystemCallHandler74, NULL, FALSE },
1059 { "ZwEnumerateDriverEntries", 22, -1, (PULONG_PTR) SystemCallHandler75, NULL, FALSE },
1060 { "ZwEnumerateKey", 12, -1, (PULONG_PTR) SystemCallHandler76, NULL, FALSE },
1061 { "ZwEnumerateSystemEnvironmentValuesEx", 34, -1, (PULONG_PTR) SystemCallHandler77, NULL, FALSE },
1062 { "ZwEnumerateValueKey", 17, -1, (PULONG_PTR) SystemCallHandler78, NULL, FALSE },
1063//XXX
1064
1065
1066 { "ZwExtendSection", 13, -1, (PULONG_PTR) SystemCallHandler79, NULL, FALSE },
1067 { "ZwFilterToken", 11, -1, (PULONG_PTR) SystemCallHandler80, NULL, FALSE },
1068
1069
1070#if HOOK_ATOM
1071 { "ZwFindAtom", 8, -1, (PULONG_PTR) HookedNtFindAtom, NULL, TRUE },
1072#else
1073 { "ZwFindAtom", 8, -1, (PULONG_PTR) SystemCallHandler81, NULL, FALSE },
1074#endif
1075
1076
1077 { "ZwFlushBuffersFile", 16, -1, (PULONG_PTR) SystemCallHandler82, NULL, FALSE },
1078 { "ZwFlushInstructionCache", 21, -1, (PULONG_PTR) SystemCallHandler83, NULL, FALSE },
1079 { "ZwFlushKey", 8, -1, (PULONG_PTR) SystemCallHandler84, NULL, FALSE },
1080 { "ZwFlushVirtualMemory", 18, -1, (PULONG_PTR) SystemCallHandler85, NULL, FALSE },
1081 { "ZwFlushWriteBuffer", 16, -1, (PULONG_PTR) SystemCallHandler86, NULL, FALSE },
1082 { "ZwFreeUserPhysicalPages", 21, -1, (PULONG_PTR) SystemCallHandler87, NULL, FALSE },
1083 { "ZwFreeVirtualMemory", 17, -1, (PULONG_PTR) SystemCallHandler88, NULL, FALSE },
1084 { "ZwFsControlFile", 13, -1, (PULONG_PTR) SystemCallHandler89, NULL, FALSE },
1085 { "ZwGetContextThread", 16, -1, (PULONG_PTR) SystemCallHandler90, NULL, FALSE },
1086 { "ZwGetCurrentProcessorNumber", 25, -1, (PULONG_PTR) SystemCallHandler91, NULL, FALSE },
1087 { "ZwGetDevicePowerState", 19, -1, (PULONG_PTR) SystemCallHandler92, NULL, FALSE },
1088 { "ZwGetPlugPlayEvent", 16, -1, (PULONG_PTR) SystemCallHandler93, NULL, FALSE },
1089 { "ZwGetWriteWatch", 13, -1, (PULONG_PTR) SystemCallHandler94, NULL, FALSE },
1090
1091//XXX
1092 { "ZwImpersonateAnonymousToken", 25, -1, (PULONG_PTR) SystemCallHandler95, NULL, FALSE },
1093 { "ZwImpersonateClientOfPort", 23, -1, (PULONG_PTR) SystemCallHandler96, NULL, FALSE },
1094 { "ZwImpersonateThread", 17, -1, (PULONG_PTR) SystemCallHandler97, NULL, FALSE },
1095
1096 { "ZwInitializeRegistry", 18, -1, (PULONG_PTR) SystemCallHandler98, NULL, FALSE },
1097 { "ZwInitiatePowerAction", 19, -1, (PULONG_PTR) SystemCallHandler99, NULL, FALSE },
1098 { "ZwIsProcessInJob", 14, -1, (PULONG_PTR) SystemCallHandler100, NULL, FALSE },
1099 { "ZwIsSystemResumeAutomatic", 23, -1, (PULONG_PTR) SystemCallHandler101, NULL, FALSE },
1100 { "ZwListenPort", 10, -1, (PULONG_PTR) SystemCallHandler102, NULL, FALSE },
1101
1102
1103#if HOOK_DRIVEROBJ
1104 { "ZwLoadDriver", 10, -1, (PULONG_PTR) HookedNtLoadDriver, NULL, TRUE },
1105#else
1106 { "ZwLoadDriver", 10, -1, (PULONG_PTR) SystemCallHandler103, NULL, FALSE },
1107#endif
1108
1109
1110 { "ZwLoadKey", 7, -1, (PULONG_PTR) SystemCallHandler104, NULL, FALSE },
1111 { "ZwLoadKey2", 8, -1, (PULONG_PTR) SystemCallHandler105, NULL, FALSE },
1112 { "ZwLoadKeyEx", 9, -1, (PULONG_PTR) SystemCallHandler106, NULL, FALSE },
1113 { "ZwLockFile", 8, -1, (PULONG_PTR) SystemCallHandler107, NULL, FALSE },
1114 { "ZwLockProductActivationKeys", 25, -1, (PULONG_PTR) SystemCallHandler108, NULL, FALSE },
1115 { "ZwLockRegistryKey", 15, -1, (PULONG_PTR) SystemCallHandler109, NULL, FALSE },
1116 { "ZwLockVirtualMemory", 17, -1, (PULONG_PTR) SystemCallHandler110, NULL, FALSE },
1117 { "ZwMakePermanentObject", 19, -1, (PULONG_PTR) SystemCallHandler111, NULL, FALSE },
1118 { "ZwMakeTemporaryObject", 19, -1, (PULONG_PTR) SystemCallHandler112, NULL, FALSE },
1119 { "ZwMapUserPhysicalPages", 20, -1, (PULONG_PTR) SystemCallHandler113, NULL, FALSE },
1120 { "ZwMapUserPhysicalPagesScatter", 27, -1, (PULONG_PTR) SystemCallHandler114, NULL, FALSE },
1121
1122
1123#if HOOK_SECTION_ZZZ
1124 { "ZwMapViewOfSection", 16, -1, (PULONG_PTR) HookedNtMapViewOfSection, NULL, TRUE },
1125#else
1126 { "ZwMapViewOfSection", 16, -1, (PULONG_PTR) SystemCallHandler115, NULL, FALSE },
1127#endif
1128
1129
1130 { "ZwModifyBootEntry", 15, -1, (PULONG_PTR) SystemCallHandler116, NULL, FALSE },
1131 { "ZwModifyDriverEntry", 17, -1, (PULONG_PTR) SystemCallHandler117, NULL, FALSE },
1132 { "ZwNotifyChangeDirectoryFile", 25, -1, (PULONG_PTR) SystemCallHandler118, NULL, FALSE },
1133 { "ZwNotifyChangeKey", 15, -1, (PULONG_PTR) SystemCallHandler119, NULL, FALSE },
1134 { "ZwNotifyChangeMultipleKeys", 24, -1, (PULONG_PTR) SystemCallHandler120, NULL, FALSE },
1135
1136
1137#if HOOK_DIROBJ
1138 { "ZwOpenDirectoryObject", 19, -1, (PULONG_PTR) HookedNtOpenDirectoryObject, NULL, TRUE },
1139#else
1140 { "ZwOpenDirectoryObject", 19, -1, (PULONG_PTR) SystemCallHandler121, NULL, FALSE },
1141#endif
1142
1143
1144#if HOOK_EVENT
1145 { "ZwOpenEvent", 9, -1, (PULONG_PTR) HookedNtOpenEvent, NULL, TRUE },
1146 { "ZwOpenEventPair", 13, -1, (PULONG_PTR) HookedNtOpenEventPair, NULL, TRUE },
1147#else
1148 { "ZwOpenEvent", 9, -1, (PULONG_PTR) SystemCallHandler122, NULL, FALSE },
1149 { "ZwOpenEventPair", 13, -1, (PULONG_PTR) SystemCallHandler123, NULL, FALSE },
1150#endif
1151
1152
1153#if HOOK_FILE
1154 { "ZwOpenFile", 8, -1, (PULONG_PTR) HookedNtOpenFile, NULL, TRUE },
1155#else
1156 { "ZwOpenFile", 8, -1, (PULONG_PTR) SystemCallHandler124, NULL, FALSE },
1157#endif
1158
1159 { "ZwOpenIoCompletion", 16, -1, (PULONG_PTR) SystemCallHandler125, NULL, FALSE },
1160
1161
1162#if HOOK_JOB
1163 { "ZwOpenJobObject", 13, -1, (PULONG_PTR) HookedNtOpenJobObject, NULL, TRUE },
1164#else
1165 { "ZwOpenJobObject", 13, -1, (PULONG_PTR) SystemCallHandler126, NULL, FALSE },
1166#endif
1167
1168
1169#if HOOK_REGISTRY
1170 { "ZwOpenKey", 7, -1, (PULONG_PTR) HookedNtOpenKey, NULL, TRUE },
1171#else
1172 { "ZwOpenKey", 7, -1, (PULONG_PTR) SystemCallHandler127, NULL, FALSE },
1173#endif
1174
1175
1176 { "ZwOpenKeyedEvent", 14, -1, (PULONG_PTR) SystemCallHandler128, NULL, FALSE },
1177
1178
1179#if HOOK_MUTANT
1180 { "ZwOpenMutant", 10, -1, (PULONG_PTR) HookedNtOpenMutant, NULL, TRUE },
1181#else
1182 { "ZwOpenMutant", 10, -1, (PULONG_PTR) SystemCallHandler129, NULL, FALSE },
1183#endif
1184
1185
1186 { "ZwOpenObjectAuditAlarm", 20, -1, (PULONG_PTR) SystemCallHandler130, NULL, FALSE },
1187
1188
1189#if HOOK_PROCESS
1190 { "ZwOpenProcess", 11, -1, (PULONG_PTR) HookedNtOpenProcess, NULL, TRUE },
1191#else
1192 { "ZwOpenProcess", 11, -1, (PULONG_PTR) SystemCallHandler131, NULL, FALSE },
1193#endif
1194
1195
1196#if HOOK_TOKEN_ZZZ
1197 { "ZwOpenProcessToken", 16, -1, (PULONG_PTR) HookedNtOpenProcessToken, NULL, TRUE },
1198 { "ZwOpenProcessTokenEx", 18, -1, (PULONG_PTR) HookedNtOpenProcessTokenEx, NULL, TRUE },
1199#else
1200 { "ZwOpenProcessToken", 16, -1, (PULONG_PTR) SystemCallHandler132, NULL, FALSE },
1201 { "ZwOpenProcessTokenEx", 18, -1, (PULONG_PTR) SystemCallHandler133, NULL, FALSE },
1202#endif
1203
1204
1205#if HOOK_SECTION
1206 { "ZwOpenSection", 11, -1, (PULONG_PTR) HookedNtOpenSection, NULL, TRUE },
1207#else
1208 { "ZwOpenSection", 11, -1, (PULONG_PTR) SystemCallHandler134, NULL, FALSE },
1209#endif
1210
1211
1212#if HOOK_SEMAPHORE
1213 { "ZwOpenSemaphore", 13, -1, (PULONG_PTR) HookedNtOpenSemaphore, NULL, TRUE },
1214#else
1215 { "ZwOpenSemaphore", 13, -1, (PULONG_PTR) SystemCallHandler135, NULL, FALSE },
1216#endif
1217
1218
1219#if HOOK_SYMLINK_ZZZ
1220 { "ZwOpenSymbolicLinkObject", 22, -1, (PULONG_PTR) HookedNtOpenSymbolicLinkObject, NULL, TRUE },
1221#else
1222 { "ZwOpenSymbolicLinkObject", 22, -1, (PULONG_PTR) SystemCallHandler136, NULL, FALSE },
1223#endif
1224
1225
1226#if HOOK_PROCESS
1227 { "ZwOpenThread", 10, -1, (PULONG_PTR) HookedNtOpenThread, NULL, TRUE },
1228#else
1229 { "ZwOpenThread", 10, -1, (PULONG_PTR) SystemCallHandler137, NULL, FALSE },
1230#endif
1231
1232
1233#if HOOK_TOKEN_ZZZ
1234 { "ZwOpenThreadToken", 15, -1, (PULONG_PTR) HookedNtOpenThreadToken, NULL, TRUE },
1235 { "ZwOpenThreadTokenEx", 17, -1, (PULONG_PTR) HookedNtOpenThreadTokenEx, NULL, TRUE },
1236#else
1237 { "ZwOpenThreadToken", 15, -1, (PULONG_PTR) SystemCallHandler138, NULL, FALSE },
1238 { "ZwOpenThreadTokenEx", 17, -1, (PULONG_PTR) SystemCallHandler139, NULL, FALSE },
1239#endif
1240
1241
1242#if HOOK_TIMER
1243 { "ZwOpenTimer", 9, -1, (PULONG_PTR) HookedNtOpenTimer, NULL, TRUE },
1244#else
1245 { "ZwOpenTimer", 9, -1, (PULONG_PTR) SystemCallHandler140, NULL, FALSE },
1246#endif
1247
1248
1249 { "ZwPlugPlayControl", 15, -1, (PULONG_PTR) SystemCallHandler141, NULL, FALSE },
1250 { "ZwPowerInformation", 16, -1, (PULONG_PTR) SystemCallHandler142, NULL, FALSE },
1251 { "ZwPrivilegeCheck", 14, -1, (PULONG_PTR) SystemCallHandler143, NULL, FALSE },
1252 { "ZwPrivilegeObjectAuditAlarm", 25, -1, (PULONG_PTR) SystemCallHandler144, NULL, FALSE },
1253 { "ZwPrivilegedServiceAuditAlarm", 27, -1, (PULONG_PTR) SystemCallHandler145, NULL, FALSE },
1254 { "ZwProtectVirtualMemory", 20, -1, (PULONG_PTR) SystemCallHandler146, NULL, FALSE },
1255 { "ZwPulseEvent", 10, -1, (PULONG_PTR) SystemCallHandler147, NULL, FALSE },
1256
1257
1258#if HOOK_FILE
1259 { "ZwQueryAttributesFile", 19, -1, (PULONG_PTR) HookedNtQueryAttributesFile, NULL, TRUE },
1260#else
1261 { "ZwQueryAttributesFile", 19, -1, (PULONG_PTR) SystemCallHandler148, NULL, FALSE },
1262#endif
1263
1264
1265 { "ZwQueryBootEntryOrder", 19, -1, (PULONG_PTR) SystemCallHandler149, NULL, FALSE },
1266 { "ZwQueryBootOptions", 16, -1, (PULONG_PTR) SystemCallHandler150, NULL, FALSE },
1267 { "ZwQueryDebugFilterState", 21, -1, (PULONG_PTR) SystemCallHandler151, NULL, FALSE },
1268 { "ZwQueryDefaultLocale", 18, -1, (PULONG_PTR) SystemCallHandler152, NULL, FALSE },
1269 { "ZwQueryDefaultUILanguage", 22, -1, (PULONG_PTR) SystemCallHandler153, NULL, FALSE },
1270
1271
1272#if FILE_HOOK_ZZZ
1273 { "ZwQueryDirectoryFile", 18, -1, (PULONG_PTR) HookedNtQueryDirectoryFile, NULL, TRUE },
1274#else
1275 { "ZwQueryDirectoryFile", 18, -1, (PULONG_PTR) SystemCallHandler154, NULL, FALSE },
1276#endif
1277
1278
1279 { "ZwQueryDirectoryObject", 20, -1, (PULONG_PTR) SystemCallHandler155, NULL, FALSE },
1280 { "ZwQueryDriverEntryOrder", 21, -1, (PULONG_PTR) SystemCallHandler156, NULL, FALSE },
1281 { "ZwQueryEaFile", 11, -1, (PULONG_PTR) SystemCallHandler157, NULL, FALSE },
1282 { "ZwQueryEvent", 10, -1, (PULONG_PTR) SystemCallHandler158, NULL, FALSE },
1283
1284
1285#if HOOK_FILE
1286 { "ZwQueryFullAttributesFile", 23, -1, (PULONG_PTR) HookedNtQueryFullAttributesFile, NULL, TRUE },
1287#else
1288 { "ZwQueryFullAttributesFile", 23, -1, (PULONG_PTR) SystemCallHandler159, NULL, FALSE },
1289#endif
1290
1291
1292 { "ZwQueryInformationAtom", 20, -1, (PULONG_PTR) SystemCallHandler160, NULL, FALSE },
1293 { "ZwQueryInformationFile", 20, -1, (PULONG_PTR) SystemCallHandler161, NULL, FALSE },
1294 { "ZwQueryInformationJobObject", 25, -1, (PULONG_PTR) SystemCallHandler162, NULL, FALSE },
1295 { "ZwQueryInformationPort", 20, -1, (PULONG_PTR) SystemCallHandler163, NULL, FALSE },
1296 { "ZwQueryInformationProcess", 23, -1, (PULONG_PTR) SystemCallHandler164, NULL, FALSE },
1297 { "ZwQueryInformationThread", 22, -1, (PULONG_PTR) SystemCallHandler165, NULL, FALSE },
1298 { "ZwQueryInformationToken", 21, -1, (PULONG_PTR) SystemCallHandler166, NULL, FALSE },
1299 { "ZwQueryInstallUILanguage", 22, -1, (PULONG_PTR) SystemCallHandler167, NULL, FALSE },
1300 { "ZwQueryIntervalProfile", 20, -1, (PULONG_PTR) SystemCallHandler168, NULL, FALSE },
1301 { "ZwQueryIoCompletion", 17, -1, (PULONG_PTR) SystemCallHandler169, NULL, FALSE },
1302 { "ZwQueryKey", 8, -1, (PULONG_PTR) SystemCallHandler170, NULL, FALSE },
1303 { "ZwQueryMultipleValueKey", 21, -1, (PULONG_PTR) SystemCallHandler171, NULL, FALSE },
1304 { "ZwQueryMutant", 11, -1, (PULONG_PTR) SystemCallHandler172, NULL, FALSE },
1305 { "ZwQueryObject", 11, -1, (PULONG_PTR) SystemCallHandler173, NULL, FALSE },
1306 { "ZwQueryOpenSubKeys", 16, -1, (PULONG_PTR) SystemCallHandler174, NULL, FALSE },
1307 { "ZwQueryOpenSubKeysEx", 18, -1, (PULONG_PTR) SystemCallHandler175, NULL, FALSE },
1308 { "ZwQueryPerformanceCounter", 23, -1, (PULONG_PTR) SystemCallHandler176, NULL, FALSE },
1309 { "ZwQueryPortInformationProcess", 27, -1, (PULONG_PTR) SystemCallHandler177, NULL, FALSE },
1310 { "ZwQueryQuotaInformationFile", 25, -1, (PULONG_PTR) SystemCallHandler178, NULL, FALSE },
1311 { "ZwQuerySection", 12, -1, (PULONG_PTR) SystemCallHandler179, NULL, FALSE },
1312 { "ZwQuerySecurityObject", 19, -1, (PULONG_PTR) SystemCallHandler180, NULL, FALSE },
1313 { "ZwQuerySemaphore", 14, -1, (PULONG_PTR) SystemCallHandler181, NULL, FALSE },
1314 { "ZwQuerySymbolicLinkObject", 23, -1, (PULONG_PTR) SystemCallHandler182, NULL, FALSE },
1315 { "ZwQuerySystemEnvironmentValue", 27, -1, (PULONG_PTR) SystemCallHandler183, NULL, FALSE },
1316 { "ZwQuerySystemEnvironmentValueEx", 29, -1, (PULONG_PTR) SystemCallHandler184, NULL, FALSE },
1317 { "ZwQuerySystemInformation", 22, -1, (PULONG_PTR) SystemCallHandler185, NULL, FALSE },
1318 { "ZwQuerySystemTime", 15, -1, (PULONG_PTR) SystemCallHandler186, NULL, FALSE },
1319 { "ZwQueryTimer", 10, -1, (PULONG_PTR) SystemCallHandler187, NULL, FALSE },
1320 { "ZwQueryTimerResolution", 20, -1, (PULONG_PTR) SystemCallHandler188, NULL, FALSE },
1321
1322
1323#if HOOK_REGISTRY_ZZZ
1324 { "ZwQueryValueKey", 13, -1, (PULONG_PTR) HookedNtQueryValueKey, NULL, TRUE },
1325#else
1326 { "ZwQueryValueKey", 13, -1, (PULONG_PTR) SystemCallHandler189, NULL, FALSE },
1327#endif
1328
1329
1330 { "ZwQueryVirtualMemory", 18, -1, (PULONG_PTR) SystemCallHandler190, NULL, FALSE },
1331 { "ZwQueryVolumeInformationFile", 26, -1, (PULONG_PTR) SystemCallHandler191, NULL, FALSE },
1332 { "ZwQueueApcThread", 14, -1, (PULONG_PTR) SystemCallHandler192, NULL, FALSE },
1333
1334
1335//XXX should we not mediate these calls? they are only raised during an error and we might
1336// not encounter them during "learning" phase? can these be abused otherwise?
1337 { "ZwRaiseException", 14, -1, (PULONG_PTR) SystemCallHandler193, NULL, FALSE },
1338 { "ZwRaiseHardError", 14, -1, (PULONG_PTR) SystemCallHandler194, NULL, FALSE },
1339
1340 /* don't mediate for performance reasons, requires a valid handle anyway */
1341 { "ZwReadFile", 8, -1, NULL, NULL, FALSE },
1342 { "ZwReadFileScatter", 15, -1, NULL, NULL, FALSE },
1343 { "ZwReadRequestData", 15, -1, NULL, NULL, FALSE },
1344 { "ZwReadVirtualMemory", 17, -1, NULL, NULL, FALSE },
1345
1346 { "ZwRegisterThreadTerminatePort", 27, -1, (PULONG_PTR) SystemCallHandler199, NULL, FALSE },
1347 { "ZwReleaseKeyedEvent", 17, -1, (PULONG_PTR) SystemCallHandler200, NULL, FALSE },
1348 { "ZwReleaseMutant", 13, -1, (PULONG_PTR) SystemCallHandler201, NULL, FALSE },
1349 { "ZwReleaseSemaphore", 16, -1, (PULONG_PTR) SystemCallHandler202, NULL, FALSE },
1350 { "ZwRemoveIoCompletion", 18, -1, (PULONG_PTR) SystemCallHandler203, NULL, FALSE },
1351 { "ZwRemoveProcessDebug", 18, -1, (PULONG_PTR) SystemCallHandler204, NULL, FALSE },
1352
1353//XXX
1354 { "ZwRenameKey", 9, -1, (PULONG_PTR) SystemCallHandler205, NULL, FALSE },
1355 { "ZwReplaceKey", 10, -1, (PULONG_PTR) SystemCallHandler206, NULL, FALSE },
1356
1357
1358 { "ZwReplyPort", 9, -1, (PULONG_PTR) SystemCallHandler207, NULL, FALSE },
1359 { "ZwReplyWaitReceivePort", 20, -1, (PULONG_PTR) SystemCallHandler208, NULL, FALSE },
1360 { "ZwReplyWaitReceivePortEx", 22, -1, (PULONG_PTR) SystemCallHandler209, NULL, FALSE },
1361 { "ZwReplyWaitReplyPort", 18, -1, (PULONG_PTR) SystemCallHandler210, NULL, FALSE },
1362 { "ZwRequestDeviceWakeup", 19, -1, (PULONG_PTR) SystemCallHandler211, NULL, FALSE },
1363 { "ZwRequestPort", 11, -1, (PULONG_PTR) SystemCallHandler212, NULL, FALSE },
1364 { "ZwRequestWaitReplyPort", 20, -1, (PULONG_PTR) SystemCallHandler213, NULL, FALSE },
1365 { "ZwRequestWakeupLatency", 20, -1, (PULONG_PTR) SystemCallHandler214, NULL, FALSE },
1366 { "ZwResetEvent", 10, -1, (PULONG_PTR) SystemCallHandler215, NULL, FALSE },
1367 { "ZwResetWriteWatch", 15, -1, (PULONG_PTR) SystemCallHandler216, NULL, FALSE },
1368 { "ZwRestoreKey", 10, -1, (PULONG_PTR) SystemCallHandler217, NULL, FALSE },
1369 { "ZwResumeProcess", 13, -1, (PULONG_PTR) SystemCallHandler218, NULL, FALSE },
1370 { "ZwResumeThread", 12, -1, (PULONG_PTR) SystemCallHandler219, NULL, FALSE },
1371 { "ZwSaveKey", 7, -1, (PULONG_PTR) SystemCallHandler220, NULL, FALSE },
1372 { "ZwSaveKeyEx", 9, -1, (PULONG_PTR) SystemCallHandler221, NULL, FALSE },
1373 { "ZwSaveMergedKeys", 14, -1, (PULONG_PTR) SystemCallHandler222, NULL, FALSE },
1374
1375
1376#if HOOK_PORT
1377 { "ZwSecureConnectPort", 17, -1, (PULONG_PTR) HookedNtSecureConnectPort, NULL, TRUE },
1378#else
1379 { "ZwSecureConnectPort", 17, -1, (PULONG_PTR) SystemCallHandler223, NULL, FALSE },
1380#endif
1381
1382
1383 { "ZwSetBootEntryOrder", 17, -1, (PULONG_PTR) SystemCallHandler224, NULL, FALSE },
1384 { "ZwSetBootOptions", 14, -1, (PULONG_PTR) SystemCallHandler225, NULL, FALSE },
1385
1386//XXX
1387 { "ZwSetContextThread", 16, -1, (PULONG_PTR) SystemCallHandler226, NULL, FALSE },
1388
1389 { "ZwSetDebugFilterState", 19, -1, (PULONG_PTR) SystemCallHandler227, NULL, FALSE },
1390 { "ZwSetDefaultHardErrorPort", 23, -1, (PULONG_PTR) SystemCallHandler228, NULL, FALSE },
1391 { "ZwSetDefaultLocale", 16, -1, (PULONG_PTR) SystemCallHandler229, NULL, FALSE },
1392 { "ZwSetDefaultUILanguage", 20, -1, (PULONG_PTR) SystemCallHandler230, NULL, FALSE },
1393 { "ZwSetDriverEntryOrder", 19, -1, (PULONG_PTR) SystemCallHandler231, NULL, FALSE },
1394 { "ZwSetEaFile", 9, -1, (PULONG_PTR) SystemCallHandler232, NULL, FALSE },
1395 { "ZwSetEvent", 8, -1, (PULONG_PTR) SystemCallHandler233, NULL, FALSE },
1396 { "ZwSetEventBoostPriority", 21, -1, (PULONG_PTR) SystemCallHandler234, NULL, FALSE },
1397 { "ZwSetHighEventPair", 16, -1, (PULONG_PTR) SystemCallHandler235, NULL, FALSE },
1398 { "ZwSetHighWaitLowEventPair", 23, -1, (PULONG_PTR) SystemCallHandler236, NULL, FALSE },
1399 { "ZwSetInformationDebugObject", 25, -1, (PULONG_PTR) SystemCallHandler237, NULL, FALSE },
1400
1401#if HOOK_FILE
1402 { "ZwSetInformationFile", 18, -1, (PULONG_PTR) HookedNtSetInformationFile, NULL, TRUE },
1403#else
1404 { "ZwSetInformationFile", 18, -1, (PULONG_PTR) SystemCallHandler238, NULL, FALSE },
1405#endif
1406
1407 { "ZwSetInformationJobObject", 23, -1, (PULONG_PTR) SystemCallHandler239, NULL, FALSE },
1408 { "ZwSetInformationKey", 17, -1, (PULONG_PTR) SystemCallHandler240, NULL, FALSE },
1409 { "ZwSetInformationObject", 20, -1, (PULONG_PTR) SystemCallHandler241, NULL, FALSE },
1410 { "ZwSetInformationProcess", 21, -1, (PULONG_PTR) SystemCallHandler242, NULL, FALSE },
1411 { "ZwSetInformationThread", 20, -1, (PULONG_PTR) SystemCallHandler243, NULL, FALSE },
1412
1413
1414#if HOOK_TOKEN
1415 { "ZwSetInformationToken", 19, -1, (PULONG_PTR) HookedNtSetInformationToken, NULL, TRUE },
1416#else
1417 { "ZwSetInformationToken", 19, -1, (PULONG_PTR) SystemCallHandler244, NULL, FALSE },
1418#endif
1419
1420
1421 { "ZwSetIntervalProfile", 18, -1, (PULONG_PTR) SystemCallHandler245, NULL, FALSE },
1422 { "ZwSetIoCompletion", 15, -1, (PULONG_PTR) SystemCallHandler246, NULL, FALSE },
1423
1424
1425#if HOOK_VDM
1426 { "ZwSetLdtEntries", 13, -1, (PULONG_PTR) HookedNtSetLdtEntries, NULL, TRUE },
1427#else
1428 { "ZwSetLdtEntries", 13, -1, (PULONG_PTR) SystemCallHandler247, NULL, FALSE },
1429#endif
1430
1431
1432 { "ZwSetLowEventPair", 15, -1, (PULONG_PTR) SystemCallHandler248, NULL, FALSE },
1433 { "ZwSetLowWaitHighEventPair", 23, -1, (PULONG_PTR) SystemCallHandler249, NULL, FALSE },
1434 { "ZwSetQuotaInformationFile", 23, -1, (PULONG_PTR) SystemCallHandler250, NULL, FALSE },
1435 { "ZwSetSecurityObject", 17, -1, (PULONG_PTR) SystemCallHandler251, NULL, FALSE },
1436 { "ZwSetSystemEnvironmentValue", 25, -1, (PULONG_PTR) SystemCallHandler252, NULL, FALSE }, // XXX intel hal supports only 1 variable LastKnownGood
1437 { "ZwSetSystemEnvironmentValueEx", 27, -1, (PULONG_PTR) SystemCallHandler253, NULL, FALSE },
1438
1439
1440#if HOOK_SYSINFO
1441 { "ZwSetSystemInformation", 20, -1, (PULONG_PTR) HookedNtSetSystemInformation, NULL, TRUE },
1442#else
1443 { "ZwSetSystemInformation", 20, -1, (PULONG_PTR) SystemCallHandler254, NULL, FALSE },
1444#endif
1445
1446
1447 { "ZwSetSystemPowerState", 19, -1, (PULONG_PTR) SystemCallHandler255, NULL, FALSE },
1448
1449
1450#if HOOK_TIME
1451 { "ZwSetSystemTime", 13, -1, (PULONG_PTR) HookedNtSetSystemTime, NULL, TRUE },
1452#else
1453 { "ZwSetSystemTime", 13, -1, (PULONG_PTR) SystemCallHandler256, NULL, FALSE },
1454#endif
1455
1456
1457 { "ZwSetThreadExecutionState", 23, -1, (PULONG_PTR) SystemCallHandler257, NULL, FALSE },
1458 { "ZwSetTimer", 8, -1, (PULONG_PTR) SystemCallHandler258, NULL, FALSE },
1459
1460
1461#if 0 //HOOK_TIME
1462 { "ZwSetTimerResolution", 18, -1, (PULONG_PTR) HookedNtSetTimerResolution, NULL, TRUE },
1463#else
1464 { "ZwSetTimerResolution", 18, -1, (PULONG_PTR) SystemCallHandler259, NULL, FALSE },
1465#endif
1466
1467
1468 { "ZwSetUuidSeed", 11, -1, (PULONG_PTR) SystemCallHandler260, NULL, FALSE },
1469
1470
1471#if HOOK_REGISTRY_ZZZ
1472 { "ZwSetValueKey", 11, -1, (PULONG_PTR) HookedNtSetValueKey, NULL, TRUE },
1473#else
1474 { "ZwSetValueKey", 11, -1, (PULONG_PTR) SystemCallHandler261, NULL, FALSE },
1475#endif
1476
1477
1478 { "ZwSetVolumeInformationFile", 24, -1, (PULONG_PTR) SystemCallHandler262, NULL, FALSE },
1479
1480//XXX
1481 { "ZwShutdownSystem", 14, -1, (PULONG_PTR) SystemCallHandler263, NULL, FALSE },
1482
1483 { "ZwSignalAndWaitForSingleObject", 28, -1, (PULONG_PTR) SystemCallHandler264, NULL, FALSE },
1484 { "ZwStartProfile", 12, -1, (PULONG_PTR) SystemCallHandler265, NULL, FALSE },
1485 { "ZwStopProfile", 11, -1, (PULONG_PTR) SystemCallHandler266, NULL, FALSE },
1486 { "ZwSuspendProcess", 14, -1, (PULONG_PTR) SystemCallHandler267, NULL, FALSE },
1487 { "ZwSuspendThread", 13, -1, (PULONG_PTR) SystemCallHandler268, NULL, FALSE },
1488 { "ZwSystemDebugControl", 18, -1, (PULONG_PTR) SystemCallHandler269, NULL, FALSE },
1489
1490//XXX
1491 { "ZwTerminateJobObject", 18, -1, (PULONG_PTR) SystemCallHandler270, NULL, FALSE },
1492 { "ZwTerminateProcess", 16, -1, (PULONG_PTR) SystemCallHandler271, NULL, FALSE },
1493 { "ZwTerminateThread", 15, -1, (PULONG_PTR) SystemCallHandler272, NULL, FALSE },
1494
1495 { "ZwTestAlert", 9, -1, (PULONG_PTR) SystemCallHandler273, NULL, FALSE },
1496 { "ZwTraceEvent", 10, -1, (PULONG_PTR) SystemCallHandler274, NULL, FALSE },
1497 { "ZwTranslateFilePath", 17, -1, (PULONG_PTR) SystemCallHandler275, NULL, FALSE },
1498
1499
1500#if HOOK_DRIVEROBJ_ZZZ
1501 { "ZwUnloadDriver", 12, -1, (PULONG_PTR) HookedNtUnloadDriver, NULL, TRUE },
1502#else
1503 { "ZwUnloadDriver", 12, -1, (PULONG_PTR) SystemCallHandler276, NULL, FALSE },
1504#endif
1505
1506
1507 { "ZwUnloadKey", 9, -1, (PULONG_PTR) SystemCallHandler277, NULL, FALSE },
1508 { "ZwUnloadKey2", 10, -1, (PULONG_PTR) SystemCallHandler278, NULL, FALSE },
1509 { "ZwUnloadKeyEx", 11, -1, (PULONG_PTR) SystemCallHandler279, NULL, FALSE },
1510 { "ZwUnlockFile", 10, -1, (PULONG_PTR) SystemCallHandler280, NULL, FALSE },
1511 { "ZwUnlockVirtualMemory", 19, -1, (PULONG_PTR) SystemCallHandler281, NULL, FALSE },
1512 { "ZwUnmapViewOfSection", 18, -1, (PULONG_PTR) SystemCallHandler282, NULL, FALSE },
1513
1514
1515#if HOOK_VDM
1516 { "ZwVdmControl", 10, -1, (PULONG_PTR) HookedNtVdmControl, NULL, TRUE },
1517#else
1518 { "ZwVdmControl", 10, -1, (PULONG_PTR) SystemCallHandler283, NULL, FALSE },
1519#endif
1520
1521
1522 { "ZwWaitForDebugEvent", 17, -1, (PULONG_PTR) SystemCallHandler284, NULL, FALSE },
1523 { "ZwWaitForKeyedEvent", 17, -1, (PULONG_PTR) SystemCallHandler285, NULL, FALSE },
1524 { "ZwWaitForMultipleObjects", 22, -1, (PULONG_PTR) SystemCallHandler286, NULL, FALSE },
1525 { "ZwWaitForSingleObject", 19, -1, (PULONG_PTR) SystemCallHandler287, NULL, FALSE },
1526 { "ZwWaitHighEventPair", 17, -1, (PULONG_PTR) SystemCallHandler288, NULL, FALSE },
1527 { "ZwWaitLowEventPair", 16, -1, (PULONG_PTR) SystemCallHandler289, NULL, FALSE },
1528
1529 /* don't mediate for performance reasons, requires a valid handle anyway */
1530 { "ZwWriteFile", 9, -1, NULL, NULL, FALSE },
1531 { "ZwWriteFileGather", 15, -1, NULL, NULL, FALSE },
1532 { "ZwWriteRequestData", 16, -1, NULL, NULL, FALSE },
1533 { "ZwWriteVirtualMemory", 18, -1, NULL, NULL, FALSE },
1534 { "ZwYieldExecution", 14, -1, NULL, NULL, FALSE },
1535};
1536
1537
1538
1539ACTION_TYPE
1540VerifySystemServiceCall(USHORT SystemServiceNumber)
1541{
1542 ACTION_TYPE Action = ACTION_NONE;
1543 PIMAGE_PID_ENTRY p;
1544 PPOLICY_RULE PolicyRule;
1545
1546
1547// LOG(LOG_SS_HOOKPROC, LOG_PRIORITY_DEBUG, ("system call %x %x %s. irql %d", ZwCalls[SystemServiceNumber].OriginalFunction, ZwCalls[SystemServiceNumber].ServiceIDNumber, ZwCalls[SystemServiceNumber].ZwName, KeGetCurrentIrql()));
1548
1549
1550 if (KeGetCurrentIrql() != PASSIVE_LEVEL)
1551 return ACTION_NONE;
1552
1553
1554 if (LearningMode)
1555 {
1556 AddRule(RULE_SYSCALL, ZwCalls[SystemServiceNumber].ZwName, 0);
1557 return ACTION_NONE;
1558 }
1559
1560
1561 /* verify policy and user return address? */
1562
1563 p = FindImagePidEntry(CURRENT_PROCESS_PID, 0);
1564
1565 if (p == NULL)
1566 {
1567 LOG(LOG_SS_PROCESS, LOG_PRIORITY_VERBOSE, ("VerifySystemServiceCall: FindImagePidEntry(%d) failed\n", CURRENT_PROCESS_PID));
1568 return ACTION_NONE;
1569 }
1570//XXX p->SecPolicy spinlock is not acquired
1571 PolicyRule = p->SecPolicy.RuleList[ RULE_SYSCALL ];
1572 if (PolicyRule)
1573 {
1574 /* Calculate the bit array ULONG we need to read (bit array consists of a bunch of ULONGs) */
1575 ULONG UlongCount = SystemServiceNumber >> UlongBitShift;
1576
1577 /* Choose the correct bit array ULONG */
1578 PULONG BitArray = &PolicyRule->ServiceBitArray[0] + UlongCount;
1579
1580 ULONG BitOffset = SystemServiceNumber - (UlongCount << UlongBitShift);
1581
1582 /* read the bit */
1583 Action = *BitArray & ( 1 << BitOffset ) ? ACTION_PERMIT : ACTION_DENY;
1584
1585 if (Action == ACTION_DENY)
1586 {
1587 LOG(LOG_SS_HOOKPROC, LOG_PRIORITY_DEBUG, ("denying system call %x %x %s\n", ZwCalls[SystemServiceNumber].OriginalFunction, ZwCalls[SystemServiceNumber].ServiceIDNumber, ZwCalls[SystemServiceNumber].ZwName));
1588 Action = ACTION_PERMIT;
1589 }
1590 }
1591
1592 return Action;
1593}
1594
1595
1596//XXX can we get rid of pushfd / popfd ?
1597//XXX move to i386.c?
1598#define SYSCALL_HANDLER(num) \
1599 __declspec(naked) void SystemCallHandler##num() \
1600 { \
1601 _asm pushad \
1602 _asm { pushfd } \
1603 if (0 && VerifySystemServiceCall(num) == ACTION_DENY)\
1604 { \
1605 _asm popfd \
1606 _asm popad \
1607 _asm mov eax, 0xC0000022 /*STATUS_ACCESS_DENIED*/ \
1608 _asm ret \
1609 } \
1610 _asm popfd \
1611 _asm popad \
1612 _asm jmp dword ptr [ ZwCalls + num*20 + 12 ] \
1613/* _asm jmp ZwCalls[num].OriginalFunction */\
1614 }
1615
1616/*
1617//XXX can find out dynamically the amount of stack space to clean up by looking at Zw* ret instruction
1618 if (PolicyCheck(RULE_SYSCALL, NULL, 0) == ACTION_DENY) \
1619 { \
1620 _asm mov eax, 0xC0000022 \
1621 _asm ret \
1622 } \
1623*/
1624
1625
1626SYSCALL_HANDLER(0) SYSCALL_HANDLER(1) SYSCALL_HANDLER(2) SYSCALL_HANDLER(3) SYSCALL_HANDLER(4)
1627SYSCALL_HANDLER(5) SYSCALL_HANDLER(6) SYSCALL_HANDLER(7) SYSCALL_HANDLER(8) SYSCALL_HANDLER(9)
1628SYSCALL_HANDLER(10) SYSCALL_HANDLER(11) SYSCALL_HANDLER(12) SYSCALL_HANDLER(13) SYSCALL_HANDLER(14)
1629SYSCALL_HANDLER(15) SYSCALL_HANDLER(16) SYSCALL_HANDLER(17) SYSCALL_HANDLER(18) SYSCALL_HANDLER(19)
1630SYSCALL_HANDLER(20) SYSCALL_HANDLER(21) SYSCALL_HANDLER(22) SYSCALL_HANDLER(23) SYSCALL_HANDLER(24)
1631SYSCALL_HANDLER(25) SYSCALL_HANDLER(26) SYSCALL_HANDLER(27) SYSCALL_HANDLER(28) SYSCALL_HANDLER(29)
1632SYSCALL_HANDLER(30) SYSCALL_HANDLER(31) SYSCALL_HANDLER(32) SYSCALL_HANDLER(33) SYSCALL_HANDLER(34)
1633SYSCALL_HANDLER(35) SYSCALL_HANDLER(36) SYSCALL_HANDLER(37) SYSCALL_HANDLER(38) SYSCALL_HANDLER(39)
1634SYSCALL_HANDLER(40) SYSCALL_HANDLER(41) SYSCALL_HANDLER(42) SYSCALL_HANDLER(43) SYSCALL_HANDLER(44)
1635SYSCALL_HANDLER(45) SYSCALL_HANDLER(46) SYSCALL_HANDLER(47) SYSCALL_HANDLER(48) SYSCALL_HANDLER(49)
1636SYSCALL_HANDLER(50) SYSCALL_HANDLER(51) SYSCALL_HANDLER(52) SYSCALL_HANDLER(53) SYSCALL_HANDLER(54)
1637SYSCALL_HANDLER(55) SYSCALL_HANDLER(56) SYSCALL_HANDLER(57) SYSCALL_HANDLER(58) SYSCALL_HANDLER(59)
1638SYSCALL_HANDLER(60) SYSCALL_HANDLER(61) SYSCALL_HANDLER(62) SYSCALL_HANDLER(63) SYSCALL_HANDLER(64)
1639SYSCALL_HANDLER(65) SYSCALL_HANDLER(66) SYSCALL_HANDLER(67) SYSCALL_HANDLER(68) SYSCALL_HANDLER(69)
1640SYSCALL_HANDLER(70) SYSCALL_HANDLER(71) SYSCALL_HANDLER(72) SYSCALL_HANDLER(73) SYSCALL_HANDLER(74)
1641SYSCALL_HANDLER(75) SYSCALL_HANDLER(76) SYSCALL_HANDLER(77) SYSCALL_HANDLER(78) SYSCALL_HANDLER(79)
1642SYSCALL_HANDLER(80) SYSCALL_HANDLER(81) SYSCALL_HANDLER(82) SYSCALL_HANDLER(83) SYSCALL_HANDLER(84)
1643SYSCALL_HANDLER(85) SYSCALL_HANDLER(86) SYSCALL_HANDLER(87) SYSCALL_HANDLER(88) SYSCALL_HANDLER(89)
1644SYSCALL_HANDLER(90) SYSCALL_HANDLER(91) SYSCALL_HANDLER(92) SYSCALL_HANDLER(93) SYSCALL_HANDLER(94)
1645SYSCALL_HANDLER(95) SYSCALL_HANDLER(96) SYSCALL_HANDLER(97) SYSCALL_HANDLER(98) SYSCALL_HANDLER(99)
1646SYSCALL_HANDLER(100) SYSCALL_HANDLER(101) SYSCALL_HANDLER(102) SYSCALL_HANDLER(103) SYSCALL_HANDLER(104)
1647SYSCALL_HANDLER(105) SYSCALL_HANDLER(106) SYSCALL_HANDLER(107) SYSCALL_HANDLER(108) SYSCALL_HANDLER(109)
1648SYSCALL_HANDLER(110) SYSCALL_HANDLER(111) SYSCALL_HANDLER(112) SYSCALL_HANDLER(113) SYSCALL_HANDLER(114)
1649SYSCALL_HANDLER(115) SYSCALL_HANDLER(116) SYSCALL_HANDLER(117) SYSCALL_HANDLER(118) SYSCALL_HANDLER(119)
1650SYSCALL_HANDLER(120) SYSCALL_HANDLER(121) SYSCALL_HANDLER(122) SYSCALL_HANDLER(123) SYSCALL_HANDLER(124)
1651SYSCALL_HANDLER(125) SYSCALL_HANDLER(126) SYSCALL_HANDLER(127) SYSCALL_HANDLER(128) SYSCALL_HANDLER(129)
1652SYSCALL_HANDLER(130) SYSCALL_HANDLER(131) SYSCALL_HANDLER(132) SYSCALL_HANDLER(133) SYSCALL_HANDLER(134)
1653SYSCALL_HANDLER(135) SYSCALL_HANDLER(136) SYSCALL_HANDLER(137) SYSCALL_HANDLER(138) SYSCALL_HANDLER(139)
1654SYSCALL_HANDLER(140) SYSCALL_HANDLER(141) SYSCALL_HANDLER(142) SYSCALL_HANDLER(143) SYSCALL_HANDLER(144)
1655SYSCALL_HANDLER(145) SYSCALL_HANDLER(146) SYSCALL_HANDLER(147) SYSCALL_HANDLER(148) SYSCALL_HANDLER(149)
1656SYSCALL_HANDLER(150) SYSCALL_HANDLER(151) SYSCALL_HANDLER(152) SYSCALL_HANDLER(153) SYSCALL_HANDLER(154)
1657SYSCALL_HANDLER(155) SYSCALL_HANDLER(156) SYSCALL_HANDLER(157) SYSCALL_HANDLER(158) SYSCALL_HANDLER(159)
1658SYSCALL_HANDLER(160) SYSCALL_HANDLER(161) SYSCALL_HANDLER(162) SYSCALL_HANDLER(163) SYSCALL_HANDLER(164)
1659SYSCALL_HANDLER(165) SYSCALL_HANDLER(166) SYSCALL_HANDLER(167) SYSCALL_HANDLER(168) SYSCALL_HANDLER(169)
1660SYSCALL_HANDLER(170) SYSCALL_HANDLER(171) SYSCALL_HANDLER(172) SYSCALL_HANDLER(173) SYSCALL_HANDLER(174)
1661SYSCALL_HANDLER(175) SYSCALL_HANDLER(176) SYSCALL_HANDLER(177) SYSCALL_HANDLER(178) SYSCALL_HANDLER(179)
1662SYSCALL_HANDLER(180) SYSCALL_HANDLER(181) SYSCALL_HANDLER(182) SYSCALL_HANDLER(183) SYSCALL_HANDLER(184)
1663SYSCALL_HANDLER(185) SYSCALL_HANDLER(186) SYSCALL_HANDLER(187) SYSCALL_HANDLER(188) SYSCALL_HANDLER(189)
1664SYSCALL_HANDLER(190) SYSCALL_HANDLER(191) SYSCALL_HANDLER(192) SYSCALL_HANDLER(193) SYSCALL_HANDLER(194)
1665SYSCALL_HANDLER(195) SYSCALL_HANDLER(196) SYSCALL_HANDLER(197) SYSCALL_HANDLER(198) SYSCALL_HANDLER(199)
1666SYSCALL_HANDLER(200) SYSCALL_HANDLER(201) SYSCALL_HANDLER(202) SYSCALL_HANDLER(203) SYSCALL_HANDLER(204)
1667SYSCALL_HANDLER(205) SYSCALL_HANDLER(206) SYSCALL_HANDLER(207) SYSCALL_HANDLER(208) SYSCALL_HANDLER(209)
1668SYSCALL_HANDLER(210) SYSCALL_HANDLER(211) SYSCALL_HANDLER(212) SYSCALL_HANDLER(213) SYSCALL_HANDLER(214)
1669SYSCALL_HANDLER(215) SYSCALL_HANDLER(216) SYSCALL_HANDLER(217) SYSCALL_HANDLER(218) SYSCALL_HANDLER(219)
1670SYSCALL_HANDLER(220) SYSCALL_HANDLER(221) SYSCALL_HANDLER(222) SYSCALL_HANDLER(223) SYSCALL_HANDLER(224)
1671SYSCALL_HANDLER(225) SYSCALL_HANDLER(226) SYSCALL_HANDLER(227) SYSCALL_HANDLER(228) SYSCALL_HANDLER(229)
1672SYSCALL_HANDLER(230) SYSCALL_HANDLER(231) SYSCALL_HANDLER(232) SYSCALL_HANDLER(233) SYSCALL_HANDLER(234)
1673SYSCALL_HANDLER(235) SYSCALL_HANDLER(236) SYSCALL_HANDLER(237) SYSCALL_HANDLER(238) SYSCALL_HANDLER(239)
1674SYSCALL_HANDLER(240) SYSCALL_HANDLER(241) SYSCALL_HANDLER(242) SYSCALL_HANDLER(243) SYSCALL_HANDLER(244)
1675SYSCALL_HANDLER(245) SYSCALL_HANDLER(246) SYSCALL_HANDLER(247) SYSCALL_HANDLER(248) SYSCALL_HANDLER(249)
1676SYSCALL_HANDLER(250) SYSCALL_HANDLER(251) SYSCALL_HANDLER(252) SYSCALL_HANDLER(253) SYSCALL_HANDLER(254)
1677SYSCALL_HANDLER(255) SYSCALL_HANDLER(256) SYSCALL_HANDLER(257) SYSCALL_HANDLER(258) SYSCALL_HANDLER(259)
1678SYSCALL_HANDLER(260) SYSCALL_HANDLER(261) SYSCALL_HANDLER(262) SYSCALL_HANDLER(263) SYSCALL_HANDLER(264)
1679SYSCALL_HANDLER(265) SYSCALL_HANDLER(266) SYSCALL_HANDLER(267) SYSCALL_HANDLER(268) SYSCALL_HANDLER(269)
1680SYSCALL_HANDLER(270) SYSCALL_HANDLER(271) SYSCALL_HANDLER(272) SYSCALL_HANDLER(273) SYSCALL_HANDLER(274)
1681SYSCALL_HANDLER(275) SYSCALL_HANDLER(276) SYSCALL_HANDLER(277) SYSCALL_HANDLER(278) SYSCALL_HANDLER(279)
1682SYSCALL_HANDLER(280) SYSCALL_HANDLER(281) SYSCALL_HANDLER(282) SYSCALL_HANDLER(283) SYSCALL_HANDLER(284)
1683SYSCALL_HANDLER(285) SYSCALL_HANDLER(286) SYSCALL_HANDLER(287) SYSCALL_HANDLER(288) SYSCALL_HANDLER(289)
1684SYSCALL_HANDLER(290) SYSCALL_HANDLER(291) SYSCALL_HANDLER(292) SYSCALL_HANDLER(293) SYSCALL_HANDLER(294)
1685
1686
1687
1688/*
1689 * InitSyscallsHooks()
1690 *
1691 * Description:
1692 * Find the correct global syscall table indeces for all system calls
1693 * (initialize "OriginalFunction" pointers). Must be called at PASSIVE_LEVEL IRQL
1694 * in order to access pageable memory.
1695 *
1696 * NOTE: Called once during driver initialization (DriverEntry()).
1697 *
1698 * Parameters:
1699 * None.
1700 *
1701 * Returns:
1702 * TRUE to indicate success, FALSE if failed.
1703 */
1704
1705BOOLEAN
1706InitSyscallsHooks()
1707{
1708 int i;
1709
1710
1711 ZwCallsNumber = sizeof(ZwCalls) / sizeof(ZwCalls[0]);
1712
1713 for (i = 0; i < ZwCallsNumber; i++)
1714 {
1715 //XXX this can be optimized to return index directly?! this way when we restore syscalls back we don't have to do the same process again??!?!
1716 ZwCalls[i].ServiceIDNumber = (USHORT) FindZwFunctionIndex(ZwCalls[i].ZwName);
1717 }
1718
1719
1720 return TRUE;
1721}
1722
1723
1724
1725/*
1726 * InstallSyscallsHooks()
1727 *
1728 * Description:
1729 * Mediate various system services. Called at DISPATCH_LEVEL IRQL.
1730 *
1731 * NOTE: Called once during driver initialization (DriverEntry()).
1732 *
1733 * Parameters:
1734 * None.
1735 *
1736 * Returns:
1737 * TRUE to indicate success, FALSE if failed.
1738 */
1739
1740BOOLEAN
1741InstallSyscallsHooks()
1742{
1743 int i;
1744
1745
1746 ZwCallsNumber = sizeof(ZwCalls) / sizeof(ZwCalls[0]);
1747
1748 for (i = 0; i < ZwCallsNumber; i++)
1749 {
1750 if (ZwCalls[i].HookFunction != NULL &&
1751 (HOOK_SYSCALLS || LearningMode || ZwCalls[i].Hijacked == TRUE))
1752 {
1753 if (ZwCalls[i].ServiceIDNumber != (USHORT) -1)
1754 {
1755 ZwCalls[i].OriginalFunction = HookSystemServiceByIndex(ZwCalls[i].ServiceIDNumber,
1756 ZwCalls[i].HookFunction);
1757 ZwCalls[i].Hijacked = TRUE;
1758 }
1759 }
1760 }
1761
1762
1763 return TRUE;
1764}
1765
1766
1767
1768/*
1769 * RemoveSyscallsHooks()
1770 *
1771 * Description:
1772 * Restores all the original system service function pointers.
1773 *
1774 * NOTE: Called once during driver unload (DriverUnload()).
1775 *
1776 * Parameters:
1777 * None.
1778 *
1779 * Returns:
1780 * Nothing.
1781 */
1782
1783void
1784RemoveSyscallsHooks()
1785{
1786 int i;
1787
1788
1789 for (i = 0; i < ZwCallsNumber; i++)
1790 {
1791 // restore hijacked system calls
1792 if (ZwCalls[i].Hijacked == TRUE && ZwCalls[i].OriginalFunction != NULL && ZwCalls[i].ServiceIDNumber != -1)
1793 {
1794// LOG(LOG_SS_HOOKPROC, LOG_PRIORITY_DEBUG, ("Restoring syscall %d %x\n", i, i));
1795
1796 HookSystemServiceByIndex(ZwCalls[i].ServiceIDNumber, ZwCalls[i].OriginalFunction);
1797 }
1798 }
1799}
diff --git a/hookproc.h b/hookproc.h
new file mode 100644
index 0000000..7756d23
--- /dev/null
+++ b/hookproc.h
@@ -0,0 +1,460 @@
1/*
2 * Copyright (c) 2004 Security Architects Corporation. All rights reserved.
3 *
4 * Module Name:
5 *
6 * hookproc.h
7 *
8 * Abstract:
9 *
10 * This module definies various types used by service operation (system call) hooking routines.
11 *
12 * Author:
13 *
14 * Eugene Tsyrklevich 16-Feb-2004
15 *
16 * Revision History:
17 *
18 * None.
19 */
20
21
22#ifndef __HOOKPROC_H__
23#define __HOOKPROC_H__
24
25
26#include "userland.h"
27
28
29/* should the following calls be intercepted? */
30
31#define HOOK_EVENT 1
32#define HOOK_FILE 1
33#define HOOK_DIROBJ 1
34#define HOOK_JOB 1
35#define HOOK_NETWORK 1
36#define HOOK_MUTANT 1
37#define HOOK_PORT 1
38#define HOOK_PROCESS 1
39#define HOOK_REGISTRY 1
40#define HOOK_SECTION 1
41#define HOOK_SEMAPHORE 1
42#define HOOK_SYMLINK 1
43#define HOOK_SYSINFO 1
44#define HOOK_TIME 1
45#define HOOK_TIMER 1
46#define HOOK_TOKEN 1
47#define HOOK_DRIVEROBJ 1
48#define HOOK_ATOM 1
49#define HOOK_VDM 1
50#define HOOK_SYSCALLS 0
51#define HOOK_DEBUG 1
52#define HOOK_MEDIA 1
53#define HOOK_BOPROT 0
54
55
56#pragma pack(push, 1)
57typedef struct _SERVICE_TABLE_DESCRIPTOR {
58
59 PULONG ServiceTableBase; /* table of function pointers */
60 PVOID ServiceCounterTable; /* used in checked build only */
61 ULONG NumberOfServices; /* number of services in this table */
62 /* extra LONG on IA64 goes here */
63 PVOID ParamTableBase; /* number of parameters */
64
65} SERVICE_TABLE_DESCRIPTOR, *PSERVICE_TABLE_DESCRIPTOR;
66#pragma pack(pop)
67
68
69/*
70 * The Service Descriptor Table index (4 bytes following the mov opcode)
71 *
72 * The index format is as follows:
73 *
74 * Leading 18 bits are all zeroes
75 * Following 2 bits are system service table index (3 bits on Win64)
76 * Following 12 bits are service number
77 */
78
79#define SERVICE_TABLE_INDEX_BITS 2
80#define NUMBER_SERVICE_TABLES (1 << SERVICE_TABLE_INDEX_BITS)
81
82#define SERVICE_ID_NUMBER_BITS 12
83#define SERVICE_ID_NUMBER_MASK ((1 << SERVICE_ID_NUMBER_BITS) - 1)
84
85
86/*
87 * The kernel's service descriptor table, which is used to find the address
88 * of the service dispatch tables to use for a service ID.
89 *
90 * Descriptor 0 is used for core services (NTDLL)
91 * Descriptor 1 is used for GUI services (WIN32K)
92 * Descriptors 2 and 3 are unused on current versions of Windows NT.
93 */
94
95__declspec(dllimport) SERVICE_TABLE_DESCRIPTOR KeServiceDescriptorTable[NUMBER_SERVICE_TABLES];
96
97
98/*
99 * not exported
100 */
101
102//PSERVICE_TABLE_DESCRIPTOR KeServiceDescriptorTableShadow;
103
104
105
106void SystemCallHandler0(); void SystemCallHandler1(); void SystemCallHandler2(); void SystemCallHandler3();
107void SystemCallHandler4(); void SystemCallHandler5(); void SystemCallHandler6(); void SystemCallHandler7();
108void SystemCallHandler8(); void SystemCallHandler9(); void SystemCallHandler10(); void SystemCallHandler11();
109void SystemCallHandler12(); void SystemCallHandler13(); void SystemCallHandler14(); void SystemCallHandler15();
110void SystemCallHandler16(); void SystemCallHandler17(); void SystemCallHandler18(); void SystemCallHandler19();
111void SystemCallHandler20(); void SystemCallHandler21(); void SystemCallHandler22(); void SystemCallHandler23();
112void SystemCallHandler24(); void SystemCallHandler25(); void SystemCallHandler26(); void SystemCallHandler27();
113void SystemCallHandler28(); void SystemCallHandler29(); void SystemCallHandler30(); void SystemCallHandler31();
114void SystemCallHandler32(); void SystemCallHandler33(); void SystemCallHandler34(); void SystemCallHandler35();
115void SystemCallHandler36(); void SystemCallHandler37(); void SystemCallHandler38(); void SystemCallHandler39();
116void SystemCallHandler40(); void SystemCallHandler41(); void SystemCallHandler42(); void SystemCallHandler43();
117void SystemCallHandler44(); void SystemCallHandler45(); void SystemCallHandler46(); void SystemCallHandler47();
118void SystemCallHandler48(); void SystemCallHandler49(); void SystemCallHandler50(); void SystemCallHandler51();
119void SystemCallHandler52(); void SystemCallHandler53(); void SystemCallHandler54(); void SystemCallHandler55();
120void SystemCallHandler56(); void SystemCallHandler57(); void SystemCallHandler58(); void SystemCallHandler59();
121void SystemCallHandler60(); void SystemCallHandler61(); void SystemCallHandler62(); void SystemCallHandler63();
122void SystemCallHandler64(); void SystemCallHandler65(); void SystemCallHandler66(); void SystemCallHandler67();
123void SystemCallHandler68(); void SystemCallHandler69(); void SystemCallHandler70(); void SystemCallHandler71();
124void SystemCallHandler72(); void SystemCallHandler73(); void SystemCallHandler74(); void SystemCallHandler75();
125void SystemCallHandler76(); void SystemCallHandler77(); void SystemCallHandler78(); void SystemCallHandler79();
126void SystemCallHandler80(); void SystemCallHandler81(); void SystemCallHandler82(); void SystemCallHandler83();
127void SystemCallHandler84(); void SystemCallHandler85(); void SystemCallHandler86(); void SystemCallHandler87();
128void SystemCallHandler88(); void SystemCallHandler89(); void SystemCallHandler90(); void SystemCallHandler91();
129void SystemCallHandler92(); void SystemCallHandler93(); void SystemCallHandler94(); void SystemCallHandler95();
130void SystemCallHandler96(); void SystemCallHandler97(); void SystemCallHandler98(); void SystemCallHandler99();
131void SystemCallHandler100(); void SystemCallHandler101(); void SystemCallHandler102(); void SystemCallHandler103();
132void SystemCallHandler104(); void SystemCallHandler105(); void SystemCallHandler106(); void SystemCallHandler107();
133void SystemCallHandler108(); void SystemCallHandler109(); void SystemCallHandler110(); void SystemCallHandler111();
134void SystemCallHandler112(); void SystemCallHandler113(); void SystemCallHandler114(); void SystemCallHandler115();
135void SystemCallHandler116(); void SystemCallHandler117(); void SystemCallHandler118(); void SystemCallHandler119();
136void SystemCallHandler120(); void SystemCallHandler121(); void SystemCallHandler122(); void SystemCallHandler123();
137void SystemCallHandler124(); void SystemCallHandler125(); void SystemCallHandler126(); void SystemCallHandler127();
138void SystemCallHandler128(); void SystemCallHandler129(); void SystemCallHandler130(); void SystemCallHandler131();
139void SystemCallHandler132(); void SystemCallHandler133(); void SystemCallHandler134(); void SystemCallHandler135();
140void SystemCallHandler136(); void SystemCallHandler137(); void SystemCallHandler138(); void SystemCallHandler139();
141void SystemCallHandler140(); void SystemCallHandler141(); void SystemCallHandler142(); void SystemCallHandler143();
142void SystemCallHandler144(); void SystemCallHandler145(); void SystemCallHandler146(); void SystemCallHandler147();
143void SystemCallHandler148(); void SystemCallHandler149(); void SystemCallHandler150(); void SystemCallHandler151();
144void SystemCallHandler152(); void SystemCallHandler153(); void SystemCallHandler154(); void SystemCallHandler155();
145void SystemCallHandler156(); void SystemCallHandler157(); void SystemCallHandler158(); void SystemCallHandler159();
146void SystemCallHandler160(); void SystemCallHandler161(); void SystemCallHandler162(); void SystemCallHandler163();
147void SystemCallHandler164(); void SystemCallHandler165(); void SystemCallHandler166(); void SystemCallHandler167();
148void SystemCallHandler168(); void SystemCallHandler169(); void SystemCallHandler170(); void SystemCallHandler171();
149void SystemCallHandler172(); void SystemCallHandler173(); void SystemCallHandler174(); void SystemCallHandler175();
150void SystemCallHandler176(); void SystemCallHandler177(); void SystemCallHandler178(); void SystemCallHandler179();
151void SystemCallHandler180(); void SystemCallHandler181(); void SystemCallHandler182(); void SystemCallHandler183();
152void SystemCallHandler184(); void SystemCallHandler185(); void SystemCallHandler186(); void SystemCallHandler187();
153void SystemCallHandler188(); void SystemCallHandler189(); void SystemCallHandler190(); void SystemCallHandler191();
154void SystemCallHandler192(); void SystemCallHandler193(); void SystemCallHandler194(); void SystemCallHandler195();
155void SystemCallHandler196(); void SystemCallHandler197(); void SystemCallHandler198(); void SystemCallHandler199();
156void SystemCallHandler200(); void SystemCallHandler201(); void SystemCallHandler202(); void SystemCallHandler203();
157void SystemCallHandler204(); void SystemCallHandler205(); void SystemCallHandler206(); void SystemCallHandler207();
158void SystemCallHandler208(); void SystemCallHandler209(); void SystemCallHandler210(); void SystemCallHandler211();
159void SystemCallHandler212(); void SystemCallHandler213(); void SystemCallHandler214(); void SystemCallHandler215();
160void SystemCallHandler216(); void SystemCallHandler217(); void SystemCallHandler218(); void SystemCallHandler219();
161void SystemCallHandler220(); void SystemCallHandler221(); void SystemCallHandler222(); void SystemCallHandler223();
162void SystemCallHandler224(); void SystemCallHandler225(); void SystemCallHandler226(); void SystemCallHandler227();
163void SystemCallHandler228(); void SystemCallHandler229(); void SystemCallHandler230(); void SystemCallHandler231();
164void SystemCallHandler232(); void SystemCallHandler233(); void SystemCallHandler234(); void SystemCallHandler235();
165void SystemCallHandler236(); void SystemCallHandler237(); void SystemCallHandler238(); void SystemCallHandler239();
166void SystemCallHandler240(); void SystemCallHandler241(); void SystemCallHandler242(); void SystemCallHandler243();
167void SystemCallHandler244(); void SystemCallHandler245(); void SystemCallHandler246(); void SystemCallHandler247();
168void SystemCallHandler248(); void SystemCallHandler249(); void SystemCallHandler250(); void SystemCallHandler251();
169void SystemCallHandler252(); void SystemCallHandler253(); void SystemCallHandler254(); void SystemCallHandler255();
170void SystemCallHandler256(); void SystemCallHandler257(); void SystemCallHandler258(); void SystemCallHandler259();
171void SystemCallHandler260(); void SystemCallHandler261(); void SystemCallHandler262(); void SystemCallHandler263();
172void SystemCallHandler264(); void SystemCallHandler265(); void SystemCallHandler266(); void SystemCallHandler267();
173void SystemCallHandler268(); void SystemCallHandler269(); void SystemCallHandler270(); void SystemCallHandler271();
174void SystemCallHandler272(); void SystemCallHandler273(); void SystemCallHandler274(); void SystemCallHandler275();
175void SystemCallHandler276(); void SystemCallHandler277(); void SystemCallHandler278(); void SystemCallHandler279();
176void SystemCallHandler280(); void SystemCallHandler281(); void SystemCallHandler282(); void SystemCallHandler283();
177void SystemCallHandler284(); void SystemCallHandler285(); void SystemCallHandler286(); void SystemCallHandler287();
178void SystemCallHandler288(); void SystemCallHandler289(); void SystemCallHandler290(); void SystemCallHandler291();
179void SystemCallHandler292(); void SystemCallHandler293(); void SystemCallHandler294();
180
181
182
183// XXX
184// SystemCallHandler macro depends on the size of this structure and the offset of the OriginalFunction!
185
186extern struct _ZwCalls
187{
188 PCHAR ZwName; // System call name
189 USHORT ZwNameLength; // System call name length
190 USHORT ServiceIDNumber; // System call index (filled in at runtime)
191 PULONG_PTR HookFunction; // Address of the hijacking function (function that will be called instead of the original system call)
192 PULONG_PTR OriginalFunction; // PlaceHolder for the address of the original syscall address
193 BOOLEAN Hijacked; // Flag indicating whether we already hijacked this system call
194 // or whether this is a special system service that needs to be hijacked initially
195};
196
197extern struct _ZwCalls ZwCalls[];
198
199
200#define ZW_ADD_ATOM_INDEX 8
201
202#define ZW_ADJUST_TOKEN_INDEX 12
203
204#define ZW_CONNECT_PORT_INDEX 33
205
206#define ZW_CREATE_DIRECTORYOBJECT_INDEX 36
207#define ZW_CREATE_EVENT_INDEX 37
208#define ZW_CREATE_EVENT_PAIR_INDEX 38
209#define ZW_CREATE_FILE_INDEX 39
210
211#define ZW_CREATE_JOBOBJECT_INDEX 41
212
213#define ZW_CREATE_KEY_INDEX 43
214
215#define ZW_CREATE_MAILSLOTFILE_INDEX 45
216#define ZW_CREATE_MUTANT_INDEX 46
217#define ZW_CREATE_NAMEDPIPEFILE_INDEX 47
218
219#define ZW_CREATE_PORT_INDEX 49
220#define ZW_CREATE_PROCESS_INDEX 50
221#define ZW_CREATE_PROCESSEX_INDEX 51
222
223#define ZW_CREATE_SECTION_INDEX 53
224#define ZW_CREATE_SEMAPHORE_INDEX 54
225#define ZW_CREATE_SYMLINK_INDEX 55
226#define ZW_CREATE_THREAD_INDEX 56
227#define ZW_CREATE_TIMER_INDEX 57
228#define ZW_CREATE_TOKEN_INDEX 58
229#define ZW_CREATE_WAITPORT_INDEX 59
230#define ZW_DEBUG_ACTIVEPROCESS_INDEX 60
231
232#define ZW_DELETE_FILE_INDEX 66
233#define ZW_DELETE_KEY_INDEX 67
234
235#define ZW_FIND_ATOM_INDEX 81
236
237#define ZW_LOAD_DRIVER_INDEX 103
238
239#define ZW_MAPVIEW_SECTION_INDEX 115
240
241#define ZW_OPEN_DIRECTORYOBJECT_INDEX 121
242#define ZW_OPEN_EVENT_INDEX 122
243#define ZW_OPEN_EVENT_PAIR_INDEX 123
244#define ZW_OPEN_FILE_INDEX 124
245
246#define ZW_OPEN_JOBOBJECT_INDEX 126
247#define ZW_OPEN_KEY_INDEX 127
248
249#define ZW_OPEN_MUTANT_INDEX 129
250
251#define ZW_OPEN_PROCESS_INDEX 131
252
253#define ZW_OPEN_SECTION_INDEX 134
254#define ZW_OPEN_SEMAPHORE_INDEX 135
255#define ZW_OPEN_SYMLINK_INDEX 136
256#define ZW_OPEN_THREAD_INDEX 137
257
258#define ZW_OPEN_TIMER_INDEX 140
259
260#define ZW_QUERY_ATTRIBUTES_FILE_INDEX 148
261
262#define ZW_QUERY_DIRECTORYFILE_INDEX 154
263
264#define ZW_QUERY_FULLATTR_FILE_INDEX 159
265
266#define ZW_QUERY_VALUE_KEY_INDEX 189
267
268#define ZW_SECURECONNECT_PORT_INDEX 223
269
270#define ZW_SET_INFO_FILE_INDEX 238
271
272#define ZW_SET_INFO_TOKEN_INDEX 244
273
274#define ZW_SET_LDT_ENTRIES_INDEX 247
275
276#define ZW_SET_SYSTEM_INFORMATION_INDEX 254
277
278#define ZW_SET_SYSTEM_TIME_INDEX 256
279
280#define ZW_SET_TIMER_RESOLUTION_INDEX 259
281
282#define ZW_SET_VALUE_KEY_INDEX 261
283
284#define ZW_UNLOAD_DRIVER_INDEX 276
285
286#define ZW_VDM_CONTROL_INDEX 283
287
288
289/*
290 * make sure we don't try to unload the driver while a system call is in progress
291 * still not atomic but we shouldn't be unloading this driver in any case
292 */
293
294#if DBG
295
296extern int HookedRoutineRunning;
297#define HOOK_ROUTINE_ENTER() NTSTATUS rc; ACTION_TYPE Action; InterlockedIncrement(&HookedRoutineRunning);
298#define HOOK_ROUTINE_EXIT(status) { InterlockedDecrement(&HookedRoutineRunning); return ((status)); }
299
300extern int HookedTDIRunning;
301#define HOOK_TDI_ENTER() NTSTATUS rc; ACTION_TYPE Action; InterlockedIncrement(&HookedTDIRunning);
302#define HOOK_TDI_ENTER_NORC() InterlockedIncrement(&HookedTDIRunning);
303#define HOOK_TDI_EXIT(status) { InterlockedDecrement(&HookedTDIRunning); return ((status)); }
304
305
306#else
307
308
309#define HOOK_ROUTINE_ENTER() NTSTATUS rc; ACTION_TYPE Action;
310#define HOOK_ROUTINE_EXIT(status) { return ((status)); }
311
312#define HOOK_TDI_ENTER() NTSTATUS rc; ACTION_TYPE Action;
313#define HOOK_TDI_ENTER_NORC()
314#define HOOK_TDI_EXIT(status) { return ((status)); }
315
316#endif
317
318
319/*
320 * Various macros used by most of the hooking routines
321 */
322
323#define POLICY_CHECK_OPTYPE_NAME(OBJECTTYPE, OPTYPE) \
324 while (KeGetPreviousMode() == UserMode) { \
325 UCHAR OpType = (OPTYPE); \
326 PWSTR PolicyFilename = NULL; \
327 USHORT PolicyLinenumber = 0; \
328 UCHAR RuleNumber = 0; \
329 LOG(LOG_SS_##OBJECTTYPE, LOG_PRIORITY_VERBOSE, ("%d %s: %s\n", (ULONG) PsGetCurrentProcessId(), FunctionName, OBJECTTYPE##NAME)); \
330 Action = PolicyCheck(RULE_##OBJECTTYPE, OBJECTTYPE##NAME, OpType, &RuleNumber, &PolicyFilename, &PolicyLinenumber);\
331 if (Action & ACTION_ASK) \
332 { \
333 LOG(LOG_SS_##OBJECTTYPE, LOG_PRIORITY_DEBUG, ("%d %s: (ask) access to %s\n", (ULONG) PsGetCurrentProcessId(), FunctionName, OBJECTTYPE##NAME)); \
334 /*XXX GetPathFromOA(ObjectAttributes, OBJECTTYPE##NAME, MAX_PATH, DO_NOT_RESOLVE_LINKS);*/ \
335 Action = IssueUserlandAskUserRequest(RULE_##OBJECTTYPE, OpType, OBJECTTYPE##NAME); \
336 } \
337 if ((Action & ACTION_QUIETDENY) == ACTION_QUIETDENY) \
338 { \
339 LOG(LOG_SS_##OBJECTTYPE, LOG_PRIORITY_VERBOSE, ("%d %s: quitely denying access to %s\n", (ULONG) PsGetCurrentProcessId(), FunctionName, OBJECTTYPE##NAME)); \
340 HOOK_ROUTINE_EXIT( STATUS_ACCESS_DENIED ); \
341 } \
342 else if (Action & ACTION_DENY) \
343 { \
344 LOG(LOG_SS_##OBJECTTYPE, LOG_PRIORITY_VERBOSE, ("%d %s: denying access to %s\n", (ULONG) PsGetCurrentProcessId(), FunctionName, OBJECTTYPE##NAME)); \
345 LogAlert(ALERT_SS_##OBJECTTYPE, OpType, RuleNumber, Action, \
346 GetObjectAccessAlertPriority(ALERT_SS_##OBJECTTYPE, OpType, Action), PolicyFilename, PolicyLinenumber, OBJECTTYPE##NAME);\
347 HOOK_ROUTINE_EXIT( STATUS_ACCESS_DENIED ); \
348 } \
349 else if (Action & ACTION_LOG) \
350 { \
351 LOG(LOG_SS_##OBJECTTYPE, LOG_PRIORITY_VERBOSE, ("%d %s: (log) access to %s\n", (ULONG) PsGetCurrentProcessId(), FunctionName, OBJECTTYPE##NAME)); \
352 LogAlert(ALERT_SS_##OBJECTTYPE, OpType, RuleNumber, Action, \
353 GetObjectAccessAlertPriority(ALERT_SS_##OBJECTTYPE, OpType, Action), PolicyFilename, PolicyLinenumber, OBJECTTYPE##NAME);\
354 } \
355 break; \
356 }
357
358
359#define POLICY_CHECK_OPTYPE(OBJECTTYPE, OPTYPE) \
360 if (KeGetPreviousMode() == UserMode && GetPathFromOA(ObjectAttributes, OBJECTTYPE##NAME, MAX_PATH, RESOLVE_LINKS) )\
361 { \
362 UCHAR OpType = (OPTYPE); \
363 PWSTR PolicyFilename = NULL; \
364 USHORT PolicyLinenumber = 0; \
365 UCHAR RuleNumber = 0; \
366 LOG(LOG_SS_##OBJECTTYPE, LOG_PRIORITY_VERBOSE, ("%d %s: %s\n", (ULONG) PsGetCurrentProcessId(), FunctionName, OBJECTTYPE##NAME)); \
367 Action = PolicyCheck(RULE_##OBJECTTYPE, OBJECTTYPE##NAME, OpType, &RuleNumber, &PolicyFilename, &PolicyLinenumber);\
368 if (Action & ACTION_ASK) \
369 { \
370 LOG(LOG_SS_##OBJECTTYPE, LOG_PRIORITY_DEBUG, ("%d %s: (ask) access to %s\n", (ULONG) PsGetCurrentProcessId(), FunctionName, OBJECTTYPE##NAME)); \
371 GetPathFromOA(ObjectAttributes, OBJECTTYPE##NAME, MAX_PATH, DO_NOT_RESOLVE_LINKS); \
372 Action = IssueUserlandAskUserRequest(RULE_##OBJECTTYPE, OpType, OBJECTTYPE##NAME); \
373 } \
374 if ((Action & ACTION_QUIETDENY) == ACTION_QUIETDENY) \
375 { \
376 LOG(LOG_SS_##OBJECTTYPE, LOG_PRIORITY_VERBOSE, ("%d %s: quitely denying access to %s\n", (ULONG) PsGetCurrentProcessId(), FunctionName, OBJECTTYPE##NAME)); \
377 HOOK_ROUTINE_EXIT( STATUS_ACCESS_DENIED ); \
378 } \
379 else if (Action & ACTION_DENY) \
380 { \
381 LOG(LOG_SS_##OBJECTTYPE, LOG_PRIORITY_VERBOSE, ("%d %s: denying access to %s\n", (ULONG) PsGetCurrentProcessId(), FunctionName, OBJECTTYPE##NAME)); \
382 GetPathFromOA(ObjectAttributes, OBJECTTYPE##NAME, MAX_PATH, DO_NOT_RESOLVE_LINKS); \
383 LogAlert(ALERT_SS_##OBJECTTYPE, OpType, RuleNumber, Action, \
384 GetObjectAccessAlertPriority(ALERT_SS_##OBJECTTYPE, OpType, Action), PolicyFilename, PolicyLinenumber, OBJECTTYPE##NAME);\
385 HOOK_ROUTINE_EXIT( STATUS_ACCESS_DENIED ); \
386 } \
387 else if (Action & ACTION_LOG) \
388 { \
389 LOG(LOG_SS_##OBJECTTYPE, LOG_PRIORITY_VERBOSE, ("%d %s: (log) access to %s\n", (ULONG) PsGetCurrentProcessId(), FunctionName, OBJECTTYPE##NAME)); \
390 GetPathFromOA(ObjectAttributes, OBJECTTYPE##NAME, MAX_PATH, DO_NOT_RESOLVE_LINKS); \
391 LogAlert(ALERT_SS_##OBJECTTYPE, OpType, RuleNumber, Action, \
392 GetObjectAccessAlertPriority(ALERT_SS_##OBJECTTYPE, OpType, Action), PolicyFilename, PolicyLinenumber, OBJECTTYPE##NAME);\
393 } \
394 }
395
396
397#define POLICY_CHECK(OBJECTTYPE) POLICY_CHECK_OPTYPE(OBJECTTYPE, Get_##OBJECTTYPE##_OperationType(DesiredAccess))
398
399
400
401#define HOOK_ROUTINE_START_OPTYPE(OBJECTTYPE, OPTYPE) \
402 CHAR OBJECTTYPE##NAME[MAX_PATH]; \
403 HOOK_ROUTINE_ENTER(); \
404 if (LearningMode == FALSE) \
405 { \
406 POLICY_CHECK_OPTYPE(OBJECTTYPE, OPTYPE); \
407 }
408
409
410#define HOOK_ROUTINE_START(OBJECTTYPE) HOOK_ROUTINE_START_OPTYPE(OBJECTTYPE, Get_##OBJECTTYPE##_OperationType(DesiredAccess))
411
412
413#define HOOK_ROUTINE_FINISH_OBJECTNAME_OPTYPE(OBJECTTYPE, OBJECTNAME, OPTYPE) \
414 if (LearningMode == TRUE /*&& NT_SUCCESS(rc)*/) \
415 { \
416 if (OBJECTNAME) \
417 { \
418 AddRule(RULE_##OBJECTTYPE, OBJECTTYPE##NAME, OPTYPE); \
419 } \
420 else \
421 { \
422 /*LOG(LOG_SS_##OBJECTTYPE, LOG_PRIORITY_DEBUG, ("%d %s: GetPathFromOA() failed. status=%x\n", (ULONG) PsGetCurrentProcessId(), FunctionName, rc));*/ \
423 } \
424 } \
425 HOOK_ROUTINE_EXIT(rc);
426
427
428#define HOOK_ROUTINE_FINISH_OPTYPE(OBJECTTYPE, OPTYPE) \
429 HOOK_ROUTINE_FINISH_OBJECTNAME_OPTYPE(OBJECTTYPE, \
430 GetPathFromOA(ObjectAttributes, OBJECTTYPE##NAME, MAX_PATH, RESOLVE_LINKS), \
431 OPTYPE)
432
433#define HOOK_ROUTINE_FINISH(OBJECTTYPE) \
434 HOOK_ROUTINE_FINISH_OBJECTNAME_OPTYPE(OBJECTTYPE, \
435 GetPathFromOA(ObjectAttributes, OBJECTTYPE##NAME, MAX_PATH, RESOLVE_LINKS), \
436 Get_##OBJECTTYPE##_OperationType(DesiredAccess))
437
438
439
440//#define USE_DEFAULT_HOOK_FUNCTION NULL
441
442
443extern PCHAR NTDLL_Base;
444extern int ZwCallsNumber;
445
446
447PVOID HookSystemService(PVOID OldService, PVOID NewService);
448PVOID HookSystemServiceByIndex(ULONG ServiceIDNumber, PVOID NewService);
449BOOLEAN HookSystemServiceByName(PCHAR ServiceName, PULONG_PTR HookFunction);
450
451BOOLEAN InitSyscallsHooks();
452BOOLEAN InstallSyscallsHooks();
453void RemoveSyscallsHooks();
454
455int FindZwFunctionIndex(PCSTR Name);
456PVOID FindFunctionBase(PCHAR ImageBase, PCSTR Name);
457ULONG FindSystemServiceNumber(PCHAR ServiceName);
458
459
460#endif /* __HOOKPROC_H__ */ \ No newline at end of file
diff --git a/i386.c b/i386.c
new file mode 100644
index 0000000..1ad1ad2
--- /dev/null
+++ b/i386.c
@@ -0,0 +1,178 @@
1/*
2 * Copyright (c) 2004 Security Architects Corporation. All rights reserved.
3 *
4 * Module Name:
5 *
6 * i386.c
7 *
8 * Abstract:
9 *
10 * This module implements various x86 processor dependant routines.
11 *
12 * Author:
13 *
14 * Eugene Tsyrklevich 07-Apr-2004
15 *
16 * Revision History:
17 *
18 * None.
19 */
20
21
22#include <NTDDK.h>
23#include "hookproc.h"
24#include "i386.h"
25#include "misc.h"
26
27
28#ifdef ALLOC_PRAGMA
29#pragma alloc_text (INIT, InitI386)
30#endif
31
32
33ULONG SystemAddressStart;
34static ULONG SharedUserDataAddress, TssAddress;
35ULONG MajorVersion, MinorVersion;
36
37
38/*
39 * InitI386()
40 *
41 * Description:
42 * Verify that we are running on Win2k, XP or 2003 on x86 platform.
43 * Also initialize various i386 related variables. Since Windows Advanced & Datacenter editions
44 * support a boot-time option that allows 3-GB user address spaces we cannot rely
45 * on static addresses for predefined structures.
46 *
47 *
48 * Parameters:
49 * None.
50 *
51 * Returns:
52 * Nothing.
53 */
54
55BOOLEAN
56InitI386()
57{
58 CHAR Gdtr[6];
59 USHORT TssOffset;
60 PKGDTENTRY TssGdtEntry;
61
62
63 PsGetVersion(&MajorVersion, &MinorVersion, NULL, NULL);
64
65
66 /*
67 * Right now we only support Windows 2000 (5.0), XP (5.1), 2003 (5.2)
68 */
69
70 if (MajorVersion != 5 || MinorVersion > 2)
71 {
72 LOG(LOG_SS_MISC, LOG_PRIORITY_DEBUG, ("InitI386: Version = %d.%d\n", MajorVersion, MinorVersion));
73 return FALSE;
74 }
75
76
77 /*
78 * Find the Shared User Data address.
79 */
80
81 if (* (PULONG) MmHighestUserAddress == 0x7FFEFFFF)
82 {
83 SharedUserDataAddress = 0x7FFE0000;
84 SystemAddressStart = 0x80000000;
85 }
86 else if (* (PULONG) MmHighestUserAddress == 0xBFFEFFFF)
87 {
88 SharedUserDataAddress = 0xBFFE0000;
89 SystemAddressStart = 0xC0000000;
90 }
91 else
92 {
93 LOG(LOG_SS_MISC, LOG_PRIORITY_DEBUG, ("InitI386: Unknown MmHighestUserAddress=%x\n", * (PULONG) MmHighestUserAddress));
94 return FALSE;
95 }
96
97
98 /*
99 * Find the TSS address.
100 *
101 * STR - Stores the segment selector from the task register (TR) in the destination operand. The
102 * destination operand can be a general-purpose register or a memory location. The segment selector
103 * stored with this instruction points to the task state segment (TSS) for the currently running task.
104 *
105 * SGDT - Stores the content of the global descriptor table register (GDTR) in the destination operand.
106 * The destination operand specifies a 6-byte memory location.
107 */
108
109 _asm
110 {
111 str TssOffset
112 sgdt Gdtr
113 }
114
115 TssGdtEntry = (PKGDTENTRY) * (PULONG) (Gdtr + 2); /* Extract the GDT address */
116 (PCHAR) TssGdtEntry += TssOffset;
117
118 TssAddress = TssGdtEntry->BaseLow | ( ((TssGdtEntry->HighWord.Bytes.BaseHi) << 24) | ((TssGdtEntry->HighWord.Bytes.BaseMid) << 16) );
119
120
121 return TRUE;
122}
123
124
125
126/*
127 * VerifyUserReturnAddress()
128 *
129 * Description:
130 * Verifies whether a specified userland return address is valid.
131 *
132 * Parameters:
133 * None.
134 *
135 * Returns:
136 * Nothing.
137 */
138
139VOID
140VerifyUserReturnAddress()
141{
142 PKTSS tss = (PKTSS) TssAddress;
143 ULONG UserEip, UserEsp;
144
145
146 /*
147 * this feature is not supported on Windows 2000 as it can make
148 * system calls from anywhere, not just ntdll.dll (it uses int 0x2e instead of sysenter)
149 */
150 if (MinorVersion == 0)
151 return;
152
153 if (KeGetPreviousMode() != UserMode)
154 return;
155
156
157 // EIP is 5 DWORDs before ESP0 on stack
158#define EIP_OFFSET 5
159
160 UserEip = * (PULONG) (tss->Esp0 - EIP_OFFSET * sizeof(DWORD));
161
162
163#define STACK_POINTER_OFFSET 2
164
165 UserEsp = * (PULONG) (tss->Esp0 - STACK_POINTER_OFFSET * sizeof(DWORD));
166 UserEsp -= 4;
167
168
169 //XXX verify that the return address is not on a writable page
170 //(might be used with Win2K which can make calls from anywhere)
171
172 if (UserEip < (ULONG) NTDLL_Base)
173 {
174 LOG(LOG_SS_MISC, LOG_PRIORITY_DEBUG, ("%d VerifyUserReturnAddress: Abnormal return user EIP=%x ESP0=%x (NTDLL_Base=%x)\n", (ULONG) PsGetCurrentProcessId(), UserEip, tss->Esp0, NTDLL_Base));
175
176 LogAlert(ALERT_SS_BOPROT, OP_INVALIDCALL, ALERT_RULE_BOPROT_INVALIDCALL, ACTION_LOG, ALERT_PRIORITY_HIGH, NULL, 0, NULL);
177 }
178}
diff --git a/i386.h b/i386.h
new file mode 100644
index 0000000..803e635
--- /dev/null
+++ b/i386.h
@@ -0,0 +1,184 @@
1/*
2 * Copyright (c) 2004 Security Architects Corporation. All rights reserved.
3 *
4 * Module Name:
5 *
6 * i386.h
7 *
8 * Abstract:
9 *
10 * This module definies various types and macros used by x86 specific routines.
11 *
12 * Author:
13 *
14 * Eugene Tsyrklevich 24-Mar-2004
15 *
16 * Revision History:
17 *
18 * None.
19 */
20
21
22#ifndef __I386_H__
23#define __I386_H__
24
25
26
27typedef struct _KTSS {
28
29 USHORT Backlink;
30 USHORT Reserved0;
31
32 ULONG Esp0;
33 USHORT Ss0;
34 USHORT Reserved1;
35
36 ULONG NotUsed1[4];
37
38 ULONG CR3;
39
40 ULONG Eip;
41
42 ULONG NotUsed2[9];
43
44 USHORT Es;
45 USHORT Reserved2;
46
47 USHORT Cs;
48 USHORT Reserved3;
49
50 USHORT Ss;
51 USHORT Reserved4;
52
53 USHORT Ds;
54 USHORT Reserved5;
55
56 USHORT Fs;
57 USHORT Reserved6;
58
59 USHORT Gs;
60 USHORT Reserved7;
61
62 USHORT LDT;
63 USHORT Reserved8;
64
65 USHORT Flags;
66
67 USHORT IoMapBase;
68
69 /* IO/INT MAPS go here */
70
71} KTSS, *PKTSS;
72
73
74typedef struct _KGDTENTRY {
75 USHORT LimitLow;
76 USHORT BaseLow;
77 union {
78 struct {
79 UCHAR BaseMid;
80 UCHAR Flags1; // Declare as bytes to avoid alignment
81 UCHAR Flags2; // Problems.
82 UCHAR BaseHi;
83 } Bytes;
84 struct {
85 ULONG BaseMid : 8;
86 ULONG Type : 5;
87 ULONG Dpl : 2;
88 ULONG Pres : 1;
89 ULONG LimitHi : 4;
90 ULONG Sys : 1;
91 ULONG Reserved_0 : 1;
92 ULONG Default_Big : 1;
93 ULONG Granularity : 1;
94 ULONG BaseHi : 8;
95 } Bits;
96 } HighWord;
97} KGDTENTRY, *PKGDTENTRY;
98
99
100#define INTERRUPTS_OFF() _asm { cli }
101#define INTERRUPTS_ON() _asm { sti }
102
103
104/*
105 * WP Write Protect (bit 16 of CR0).
106 * Inhibits supervisor-level procedures from writing into user-level read-only pages when set;
107 * allows supervisor-level procedures to write into user-level read-only pages when clear.
108 * This flag facilitates implementation of the copyon-write method of creating a new process (forking)
109 * used by operating systems such as UNIX.
110 */
111
112#define CR0_WP_BIT (0x10000)
113
114#define MEMORY_PROTECTION_OFF() \
115 __asm mov eax, cr0 \
116 __asm and eax, NOT CR0_WP_BIT \
117 __asm mov cr0, eax
118
119#define MEMORY_PROTECTION_ON() \
120 __asm mov eax, cr0 \
121 __asm or eax, CR0_WP_BIT \
122 __asm mov cr0, eax
123
124
125
126/* x86 opcodes */
127
128#define X86_OPCODE_PUSH 0x68
129#define X86_OPCODE_MOV_EAX_VALUE 0xB8
130
131#define X86_OPCODE_CALL_EAX 0xD0FF
132#define X86_OPCODE_JMP_DWORD_PTR 0x25FF
133
134
135
136/*
137 * Save a value on stack:
138 *
139 * push PushValue
140 */
141
142#define ASM_PUSH(CodeAddress, PushValue) \
143 * (PCHAR) (CodeAddress)++ = X86_OPCODE_PUSH; \
144 * (PULONG) (CodeAddress) = (ULONG) (PushValue); \
145 (PCHAR) (CodeAddress) += 4;
146
147/*
148 * Call a function:
149 *
150 * mov eax, FunctionAddress
151 * call eax
152 */
153
154#define ASM_CALL(CodeAddress, FunctionAddress) \
155 * (PCHAR) (CodeAddress)++ = X86_OPCODE_MOV_EAX_VALUE; \
156 * (PULONG) (CodeAddress) = (ULONG) (FunctionAddress); \
157 (PCHAR) (CodeAddress) += 4; \
158 * ((PUSHORT) (CodeAddress))++ = X86_OPCODE_CALL_EAX;
159
160
161/*
162 * Jump to a specified address:
163 *
164 * jmp dword ptr [next_4_bytes]
165 * *(next_4_bytes) = address
166 *
167 * NOTE XXX: this should be converted to a direct jmp address but i
168 * can't figure out how that instruction is encoded (opcode 0xE9)
169 */
170
171#define ASM_JMP(CodeAddress, JmpAddress) \
172 * ((PUSHORT) (CodeAddress))++ = X86_OPCODE_JMP_DWORD_PTR; \
173 * (PULONG) (CodeAddress) = (ULONG) (JmpAddress); \
174 (PCHAR) (CodeAddress) += 4;
175
176
177extern ULONG SystemAddressStart;
178
179
180BOOLEAN InitI386();
181VOID VerifyUserReturnAddress();
182
183
184#endif /* __I386_H__ */ \ No newline at end of file
diff --git a/job.c b/job.c
new file mode 100644
index 0000000..cccf224
--- /dev/null
+++ b/job.c
@@ -0,0 +1,157 @@
1/*
2 * Copyright (c) 2004 Security Architects Corporation. All rights reserved.
3 *
4 * Module Name:
5 *
6 * job.c
7 *
8 * Abstract:
9 *
10 * This module implements various job object hooking routines.
11 *
12 * Author:
13 *
14 * Eugene Tsyrklevich 25-Mar-2004
15 *
16 * Revision History:
17 *
18 * None.
19 */
20
21
22#include <NTDDK.h>
23#include "job.h"
24#include "policy.h"
25#include "pathproc.h"
26#include "hookproc.h"
27#include "accessmask.h"
28#include "learn.h"
29#include "log.h"
30
31
32#ifdef ALLOC_PRAGMA
33#pragma alloc_text (INIT, InitJobHooks)
34#endif
35
36
37fpZwCreateJobObject OriginalNtCreateJobObject = NULL;
38fpZwOpenJobObject OriginalNtOpenJobObject = NULL;
39
40
41/*
42 * HookedNtCreateJobObject()
43 *
44 * Description:
45 * This function mediates the NtCreateJobObject() system service and checks the
46 * provided job object name against the global and current process security policies.
47 *
48 * NOTE: ZwCreateJobObject creates or opens a job object. [NAR]
49 *
50 * Parameters:
51 * Those of NtCreateJobObject().
52 *
53 * Returns:
54 * STATUS_ACCESS_DENIED if the call does not pass the security policy check.
55 * Otherwise, NTSTATUS returned by NtCreateJobObject().
56 */
57
58NTSTATUS
59NTAPI
60HookedNtCreateJobObject
61(
62 OUT PHANDLE JobHandle,
63 IN ACCESS_MASK DesiredAccess,
64 IN POBJECT_ATTRIBUTES ObjectAttributes
65)
66{
67 PCHAR FunctionName = "HookedNtCreateJobObject";
68
69
70 HOOK_ROUTINE_START(JOB);
71
72
73 ASSERT(OriginalNtCreateJobObject);
74
75 rc = OriginalNtCreateJobObject(JobHandle, DesiredAccess, ObjectAttributes);
76
77
78 HOOK_ROUTINE_FINISH(JOB);
79}
80
81
82
83/*
84 * HookedNtOpenJobObject()
85 *
86 * Description:
87 * This function mediates the NtOpenJobObject() system service and checks the
88 * provided job object name against the global and current process security policies.
89 *
90 * NOTE: ZwOpenJobObject opens a job object. [NAR]
91 *
92 * Parameters:
93 * Those of NtOpenJobObject().
94 *
95 * Returns:
96 * STATUS_ACCESS_DENIED if the call does not pass the security policy check.
97 * Otherwise, NTSTATUS returned by NtOpenJobObject().
98 */
99
100NTSTATUS
101NTAPI
102HookedNtOpenJobObject
103(
104 OUT PHANDLE JobHandle,
105 IN ACCESS_MASK DesiredAccess,
106 IN POBJECT_ATTRIBUTES ObjectAttributes
107)
108{
109 PCHAR FunctionName = "HookedNtOpenJobObject";
110
111
112 HOOK_ROUTINE_START(JOB);
113
114
115 ASSERT(OriginalNtOpenJobObject);
116
117 rc = OriginalNtOpenJobObject(JobHandle, DesiredAccess, ObjectAttributes);
118
119
120 HOOK_ROUTINE_FINISH(JOB);
121}
122
123
124
125/*
126 * InitJobHooks()
127 *
128 * Description:
129 * Initializes all the mediated job object operation pointers. The "OriginalFunction" pointers
130 * are initialized by InstallSyscallsHooks() that must be called prior to this function.
131 *
132 * NOTE: Called once during driver initialization (DriverEntry()).
133 *
134 * Parameters:
135 * None.
136 *
137 * Returns:
138 * TRUE to indicate success, FALSE if failed.
139 */
140
141BOOLEAN
142InitJobHooks()
143{
144 if ( (OriginalNtCreateJobObject = (fpZwCreateJobObject) ZwCalls[ZW_CREATE_JOBOBJECT_INDEX].OriginalFunction) == NULL)
145 {
146 LOG(LOG_SS_JOB, LOG_PRIORITY_DEBUG, ("InitJobObjectHooks: OriginalNtCreateJobObject is NULL\n"));
147 return FALSE;
148 }
149
150 if ( (OriginalNtOpenJobObject = (fpZwOpenJobObject) ZwCalls[ZW_OPEN_JOBOBJECT_INDEX].OriginalFunction) == NULL)
151 {
152 LOG(LOG_SS_JOB, LOG_PRIORITY_DEBUG, ("InitJobObjectHooks: OriginalNtOpenJobObject is NULL\n"));
153 return FALSE;
154 }
155
156 return TRUE;
157}
diff --git a/job.h b/job.h
new file mode 100644
index 0000000..8328d42
--- /dev/null
+++ b/job.h
@@ -0,0 +1,68 @@
1/*
2 * Copyright (c) 2004 Security Architects Corporation. All rights reserved.
3 *
4 * Module Name:
5 *
6 * job.h
7 *
8 * Abstract:
9 *
10 * This module defines various types used by job object hooking routines.
11 *
12 * Author:
13 *
14 * Eugene Tsyrklevich 25-Mar-2004
15 *
16 * Revision History:
17 *
18 * None.
19 */
20
21
22#ifndef __JOB_H__
23#define __JOB_H__
24
25
26
27/*
28 * ZwCreateJobObject creates or opens a job object. [NAR]
29 */
30
31typedef NTSTATUS (*fpZwCreateJobObject) (
32 OUT PHANDLE JobHandle,
33 IN ACCESS_MASK DesiredAccess,
34 IN POBJECT_ATTRIBUTES ObjectAttributes
35 );
36
37NTSTATUS
38NTAPI
39HookedNtCreateJobObject(
40 OUT PHANDLE JobHandle,
41 IN ACCESS_MASK DesiredAccess,
42 IN POBJECT_ATTRIBUTES ObjectAttributes
43 );
44
45
46/*
47 * ZwOpenJobObject opens a job object. [NAR]
48 */
49
50typedef NTSTATUS (*fpZwOpenJobObject) (
51 OUT PHANDLE JobHandle,
52 IN ACCESS_MASK DesiredAccess,
53 IN POBJECT_ATTRIBUTES ObjectAttributes
54 );
55
56NTSTATUS
57NTAPI
58HookedNtOpenJobObject(
59 OUT PHANDLE JobHandle,
60 IN ACCESS_MASK DesiredAccess,
61 IN POBJECT_ATTRIBUTES ObjectAttributes
62 );
63
64
65BOOLEAN InitJobHooks();
66
67
68#endif /* __JOB_H__ */
diff --git a/learn.c b/learn.c
new file mode 100644
index 0000000..0bcdd53
--- /dev/null
+++ b/learn.c
@@ -0,0 +1,1414 @@
1/*
2 * Copyright (c) 2004 Security Architects Corporation. All rights reserved.
3 *
4 * Module Name:
5 *
6 * learn.c
7 *
8 * Abstract:
9 *
10 * This module implements various policy-auto-generation routines.
11 * Policy auto generation works by monitoring all system calls and remembering their
12 * argument values. These are then saved in a policy file.
13 *
14 * Author:
15 *
16 * Eugene Tsyrklevich 24-Feb-2004
17 *
18 * Revision History:
19 *
20 * None.
21 */
22
23
24#include <NTDDK.h>
25#include "learn.h"
26#include "accessmask.h"
27#include "hookproc.h"
28#include "procname.h"
29#include "process.h"
30#include "log.h"
31
32
33#ifdef ALLOC_PRAGMA
34#pragma alloc_text (INIT, InitLearningMode)
35#endif
36
37
38//XXX on a terminal server, global\* might need to be handled specially
39
40WCHAR ProcessToMonitor[MAX_PROCESS_NAME] = L"";
41
42BOOLEAN LearningMode = FALSE;
43HANDLE hFile;
44INT64 offset;
45
46BOOLEAN IsGuiThread = FALSE; /* does the process we are profiling contain any GUI threads? */
47
48SECURITY_POLICY NewPolicy;
49
50
51
52/*
53 * InitLearningMode()
54 *
55 * Description:
56 * Initialize a learning/training mode. Training mode is used to create process policies that
57 * describe all the resources used by a process.
58 *
59 * Called during driver initialization (DriverEntry()) or from DriverDeviceControl().
60 *
61 * Parameters:
62 * None.
63 *
64 * Returns:
65 * TRUE to indicate success, FALSE if failed.
66 */
67
68BOOLEAN
69InitLearningMode()
70{
71 LOG(LOG_SS_LEARN, LOG_PRIORITY_VERBOSE, ("InitLearningMode: Entered.\n"));
72
73
74 /* initialize the NewPolicy */
75 RtlZeroMemory(&NewPolicy, sizeof(NewPolicy));
76
77 KeInitializeSpinLock(&NewPolicy.SpinLock);
78
79 NewPolicy.ProtectionFlags = PROTECTION_ALL_ON;
80
81
82 /*
83 * Load an existing policy (if there is one) and use it as a template
84 */
85
86 if (FindAndLoadSecurityPolicy(&NewPolicy, ProcessToMonitor, NULL) == FALSE)
87 {
88 LOG(LOG_SS_LEARN, LOG_PRIORITY_DEBUG, ("InitLearningMode: Learning about '%S'. An existing policy not found.\n", ProcessToMonitor));
89
90 NewPolicy.DefaultPolicyAction = ACTION_LOG;
91 }
92 else
93 {
94 LOG(LOG_SS_LEARN, LOG_PRIORITY_DEBUG, ("InitLearningMode: Learning about '%S'. Using a pre-existing policy.\n", ProcessToMonitor));
95 }
96
97
98 return TRUE;
99}
100
101
102
103/*************************************************************************************************
104 *
105 * Path Filters
106 * Used to convert kernel object names into their userland representation
107 * (i.e. registry \REGISTRY\USER will be converted to HKEY_USERS
108 *
109 *************************************************************************************************/
110
111
112
113/*
114 * FilterFilePath()
115 *
116 * Description:
117 * Convert kernel file paths to their userland representation (i.e. removing \??\, \DosDevices\, references).
118 *
119 * Parameters:
120 * path - Pointer to a source character file path.
121 *
122 * Returns:
123 * Pointer to a post-processed file path.
124 */
125
126PCHAR
127FilterFilePath(PCHAR path)
128{
129 CHAR buffer[MAX_PATH];
130
131
132 if (path[0] != '\\' && path[0] != '%')
133 {
134// KdPrint(("FilterFilePath: special filename %s\n", path));
135// return NULL;
136 }
137
138
139 if (_strnicmp(path, "\\??\\pipe", 8) == 0)
140 {
141 return path + 3;
142 }
143
144 if (_strnicmp(path, "\\??\\", 4) == 0)
145 {
146 path += 4;
147 }
148 else if (_strnicmp(path, "\\DosDevices\\", 12) == 0)
149 {
150 path += 12;
151 }
152 else if (_strnicmp(path, CDrive, CDriveLength) == 0 && CDriveLength)
153 {
154 /* replace any possible \device\harddiskvolumeX references with a DOS C:\ name */
155 //XXX what about d:\ and so on?
156
157 path[CDriveLength-2] = 'C';
158 path[CDriveLength-1] = ':';
159
160 path += CDriveLength - 2;
161 }
162
163
164
165 if (_strnicmp(path, SystemRootDirectory, SystemRootDirectoryLength) == 0 && SystemRootDirectoryLength)
166 {
167 /* replace \windows (systemroot) references with SystemRoot */
168
169 strcpy(buffer, "%SystemRoot%");
170 strcat(buffer, path + SystemRootDirectoryLength);
171
172 path = buffer;
173 }
174 else if (_strnicmp(path, SystemRootUnresolved, SystemRootUnresolvedLength) == 0 && SystemRootUnresolvedLength)
175 {
176 /* replace c:\windows (systemroot) references with SystemRoot */
177
178 strcpy(buffer, "%SystemRoot%");
179 strcat(buffer, path + SystemRootUnresolvedLength);
180
181 path = buffer;
182 }
183 else if (_strnicmp(path, "\\SystemRoot\\", 12) == 0)
184 {
185 strcpy(buffer, "%SystemRoot%");
186 strcat(buffer, path + 11);
187
188 path = buffer;
189 }
190 else if ((path[0] == SystemDrive || path[0] == (CHAR) tolower(SystemDrive)) && path[1] == ':')
191 {
192 /* replace any system drive references with "SystemDrive" */
193 strcpy(buffer, "%SystemDrive%");
194 strcat(buffer, path + 1);
195
196 path = buffer;
197 }
198
199
200 return path;
201}
202
203
204
205/*
206 * FilterMailslotPath()
207 *
208 * Description:
209 * Convert kernel mailslot paths to their userland representation.
210 *
211 * Parameters:
212 * path - Pointer to a source character path.
213 *
214 * Returns:
215 * Pointer to a post-processed path.
216 */
217
218PCHAR
219FilterMailslotPath(PCHAR path)
220{
221 if (_strnicmp(path, "\\mailslot\\", 10) == 0)
222 return path + 10;
223
224 if (_strnicmp(path, "\\??\\mailslot\\", 13) == 0)
225 return path + 13;
226
227 if (_strnicmp(path, "\\device\\mailslot\\", 17) == 0)
228 return path + 17;
229
230 return path;
231}
232
233
234
235/*
236 * FilterNamedpipePath()
237 *
238 * Description:
239 * Convert kernel namedpipe paths to their userland representation.
240 *
241 * Parameters:
242 * path - Pointer to a source character path.
243 *
244 * Returns:
245 * Pointer to a post-processed path.
246 */
247
248PCHAR
249FilterNamedpipePath(PCHAR path)
250{
251 if (_strnicmp(path, "\\pipe\\", 6) == 0)
252 return path + 6;
253
254 if (_strnicmp(path, "\\??\\pipe\\", 9) == 0)
255 return path + 9;
256
257 if (_strnicmp(path, "\\device\\namedpipe\\", 18) == 0)
258 return path + 18;
259
260 return path;
261}
262
263
264
265/*
266 * FilterRegistryPath()
267 *
268 * Description:
269 * Convert kernel registry paths to their userland equivalents
270 * (i.e. replacing \REGISTRY\USER\ kernel path with its userland HKEY_USERS\ representation).
271 *
272 * Parameters:
273 * path - Pointer to a source character registry path.
274 *
275 * Returns:
276 * Pointer to a post-processed registry path.
277 */
278
279PCHAR
280FilterRegistryPath(PCHAR path)
281{
282 static char buffer[MAX_PATH];
283
284
285//XXX use reverse symlink lookup for this?!?!?
286
287 if (_strnicmp(path, "\\REGISTRY\\", 10) == 0)
288 {
289 /* replace \Registry\User\ with HKEY_USERS\ */
290 if (_strnicmp(path + 10, "USER\\", 5) == 0)
291 {
292 strcpy(path + 4, "HKEY_USERS");
293 path[14] = '\\';
294 return path + 4;
295 }
296
297 /* replace \Registry\Machine\ with HKEY_LOCAL_MACHINE\ */
298 if (_strnicmp(path + 10, "MACHINE\\", 8) == 0)
299 {
300 strcpy(buffer, "HKEY_LOCAL_MACHINE\\");
301 strncat(buffer, path + 18, MAX_PATH - 20);
302
303 return buffer;
304 }
305 }
306
307
308 return path;
309}
310
311
312
313/*
314 * FilterBaseNamedObjectsPath()
315 *
316 * Description:
317 * Convert kernel paths to their userland representation (by removing \BaseNamedObjects\ kernel reference).
318 *
319 * Parameters:
320 * path - Pointer to a source character event or semaphore path.
321 *
322 * Returns:
323 * Pointer to a post-processed path.
324 */
325
326PCHAR
327FilterBaseNamedObjectsPath(PCHAR path)
328{
329 if (_strnicmp(path, "\\BaseNamedObjects\\", 18) == 0)
330 {
331 return path + 18;
332 }
333
334 return path;
335}
336
337
338
339/*
340 * FilterDll()
341 *
342 * Description:
343 * Convert kernel DLL path to its userland representation
344 * (i.e. removing \KnownDlls\ kernel reference).
345 *
346 * Parameters:
347 * path - Pointer to a source character DLL path.
348 *
349 * Returns:
350 * Pointer to a post-processed DLL path.
351 */
352
353PCHAR
354FilterDll(PCHAR path)
355{
356 if (_strnicmp(path, "\\KnownDlls\\", 11) == 0)
357 {
358 return path + 11;
359 }
360
361 return path;
362}
363
364
365
366/*
367 * FilterPath()
368 *
369 * Description:
370 * Filter stub.
371 *
372 * Parameters:
373 * path - Pointer to a source character path.
374 *
375 * Returns:
376 * Pointer to an unmodified path.
377 */
378
379PCHAR
380FilterPath(PCHAR path)
381{
382 return path;
383}
384
385
386
387/*************************************************************************************************
388 *
389 * Operation Filters
390 * Convert operations (such as OP_READ, OP_WRITE) into their ASCII representation.
391 * (i.e. file OP_READ will be translated to "read" while atom OP_READ will become "find"
392 *
393 *************************************************************************************************/
394
395
396
397/*
398 * FilterOperation()
399 *
400 * Description:
401 * Convert operations (such as OP_READ, OP_WRITE) into their ASCII representation.
402 *
403 * Parameters:
404 * OperationType - operation type.
405 *
406 * Returns:
407 * Pointer to an ASCII string.
408 */
409
410PCHAR
411FilterOperation(UCHAR OperationType)
412{
413 if (IS_BIT_SET(OperationType, OP_READ_WRITE) &&
414 (IS_BIT_SET(OperationType, OP_DELETE) || IS_BIT_SET(OperationType, OP_EXECUTE)))
415
416 return "all";
417
418
419 if (IS_BIT_SET(OperationType, OP_DELETE))
420 return "delete";
421
422 if (IS_BIT_SET(OperationType, OP_READ_WRITE))
423 return "rw";
424
425 if (IS_BIT_SET(OperationType, OP_READ))
426 return "read";
427
428 if (IS_BIT_SET(OperationType, OP_WRITE))
429 return "write";
430
431 if (IS_BIT_SET(OperationType, OP_EXECUTE))
432 return "execute";
433
434
435 //XXX what about when multiple bits are set? read + delete?
436 LOG(LOG_SS_LEARN, LOG_PRIORITY_DEBUG, ("FilterOperation: invalid operation type %d\n", OperationType));
437
438
439 return "all";
440}
441
442
443
444/*
445 * FilterSimpleOperation()
446 *
447 * Description:
448 * Convert operations (such as OP_READ, OP_WRITE) into their ASCII representation.
449 *
450 * Parameters:
451 * OperationType - operation type.
452 *
453 * Returns:
454 * Pointer to an ASCII string.
455 */
456
457PCHAR
458FilterSimpleOperation(UCHAR OperationType)
459{
460 if (IS_BIT_SET(OperationType, OP_READ_WRITE))
461 return "all";
462
463 if (IS_BIT_SET(OperationType, OP_READ))
464 return "read";
465
466 if (IS_BIT_SET(OperationType, OP_WRITE))
467 return "write";
468
469 LOG(LOG_SS_LEARN, LOG_PRIORITY_DEBUG, ("FilterSimpleOperation: invalid operation type %d\n", OperationType));
470
471
472 return "all";
473}
474
475
476
477/*
478 * FilterCreateOpenOperation()
479 *
480 * Description:
481 * Convert OP_CREATE and OP_OPEN) into their ASCII representation.
482 *
483 * Parameters:
484 * OperationType - operation type.
485 *
486 * Returns:
487 * Pointer to an ASCII string.
488 */
489
490PCHAR
491FilterCreateOpenOperation(UCHAR OperationType)
492{
493 if (IS_BIT_SET(OperationType, OP_CREATE) &&
494 IS_BIT_SET(OperationType, OP_OPEN))
495
496 return "all";
497
498 if (IS_BIT_SET(OperationType, OP_CREATE))
499 return "create";
500
501 if (IS_BIT_SET(OperationType, OP_OPEN))
502 return "open";
503
504
505 LOG(LOG_SS_LEARN, LOG_PRIORITY_DEBUG, ("FilterCreateOpenOperation: invalid operation type %d\n", OperationType));
506
507
508 return "all";
509}
510
511
512
513/*
514 * FilterDirectoryOperation()
515 *
516 * Description:
517 * Convert operations (such as OP_DIR_CREATE) into their ASCII representation.
518 *
519 * Parameters:
520 * OperationType - operation type.
521 *
522 * Returns:
523 * Pointer to an ASCII string.
524 */
525
526PCHAR
527FilterDirectoryOperation(UCHAR OperationType)
528{
529 if (IS_BIT_SET(OperationType, OP_DIR_CREATE))
530 return "create";
531
532 return "all";
533}
534
535
536
537/*
538 * FilterProcessOperation()
539 *
540 * Description:
541 * Convert operations (such as OP_PROC_OPEN) into their ASCII representation.
542 *
543 * Parameters:
544 * OperationType - operation type.
545 *
546 * Returns:
547 * Pointer to an ASCII string.
548 */
549
550PCHAR
551FilterProcessOperation(UCHAR OperationType)
552{
553 if (IS_BIT_SET(OperationType, OP_PROC_OPEN) &&
554 IS_BIT_SET(OperationType, OP_PROC_EXECUTE))
555
556 return "all";
557
558
559 if (IS_BIT_SET(OperationType, OP_PROC_OPEN))
560 return "open";
561
562 if (IS_BIT_SET(OperationType, OP_PROC_EXECUTE))
563 return "execute";
564
565
566 return "all";
567}
568
569
570
571/*
572 * FilterNetworkOperation()
573 *
574 * Description:
575 * Convert operations (such as OP_CONNECT) into their ASCII representation.
576 *
577 * Parameters:
578 * OperationType - operation type.
579 *
580 * Returns:
581 * Pointer to an ASCII string.
582 */
583
584PCHAR
585FilterNetworkOperation(UCHAR OperationType)
586{
587 if (IS_BIT_SET(OperationType, OP_TCPCONNECT))
588 return "tcpconnect";
589
590 if (IS_BIT_SET(OperationType, OP_UDPCONNECT))
591 return "udpconnect";
592
593 if (IS_BIT_SET(OperationType, OP_CONNECT))
594 return "connect";
595
596 if (IS_BIT_SET(OperationType, OP_BIND))
597 return "bind";
598
599
600 LOG(LOG_SS_LEARN, LOG_PRIORITY_DEBUG, ("FilterNetworkOperation: invalid operation type %d\n", OperationType));
601
602
603 return "all";
604}
605
606
607
608/*
609 * FilterPortOperation()
610 *
611 * Description:
612 * Convert port operations (such as OP_PORT_CONNECT) into their ASCII representation.
613 *
614 * Parameters:
615 * OperationType - operation type.
616 *
617 * Returns:
618 * Pointer to an ASCII string.
619 */
620
621PCHAR
622FilterPortOperation(UCHAR OperationType)
623{
624 if (IS_BIT_SET(OperationType, OP_PORT_CREATE) &&
625 IS_BIT_SET(OperationType, OP_PORT_CONNECT))
626
627 return "all";
628
629
630 if (IS_BIT_SET(OperationType, OP_PORT_CREATE))
631 return "create";
632
633 if (IS_BIT_SET(OperationType, OP_PORT_CONNECT))
634 return "connect";
635
636
637 LOG(LOG_SS_LEARN, LOG_PRIORITY_DEBUG, ("FilterPortOperation: invalid operation type %d\n", OperationType));
638
639
640 return "all";
641}
642
643
644
645/*
646 * FilterAtomOperation()
647 *
648 * Description:
649 * Convert atom operations (such as OP_READ, OP_WRITE) into their ASCII representation.
650 *
651 * Parameters:
652 * OperationType - operation type.
653 *
654 * Returns:
655 * Pointer to an ASCII string.
656 */
657
658PCHAR
659FilterAtomOperation(UCHAR OperationType)
660{
661 if (IS_BIT_SET(OperationType, OP_ADD) &&
662 IS_BIT_SET(OperationType, OP_FIND))
663
664 return "all";
665
666 if (IS_BIT_SET(OperationType, OP_ADD))
667 return "add";
668
669 if (IS_BIT_SET(OperationType, OP_FIND))
670 return "find";
671
672
673 LOG(LOG_SS_LEARN, LOG_PRIORITY_DEBUG, ("FilterAtomOperation: invalid operation type %d\n", OperationType));
674
675
676 return "all";
677}
678
679
680
681/*
682 * FilterDriverOperation()
683 *
684 * Description:
685 * Convert driver object operations (such as OP_READ, OP_WRITE) into their ASCII representation.
686 *
687 * Parameters:
688 * OperationType - operation type.
689 *
690 * Returns:
691 * Pointer to an ASCII string.
692 */
693
694PCHAR
695FilterDriverOperation(UCHAR OperationType)
696{
697 if (IS_BIT_SET(OperationType, OP_LOAD))
698 return "load";
699
700 if (IS_BIT_SET(OperationType, OP_REGLOAD))
701 return "regload";
702
703 LOG(LOG_SS_LEARN, LOG_PRIORITY_DEBUG, ("FilterDriverOperation: invalid operation type %d\n", OperationType));
704
705 return "load";
706}
707
708
709
710/*
711 * FilterDllOperation()
712 *
713 * Description:
714 * Convert DLL operations (such as OP_READ, OP_WRITE) into their ASCII representation.
715 *
716 * Parameters:
717 * OperationType - operation type.
718 *
719 * Returns:
720 * Pointer to an ASCII string.
721 */
722
723PCHAR
724FilterDllOperation(UCHAR OperationType)
725{
726 return "load";
727}
728
729
730
731/*
732 * FilterServiceOperation()
733 *
734 * Description:
735 * Convert service operations (such as OP_START, OP_WRITE) into their ASCII representation.
736 *
737 * Parameters:
738 * OperationType - operation type.
739 *
740 * Returns:
741 * Pointer to an ASCII string.
742 */
743
744PCHAR
745FilterServiceOperation(UCHAR OperationType)
746{
747 if (IS_BIT_SET(OperationType, OP_SERVICE_START))
748 return "start";
749
750 if (IS_BIT_SET(OperationType, OP_SERVICE_STOP))
751 return "stop";
752
753 if (IS_BIT_SET(OperationType, OP_SERVICE_CREATE))
754 return "create";
755
756 if (IS_BIT_SET(OperationType, OP_SERVICE_DELETE))
757 return "delete";
758
759
760 LOG(LOG_SS_LEARN, LOG_PRIORITY_DEBUG, ("FilterServiceOperation: invalid operation type %d\n", OperationType));
761
762
763 return "all";
764}
765
766
767
768/*
769 * FilterTimeOperation()
770 *
771 * Description:
772 * Convert time operations (such as OP_TIME_CHANGE) into their ASCII representation.
773 *
774 * Parameters:
775 * OperationType - operation type.
776 *
777 * Returns:
778 * Pointer to an ASCII string.
779 */
780
781PCHAR
782FilterTimeOperation(UCHAR OperationType)
783{
784 if (IS_BIT_SET(OperationType, OP_TIME_CHANGE))
785 return "change";
786
787
788 LOG(LOG_SS_LEARN, LOG_PRIORITY_DEBUG, ("FilterTimeOperation: invalid operation type %d\n", OperationType));
789
790
791 return "all";
792}
793
794
795
796/*
797 * FilterTokenOperation()
798 *
799 * Description:
800 * Convert token operations (such as OP_TOKEN_MODIFY) into their ASCII representation.
801 *
802 * Parameters:
803 * OperationType - operation type.
804 *
805 * Returns:
806 * Pointer to an ASCII string.
807 */
808
809PCHAR
810FilterTokenOperation(UCHAR OperationType)
811{
812 if (IS_BIT_SET(OperationType, OP_TOKEN_MODIFY))
813 return "modify";
814
815
816 LOG(LOG_SS_LEARN, LOG_PRIORITY_DEBUG, ("FilterTokenOperation: invalid operation type %d\n", OperationType));
817
818
819 return "all";
820}
821
822
823
824/*
825 * FilterSyscallOperation()
826 *
827 * Description:
828 * This function is never supposed to be called.
829 *
830 * Parameters:
831 * OperationType - operation type.
832 *
833 * Returns:
834 * An error.
835 */
836
837PCHAR
838FilterSyscallOperation(UCHAR OperationType)
839{
840 LOG(LOG_SS_LEARN, LOG_PRIORITY_DEBUG, ("FilterSyscallOperation: this function is not supposed to be called.\n"));
841
842 return "error";
843}
844
845
846
847typedef PCHAR (*fpFilterObject) (PCHAR path);
848typedef PCHAR (*fpFilterOperation) (UCHAR OperationType);
849
850
851/* in C++ these would be member methods */
852
853struct
854{
855 PCHAR Prefix;
856 fpFilterObject FilterObjectProc;
857 fpFilterOperation FilterOperationProc;
858
859} RuleTypeData[] =
860{
861 { "file", FilterFilePath, FilterOperation },
862 { "directory", FilterFilePath, FilterDirectoryOperation },
863 { "mailslot", FilterMailslotPath, FilterSimpleOperation },
864 { "namedpipe", FilterNamedpipePath, FilterSimpleOperation },
865 { "registry", FilterRegistryPath, FilterOperation },
866 { "section", FilterBaseNamedObjectsPath, FilterOperation },
867 { "dll", FilterDll, FilterDllOperation },
868 { "event", FilterBaseNamedObjectsPath, FilterCreateOpenOperation },
869 { "semaphore", FilterBaseNamedObjectsPath, FilterCreateOpenOperation },
870 { "job", FilterBaseNamedObjectsPath, FilterCreateOpenOperation },
871 { "mutex", FilterBaseNamedObjectsPath, FilterCreateOpenOperation },
872 { "port", FilterPath, FilterPortOperation },
873 { "symlink", FilterPath, FilterCreateOpenOperation },
874 { "timer", FilterBaseNamedObjectsPath, FilterCreateOpenOperation },
875 { "process", FilterFilePath, FilterProcessOperation },
876 { "driver", FilterFilePath, FilterDriverOperation },
877 { "dirobj", FilterPath, FilterCreateOpenOperation },
878 { "atom", FilterPath, FilterAtomOperation },
879
880 { "network", FilterPath, FilterNetworkOperation },
881 { "service", FilterPath, FilterServiceOperation },
882 { "time", FilterPath, FilterTimeOperation },
883 { "token", FilterPath, FilterTokenOperation },
884 { "syscall", FilterPath, FilterSyscallOperation },
885};
886
887
888
889/*
890 * DecodeAction()
891 *
892 * Description:
893 * .
894 *
895 * Parameters:
896 * .
897 *
898 * Returns:
899 * .
900 */
901
902PCHAR
903DecodeAction(UCHAR ActionType)
904{
905 switch (ActionType)
906 {
907 case ACTION_ASK:
908 case ACTION_ASK_DEFAULT:
909 return "ask";
910
911 case ACTION_PERMIT:
912 case ACTION_ASK_PERMIT:
913 case ACTION_PERMIT_DEFAULT:
914 return "permit";
915
916 case ACTION_DENY:
917 case ACTION_ASK_DENY:
918 case ACTION_DENY_DEFAULT:
919 return "deny";
920
921 case ACTION_LOG:
922 case ACTION_ASK_LOG:
923 case ACTION_LOG_DEFAULT:
924 return "log";
925
926 case ACTION_QUIETDENY:
927 case ACTION_QUIETDENY_DEFAULT:
928 return "quietdeny";
929
930 case ACTION_TERMINATE:
931 case ACTION_ASK_TERMINATE:
932 return "log";
933
934 default:
935 return "unknown";
936 }
937}
938
939
940
941/*
942 * CreateRule()
943 *
944 * Description:
945 * Generate an ASCII rule for rule 'r' of type RuleType.
946 *
947 * Parameters:
948 * RuleType - rule type.
949 * r - rule itself.
950 * buffer - output buffer.
951 *
952 * Returns:
953 * TRUE if a rule was created, FALSE otherwise.
954 */
955
956BOOLEAN
957CreateRule(RULE_TYPE RuleType, PPOLICY_RULE r, PCHAR buffer)
958{
959 PCHAR name;
960
961
962 ASSERT(r);
963 ASSERT(buffer);
964
965
966 if (r->MatchType != MATCH_ALL)
967 {
968 name = RuleTypeData[ RuleType ].FilterObjectProc(r->Name);
969
970 /* if name is NULL there is no need to remember this rule */
971 if (name == NULL)
972 return FALSE;
973
974 if (strlen(name) > MAX_PATH)
975 {
976 LOG(LOG_SS_LEARN, LOG_PRIORITY_DEBUG, ("CreateRule: name '%s' is too long\n", name));
977 return FALSE;
978 }
979
980 }
981
982
983 /*
984 * construct the "objecttype_operation: " part first
985 */
986
987 strcpy(buffer, RuleTypeData[ RuleType ].Prefix);
988
989 strcat(buffer, "_");
990
991 strcat(buffer, RuleTypeData[ RuleType ].FilterOperationProc(r->OperationType));
992
993 strcat(buffer, ": ");
994
995
996 /*
997 * now construct the action part
998 */
999
1000 if (r->MatchType != MATCH_ALL)
1001 {
1002 strcat(buffer, "name ");
1003
1004 if (r->MatchType == MATCH_WILDCARD)
1005 strcat(buffer, "match \"");
1006 else
1007 strcat(buffer, "eq \"");
1008
1009 strcat(buffer, name);
1010
1011 strcat(buffer, "\" then ");
1012 }
1013
1014 strcat(buffer, DecodeAction(r->ActionType));
1015
1016
1017 /* add optional rule clause */
1018 if (r->RuleNumber != 0)
1019 {
1020 CHAR rule[16];
1021
1022 sprintf(rule, " [rule %d]", r->RuleNumber);
1023
1024 strcat(buffer, rule);
1025 }
1026
1027
1028 return TRUE;
1029}
1030
1031
1032
1033/*
1034 * CreateServiceRule()
1035 *
1036 * Description:
1037 * .
1038 *
1039 * Parameters:
1040 * .
1041 *
1042 * Returns:
1043 * .
1044 */
1045
1046BOOLEAN
1047CreateServiceRule(PPOLICY_RULE r, PCHAR buffer)
1048{
1049 strcpy(buffer, "service_");
1050 strcat(buffer, r->Name + 2);
1051 strcat(buffer, ": permit");
1052
1053 return TRUE;
1054}
1055
1056
1057
1058BOOLEAN WriteRule(PCHAR rule);
1059BOOLEAN WritePolicyFile(PCHAR buffer);
1060
1061
1062/*
1063 * FlushPolicy()
1064 *
1065 * Description:
1066 * .
1067 *
1068 * Parameters:
1069 * .
1070 *
1071 * Returns:
1072 * Nothing.
1073 */
1074
1075void
1076FlushPolicy()
1077{
1078 PPOLICY_RULE r;
1079 KIRQL irql;
1080 char buffer[MAX_PATH*2];
1081 UCHAR i;
1082 BOOLEAN ValidRule;
1083
1084
1085 // cannot write to files while holding spinlock (irql != PASSIVE_LEVEL)
1086// KeAcquireSpinLock(&NewPolicy.SpinLock, &irql);
1087
1088 sprintf(buffer, "\r\n# %S Default Process Policy\r\n", ProcessToMonitor);
1089 WriteRule(buffer);
1090
1091 sprintf(buffer, "policy_default: %s\r\n", DecodeAction(NewPolicy.DefaultPolicyAction));
1092 WriteRule(buffer);
1093
1094 if (! IS_OVERFLOW_PROTECTION_ON(NewPolicy))
1095 WriteRule("protection_overflow: off");
1096
1097 if (! IS_USERLAND_PROTECTION_ON(NewPolicy))
1098 WriteRule("protection_userland: off");
1099
1100 if (! IS_EXTENSION_PROTECTION_ON(NewPolicy))
1101 WriteRule("protection_extension: off");
1102
1103 if (! IS_DEBUGGING_PROTECTION_ON(NewPolicy))
1104 WriteRule("protection_debugging: off");
1105
1106 if (! IS_VDM_PROTECTION_ON(NewPolicy))
1107 WriteRule("protection_dos16: off");
1108
1109
1110// KdPrint(("%s process\n", IsGuiThread ? "GUI" : "NON GUI"));
1111
1112
1113 for (i = 0; i < RULE_LASTONE; i++)
1114 {
1115 r = NewPolicy.RuleList[i];
1116
1117 if (r)
1118 {
1119 WritePolicyFile("\r\n\r\n# ");
1120 WritePolicyFile(RuleTypeData[i].Prefix);
1121 WritePolicyFile(" related operations\r\n\r\n");
1122 }
1123
1124 while (r)
1125 {
1126 if (i != RULE_SYSCALL)
1127 ValidRule = CreateRule(i, r, buffer);
1128 else
1129 ValidRule = CreateServiceRule(r, buffer);
1130
1131 if (ValidRule == TRUE)
1132 WriteRule(buffer);
1133
1134 r = (PPOLICY_RULE) r->Next;
1135 }
1136 }
1137
1138
1139// KeReleaseSpinLock(&NewPolicy.SpinLock, irql);
1140}
1141
1142
1143
1144/*
1145 * ShutdownLearningMode()
1146 *
1147 * Description:
1148 * .
1149 *
1150 * Parameters:
1151 * .
1152 *
1153 * Returns:
1154 * Nothing.
1155 */
1156
1157BOOLEAN
1158ShutdownLearningMode()
1159{
1160 UNICODE_STRING pathname;
1161 OBJECT_ATTRIBUTES oa;
1162 IO_STATUS_BLOCK isb;
1163 WCHAR PolicyPath[MAX_PATH];
1164
1165
1166 /* now open a file where the new policy will be written, possibly clobbering the old policy */
1167 //XXX should really copy an existing policy to a .bak file
1168
1169// _snwprintf(PolicyPath, MAX_PATH, L"\\??\\c:\\policy\\%s.policy", ProcessToMonitor);
1170 _snwprintf(PolicyPath, MAX_PATH, L"\\??\\%s\\policy\\%s.policy", OzoneInstallPath, ProcessToMonitor);
1171 PolicyPath[MAX_PATH - 1] = 0;
1172
1173
1174 LOG(LOG_SS_LEARN, LOG_PRIORITY_DEBUG, ("ShutdownLearningMode: Writing policy to %S\n", PolicyPath));
1175
1176
1177 RtlInitUnicodeString(&pathname, PolicyPath);
1178
1179 InitializeObjectAttributes(&oa, &pathname, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL);
1180
1181 if (!NT_SUCCESS(ZwCreateFile(&hFile, GENERIC_WRITE, &oa, &isb,
1182 NULL, 0, 0, FILE_SUPERSEDE,
1183 FILE_SYNCHRONOUS_IO_NONALERT, NULL, 0)))
1184 {
1185 LOG(LOG_SS_LEARN, LOG_PRIORITY_DEBUG, ("ShutdownLearningMode: Failed to open file %S\n", pathname.Buffer));
1186 return FALSE;
1187 }
1188
1189 offset = 0;
1190
1191 FlushPolicy();
1192
1193 PolicyDelete(&NewPolicy);
1194
1195 ZwClose(hFile);
1196 hFile = 0;
1197
1198
1199 return TRUE;
1200}
1201
1202
1203
1204/*
1205 * WritePolicyFile()
1206 *
1207 * Description:
1208 * .
1209 *
1210 * Parameters:
1211 * .
1212 *
1213 * Returns:
1214 * Nothing.
1215 */
1216
1217BOOLEAN
1218WritePolicyFile(PCHAR buffer)
1219{
1220 int len = strlen(buffer);
1221 IO_STATUS_BLOCK isb;
1222
1223
1224 if (!NT_SUCCESS(ZwWriteFile(hFile, NULL, NULL, NULL, &isb, (PVOID) buffer, len, (PLARGE_INTEGER) &offset, NULL)))
1225 {
1226 LOG(LOG_SS_LEARN, LOG_PRIORITY_DEBUG, ("WritePolicyFile(): ZwReadFile failed\n"));
1227 return FALSE;
1228 }
1229
1230 if (isb.Information != len)
1231 {
1232 LOG(LOG_SS_LEARN, LOG_PRIORITY_DEBUG, ("WritePolicyFile(): Asked to write %d bytes. Wrote only %d\n", len, isb.Information));
1233 }
1234
1235 offset += isb.Information;
1236
1237
1238 return TRUE;
1239}
1240
1241
1242
1243/*
1244 * WriteRule()
1245 *
1246 * Description:
1247 * .
1248 *
1249 * Parameters:
1250 * .
1251 *
1252 * Returns:
1253 * Nothing.
1254 */
1255
1256BOOLEAN
1257WriteRule(PCHAR rule)
1258{
1259 BOOLEAN ret, ret2;
1260
1261 ret = WritePolicyFile(rule);
1262 ret2 = WritePolicyFile("\r\n");
1263
1264 return ret && ret2;
1265}
1266
1267
1268
1269/*
1270 * RememberRule()
1271 *
1272 * Description:
1273 * Create a new rule.
1274 *
1275 * Parameters:
1276 * RuleType - rule type.
1277 * ObjectName - name of an object associated with the current rule.
1278 * OperationType - operation type.
1279 *
1280 * Returns:
1281 * TRUE to indicate success, FALSE if failed.
1282 */
1283
1284BOOLEAN
1285RememberRule(RULE_TYPE RuleType, PCHAR ObjectName, UCHAR OperationType)
1286{
1287 PPOLICY_RULE rule = NewPolicy.RuleList[RuleType];
1288 KIRQL irql;
1289 int len = 0;
1290
1291
1292 if (ObjectName)
1293 len = strlen(ObjectName);
1294
1295
1296 KeAcquireSpinLock(&NewPolicy.SpinLock, &irql);
1297
1298
1299 /*
1300 * don't save duplicate rules
1301 */
1302
1303 while (rule != NULL)
1304 {
1305 if ( (rule->MatchType == MATCH_ALL) ||
1306 (rule->MatchType == MATCH_SINGLE && len == rule->NameLength && _stricmp(ObjectName, rule->Name) == 0) ||
1307 (rule->MatchType == MATCH_WILDCARD && WildcardMatch(ObjectName, rule->Name) == WILDCARD_MATCH) )
1308 {
1309 rule->OperationType |= OperationType;
1310
1311 KeReleaseSpinLock(&NewPolicy.SpinLock, irql);
1312
1313 return TRUE;
1314 }
1315
1316 rule = (PPOLICY_RULE) rule->Next;
1317 }
1318
1319
1320 rule = ExAllocatePoolWithTag(NonPagedPool, sizeof(POLICY_RULE) + len, _POOL_TAG);
1321 if (rule == NULL)
1322 {
1323 LOG(LOG_SS_LEARN, LOG_PRIORITY_DEBUG, ("RememberRule: out of memory\n"));
1324 return FALSE;
1325 }
1326
1327 RtlZeroMemory(rule, sizeof(POLICY_RULE));
1328
1329 rule->ActionType = ACTION_PERMIT;
1330 rule->OperationType = OperationType;
1331
1332 if (ObjectName)
1333 {
1334 rule->NameLength = (USHORT) len;
1335 strcpy(rule->Name, ObjectName);
1336 rule->MatchType = MATCH_SINGLE;
1337 }
1338 else
1339 {
1340 rule->MatchType = MATCH_ALL;
1341 }
1342
1343 rule->Next = NewPolicy.RuleList[RuleType];
1344 NewPolicy.RuleList[RuleType] = rule;
1345
1346
1347 KeReleaseSpinLock(&NewPolicy.SpinLock, irql);
1348
1349
1350 return TRUE;
1351}
1352
1353
1354
1355/*
1356 * DetermineThreadType()
1357 *
1358 * Description:
1359 * Determine whether a thread is GUI enabled or not. Done by checking which
1360 * system call table the thread is using.
1361 *
1362 * Parameters:
1363 * None.
1364 *
1365 * Returns:
1366 * Nothing.
1367 */
1368
1369void
1370DetermineThreadType()
1371{
1372 if (ThreadServiceTableOffset == 0)
1373 return;
1374
1375 if (* (PULONG) ((PCHAR) PsGetCurrentThread() + ThreadServiceTableOffset) != (ULONG) &KeServiceDescriptorTable[0])
1376 IsGuiThread = TRUE;
1377}
1378
1379
1380
1381/*
1382 * AddRule()
1383 *
1384 * Description:
1385 * Create a new rule for a particular rule type, operation type and object.
1386 *
1387 * Parameters:
1388 * RuleType - rule type.
1389 * str - optional character object name.
1390 * OperationType - operation taking place.
1391 *
1392 * Returns:
1393 * Nothing.
1394 */
1395
1396BOOLEAN
1397AddRule(RULE_TYPE RuleType, PCHAR str, UCHAR OperationType)
1398{
1399 PWSTR filename;
1400
1401
1402 filename = wcsrchr(GetCurrentProcessName(), L'\\');
1403 if (filename == NULL)
1404 filename = GetCurrentProcessName();
1405 else
1406 ++filename;
1407
1408 if (_wcsicmp(filename, ProcessToMonitor) != 0)
1409 return TRUE;
1410
1411// DetermineThreadType();
1412
1413 return RememberRule(RuleType, str, OperationType);
1414}
diff --git a/learn.h b/learn.h
new file mode 100644
index 0000000..e8a3866
--- /dev/null
+++ b/learn.h
@@ -0,0 +1,43 @@
1/*
2 * Copyright (c) 2004 Security Architects Corporation. All rights reserved.
3 *
4 * Module Name:
5 *
6 * learn.h
7 *
8 * Abstract:
9 *
10 * This module implements various types and definitions used by the policy-auto-generation code.
11 *
12 * Author:
13 *
14 * Eugene Tsyrklevich 24-Feb-2004
15 *
16 * Revision History:
17 *
18 * None.
19 */
20
21#ifndef __LEARN_H__
22#define __LEARN_H__
23
24
25#include "policy.h"
26
27
28extern BOOLEAN LearningMode;
29
30extern SECURITY_POLICY NewPolicy;
31
32/* In characters */
33#define MAX_PROCESS_NAME 32
34
35extern WCHAR ProcessToMonitor[];
36
37
38BOOLEAN InitLearningMode();
39BOOLEAN ShutdownLearningMode();
40BOOLEAN AddRule(RULE_TYPE RuleType, PCHAR str, UCHAR OperationType);
41
42
43#endif /* __LEARN_H__ */ \ No newline at end of file
diff --git a/log.c b/log.c
new file mode 100644
index 0000000..7048b05
--- /dev/null
+++ b/log.c
@@ -0,0 +1,459 @@
1/*
2 * Copyright (c) 2004 Security Architects Corporation. All rights reserved.
3 *
4 * Module Name:
5 *
6 * log.c
7 *
8 * Abstract:
9 *
10 * This module implements various alert logging routines.
11 *
12 * Author:
13 *
14 * Eugene Tsyrklevich 24-Mar-2004
15 *
16 * Revision History:
17 *
18 * None.
19 */
20
21
22#include "log.h"
23#include "procname.h"
24#include "policy.h" // CDrive declaration
25
26
27#ifdef ALLOC_PRAGMA
28#pragma alloc_text (INIT, InitLog)
29#pragma alloc_text (PAGE, ShutdownLog)
30#pragma alloc_text (PAGE, LogPostBootup)
31#endif
32
33
34KSPIN_LOCK gLogSpinLock;
35
36PKEVENT LogUserEvent = NULL;
37HANDLE LogUserEventHandle = NULL;
38
39PSECURITY_ALERT LogList = NULL; /* alert queue */
40PSECURITY_ALERT LastAlert = NULL; /* pointer to the last queued alert, used for quick inserts */
41
42USHORT NumberOfAlerts; /* number of queued alerts */
43
44
45
46/*
47 * GetObjectAccessAlertPriority()
48 *
49 * Description:
50 * Figure out a priority for object access alert category.
51 *
52 * Parameters:
53 * AlertSubSystem
54 * Operation
55 * ActionTaken
56 *
57 * Returns:
58 * Chosen priority.
59 */
60
61ALERT_PRIORITY
62GetObjectAccessAlertPriority(UCHAR AlertSubSystem, UCHAR Operation, ACTION_TYPE ActionTaken)
63{
64 switch (AlertSubSystem)
65 {
66 case RULE_FILE:
67 case RULE_DIRECTORY:
68 case RULE_NAMEDPIPE:
69 case RULE_REGISTRY:
70 case RULE_SECTION:
71 case RULE_JOB:
72 case RULE_PORT:
73 case RULE_SYMLINK:
74
75 /* default actions are given low priority */
76 if (ActionTaken & ACTION_DEFAULT)
77 return ALERT_PRIORITY_LOW;
78
79 /* non-read operations are marked medium priority */
80 if (Operation != OP_READ)
81 return ALERT_PRIORITY_MEDIUM;
82
83 /* whilst read operations are marked low priority */
84 return ALERT_PRIORITY_LOW;
85
86
87 /* high priority rules */
88 case RULE_DLL:
89 case RULE_PROCESS:
90 case RULE_DRIVER:
91 case RULE_NETWORK:
92 case RULE_SERVICE:
93
94 return ALERT_PRIORITY_HIGH;
95
96
97 case RULE_TIME:
98 case RULE_TOKEN:
99
100 return ALERT_PRIORITY_MEDIUM;
101
102
103 /* low priority rules */
104 case RULE_MAILSLOT:
105 case RULE_EVENT:
106 case RULE_SEMAPHORE:
107 case RULE_MUTANT:
108 case RULE_DIROBJ:
109 case RULE_ATOM:
110 case RULE_SYSCALL:
111 case RULE_TIMER:
112
113 return ALERT_PRIORITY_LOW;
114
115
116 default:
117 LOG(LOG_SS_MISC, LOG_PRIORITY_DEBUG, ("GetAlertPriority: Unknown alert subsystem %d\n", AlertSubSystem));
118 return ALERT_PRIORITY_MEDIUM;
119 }
120}
121
122
123
124/*
125 * FilterObjectName()
126 *
127 * Description:
128 * .
129 *
130 * Parameters:
131 * .
132 *
133 * Returns:
134 * Nothing.
135 */
136//XXX move elsewhere
137PCHAR
138FilterObjectName(PCHAR ObjectName)
139{
140 if (_strnicmp(ObjectName, "\\??\\PIPE\\", 9) == 0)
141 return ObjectName + 3;
142
143 if (_strnicmp(ObjectName, "\\??\\", 4) == 0)
144 return ObjectName + 4;
145
146 if (_strnicmp(ObjectName, "\\DosDevices\\", 12) == 0)
147 return ObjectName + 12;
148
149 if (_strnicmp(ObjectName, "\\BaseNamedObjects\\", 18) == 0)
150 return ObjectName + 18;
151
152 if (_strnicmp(ObjectName, CDrive, CDriveLength) == 0 && CDriveLength)
153 {
154 /* replace any possible \device\harddiskvolumeX references with a DOS C:\ name */
155 ObjectName[CDriveLength-2] = 'C';
156 ObjectName[CDriveLength-1] = ':';
157
158 ObjectName += CDriveLength - 2;
159 }
160
161
162 return ObjectName;
163}
164
165
166
167/*
168 * LogAlert()
169 *
170 * Description:
171 * .
172 *
173 * Parameters:
174 * .
175 *
176 * Returns:
177 * Nothing.
178 */
179
180VOID
181LogAlert(UCHAR AlertSubSystem, UCHAR OperationType, UCHAR AlertRuleNumber, ACTION_TYPE ActionTaken, ALERT_PRIORITY AlertPriority, PWSTR PolicyFilename, USHORT PolicyLineNumber, PCHAR ObjectName)
182{
183 USHORT Size;
184 PSECURITY_ALERT pAlert;
185 KIRQL irql;
186
187#define NAME_BUFFER_SIZE 256
188 ANSI_STRING asObjectName;
189 UNICODE_STRING usObjectName;
190 WCHAR ProcessName[NAME_BUFFER_SIZE], ObjectNameW[NAME_BUFFER_SIZE] = { 0 };
191 USHORT ObjectNameLength = 0, ProcessNameLength = 0, PolicyNameLength = 0;
192
193/*
194 if (PolicyFilename == NULL)
195 {
196 LOG(LOG_SS_MISC, LOG_PRIORITY_DEBUG, (("LogAlert: NULL PolicyFilename\n"));
197 return;
198 }
199*/
200
201 /* \KnownDlls section rules need to be converted to DLLs */
202 if (AlertSubSystem == RULE_SECTION)
203 {
204 if (_strnicmp(ObjectName, "\\KnownDlls\\", 11) == 0)
205 {
206 ObjectName += 11;
207 AlertSubSystem = RULE_DLL;
208 OperationType = OP_LOAD;
209 }
210 }
211
212
213 if (ObjectName)
214 {
215 ObjectName = FilterObjectName(ObjectName);
216
217 usObjectName.Length = 0;
218 usObjectName.MaximumLength = sizeof(ObjectNameW);
219 usObjectName.Buffer = ObjectNameW;
220
221 RtlInitAnsiString(&asObjectName, ObjectName);
222
223 RtlAnsiStringToUnicodeString(&usObjectName, &asObjectName, FALSE);
224 ObjectNameW[ asObjectName.Length ] = 0;
225 }
226
227
228 wcsncpy(ProcessName, GetCurrentProcessName(), NAME_BUFFER_SIZE - 1);
229 ProcessName[NAME_BUFFER_SIZE - 1] = 0;
230
231
232 /*
233 * extra +1 for ProcessName & PolicyName zero termination
234 * (ObjectName zero is covered by SECURITY_ALERT wchar[1] declaration)
235 */
236
237 if (ObjectName)
238 ObjectNameLength = (USHORT) wcslen(ObjectNameW);
239
240 ProcessNameLength = (USHORT) wcslen(ProcessName);
241
242 if (PolicyFilename)
243 PolicyNameLength = (USHORT) wcslen(PolicyFilename);
244
245 Size = sizeof(SECURITY_ALERT) + (ObjectNameLength + ProcessNameLength + 1 + PolicyNameLength + 1) * sizeof(WCHAR);
246
247
248 if ((pAlert = (PSECURITY_ALERT) GetCurrentUserSid(&Size)) == NULL)
249 {
250 LOG(LOG_SS_MISC, LOG_PRIORITY_DEBUG, ("NULL UserInfo. Security Alert\n"));
251 return;
252 }
253
254
255 pAlert->Next = NULL;
256 pAlert->Size = Size;
257 pAlert->AlertSubsystem = AlertSubSystem;
258 pAlert->AlertType = OperationType;
259 pAlert->AlertRuleNumber = AlertRuleNumber;
260 pAlert->Priority = AlertPriority;
261 pAlert->ObjectNameLength = ObjectNameLength;
262 pAlert->ProcessNameLength = ProcessNameLength;
263 pAlert->PolicyNameLength = PolicyNameLength;
264 pAlert->ProcessId = (ULONG) PsGetCurrentProcessId();
265 pAlert->Action = ActionTaken;
266 pAlert->PolicyLineNumber = PolicyLineNumber;
267
268
269 if (ObjectName)
270 wcscpy(pAlert->ObjectName, ObjectNameW);
271
272 /* process name follows the object name */
273 wcscpy(pAlert->ObjectName + ObjectNameLength + 1, ProcessName);
274
275 /* policy name follows the process name */
276 if (PolicyFilename)
277 wcscpy(pAlert->ObjectName + ObjectNameLength + 1 + ProcessNameLength + 1, PolicyFilename);
278
279 /* save the alert for user agent to pick-up */
280 if (ObjectName)
281 {
282 LOG(LOG_SS_MISC, LOG_PRIORITY_DEBUG, ("%S Alert. Name %S. Object type %d. Alert type %d.\n", ProcessName, pAlert->ObjectName, pAlert->AlertSubsystem, pAlert->AlertType));
283 }
284 else
285 {
286 LOG(LOG_SS_MISC, LOG_PRIORITY_DEBUG, ("%S Alert. Object type %d. Alert type %d.\n", ProcessName, pAlert->AlertSubsystem, pAlert->AlertType));
287 }
288
289
290 KeAcquireSpinLock(&gLogSpinLock, &irql);
291 {
292 /*
293 * Put a ceiling on how many alerts we can queue, otherwise we can run out of memory
294 * if userland service is down
295 */
296
297 if (NumberOfAlerts > MAXIMUM_OUTSTANDING_ALERTS)
298 {
299 LOG(LOG_SS_MISC, LOG_PRIORITY_DEBUG, ("LogAlert: Exceeded maximum number of queued alerts. Dropping.\n"));
300
301 ExFreePoolWithTag(pAlert, _POOL_TAG);
302
303 KeReleaseSpinLock(&gLogSpinLock, irql);
304
305 return;
306 }
307
308 ++NumberOfAlerts;
309
310 /*
311 * Append alerts to the end of the list so that they show up in a proper order when
312 * picked up by the userland service
313 */
314
315 if (LogList == NULL)
316 {
317 /* first alert on the list */
318 LastAlert = LogList = pAlert;
319 }
320 else
321 {
322 LastAlert->Next = pAlert;
323 LastAlert = pAlert;
324 }
325
326// pAlert->Next = LogList;
327// LogList = pAlert;
328 }
329 KeReleaseSpinLock(&gLogSpinLock, irql);
330
331
332 /*
333 * Pulse the event to notify the user agent.
334 * User-mode apps can't reset a kernel mode event, which is why we're pulsing it here.
335 */
336
337 if (LogUserEvent)
338 {
339 KeSetEvent(LogUserEvent, 0, FALSE);
340 KeClearEvent(LogUserEvent);
341 }
342}
343
344
345
346/*
347 * LogPostBootup()
348 *
349 * Description:
350 * Initializes logging related data once computer is done booting up.
351 *
352 * \BaseNamedObjects object directory is not created until the Win32® system initializes.
353 * Therefore, drivers that are loaded at boot time cannot create event objects in their DriverEntry
354 * routines that are visible to user-mode programs.
355 *
356 * Parameters:
357 * None.
358 *
359 * Returns:
360 * TRUE to indicate success, FALSE if failed.
361 */
362
363BOOLEAN
364LogPostBootup()
365{
366 UNICODE_STRING uszLogEventString;
367
368
369 ASSERT(BootingUp == FALSE);
370
371
372 /* Create events for user-mode processes to monitor */
373 RtlInitUnicodeString(&uszLogEventString, LOG_USER_EVENT_NAME);
374
375
376 if ((LogUserEvent = IoCreateNotificationEvent(&uszLogEventString, &LogUserEventHandle)) == NULL)
377 {
378 LOG(LOG_SS_MISC, LOG_PRIORITY_DEBUG, ("LogPostBootup: IoCreateNotificationEvent failed\n"));
379 return FALSE;
380 }
381
382 KeClearEvent(LogUserEvent);
383
384
385 return TRUE;
386}
387
388
389
390/*
391 * InitLog()
392 *
393 * Description:
394 * Initializes logging related data.
395 *
396 * NOTE: Called once during driver initialization (DriverEntry()).
397 *
398 * Parameters:
399 * None.
400 *
401 * Returns:
402 * TRUE to indicate success, FALSE if failed.
403 */
404
405BOOLEAN
406InitLog()
407{
408 KeInitializeSpinLock(&gLogSpinLock);
409
410
411 if (BootingUp == FALSE)
412
413 return LogPostBootup();
414
415
416 return TRUE;
417}
418
419
420
421/*
422 * ShutdownLog()
423 *
424 * Description:
425 * Clean up the logging subsystem - close all the handles & delete any outstanding alerts.
426 *
427 * NOTE: Called once during driver unload (DriverUnload()).
428 *
429 * Parameters:
430 * None.
431 *
432 * Returns:
433 * Nothing.
434 */
435
436VOID
437ShutdownLog()
438{
439 PSECURITY_ALERT tmp;
440 KIRQL irql;
441
442
443 if (LogUserEventHandle)
444 ZwClose(LogUserEventHandle);
445
446
447 /* XXX logs will need to be flushed to a file and then sent to MC */
448 KeAcquireSpinLock(&gLogSpinLock, &irql);
449 {
450 while (LogList)
451 {
452 tmp = LogList;
453 LogList = LogList->Next;
454
455 ExFreePoolWithTag(tmp, _POOL_TAG);
456 }
457 }
458 KeReleaseSpinLock(&gLogSpinLock, irql);
459}
diff --git a/log.h b/log.h
new file mode 100644
index 0000000..3e5b77e
--- /dev/null
+++ b/log.h
@@ -0,0 +1,236 @@
1/*
2 * Copyright (c) 2004 Security Architects Corporation. All rights reserved.
3 *
4 * Module Name:
5 *
6 * log.h
7 *
8 * Abstract:
9 *
10 * This module defines various macros used for logging.
11 *
12 * Author:
13 *
14 * Eugene Tsyrklevich 17-Mar-2004
15 *
16 * Revision History:
17 *
18 * None.
19 */
20
21
22#ifndef __LOG_H__
23#define __LOG_H__
24
25
26#include <NTDDK.h>
27#include "ntproto.h"
28#include "misc.h"
29
30
31/* maximum number of alerts the kernel will queue */
32#define MAXIMUM_OUTSTANDING_ALERTS 1000
33
34#define LOG_USER_EVENT_NAME L"\\BaseNamedObjects\\OzoneLogEvent"
35
36
37/*
38 * Logging SubSystems
39 */
40
41#define LOG_SS_DRIVER_INTERNAL (1 << 0)
42#define LOG_SS_POLICY (1 << 1)
43#define LOG_SS_POLICY_PARSER (1 << 2)
44#define LOG_SS_FILE (1 << 3)
45#define LOG_SS_DIRECTORY (1 << 3) // same as LOG_SS_FILE, used in HookedNtCreateFile
46#define LOG_SS_SEMAPHORE (1 << 4)
47#define LOG_SS_EVENT (1 << 5)
48#define LOG_SS_SECTION (1 << 6)
49#define LOG_SS_REGISTRY (1 << 7)
50#define LOG_SS_PROCESS (1 << 8)
51#define LOG_SS_HOOKPROC (1 << 9)
52#define LOG_SS_LEARN (1 << 10)
53#define LOG_SS_PATHPROC (1 << 11)
54#define LOG_SS_NETWORK (1 << 12)
55#define LOG_SS_TIME (1 << 13)
56#define LOG_SS_SYSINFO (1 << 14)
57#define LOG_SS_JOB (1 << 15)
58#define LOG_SS_MUTANT (1 << 16)
59#define LOG_SS_PORT (1 << 17)
60#define LOG_SS_SYMLINK (1 << 18)
61#define LOG_SS_TIMER (1 << 19)
62#define LOG_SS_TOKEN (1 << 20)
63#define LOG_SS_NAMEDPIPE (1 << 21)
64#define LOG_SS_MAILSLOT (1 << 22)
65#define LOG_SS_DRIVER (1 << 23)
66#define LOG_SS_DIROBJ (1 << 24)
67#define LOG_SS_ATOM (1 << 25)
68#define LOG_SS_VDM (1 << 26)
69#define LOG_SS_DEBUG (1 << 27)
70#define LOG_SS_DRIVE (1 << 28)
71#define LOG_SS_MISC (1 << 29)
72
73
74/* log the following subsytems */
75
76#define LOG_SUBSYSTEMS (LOG_SS_ATOM | \
77 LOG_SS_DIROBJ | \
78 LOG_SS_DRIVER | \
79 LOG_SS_DRIVER_INTERNAL | \
80 LOG_SS_EVENT | \
81 LOG_SS_FILE | \
82 LOG_SS_HOOKPROC | \
83 LOG_SS_JOB | \
84 LOG_SS_LEARN | \
85 LOG_SS_MAILSLOT | \
86 LOG_SS_MISC | \
87 LOG_SS_MUTANT | \
88 LOG_SS_NAMEDPIPE | \
89 LOG_SS_NETWORK | \
90 LOG_SS_PATHPROC | \
91 LOG_SS_POLICY | \
92 LOG_SS_POLICY_PARSER | \
93 LOG_SS_PORT | \
94 LOG_SS_PROCESS | \
95 LOG_SS_REGISTRY | \
96 LOG_SS_SECTION | \
97 LOG_SS_SEMAPHORE | \
98 LOG_SS_SYMLINK | \
99 LOG_SS_SYSINFO | \
100 LOG_SS_TIME | \
101 LOG_SS_TIMER | \
102 LOG_SS_TOKEN | \
103 LOG_SS_VDM | \
104 LOG_SS_DRIVE | \
105 LOG_SS_DEBUG)
106
107#define LOG_PRIORITY_VERBOSE 1
108#define LOG_PRIORITY_DEBUG 2
109#define LOG_PRIORITY_WARNING 3
110#define LOG_PRIORITY_ERROR 4
111#define LOG_PRIORITY_CRITICAL 5
112
113
114#define MINIMUM_LOGGING_PRIORITY LOG_PRIORITY_DEBUG
115
116
117#define LOG(subsystem, priority, msg) \
118 do { \
119 if (priority >= LOG_PRIORITY_WARNING) { \
120 DbgPrint msg; \
121 } else if (priority > MINIMUM_LOGGING_PRIORITY){\
122 KdPrint(msg); \
123 } else if (subsystem & LOG_SUBSYSTEMS) { \
124 if (priority == MINIMUM_LOGGING_PRIORITY) { \
125 KdPrint(msg); \
126 } \
127 } \
128 } while(0)
129
130
131
132/*
133 * Alert SubSystems (sorted in the same order as RULEs in policy.h)
134 *
135 * We have an alert subsystem for each category of alert that Ozone generates.
136 * (These are mostly the same as RuleTypes plus several extra ones)
137 */
138
139#define ALERT_SS_FILE 0
140#define ALERT_SS_DIRECTORY 1
141#define ALERT_SS_MAILSLOT 2
142#define ALERT_SS_NAMEDPIPE 3
143#define ALERT_SS_REGISTRY 4
144#define ALERT_SS_SECTION 5
145#define ALERT_SS_DLL 6
146#define ALERT_SS_EVENT 7
147#define ALERT_SS_SEMAPHORE 8
148#define ALERT_SS_JOB 9
149#define ALERT_SS_MUTANT 10
150#define ALERT_SS_PORT 11
151#define ALERT_SS_SYMLINK 12
152#define ALERT_SS_TIMER 13
153#define ALERT_SS_PROCESS 14
154#define ALERT_SS_DRIVER 15
155#define ALERT_SS_DIROBJ 16
156#define ALERT_SS_ATOM 17
157
158#define ALERT_SS_NETWORK 18
159#define ALERT_SS_SERVICE 19
160#define ALERT_SS_TIME 20
161#define ALERT_SS_TOKEN 21
162#define ALERT_SS_SYSCALL 22
163#define ALERT_SS_VDM 23
164#define ALERT_SS_DEBUG 24
165#define ALERT_SS_BOPROT 25
166
167
168/*
169 * Alert Rules
170 */
171
172#define ALERT_RULE_NONE 0
173
174#define ALERT_RULE_PROCESS_EXEC_2EXTS 1 // Executing a binary with more than one extension
175#define ALERT_RULE_PROCESS_EXEC_UNKNOWN 2 // Executing a binary with an unknown extension
176#define ALERT_RULE_PROCESS_EXEC_NOEXT 3 // Executing binary without an extension
177
178#define ALERT_RULE_BOPROT_INVALIDCALL 1 // System call originating directly from user code
179
180
181/* defined in policy.h */
182typedef unsigned char ACTION_TYPE;
183typedef struct _POLICY_RULE POLICY_RULE, *PPOLICY_RULE;
184typedef enum _AlertPriority ALERT_PRIORITY;
185
186
187#pragma pack(push, 1)
188typedef struct _SECURITY_ALERT
189{
190 struct _SECURITY_ALERT *Next;
191
192 /* size of the entire alert = sizeof(SECURITY_ALERT) + strlen(ObjectName) + sizeof(SID) */
193 USHORT Size;
194 UCHAR AlertSubsystem;
195 UCHAR AlertType;
196 UCHAR AlertRuleNumber;
197 UCHAR/*ALERT_PRIORITY*/ Priority;
198 UCHAR/*ACTION_TYPE*/ Action; /* UINT8 Action that was taken (denied, logged) */
199 ULONG ProcessId;
200 USHORT ObjectNameLength;
201 USHORT ProcessNameLength;
202 USHORT PolicyNameLength;
203 USHORT PolicyLineNumber;
204
205 /* space for ObjectName, ProcessName, PolicyName and SID are dynamically allocated */
206 WCHAR ObjectName[ANYSIZE_ARRAY];
207
208 /* ProcessName follows the zero-terminated ObjectName */
209// WCHAR ProcessName[ANYSIZE_ARRAY];
210
211 /* PolicyName follows the zero-terminated ProcessName */
212// WCHAR PolicyName[ANYSIZE_ARRAY];
213
214 /* SID follows the zero-terminated PolicyName */
215// SID_AND_ATTRIBUTES UserInfo;
216
217} SECURITY_ALERT, *PSECURITY_ALERT;
218#pragma pack(pop)
219
220
221extern KSPIN_LOCK gLogSpinLock;
222extern PSECURITY_ALERT LogList;
223extern PSECURITY_ALERT LastAlert;
224extern USHORT NumberOfAlerts;
225
226
227BOOLEAN InitLog();
228VOID ShutdownLog();
229VOID LogAlert(UCHAR AlertSubSystem, UCHAR OperationType, UCHAR AlertRuleNumber, ACTION_TYPE ActionTaken, ALERT_PRIORITY AlertPriority, PWSTR PolicyFilename, USHORT PolicyLineNumber, PCHAR ObjectName);
230ALERT_PRIORITY GetObjectAccessAlertPriority(UCHAR AlertSubSystem, UCHAR Operation, ACTION_TYPE ActionTaken);
231BOOLEAN LogPostBootup();
232
233PCHAR FilterObjectName(PCHAR ObjectName);
234
235
236#endif /* __LOG_H__ */
diff --git a/media.c b/media.c
new file mode 100644
index 0000000..813bf71
--- /dev/null
+++ b/media.c
@@ -0,0 +1,444 @@
1/*
2 * Copyright (c) 2004 Security Architects Corporation. All rights reserved.
3 *
4 * Module Name:
5 *
6 * media.c
7 *
8 * Abstract:
9 *
10 * This module deals with removable media drives. Removable media drives can be made read-only
11 * or disabled altogether.
12 *
13 * Addition of removable drives is detected by monitoring the creation new drive symbolic links.
14 * Drive removal is detected by receiving Plug-and-Play notification.
15 *
16 * Note: Plug-and-Play notifications are not used to detect addition of removable drives since
17 * drive letters are not yet assigned when notifications arrive.
18 *
19 * Author:
20 *
21 * Eugene Tsyrklevich 02-Jun-2004
22 */
23
24
25#include <NTDDK.h>
26
27#undef DEFINE_GUID
28#define DEFINE_GUID(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) const GUID name \
29 = { l, w1, w2, { b1, b2, b3, b4, b5, b6, b7, b8 } }
30
31#include <ntddstor.h>
32#include <wdmguid.h>
33#include "media.h"
34#include "pathproc.h"
35#include "policy.h"
36
37
38#ifdef ALLOC_PRAGMA
39#pragma alloc_text (INIT, InitRemovableMediaHooks)
40#pragma alloc_text (PAGE, RemoveRemovableMediaHooks)
41#endif
42
43
44//XXX investigate IoRegisterFsRegistrationChange
45//reference: www.pulsetrainsw.com/articlesitem.asp?id=3
46
47PVOID DiskNotificationEntry = NULL, CdromNotificationEntry = NULL;
48
49/* removable media flags defined in drive.h (READONLY, etc) */
50UCHAR MediaRemovableFlags = 0;
51
52
53typedef struct _WORK_CONTEXT
54{
55 PIO_WORKITEM Item;
56 UNICODE_STRING SymbolicLinkName;
57
58} WORK_CONTEXT, *PWORK_CONTEXT;
59
60
61
62/*
63 * AddDrive()
64 *
65 * Description:
66 * Create policy access rules for removable drives as they are added at runtime.
67 *
68 * Parameters:
69 * pusDriveName - .
70 * DriveLetter - Letter of the drive being added.
71 *
72 * Returns:
73 * Nothing.
74 */
75
76VOID
77AddDrive(PUNICODE_STRING pusDriveName, CHAR DriveLetter)
78{
79 PDEVICE_OBJECT pDeviceObject;
80 PFILE_OBJECT fo;
81 NTSTATUS rc;
82
83
84 rc = IoGetDeviceObjectPointer(pusDriveName, FILE_READ_ATTRIBUTES, &fo, &pDeviceObject);
85 if (! NT_SUCCESS(rc))
86 {
87 LOG(LOG_SS_DRIVE, LOG_PRIORITY_VERBOSE, ("AddDrive: IoGetDeviceObjectPointer failed with status %x\n", rc));
88 return;
89 }
90
91
92 LOG(LOG_SS_DRIVE, LOG_PRIORITY_DEBUG, ("AddDrive(%S): %d\n", pusDriveName->Buffer, pDeviceObject->Characteristics));
93
94
95 if (pDeviceObject->Characteristics & FILE_REMOVABLE_MEDIA)
96 {
97 CHAR rule[MAX_PATH];
98
99
100 LOG(LOG_SS_DRIVE, LOG_PRIORITY_DEBUG, ("AddDrive: removable drive! %c: %S\n", DriveLetter, pusDriveName->Buffer));
101
102
103 /* Create a new global policy rule */
104
105 if (IS_REMOVABLE_MEDIA_DISABLED())
106 {
107 sprintf(rule, "name match \"%c:\\*\" then %s", DriveLetter, "deny");
108
109 PolicyParseObjectRule(&gSecPolicy, RULE_FILE, "all", rule);
110
111 /* no need to process other rules, this one denies everything already */
112 return;
113 }
114
115 if (IS_REMOVABLE_MEDIA_READONLY() /*&& !(pDeviceObject->Characteristics & FILE_READ_ONLY_DEVICE)*/)
116 {
117 sprintf(rule, "name match \"%c:\\*\" then %s", DriveLetter, "deny");
118
119 PolicyParseObjectRule(&gSecPolicy, RULE_FILE, "write", rule);
120 }
121
122 if (IS_REMOVABLE_MEDIA_NOEXECUTE())
123 {
124 sprintf(rule, "name match \"%c:\\*\" then %s", DriveLetter, "deny");
125
126 PolicyParseObjectRule(&gSecPolicy, RULE_FILE, "execute", rule);
127 }
128 }
129
130
131 return;
132}
133
134
135
136/*
137 * RemoveDrive()
138 *
139 * Description:
140 * .
141 *
142 * Parameters:
143 * pusDriveName - .
144 *
145 * Returns:
146 * Nothing.
147 */
148
149VOID
150RemoveDrive(PUNICODE_STRING pusDriveName)
151{
152 PDEVICE_OBJECT pDeviceObject;
153 PFILE_OBJECT fo;
154 NTSTATUS rc;
155
156
157 rc = IoGetDeviceObjectPointer(pusDriveName, FILE_READ_ATTRIBUTES, &fo, &pDeviceObject);
158 if (! NT_SUCCESS(rc))
159 {
160 LOG(LOG_SS_DRIVE, LOG_PRIORITY_DEBUG, ("RemoveDrive: IoGetDeviceObjectPointer failed with status %x\n", rc));
161 return;
162 }
163
164
165 if (pDeviceObject->Characteristics & FILE_REMOVABLE_MEDIA)
166 LOG(LOG_SS_DRIVE, LOG_PRIORITY_DEBUG, ("RemoveDrive: removable drive! %S\n", pusDriveName->Buffer));
167
168
169// rc = RtlVolumeDeviceToDosName(pDeviceObject, pusDriveName);
170// if (NT_SUCCESS(rc))
171// LOG(LOG_SS_DRIVE, LOG_PRIORITY_DEBUG, ("RemoveDrive: IoVolumeDeviceToDosName returned %S\n", pusDriveName->Buffer));
172}
173
174
175
176/*
177 * MonitorDriveLinks()
178 *
179 * Description:
180 * This routine is called from HookedNtCreateSymbolicLinkObject whenever a new symbolic link is created.
181 * ProcessDriveLink is responsible for monitoring the creation of any new media drives. When a new removable
182 * media drive is added to a system, a new symbolic link "\GLOBAL??\X:" is created (where X is the
183 * assigned drive letter).
184 *
185 * Note: We are not interested in creation of "fake" drives (i.e. subst c: z:\) since those will be
186 * correctly resolved by symbolic link name resolution code (policy enforcement). "Fake" drives
187 * are added in userland and come up as "\??\X:".
188 *
189 * Parameters:
190 * Link - created symbolic link name.
191 *
192 * Returns:
193 * Nothing.
194 */
195
196VOID
197MonitorDriveLinks(const PCHAR Link)
198{
199 CHAR DriveLetter;
200 ANSI_STRING AnsiString;
201 UNICODE_STRING UnicodeString;
202 int len = strlen(Link);
203
204
205 /* match \GLOBAL??\Z: && \??\Z: drive references */
206 if (len == 12 && (strncmp(Link, "\\GLOBAL??\\", 10) == 0) && isalpha(Link[10]) && Link[11] == ':')
207 {
208 LOG(LOG_SS_DRIVE, LOG_PRIORITY_DEBUG, ("MonitorDriveLinks: matched \\global??\\. letter %c\n", Link[10]));
209
210 DriveLetter = Link[10];
211 }
212 else if (len == 6 && (strncmp(Link, "\\??\\", 4) == 0) && isalpha(Link[4]) && Link[5] == ':')
213 {
214 LOG(LOG_SS_DRIVE, LOG_PRIORITY_DEBUG, ("MonitorDriveLinks: matched \\??\\. letter %c\n", Link[4]));
215
216 DriveLetter = Link[4];
217 }
218 else
219 {
220 return;
221 }
222
223
224 RtlInitAnsiString(&AnsiString, Link);
225
226 if (NT_SUCCESS(RtlAnsiStringToUnicodeString(&UnicodeString, &AnsiString, TRUE)))
227 {
228 AddDrive(&UnicodeString, DriveLetter);
229
230 RtlFreeUnicodeString(&UnicodeString);
231 }
232 else
233 {
234 LOG(LOG_SS_DRIVE, LOG_PRIORITY_DEBUG, ("MonitorDriveLinks: failed to convert %s\n", Link));
235 }
236}
237
238
239
240/*
241 * PnpWorker()
242 *
243 * Description:
244 * A work item routine that runs at PASSIVE_LEVEL irql. The routine is scheduled by PnpCallback
245 * which is not allowed to block.
246 *
247 * PnpWorker calls RemoveDrive() with a drive name setup by PnpCallback.
248 *
249 * Parameters:
250 * pDeviceObject - .
251 * Context - .
252 *
253 * Returns:
254 * Nothing.
255 */
256
257VOID
258PnpWorker(IN PDEVICE_OBJECT pDeviceObject, IN PVOID Context)
259{
260 PWORK_CONTEXT WorkContext = (PWORK_CONTEXT) Context;
261
262
263 if (WorkContext == NULL)
264 {
265 LOG(LOG_SS_DRIVE, LOG_PRIORITY_DEBUG, ("PnpWorker: WorkContext = NULL\n"));
266 return;
267 }
268
269 LOG(LOG_SS_DRIVE, LOG_PRIORITY_DEBUG, ("PnpWorker: %S\n", WorkContext->SymbolicLinkName.Buffer));
270
271
272 RemoveDrive(&WorkContext->SymbolicLinkName);
273
274
275 IoFreeWorkItem(WorkContext->Item);
276
277 ExFreePoolWithTag(WorkContext, _POOL_TAG);
278}
279
280
281
282/*
283 * PnpCallback()
284 *
285 * Description:
286 * Plug-and-Play callback. Gets called when a p-n-p drive/cdrom interface is modified
287 * (i.e. when a removable drive is added or removed from the system).
288 *
289 * Parameters:
290 * NotificationStructure - DEVICE_INTERFACE_CHANGE_NOTIFICATION indicating which interface changed.
291 * Context - the driver's device context.
292 *
293 * Returns:
294 * STATUS_SUCCESS.
295 */
296
297NTSTATUS
298PnpCallback(IN PVOID NotificationStructure, IN PVOID Context)
299{
300 PDEVICE_INTERFACE_CHANGE_NOTIFICATION Notify = (PDEVICE_INTERFACE_CHANGE_NOTIFICATION) NotificationStructure;
301 PDEVICE_OBJECT pDeviceObject = (PDEVICE_OBJECT) Context;
302 PIO_WORKITEM WorkItem;
303 PWORK_CONTEXT WorkContext;
304
305
306 if (IsEqualGUID((LPGUID) &Notify->Event, (LPGUID) &GUID_DEVICE_INTERFACE_REMOVAL))
307 {
308 LOG(LOG_SS_DRIVE, LOG_PRIORITY_DEBUG, ("GUID_DEVICE_INTERFACE_REMOVAL %S\n", Notify->SymbolicLinkName->Buffer));
309/*
310 }
311
312
313 if (IsEqualGUID((LPGUID) &Notify->Event, (LPGUID) &GUID_DEVICE_INTERFACE_ARRIVAL) ||
314 IsEqualGUID((LPGUID) &Notify->Event, (LPGUID) &GUID_DEVICE_INTERFACE_REMOVAL))
315 {
316 LOG(LOG_SS_DRIVE, LOG_PRIORITY_DEBUG, ("GUID_DEVICE_INTERFACE_ARRIVAL %x %S\n", Notify->SymbolicLinkName, Notify->SymbolicLinkName->Buffer));
317*/
318
319 /*
320 * Schedule a work item to process this request. Cannot block in this callback function.
321 */
322
323 WorkItem = IoAllocateWorkItem(pDeviceObject);
324
325 WorkContext = (PWORK_CONTEXT) ExAllocatePoolWithTag(PagedPool,
326 sizeof(WORK_CONTEXT) + Notify->SymbolicLinkName->Length,
327 _POOL_TAG);
328 if (!WorkContext)
329 {
330 IoFreeWorkItem(WorkItem);
331 return(STATUS_SUCCESS);
332 }
333
334 WorkContext->SymbolicLinkName.Buffer = (PWSTR) ((PCHAR) &WorkContext->SymbolicLinkName + sizeof(UNICODE_STRING));
335 WorkContext->SymbolicLinkName.MaximumLength = Notify->SymbolicLinkName->Length;
336 WorkContext->SymbolicLinkName.Length = 0;
337
338 WorkContext->Item = WorkItem;
339 RtlCopyUnicodeString(&WorkContext->SymbolicLinkName, Notify->SymbolicLinkName);
340
341 IoQueueWorkItem(WorkItem, PnpWorker, DelayedWorkQueue, WorkContext);
342 }
343
344
345 return STATUS_SUCCESS;
346}
347
348
349
350/*
351 * InitRemovableMediaHooks()
352 *
353 * Description:
354 * Process any existing drives and register Plug-and-Play notifications for future drive additions/removals.
355 *
356 * NOTE: Called once during driver initialization (DriverEntry()).
357 *
358 * Parameters:
359 * None.
360 *
361 * Returns:
362 * TRUE to indicate success, FALSE if failed.
363 */
364
365BOOLEAN
366InitRemovableMediaHooks(IN PDRIVER_OBJECT pDriverObject, IN PDEVICE_OBJECT pDeviceObject)
367{
368 UNICODE_STRING Name;
369 WCHAR Buffer[MAX_PATH] = L"\\??\\A:";
370 NTSTATUS rc;
371 HANDLE hLink;
372 OBJECT_ATTRIBUTES oa;
373 char DriveLetter;
374
375
376 for (DriveLetter = 'A'; DriveLetter <= 'Z'; DriveLetter++)
377 {
378 Buffer[4] = DriveLetter;
379
380 RtlInitUnicodeString(&Name, Buffer);
381
382 AddDrive(&Name, DriveLetter);
383 }
384
385
386 rc = IoRegisterPlugPlayNotification(EventCategoryDeviceInterfaceChange,
387 0,//PNPNOTIFY_DEVICE_INTERFACE_INCLUDE_EXISTING_INTERFACES,
388 (LPGUID) &GUID_DEVINTERFACE_DISK,
389 pDriverObject,
390 PnpCallback,
391 pDeviceObject,
392 &DiskNotificationEntry);
393
394 if (! NT_SUCCESS(rc))
395 {
396 LOG(LOG_SS_DRIVE, LOG_PRIORITY_DEBUG, ("InitRemovableMediaHooks: IoRegisterPlugPlayNotification failed with status %x\n", rc));
397 return FALSE;
398 }
399
400
401 rc = IoRegisterPlugPlayNotification(EventCategoryDeviceInterfaceChange,
402 0,//PNPNOTIFY_DEVICE_INTERFACE_INCLUDE_EXISTING_INTERFACES,
403 (LPGUID) &GUID_DEVINTERFACE_CDROM,
404 pDriverObject,
405 PnpCallback,
406 pDeviceObject,
407 &CdromNotificationEntry);
408
409 if (! NT_SUCCESS(rc))
410 {
411 LOG(LOG_SS_DRIVE, LOG_PRIORITY_DEBUG, ("InitRemovableMediaHooks: IoRegisterPlugPlayNotification2 failed with status %x\n", rc));
412 return FALSE;
413 }
414
415
416 return TRUE;
417}
418
419
420
421/*
422 * RemoveRemovableMediaHooks()
423 *
424 * Description:
425 * Unregister Plug-and-Play notifications.
426 *
427 * Parameters:
428 * None.
429 *
430 * Returns:
431 * Nothing.
432 */
433
434VOID
435RemoveRemovableMediaHooks()
436{
437 if (DiskNotificationEntry)
438 if (! NT_SUCCESS(IoUnregisterPlugPlayNotification(DiskNotificationEntry)))
439 LOG(LOG_SS_DRIVE, LOG_PRIORITY_DEBUG, ("RemoveRemovableMediaHooks: IoUnregisterPlugPlayNotification failed\n"));
440
441 if (CdromNotificationEntry)
442 if (! NT_SUCCESS(IoUnregisterPlugPlayNotification(CdromNotificationEntry)))
443 LOG(LOG_SS_DRIVE, LOG_PRIORITY_DEBUG, ("RemoveRemovableMediaHooks: IoUnregisterPlugPlayNotification2 failed\n"));
444}
diff --git a/media.h b/media.h
new file mode 100644
index 0000000..250510e
--- /dev/null
+++ b/media.h
@@ -0,0 +1,40 @@
1/*
2 * Copyright (c) 2004 Security Architects Corporation. All rights reserved.
3 *
4 * Module Name:
5 *
6 * media.c
7 *
8 * Abstract:
9 *
10 * This module deals with removable media drives.
11 *
12 * Author:
13 *
14 * Eugene Tsyrklevich 02-Jun-2004
15 */
16
17
18#ifndef __MEDIA_H__
19#define __MEDIA_H__
20
21
22#define MEDIA_REMOVABLE_PERMIT 0
23#define MEDIA_REMOVABLE_DISABLE 1
24#define MEDIA_REMOVABLE_READONLY 2
25#define MEDIA_REMOVABLE_NOEXECUTE 4
26
27#define IS_REMOVABLE_MEDIA_READONLY() ((MediaRemovableFlags & MEDIA_REMOVABLE_READONLY) == MEDIA_REMOVABLE_READONLY)
28#define IS_REMOVABLE_MEDIA_DISABLED() ((MediaRemovableFlags & MEDIA_REMOVABLE_DISABLE) == MEDIA_REMOVABLE_DISABLE)
29#define IS_REMOVABLE_MEDIA_NOEXECUTE() ((MediaRemovableFlags & MEDIA_REMOVABLE_NOEXECUTE) == MEDIA_REMOVABLE_NOEXECUTE)
30
31
32extern UCHAR MediaRemovableFlags;
33
34
35BOOLEAN InitRemovableMediaHooks(IN PDRIVER_OBJECT pDriverObject, IN PDEVICE_OBJECT pDeviceObject);
36VOID RemoveRemovableMediaHooks();
37VOID MonitorDriveLinks(const PCHAR Link);
38
39
40#endif /* __MEDIA_H__ */
diff --git a/misc.c b/misc.c
new file mode 100644
index 0000000..1381272
--- /dev/null
+++ b/misc.c
@@ -0,0 +1,943 @@
1/*
2 * Copyright (c) 2004 Security Architects Corporation. All rights reserved.
3 *
4 * Module Name:
5 *
6 * misc.c
7 *
8 * Abstract:
9 *
10 * This module implements various miscellaneous routines.
11 *
12 * Author:
13 *
14 * Eugene Tsyrklevich 24-Feb-2004
15 *
16 * Revision History:
17 *
18 * None.
19 */
20
21
22#include "misc.h"
23#include "process.h"
24#include "userland.h"
25#include "policy.h"
26#include "token.h"
27
28
29BOOLEAN BootingUp = FALSE;
30
31
32/*
33 * atoi()
34 *
35 * Description:
36 * Convert a given string to an integer.
37 *
38 * Parameters:
39 * buf - Pointer to a source character string.
40 *
41 * Returns:
42 * String's integer value (0 in case of an error).
43 */
44
45INT32
46atoi(IN PCHAR buf)
47{
48 int ret = 0;
49
50
51 while (*buf >= '0' && *buf <= '9')
52 {
53 ret *= 10;
54 ret += *buf - '0';
55 buf++;
56 }
57
58
59 return ret;
60}
61
62
63
64/*
65 * itoa()
66 *
67 * Description:
68 * Convert an integer to a string.
69 *
70 * Parameters:
71 * value - Number to be converted.
72 * string - String result.
73 * radix - Base of value; must be in the range 2 – 36.
74 *
75 * Returns:
76 * Pointer to a string.
77 */
78
79PCHAR
80itoa(int value, char *string, unsigned int radix)
81{
82 static const char base36[] = "0123456789abcdefghijklmnopqrstuvwxyz";
83 PCHAR s;
84 int tmp = value;
85 int digits = 1;
86
87
88 ASSERT(radix > 1 && radix < (int) sizeof base36);
89 ASSERT(string);
90 ASSERT(value >= 0);
91
92 while ((tmp /= (int)radix) != 0)
93 ++digits;
94
95 s = string;
96
97 string += digits;
98 *string = '\0';
99
100 do {
101
102 *--string = base36[value % radix];
103
104 } while ((value /= radix) != 0);
105
106
107 return string;
108}
109
110
111
112/*
113 * ntohl()
114 *
115 * Description:
116 * Convert a ULONG from TCP/IP network order to host byte order (which is little-endian on Intel processors).
117 *
118 * Parameters:
119 * netlong - 32-bit number in TCP/IP network byte order.
120 *
121 * Returns:
122 * The value in host byte order.
123 * If the netlong parameter was already in host byte order, then no operation is performed.
124 */
125
126ULONG
127ntohl(IN ULONG netlong)
128{
129 ULONG result = 0;
130
131 ((char *)&result)[0] = ((char *)&netlong)[3];
132 ((char *)&result)[1] = ((char *)&netlong)[2];
133 ((char *)&result)[2] = ((char *)&netlong)[1];
134 ((char *)&result)[3] = ((char *)&netlong)[0];
135
136 return result;
137}
138
139
140
141/*
142 * ntohs()
143 *
144 * Description:
145 * Convert a USHORT from TCP/IP network byte order to host byte order (which is little-endian on Intel processors).
146 *
147 * Parameters:
148 * netshort - 16-bit number in TCP/IP network byte order.
149 *
150 * Returns:
151 * The value in host byte order.
152 * If the netshort parameter was already in host byte order, then no operation is performed.
153 */
154
155USHORT
156ntohs(IN USHORT netshort)
157{
158 USHORT result = 0;
159
160 ((char *)&result)[0] = ((char *)&netshort)[1];
161 ((char *)&result)[1] = ((char *)&netshort)[0];
162
163 return result;
164}
165
166
167/*
168 * htonl()
169 *
170 * Description:
171 * Converts a ULONG from host to TCP/IP network byte order (which is big-endian).
172 *
173 * Parameters:
174 * hostlong - 32-bit number in host byte order.
175 *
176 * Returns:
177 * The value in TCP/IP's network byte order.
178 */
179
180ULONG
181htonl(ULONG hostlong)
182{
183 ULONG r1, r2, r3, r4;
184
185 r1 = (hostlong >> 24);
186 r2 = (hostlong << 24);
187 r3 = (hostlong & 0xff00) << 8;
188 r4 = (hostlong >> 8) & 0xff00;
189
190 return (r1 | r2 | r3 | r4);
191}
192
193
194
195/*
196 * inet_aton()
197 *
198 * Description:
199 * Convert a ULONG from host to TCP/IP network byte order (which is big-endian).
200 *
201 * Parameters:
202 * hostlong - 32-bit number in host byte order.
203 *
204 * Returns:
205 * returns the value in TCP/IP's network byte order.
206 */
207
208#define _islower(c) ( ((c) >= 'a' && (c) <= 'f') )
209#define _isxdigit(c) ( ((c) >= 'a' && (c) <= 'f') || ((c) >= 'A' && (c) <= 'F') )
210#define _isascii(c) ( (c) <= 0177 )
211#define _isdigit(c) ( ((c) >= '0' && (c) <= '9') )
212#define _isspace(c) ( ((c) == ' ' ) )
213
214//XXX verify... can invalid IPs be accepted as valid ones?
215
216
217/*
218 * inet_addr() XXX rewrite
219 *
220 * Description:
221 * Convert a string containing an (IPv4) Internet Protocol dotted address into a ULONG (network order).
222 *
223 * Parameters:
224 * cp - Null-terminated character string representing a number expressed in the Internet
225 * standard ".'' (dotted) notation.
226 *
227 * Returns:
228 * A ULONG value containing a suitable binary representation of the Internet address given.
229 */
230
231ULONG
232inet_addr(PCCHAR cp)
233{
234 ULONG val;
235 int base, n;
236 char c;
237 unsigned int parts[4];
238 unsigned int *pp = parts;
239
240 c = *cp;
241 for (;;) {
242 /*
243 * Collect number up to ``.''.
244 * Values are specified as for C:
245 * 0x=hex, 0=octal, isdigit=decimal.
246 */
247 if (!_isdigit(c))
248 return (0);
249
250 val = 0; base = 10;
251//XXX get rid of multiple base support?
252 if (c == '0') {
253 c = *++cp;
254 if (c == 'x' || c == 'X')
255 base = 16, c = *++cp;
256 else
257 base = 8;
258 }
259
260 for (;;) {
261 if (_isascii(c) && _isdigit(c)) {
262 val = (val * base) + (c - '0');
263 c = *++cp;
264 } else if (base == 16 && _isascii(c) && _isxdigit(c)) {
265 val = (val << 4) |
266 (c + 10 - (_islower(c) ? 'a' : 'A'));
267 c = *++cp;
268 } else
269 break;
270 }
271
272 if (c == '.') {
273 /*
274 * Internet format:
275 * a.b.c.d
276 * a.b.c (with c treated as 16 bits)
277 * a.b (with b treated as 24 bits)
278 */
279 if (pp >= parts + 3)
280 return (0);
281 *pp++ = val;
282 c = *++cp;
283 } else
284 break;
285 }
286 /*
287 * Check for trailing characters.
288 */
289 if (c != '\0' && (!_isascii(c) || !_isspace(c)))
290 return (0);
291 /*
292 * Concoct the address according to
293 * the number of parts specified.
294 */
295 n = pp - parts + 1;
296 switch (n) {
297
298 case 0:
299 return (0); /* initial nondigit */
300
301 case 1: /* a -- 32 bits */
302 break;
303
304 case 2: /* a.b -- 8.24 bits */
305 if (val > 0xffffff)
306 return (0);
307 val |= parts[0] << 24;
308 break;
309
310 case 3: /* a.b.c -- 8.8.16 bits */
311 if (val > 0xffff)
312 return (0);
313 val |= (parts[0] << 24) | (parts[1] << 16);
314 break;
315
316 case 4: /* a.b.c.d -- 8.8.8.8 bits */
317 if (val > 0xff)
318 return (0);
319 val |= (parts[0] << 24) | (parts[1] << 16) | (parts[2] << 8);
320 break;
321 }
322
323 return htonl(val);
324}
325
326
327
328/*
329 * inet_ntoa()
330 *
331 * Description:
332 * Convert an (IPv4) Internet network address into a string in Internet standard dotted format.
333 *
334 * Parameters:
335 * ina - ULONG that represents an Internet host address.
336 *
337 * Returns:
338 * A character pointer to a static buffer containing the text address in standard ".'' notation.
339 */
340
341//XXX not SMP safe
342PCHAR
343inet_ntoa2(ULONG ina)
344{
345 static char buf[4*sizeof "123"];
346 unsigned char *ucp = (unsigned char *)&ina;
347
348 sprintf(buf, "%d.%d.%d.%d",
349 ucp[0] & 0xff,
350 ucp[1] & 0xff,
351 ucp[2] & 0xff,
352 ucp[3] & 0xff);
353
354 return buf;
355}
356
357/* XXX move to netmisc.c or network.c */
358VOID
359inet_ntoa(ULONG ina, PCHAR buf)
360{
361 unsigned char *ucp = (unsigned char *)&ina;
362
363 sprintf(buf, "%d.%d.%d.%d",
364 ucp[0] & 0xff,
365 ucp[1] & 0xff,
366 ucp[2] & 0xff,
367 ucp[3] & 0xff);
368}
369
370
371
372/*
373 * VerifyUnicodeString()
374 *
375 * Description:
376 * Make sure Unicode String buffer is readable.
377 *
378 * Parameters:
379 * InputUnicodeString - input unicode buffer.
380 * OutputUnicodeString - output buffer.
381 *
382 * Returns:
383 * TRUE to indicate success, FALSE is failed.
384 */
385
386#define FINISH_VerifyUnicodeString(msg) \
387 do { \
388 LOG(LOG_SS_MISC, LOG_PRIORITY_DEBUG, msg); \
389 return(FALSE); \
390 } while(0)
391
392BOOLEAN
393VerifyUnicodeString(IN PUNICODE_STRING InputUnicodeString, OUT PUNICODE_STRING OutputUnicodeString)
394{
395 if (! ARGUMENT_PRESENT(InputUnicodeString) )
396
397 FINISH_VerifyUnicodeString(("VerifyUnicodeString: Unicode string is NULL\n"));
398
399
400 /* this code is duplicated in pathproc.c!GetPathFromHandle for efficiency */
401 __try
402 {
403 if (KeGetPreviousMode() != KernelMode)
404 {
405 ProbeForRead(InputUnicodeString, sizeof(UNICODE_STRING), sizeof(ULONG));
406
407 *OutputUnicodeString = ProbeAndReadUnicodeString(InputUnicodeString);
408 }
409 else
410 {
411 *OutputUnicodeString = *InputUnicodeString;
412 }
413
414
415 if (OutputUnicodeString->Length == 0)
416
417 return FALSE;
418
419
420 if (((OutputUnicodeString->Length & (sizeof(WCHAR) - 1)) != 0) ||
421 (OutputUnicodeString->Length > bMAX_PATH - sizeof(WCHAR)) )
422
423 FINISH_VerifyUnicodeString(("VerifyUnicodeString: invalid wchar string length = %d\n", OutputUnicodeString->Length));
424
425
426 if (KeGetPreviousMode() != KernelMode)
427
428 ProbeForRead(OutputUnicodeString->Buffer, OutputUnicodeString->Length, sizeof(WCHAR));
429 }
430
431 __except(EXCEPTION_EXECUTE_HANDLER)
432 {
433 NTSTATUS status = GetExceptionCode();
434
435 LOG(LOG_SS_MISC, LOG_PRIORITY_DEBUG, ("VerifyUnicodeString: caught an exception. status = 0x%x\n", status));
436
437 return(FALSE);
438 }
439
440 return(TRUE);
441}
442
443
444
445/*
446 * VerifyPwstr()
447 *
448 * Description:
449 * Make sure PWSTR buffer is readable.
450 *
451 * Parameters:
452 * InputString - input PWSTR buffer.
453 * InputStringLength - input string length.
454 *
455 * Returns:
456 * TRUE to indicate success, FALSE is failed.
457 */
458
459#define FINISH_VerifyPwstr(msg) \
460 do { \
461 LOG(LOG_SS_MISC, LOG_PRIORITY_DEBUG, msg); \
462 return(FALSE); \
463 } while(0)
464
465BOOLEAN
466VerifyPwstr(IN PWSTR InputString, IN ULONG InputStringLength)
467{
468 if (! ARGUMENT_PRESENT(InputString) )
469
470 FINISH_VerifyPwstr(("VerifyPwstr: Input string is NULL\n"));
471
472
473 if ((InputStringLength == 0) ||
474 ((InputStringLength & (sizeof(WCHAR) - 1)) != 0) ||
475 (InputStringLength > bMAX_PATH - sizeof(WCHAR)) )
476
477 FINISH_VerifyPwstr(("VerifyPwstr: invalid wchar string length = %d\n", InputStringLength));
478
479
480 if (KeGetPreviousMode() != KernelMode)
481 {
482 __try
483 {
484 ProbeForRead(InputString, InputStringLength, sizeof(WCHAR));
485 }
486
487 __except(EXCEPTION_EXECUTE_HANDLER)
488 {
489 NTSTATUS status = GetExceptionCode();
490
491 LOG(LOG_SS_MISC, LOG_PRIORITY_DEBUG, ("VerifyPwstr: caught an exception. address=%x, status = 0x%x\n", InputString, status));
492
493 return(FALSE);
494 }
495 }
496
497
498 return(TRUE);
499}
500
501
502
503/*
504 * ReadStringRegistryValue()
505 *
506 * Description:
507 * .
508 *
509 * Parameters:
510 * .
511 *
512 * Returns:
513 * TRUE to indicate success, FALSE is failed.
514 */
515
516#define FINISH_ReadStringRegistryValue(msg) \
517 do { \
518 LOG(LOG_SS_MISC, LOG_PRIORITY_DEBUG, msg); \
519 if (vpip) ExFreePoolWithTag(vpip, _POOL_TAG); \
520 if (hKey) ZwClose(hKey); \
521 return(NULL); \
522 } while(0)
523
524PKEY_VALUE_PARTIAL_INFORMATION
525ReadStringRegistryValue(IN PWSTR RegistryPath, IN PWSTR KeyName, OUT ULONG *VPIPSize)
526{
527 OBJECT_ATTRIBUTES oa;
528 HANDLE hKey = 0;
529 UNICODE_STRING usRegistryPath, usKeyName;
530 ULONG size;
531 NTSTATUS status;
532 PKEY_VALUE_PARTIAL_INFORMATION vpip = NULL;
533 PCHAR FunctionName = "ReadStringRegistryValue";
534
535
536 if (RegistryPath == NULL || KeyName == NULL)
537
538 FINISH_ReadStringRegistryValue(("%s: Received NULL parameter. %x %x\n", RegistryPath, KeyName));
539
540
541 RtlInitUnicodeString(&usRegistryPath, RegistryPath);
542
543 InitializeObjectAttributes(&oa, &usRegistryPath, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL);
544
545 status = ZwOpenKey(&hKey, KEY_QUERY_VALUE , &oa);
546 if (! NT_SUCCESS(status))
547
548 FINISH_ReadStringRegistryValue(("%s: ZwOpenKey('%S') failed with status=%x\n", FunctionName, RegistryPath, status));
549
550
551 RtlInitUnicodeString(&usKeyName, KeyName);
552
553 status = ZwQueryValueKey(hKey, &usKeyName, KeyValuePartialInformation, NULL, 0, &size);
554 if (status == STATUS_OBJECT_NAME_NOT_FOUND || size == 0)
555
556 FINISH_ReadStringRegistryValue(("%s: ZwQueryValueKey(%S) failed with status=%x\n", FunctionName, KeyName, status));
557
558
559 vpip = (PKEY_VALUE_PARTIAL_INFORMATION) ExAllocatePoolWithTag(PagedPool, size, _POOL_TAG);
560
561 if (!vpip)
562
563 FINISH_ReadStringRegistryValue(("%s: out of memory\n", FunctionName));
564
565
566 status = ZwQueryValueKey(hKey, &usKeyName, KeyValuePartialInformation, vpip, size, &size);
567 if (! NT_SUCCESS(status))
568
569 FINISH_ReadStringRegistryValue(("%s: ZwQueryValueKey2(%S) failed with status=%x\n", FunctionName, KeyName, status));
570
571
572 if (vpip->Type != REG_SZ)
573
574 FINISH_ReadStringRegistryValue(("%s: Wrong Type: %x\n", FunctionName, vpip->Type));
575
576
577 ZwClose(hKey);
578
579
580 *VPIPSize = size;
581
582
583 return vpip;
584}
585
586
587
588/*
589 * ReadStringRegistryValueA()
590 *
591 * Description:
592 * Read an ASCII value from the registry.
593 *
594 * Parameters:
595 * .
596 *
597 * Returns:
598 * TRUE to indicate success, FALSE is failed.
599 */
600
601BOOLEAN
602ReadStringRegistryValueA(IN PWSTR RegistryPath, IN PWSTR KeyName, OUT PCHAR Buffer, IN USHORT BufferSize)
603{
604 PKEY_VALUE_PARTIAL_INFORMATION vpip;
605 ULONG size;
606
607
608 ASSERT(Buffer);
609
610
611 if ((vpip = ReadStringRegistryValue(RegistryPath, KeyName, &size)) == NULL)
612 return FALSE;
613
614
615 if (_snprintf(Buffer, BufferSize, "%S", (PWSTR) &vpip->Data) < 0)
616 {
617 LOG(LOG_SS_MISC, LOG_PRIORITY_DEBUG, ("%s: Buffer is too small %d vs %d\n", BufferSize, size));
618 ExFreePoolWithTag(vpip, _POOL_TAG);
619 return FALSE;
620 }
621 Buffer[BufferSize - 1] = 0;
622
623
624 ExFreePoolWithTag(vpip, _POOL_TAG);
625
626
627 return TRUE;
628}
629
630
631
632/*
633 * ReadStringRegistryValueW()
634 *
635 * Description:
636 * Read a UNICODE value from the registry.
637 *
638 * Parameters:
639 * .
640 *
641 * Returns:
642 * TRUE to indicate success, FALSE is failed.
643 */
644
645BOOLEAN
646ReadStringRegistryValueW(IN PWSTR RegistryPath, IN PWSTR KeyName, OUT PWSTR Buffer, IN USHORT BufferSize)
647{
648 PKEY_VALUE_PARTIAL_INFORMATION vpip;
649 ULONG size;
650
651
652 ASSERT(Buffer);
653
654
655 if ((vpip = ReadStringRegistryValue(RegistryPath, KeyName, &size)) == NULL)
656 return FALSE;
657
658
659 if ((size - sizeof(KEY_VALUE_PARTIAL_INFORMATION)) + 1 > BufferSize)
660 {
661 LOG(LOG_SS_MISC, LOG_PRIORITY_DEBUG, ("%s: Buffer is too small %d vs %d\n", BufferSize, size));
662 ExFreePoolWithTag(vpip, _POOL_TAG);
663 return FALSE;
664 }
665
666 wcsncpy(Buffer, (PWSTR) vpip->Data, BufferSize);
667 Buffer[BufferSize - 1] = 0;
668
669
670 ExFreePoolWithTag(vpip, _POOL_TAG);
671
672
673 return TRUE;
674}
675
676
677
678/*
679 * ReadSymlinkValue()
680 *
681 * Description:
682 * .
683 *
684 * Parameters:
685 * .
686 *
687 * Returns:
688 * TRUE to indicate success, FALSE is failed.
689 */
690
691#define FINISH_ReadSymlinkValue(msg) \
692 do { \
693 LOG(LOG_SS_MISC, LOG_PRIORITY_DEBUG, msg); \
694 if (hLink) ZwClose(hLink); \
695 return(FALSE); \
696 } while(0)
697
698BOOLEAN
699ReadSymlinkValue(IN PWSTR SymlinkPath, OUT PCHAR Buffer, IN USHORT BufferSize)
700{
701 OBJECT_ATTRIBUTES oa;
702 HANDLE hLink = 0;
703 UNICODE_STRING usLink;
704 ANSI_STRING asLink;
705 WCHAR Link[MAX_PATH];
706 ULONG size;
707 NTSTATUS status;
708
709
710 RtlInitUnicodeString(&usLink, SymlinkPath);
711 InitializeObjectAttributes(&oa, &usLink, OBJ_CASE_INSENSITIVE|OBJ_KERNEL_HANDLE, NULL, NULL);
712
713 status = ZwOpenSymbolicLinkObject(&hLink, GENERIC_READ, &oa);
714 if (! NT_SUCCESS(status))
715
716 FINISH_ReadSymlinkValue(("ReadSymlinkValue: Unable to open '%S' link. status=%x\n", SymlinkPath, status));
717
718
719 usLink.Buffer = Link;
720 usLink.MaximumLength = bMAX_PATH;
721 usLink.Length = 0;
722
723 status = ZwQuerySymbolicLinkObject(hLink, &usLink, NULL);
724 if (! NT_SUCCESS(status))
725
726 FINISH_ReadSymlinkValue(("ReadSymlinkValue: Unable to query SystemRoot link. status=%x\n", status));
727
728
729 asLink.Length = 0;
730 asLink.MaximumLength = BufferSize;
731 asLink.Buffer = Buffer;
732
733 RtlUnicodeStringToAnsiString(&asLink, &usLink, FALSE);
734 asLink.Buffer[asLink.Length] = '\0';
735
736
737 ZwClose(hLink);
738
739 return TRUE;
740}
741
742
743
744/*
745 * RunPostBootup()
746 *
747 * Description:
748 * Initializes any subsystems that require to be initialized after the system finished booting up.
749 *
750 * Parameters:
751 * None.
752 *
753 * Returns:
754 * Nothing.
755 */
756
757VOID
758InitPostBootup()
759{
760 ASSERT(BootingUp == FALSE);
761
762 ProcessPostBootup();
763 LogPostBootup();
764 PolicyPostBootup();
765 UserlandPostBootup();
766}
767
768
769
770/*
771 * GetCurrentUserSid()
772 *
773 * Description:
774 * Retrieves current user's SID.
775 *
776 * Parameters:
777 * Size - Extra number of bytes to allocate [IN]. Total number of bytes allocated [OUT].
778 *
779 * Returns:
780 * Pointer to an allocated memory block, the actual SID is at offset +Size.
781 * NULL is failed.
782 */
783
784typedef struct _TOKEN_GROUPS {
785 DWORD GroupCount;
786 SID_AND_ATTRIBUTES Groups[ANYSIZE_ARRAY];
787} TOKEN_GROUPS, *PTOKEN_GROUPS;
788
789PCHAR
790GetCurrentUserSid(PUSHORT Size) // IN OUT
791{
792 HANDLE TokenHandle;
793 NTSTATUS status;
794 ULONG TokenSize, tmp;
795 PCHAR UserInfo;
796 PSID_AND_ATTRIBUTES psa;
797// PTOKEN_GROUPS ptg;
798// PSID ps;
799
800
801 status = ZwOpenThreadToken(CURRENT_THREAD, TOKEN_QUERY, FALSE, &TokenHandle);
802
803 if (! NT_SUCCESS(status))
804 {
805 if (status != STATUS_NO_TOKEN)
806 {
807 LOG(LOG_SS_MISC, LOG_PRIORITY_DEBUG, ("%d GetCurrentUserSid: ZwOpenThreadToken failed with status %x\n", status));
808 return NULL;
809 }
810
811 status = ZwOpenProcessToken(CURRENT_PROCESS, TOKEN_QUERY, &TokenHandle);
812
813 if (! NT_SUCCESS(status))
814 {
815 LOG(LOG_SS_MISC, LOG_PRIORITY_DEBUG, ("%d GetCurrentUserSid: ZwOpenProcessToken failed with status %x\n", status));
816 return NULL;
817 }
818 }
819
820
821 /* first, find out the total amount of token information to be returned */
822
823 status = ZwQueryInformationToken(TokenHandle, TokenUser, &TokenSize, 0, &TokenSize);
824// status = ZwQueryInformationToken(TokenHandle, TokenGroups, &TokenSize, 0, &TokenSize);
825// status = ZwQueryInformationToken(TokenHandle, TokenPrimaryGroup, &TokenSize, 0, &TokenSize);
826 if (status != STATUS_BUFFER_TOO_SMALL || TokenSize == 0)
827 {
828 LOG(LOG_SS_MISC, LOG_PRIORITY_DEBUG, ("GetCurrentUserSid: ZwQueryInformationToken failed. status=%x size=%d\n", status, TokenSize));
829 return NULL;
830 }
831
832
833 /* second, allocate the required amount of memory */
834
835 UserInfo = ExAllocatePoolWithTag(NonPagedPool, TokenSize + *Size, _POOL_TAG);
836 if (UserInfo == NULL)
837 {
838 LOG(LOG_SS_MISC, LOG_PRIORITY_DEBUG, ("GetCurrentUserSid: out of memory (requested %d bytes)\n", TokenSize + *Size));
839 return NULL;
840 }
841
842
843 psa = (PSID_AND_ATTRIBUTES) (UserInfo + *Size);
844// ptg = (PTOKEN_GROUPS) (UserInfo + *Size);
845// ps = (PSID) (UserInfo + *Size);
846
847
848 /* third, request the token information */
849
850 status = ZwQueryInformationToken(TokenHandle, TokenUser, psa, TokenSize, &tmp);
851// status = ZwQueryInformationToken(TokenHandle, TokenGroups, psa, TokenSize, &tmp);
852// status = ZwQueryInformationToken(TokenHandle, TokenPrimaryGroup, ps, TokenSize, &tmp);
853 if (! NT_SUCCESS(status))
854 {
855 LOG(LOG_SS_MISC, LOG_PRIORITY_DEBUG, ("GetCurrentUserSid: ZwQueryInformationToken failed with status %x\n", status));
856 ExFreePoolWithTag(UserInfo, _POOL_TAG);
857 return NULL;
858 }
859
860 ZwClose(TokenHandle);
861
862
863 /* convert absolute SID into a relative one */
864 psa->Sid = (PSID) ( (PCHAR) psa->Sid - (PCHAR) psa );
865/*
866 for (tmp = 0; tmp < ptg->GroupCount; tmp++)
867 {
868 ptg->Groups[tmp].Sid = (PSID) ( (PCHAR) ptg->Groups[tmp].Sid - (PCHAR) ptg->Groups );
869 }
870*/
871// * (PULONG) ps = 4;
872
873 /* return size value */
874 *Size += (USHORT) TokenSize;
875
876 return UserInfo;
877}
878
879
880
881/*
882 * NOTE: Adapted from "The VTrace Tool: Building a System Tracer for Windows NT and Windows 2000" -- MSDN Magazine, October 2000
883 * NOTE2: This function should only be called on Windows 2000+.
884 * It's not necessary on Windows NT, and, besides, on Windows NT 4.0 SP3 and earlier,
885 * MmMapLockedPages() does not give the result we need.
886 */
887
888PVOID
889ExchangeReadOnlyMemoryPointer(IN OUT PVOID *Target, IN PVOID Value)
890{
891 PMDL MDL;
892 PVOID MappedAddress, ReturnValue;
893
894
895 MDL = IoAllocateMdl(Target, sizeof(Value), FALSE, FALSE, NULL);
896
897 if (MDL == NULL)
898 return NULL;
899
900
901// MmBuildMdlForNonPagedPool(MDL);
902
903
904 /*
905 * Calls to MmProbeAndLockPages must be enclosed in a try/except block.
906 * If the pages do not support the specified operation, the routine raises the
907 * STATUS_ACCESS_VIOLATION exception.
908 */
909
910 __try
911 {
912 MmProbeAndLockPages(MDL, KernelMode, IoModifyAccess);
913 }
914
915 __except(EXCEPTION_EXECUTE_HANDLER)
916 {
917 LOG(LOG_SS_MISC, LOG_PRIORITY_DEBUG, ("ExchangeReadOnlyMemoryPointer(%x, %x): Caught an exception\n", Target, Value));
918 IoFreeMdl(MDL);
919 return NULL;
920 }
921
922
923// MappedAddress = MmMapLockedPages(MDL, KernelMode);
924 MappedAddress = MmMapLockedPagesSpecifyCache(MDL, KernelMode, MmNonCached, NULL, FALSE, NormalPagePriority);
925
926 if (MappedAddress == NULL)
927 {
928 MmUnlockPages(MDL);
929 IoFreeMdl(MDL);
930 return NULL;
931 }
932
933
934 ReturnValue = InterlockedExchangePointer(MappedAddress, Value);
935
936
937 MmUnmapLockedPages(MappedAddress, MDL);
938 MmUnlockPages(MDL);
939 IoFreeMdl(MDL);
940
941
942 return ReturnValue;
943}
diff --git a/misc.h b/misc.h
new file mode 100644
index 0000000..e49e28d
--- /dev/null
+++ b/misc.h
@@ -0,0 +1,101 @@
1/*
2 * Copyright (c) 2004 Security Architects Corporation. All rights reserved.
3 *
4 * Module Name:
5 *
6 * misc.h
7 *
8 * Abstract:
9 *
10 * This module definies various types used by miscellaneous routines.
11 *
12 * Author:
13 *
14 * Eugene Tsyrklevich 23-Feb-2004
15 *
16 * Revision History:
17 *
18 * None.
19 */
20
21
22#ifndef __MISC_H__
23#define __MISC_H__
24
25
26#include <NTDDK.h>
27#include "pathproc.h"
28#include "log.h"
29
30
31// win2k ddk does not know about ExFreePoolWithTag?
32/*
33#ifndef ExFreePoolWithTag
34#define ExFreePoolWithTag(p, tag) ExFreePool(p)
35#endif
36*/
37
38#define _POOL_TAG 'nozO'
39
40
41/* convert seconds into units of 100 nanoseconds for KeWaitFor* & KeDelayExecutionThread functions */
42#define SECONDS(s) ((s) * -10000000)
43
44
45#define ProbeAndReadUnicodeString(Source) \
46 (((Source) >= (UNICODE_STRING * const)MM_USER_PROBE_ADDRESS) ? \
47 (*(volatile UNICODE_STRING * const)MM_USER_PROBE_ADDRESS) : (*(volatile UNICODE_STRING *)(Source)))
48
49
50/* extern defines */
51
52KPROCESSOR_MODE
53KeGetPreviousMode(
54 VOID
55 );
56
57
58int sprintf(char *buffer, const char *format, ...);
59int _snprintf(char *buffer, size_t count, const char *format, ...);
60int _snwprintf(wchar_t *buffer, size_t count, const wchar_t *format, ...);
61
62BOOLEAN LearningModePostBootup();
63
64
65#define CURRENT_PROCESS_PID ((ULONG) PsGetCurrentProcessId())
66
67
68#define ON 1
69#define OFF 0
70
71
72/* internal defines */
73
74extern BOOLEAN BootingUp;
75
76
77INT32 atoi(IN PCHAR buf);
78PCHAR itoa(int value, char *string, unsigned int radix);
79
80/* XXX move to netmisc.c */
81ULONG ntohl(IN ULONG netlong);
82USHORT ntohs(IN USHORT netshort);
83
84ULONG inet_addr(IN PCCHAR cp);
85VOID inet_ntoa(ULONG ina, PCHAR buf);
86PCHAR inet_ntoa2(IN ULONG ina);
87
88BOOLEAN VerifyUnicodeString(IN PUNICODE_STRING InputUnicodeString, OUT PUNICODE_STRING OutputUnicodeString);
89BOOLEAN VerifyPwstr(IN PWSTR InputString, IN ULONG InputStringLength);
90
91BOOLEAN ReadStringRegistryValueA(IN PWSTR RegistryPath, IN PWSTR KeyName, OUT PCHAR Buffer, IN USHORT BufferSize);
92BOOLEAN ReadStringRegistryValueW(IN PWSTR RegistryPath, IN PWSTR KeyName, OUT PWSTR Buffer, IN USHORT BufferSize);
93BOOLEAN ReadSymlinkValue(IN PWSTR SymlinkPath, OUT PCHAR Buffer, IN USHORT BufferSize);
94
95VOID InitPostBootup();
96PCHAR GetCurrentUserSid(PUSHORT Size);
97
98PVOID ExchangeReadOnlyMemoryPointer(IN OUT PVOID *Target, IN PVOID Value);
99
100
101#endif /* __MISC_H__ */ \ No newline at end of file
diff --git a/mutant.c b/mutant.c
new file mode 100644
index 0000000..ec324ca
--- /dev/null
+++ b/mutant.c
@@ -0,0 +1,151 @@
1/*
2 * Copyright (c) 2004 Security Architects Corporation. All rights reserved.
3 *
4 * Module Name:
5 *
6 * mutant.c
7 *
8 * Abstract:
9 *
10 * This module implements various mutant (mutex) hooking routines.
11 *
12 * Author:
13 *
14 * Eugene Tsyrklevich 25-Mar-2004
15 *
16 * Revision History:
17 *
18 * None.
19 */
20
21
22#include "mutant.h"
23
24
25#ifdef ALLOC_PRAGMA
26#pragma alloc_text (INIT, InitMutantHooks)
27#endif
28
29
30fpZwCreateMutant OriginalNtCreateMutant = NULL;
31fpZwOpenMutant OriginalNtOpenMutant = NULL;
32
33
34/*
35 * HookedNtCreateMutant()
36 *
37 * Description:
38 * This function mediates the NtCreateMutant() system service and checks the
39 * provided mutant name against the global and current process security policies.
40 *
41 * NOTE: ZwCreateMutant creates or opens a mutant object. [NAR]
42 *
43 * Parameters:
44 * Those of NtCreateMutant().
45 *
46 * Returns:
47 * STATUS_ACCESS_DENIED if the call does not pass the security policy check.
48 * Otherwise, NTSTATUS returned by NtCreateMutant().
49 */
50
51NTSTATUS
52NTAPI
53HookedNtCreateMutant
54(
55 OUT PHANDLE MutantHandle,
56 IN ACCESS_MASK DesiredAccess,
57 IN POBJECT_ATTRIBUTES ObjectAttributes,
58 IN BOOLEAN InitialOwner
59)
60{
61 PCHAR FunctionName = "HookedNtCreateMutant";
62
63
64 HOOK_ROUTINE_START(MUTANT);
65
66
67 ASSERT(OriginalNtCreateMutant);
68
69 rc = OriginalNtCreateMutant(MutantHandle, DesiredAccess, ObjectAttributes, InitialOwner);
70
71
72 HOOK_ROUTINE_FINISH(MUTANT);
73}
74
75
76
77/*
78 * HookedNtOpenMutant()
79 *
80 * Description:
81 * This function mediates the NtOpenMutant() system service and checks the
82 * provided mutant name against the global and current process security policies.
83 *
84 * NOTE: ZwOpenMutant opens a mutant object. [NAR]
85 *
86 * Parameters:
87 * Those of NtOpenMutant().
88 *
89 * Returns:
90 * STATUS_ACCESS_DENIED if the call does not pass the security policy check.
91 * Otherwise, NTSTATUS returned by NtOpenMutant().
92 */
93
94NTSTATUS
95NTAPI
96HookedNtOpenMutant
97(
98 OUT PHANDLE MutantHandle,
99 IN ACCESS_MASK DesiredAccess,
100 IN POBJECT_ATTRIBUTES ObjectAttributes
101)
102{
103 PCHAR FunctionName = "HookedNtOpenMutant";
104
105
106 HOOK_ROUTINE_START(MUTANT);
107
108
109 ASSERT(OriginalNtOpenMutant);
110
111 rc = OriginalNtOpenMutant(MutantHandle, DesiredAccess, ObjectAttributes);
112
113
114 HOOK_ROUTINE_FINISH(MUTANT);
115}
116
117
118
119/*
120 * InitMutantHooks()
121 *
122 * Description:
123 * Initializes all the mediated mutant operation pointers. The "OriginalFunction" pointers
124 * are initialized by InstallSyscallsHooks() that must be called prior to this function.
125 *
126 * NOTE: Called once during driver initialization (DriverEntry()).
127 *
128 * Parameters:
129 * None.
130 *
131 * Returns:
132 * TRUE to indicate success, FALSE if failed.
133 */
134
135BOOLEAN
136InitMutantHooks()
137{
138 if ( (OriginalNtCreateMutant = (fpZwCreateMutant) ZwCalls[ZW_CREATE_MUTANT_INDEX].OriginalFunction) == NULL)
139 {
140 LOG(LOG_SS_MUTANT, LOG_PRIORITY_DEBUG, ("InitMutantHooks: OriginalNtCreateMutant is NULL\n"));
141 return FALSE;
142 }
143
144 if ( (OriginalNtOpenMutant = (fpZwOpenMutant) ZwCalls[ZW_OPEN_MUTANT_INDEX].OriginalFunction) == NULL)
145 {
146 LOG(LOG_SS_MUTANT, LOG_PRIORITY_DEBUG, ("InitMutantHooks: OriginalNtOpenMutant is NULL\n"));
147 return FALSE;
148 }
149
150 return TRUE;
151}
diff --git a/mutant.h b/mutant.h
new file mode 100644
index 0000000..ab801fa
--- /dev/null
+++ b/mutant.h
@@ -0,0 +1,78 @@
1/*
2 * Copyright (c) 2004 Security Architects Corporation. All rights reserved.
3 *
4 * Module Name:
5 *
6 * mutant.h
7 *
8 * Abstract:
9 *
10 * This module defines various types used by mutant (mutex) hooking routines.
11 *
12 * Author:
13 *
14 * Eugene Tsyrklevich 25-Mar-2004
15 *
16 * Revision History:
17 *
18 * None.
19 */
20
21
22#ifndef __MUTANT_H__
23#define __MUTANT_H__
24
25
26#include <NTDDK.h>
27#include "policy.h"
28#include "pathproc.h"
29#include "hookproc.h"
30#include "accessmask.h"
31#include "learn.h"
32#include "log.h"
33
34
35/*
36 * ZwCreateMutant creates or opens a mutant object. [NAR]
37 */
38
39typedef NTSTATUS (*fpZwCreateMutant) (
40 OUT PHANDLE MutantHandle,
41 IN ACCESS_MASK DesiredAccess,
42 IN POBJECT_ATTRIBUTES ObjectAttributes,
43 IN BOOLEAN InitialOwner
44 );
45
46NTSTATUS
47NTAPI
48HookedNtCreateMutant(
49 OUT PHANDLE MutantHandle,
50 IN ACCESS_MASK DesiredAccess,
51 IN POBJECT_ATTRIBUTES ObjectAttributes,
52 IN BOOLEAN InitialOwner
53 );
54
55
56/*
57 * ZwOpenMutant opens a mutant object. [NAR]
58 */
59
60typedef NTSTATUS (*fpZwOpenMutant) (
61 OUT PHANDLE MutantHandle,
62 IN ACCESS_MASK DesiredAccess,
63 IN POBJECT_ATTRIBUTES ObjectAttributes
64 );
65
66NTSTATUS
67NTAPI
68HookedNtOpenMutant(
69 OUT PHANDLE MutantHandle,
70 IN ACCESS_MASK DesiredAccess,
71 IN POBJECT_ATTRIBUTES ObjectAttributes
72 );
73
74
75BOOLEAN InitMutantHooks();
76
77
78#endif /* __MUTANT_H__ */
diff --git a/network.c b/network.c
new file mode 100644
index 0000000..3564db2
--- /dev/null
+++ b/network.c
@@ -0,0 +1,715 @@
1/*
2 * Copyright (c) 2004 Security Architects Corporation. All rights reserved.
3 *
4 * Module Name:
5 *
6 * network.c
7 *
8 * Abstract:
9 *
10 * This module defines various routines used for hooking the Transport Driver Interface (TDI) network routines.
11 *
12 * Author:
13 *
14 * Eugene Tsyrklevich 12-Mar-2004
15 *
16 * Revision History:
17 *
18 * None.
19 */
20
21
22#include <NTDDK.h>
23#include <tdikrnl.h>
24#include <ctype.h>
25#include "network.h"
26#include "hookproc.h"
27#include "userland.h"
28#include "learn.h"
29#include "policy.h"
30#include "log.h"
31
32
33#ifdef ALLOC_PRAGMA
34#pragma alloc_text (INIT, InstallNetworkHooks)
35#pragma alloc_text (PAGE, RemoveNetworkHooks)
36#endif
37
38
39//XXX fast io is not handled. TdiDispatchFastDeviceControl
40
41
42PDEVICE_OBJECT pTcpDevice = NULL, pTcpDeviceOriginal = NULL;
43PDEVICE_OBJECT pUdpDevice = NULL, pUdpDeviceOriginal = NULL;
44PDEVICE_OBJECT pIpDevice = NULL, pIpDeviceOriginal = NULL;
45
46#if DBG
47int HookedTDIRunning = 0;
48#endif
49
50
51/*
52 * TdiStub() XXX remove
53 *
54 * Description:
55 * .
56 *
57 * Parameters:
58 * pIrp - IRP (I/O Request Packet) request.
59 * pIrpStack - .
60 * pCompletion - .
61 *
62 * Returns:
63 * STATUS_SUCCESS.
64 */
65
66NTSTATUS
67TdiStub(IN PIRP pIrp, IN PIO_STACK_LOCATION pIrpStack, OUT PTDI_CALLBACK pCompletion, IN ULONG DeviceType)
68{
69// LOG(LOG_SS_NETWORK, LOG_PRIORITY_DEBUG, ("TdiStub(%x %x %x)\n", pIrp, pIrpStack, pCompletion));
70 return STATUS_SUCCESS;
71}
72
73
74
75NTSTATUS
76TdiSetEventHandler(IN PIRP pIrp, IN PIO_STACK_LOCATION pIrpStack, OUT PTDI_CALLBACK pCompletion, IN ULONG DeviceType)
77{
78 PTDI_REQUEST_KERNEL_SET_EVENT r = (PTDI_REQUEST_KERNEL_SET_EVENT) &pIrpStack->Parameters;
79
80
81 if (r->EventType != TDI_EVENT_CONNECT)
82 {
83 LOG(LOG_SS_NETWORK, LOG_PRIORITY_DEBUG, ("%d TdiSetEventHandler: %x %x %x\n", CURRENT_PROCESS_PID, r->EventType, r->EventHandler, r->EventContext));
84 return STATUS_SUCCESS;
85 }
86
87
88 if (r->EventHandler == NULL)
89 {
90 LOG(LOG_SS_NETWORK, LOG_PRIORITY_DEBUG, ("%d TdiSetEventHandler: TDI_EVENT_CONNECT deregistration %x %x %x\n", CURRENT_PROCESS_PID, r->EventHandler, r->EventContext, pIrpStack->FileObject));
91 return STATUS_SUCCESS;
92 }
93
94
95 LOG(LOG_SS_NETWORK, LOG_PRIORITY_DEBUG, ("%d TdiSetEventHandler: TDI_EVENT_CONNECT %x %x %x\n", CURRENT_PROCESS_PID, r->EventHandler, r->EventContext, pIrpStack->FileObject));
96
97
98 return STATUS_SUCCESS;
99}
100
101
102
103NTSTATUS
104TdiConnect(IN PIRP pIrp, IN PIO_STACK_LOCATION pIrpStack, OUT PTDI_CALLBACK pCompletion, IN ULONG DeviceType)
105{
106 /*
107 * IrpSp->Parameters
108 *
109 * Pointer to a TDI_REQUEST_KERNEL_CONNECT structure, equivalent to the TDI_REQUEST_KERNEL structure.
110 */
111
112 PTDI_REQUEST_KERNEL_CONNECT ConnectInfo = (PTDI_REQUEST_KERNEL_CONNECT) &pIrpStack->Parameters;
113 PTRANSPORT_ADDRESS pTransportAddress;
114 PTA_ADDRESS pAddress;
115 PTDI_ADDRESS_IP ip;
116 CHAR NETWORKNAME[MAX_PATH];
117 PCHAR FunctionName = "TdiConnect";
118
119
120 HOOK_ROUTINE_ENTER();
121
122
123 if (! MmIsAddressValid(ConnectInfo) ||
124 ! MmIsAddressValid(ConnectInfo->RequestConnectionInformation) ||
125 ! MmIsAddressValid(ConnectInfo->RequestConnectionInformation->RemoteAddress))
126 {
127 LOG(LOG_SS_NETWORK, LOG_PRIORITY_DEBUG, ("TdiConnect: MmIsAddressValid failed\n"));
128 HOOK_ROUTINE_EXIT(STATUS_SUCCESS);
129 }
130
131
132 pTransportAddress = (PTRANSPORT_ADDRESS) ConnectInfo->RequestConnectionInformation->RemoteAddress;
133
134 pAddress = (PTA_ADDRESS) pTransportAddress->Address;
135
136 /* verify that the specified address is a single IP address */
137 if (pTransportAddress->TAAddressCount != 1 ||
138 pAddress->AddressType != TDI_ADDRESS_TYPE_IP ||
139 pAddress->AddressLength != TDI_ADDRESS_LENGTH_IP)
140 {
141 LOG(LOG_SS_NETWORK, LOG_PRIORITY_DEBUG, ("%d TdiConnect: Invalid address detected\n", CURRENT_PROCESS_PID));
142 HOOK_ROUTINE_EXIT(STATUS_SUCCESS);
143 }
144
145 ip = (PTDI_ADDRESS_IP) &pAddress->Address;
146
147
148 LOG(LOG_SS_NETWORK, LOG_PRIORITY_DEBUG, ("%d TdiConnect(%x %x %x). %d %x:%u (%s)\n", (ULONG) PsGetCurrentProcessId(), pIrp, pIrpStack, pCompletion, pTransportAddress->TAAddressCount, ntohl(ip->in_addr), ntohs(ip->sin_port), inet_ntoa2(ip->in_addr)));
149
150
151 inet_ntoa(ip->in_addr, NETWORKNAME);
152
153 if (LearningMode == FALSE)
154 {
155 POLICY_CHECK_OPTYPE_NAME(NETWORK, DeviceType == NET_DEVICE_TYPE_TCP ? OP_TCPCONNECT : OP_UDPCONNECT);
156 }
157 else
158 {
159 // learning mode
160 AddRule(RULE_NETWORK, NETWORKNAME, DeviceType == NET_DEVICE_TYPE_TCP ? OP_TCPCONNECT : OP_UDPCONNECT);
161 }
162
163
164 HOOK_ROUTINE_EXIT(STATUS_SUCCESS);
165}
166
167
168
169NTSTATUS
170TdiListen(IN PIRP pIrp, IN PIO_STACK_LOCATION pIrpStack, OUT PTDI_CALLBACK pCompletion, IN ULONG DeviceType)
171{
172 /*
173 * IrpSp->Parameters
174 *
175 * Pointer to a TDI_REQUEST_KERNEL_LISTEN structure, equivalent to the TDI_REQUEST_KERNEL structure.
176 */
177
178 PTDI_REQUEST_KERNEL_LISTEN ListenInfo = (PTDI_REQUEST_KERNEL_LISTEN) &pIrpStack->Parameters;
179 PTRANSPORT_ADDRESS pTransportAddress;
180 PTA_ADDRESS pAddress;
181 PTDI_ADDRESS_IP ip;
182
183
184 if (! MmIsAddressValid(ListenInfo) ||
185 ! MmIsAddressValid(ListenInfo->RequestConnectionInformation) ||
186 ! MmIsAddressValid(ListenInfo->RequestConnectionInformation->RemoteAddress))
187 {
188 LOG(LOG_SS_NETWORK, LOG_PRIORITY_DEBUG, ("TdiListen: MmIsAddressValid failed\n"));
189 HOOK_ROUTINE_EXIT(STATUS_SUCCESS);
190 }
191
192 pTransportAddress = (PTRANSPORT_ADDRESS) ListenInfo->RequestConnectionInformation->RemoteAddress;
193
194 pAddress = (PTA_ADDRESS) pTransportAddress->Address;
195
196 /* verify that the specified address is a single IP address */
197 if (pTransportAddress->TAAddressCount != 1 ||
198 pAddress->AddressType != TDI_ADDRESS_TYPE_IP ||
199 pAddress->AddressLength != TDI_ADDRESS_LENGTH_IP)
200 {
201 LOG(LOG_SS_NETWORK, LOG_PRIORITY_DEBUG, ("%d TdiListen: Invalid address detected\n", CURRENT_PROCESS_PID));
202 HOOK_ROUTINE_EXIT(STATUS_SUCCESS);
203 }
204
205 ip = (PTDI_ADDRESS_IP) &pAddress->Address;
206
207
208 LOG(LOG_SS_NETWORK, LOG_PRIORITY_DEBUG, ("TdiListen(%x %x %x). %d %x:%u (%s)\n", pIrp, pIrpStack, pCompletion, pTransportAddress->TAAddressCount, ntohl(ip->in_addr), ntohs(ip->sin_port), inet_ntoa2(ip->in_addr)));
209
210
211 return STATUS_SUCCESS;
212}
213
214
215
216NTSTATUS
217TdiAccept(IN PIRP pIrp, IN PIO_STACK_LOCATION pIrpStack, OUT PTDI_CALLBACK pCompletion, IN ULONG DeviceType)
218{
219 /*
220 * IrpSp->Parameters
221 *
222 * Specifies a TDI_REQUEST_KERNEL_ACCEPT structure.
223 */
224
225 PTDI_REQUEST_KERNEL_ACCEPT AcceptInfo = (PTDI_REQUEST_KERNEL_ACCEPT) &pIrpStack->Parameters;
226 PTRANSPORT_ADDRESS pTransportAddress = (PTRANSPORT_ADDRESS) AcceptInfo->RequestConnectionInformation->RemoteAddress;
227 PTA_ADDRESS pAddress = (PTA_ADDRESS) pTransportAddress->Address;
228 PTDI_ADDRESS_IP ip = (PTDI_ADDRESS_IP) &pAddress->Address;
229
230
231 LOG(LOG_SS_NETWORK, LOG_PRIORITY_DEBUG, ("TdiAccept(%x %x %x). %d %x:%u (%s)\n", pIrp, pIrpStack, pCompletion, pTransportAddress->TAAddressCount, ntohl(ip->in_addr), ntohs(ip->sin_port), inet_ntoa2(ip->in_addr)));
232
233
234 return STATUS_SUCCESS;
235}
236
237
238/*
239NTSTATUS
240GenericCompletion(IN PDEVICE_OBJECT pDevObj, IN PIRP pIrp, IN PVOID pContext)
241{
242 if (pIrp->PendingReturned )
243 IoMarkIrpPending(pIrp);
244
245 return STATUS_SUCCESS;
246}
247*/
248
249
250TDI_IOCTL TdiIoctl[] =
251{
252 { TDI_ASSOCIATE_ADDRESS, "TDI_ASSOCIATE_ADDRESS", TdiStub },
253 { TDI_DISASSOCIATE_ADDRESS, "TDI_DISASSOCIATE_ADDRESS", TdiStub },
254 { TDI_CONNECT, "TDI_CONNECT", TdiConnect },
255 { TDI_LISTEN, "TDI_LISTEN", TdiListen },
256 { TDI_ACCEPT, "TDI_ACCEPT", TdiAccept },
257 { TDI_DISCONNECT, "TDI_DISCONNECT", TdiStub },
258 { TDI_SEND, "TDI_SEND", TdiStub },
259 { TDI_RECEIVE, "TDI_RECEIVE", TdiStub },
260 { TDI_SEND_DATAGRAM, "TDI_SEND_DATAGRAM", TdiStub },
261 { TDI_RECEIVE_DATAGRAM, "TDI_RECEIVE_DATAGRAM", TdiStub },
262 { TDI_SET_EVENT_HANDLER, "TDI_SET_EVENT_HANDLER", TdiSetEventHandler },
263 { TDI_QUERY_INFORMATION, "TDI_QUERY_INFORMATION", TdiStub },
264 { TDI_SET_INFORMATION, "TDI_SET_INFORMATION", TdiStub },
265 { TDI_ACTION, "TDI_ACTION", TdiStub },
266 { TDI_DIRECT_SEND, "TDI_DIRECT_SEND", TdiStub },
267 { TDI_DIRECT_SEND_DATAGRAM, "TDI_DIRECT_SEND_DATAGRAM", TdiStub },
268};
269
270
271
272//XXX this function can be called from HookedNtCreateFile (-> NtCreateFile -> IoCreateFile -> ObOpenObjectbyName -> ... -> TDI)
273BOOLEAN
274TDIDispatch(PDEVICE_OBJECT pDeviceObject, PIRP pIrp, NTSTATUS *status)
275{
276 PIO_STACK_LOCATION pIrpStack;
277 TDI_CALLBACK Callback;
278 ULONG DeviceType = 0;
279
280
281 if (pDeviceObject == pTcpDevice)
282 {
283 DeviceType = NET_DEVICE_TYPE_TCP;
284 }
285 else if (pDeviceObject == pUdpDevice)
286 {
287 DeviceType = NET_DEVICE_TYPE_UDP;
288 }
289 else if (pDeviceObject == pIpDevice)
290 {
291 DeviceType = NET_DEVICE_TYPE_IP;
292 }
293 else
294 {
295 return FALSE;
296 }
297
298
299 HOOK_TDI_ENTER_NORC();
300
301
302 pIrpStack = IoGetCurrentIrpStackLocation(pIrp);
303
304
305 memset(&Callback, 0, sizeof(Callback));
306
307// if (pIrpStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_TDI_QUERY_DIRECT_SEND_HANDLER)
308// {
309// LOG(LOG_SS_NETWORK, LOG_PRIORITY_DEBUG, ("IOCTL_TDI_QUERY_DIRECT_SEND_HANDLER\n"));
310// }
311
312 switch (pIrpStack->MajorFunction)
313 {
314 case IRP_MJ_CREATE:
315
316 *status = TDICreate(pDeviceObject, pIrp, pIrpStack, &Callback);
317
318 break;
319
320
321 case IRP_MJ_DEVICE_CONTROL:
322
323// if (DeviceType == NET_DEVICE_TYPE_IP && pIrpStack->Parameters.DeviceIoControl.IoControlCode == 0x120000)
324 if (DeviceType == NET_DEVICE_TYPE_IP)
325 {
326 LOG(LOG_SS_NETWORK, LOG_PRIORITY_VERBOSE, ("%d pIpDevice in use (%x %x %x)\n", (ULONG) PsGetCurrentProcessId(), pIrpStack->Parameters.DeviceIoControl.IoControlCode, pIrpStack->MajorFunction, pIrpStack->MinorFunction));
327// *status = STATUS_ACCESS_DENIED;
328 break;
329 }
330
331 if (KeGetCurrentIrql() != PASSIVE_LEVEL || ! NT_SUCCESS(TdiMapUserRequest(pDeviceObject, pIrp, pIrpStack)))
332 {
333 LOG(LOG_SS_NETWORK, LOG_PRIORITY_VERBOSE, ("TdiMapUserRequest failed: %x (irql %d)\n", pIrpStack->Parameters.DeviceIoControl.IoControlCode, KeGetCurrentIrql()));
334 break;
335 }
336
337 LOG(LOG_SS_NETWORK, LOG_PRIORITY_VERBOSE, ("IRP_MJ_DEVICE_CONTROL2 %x\n", pIrpStack->Parameters.DeviceIoControl.IoControlCode));
338
339 /* FALLTHROUGH */
340
341
342 case IRP_MJ_INTERNAL_DEVICE_CONTROL:
343 {
344 int i;
345
346 if (DeviceType == NET_DEVICE_TYPE_IP)
347 LOG(LOG_SS_NETWORK, LOG_PRIORITY_DEBUG, ("%d pIpDevice in use2\n", (ULONG) PsGetCurrentProcessId()));
348
349 for (i = 0; i < sizeof(TdiIoctl) / sizeof(TdiIoctl[0]); i++)
350 {
351 if (TdiIoctl[i].MinorFunction == pIrpStack->MinorFunction)
352 {
353 if (TdiIoctl[i].pfRoutine == TdiStub)
354 LOG(LOG_SS_NETWORK, LOG_PRIORITY_VERBOSE, ("%d IRP_MJ_INTERNAL_DEVICE_CONTROL %s\n", (ULONG) PsGetCurrentProcessId(), TdiIoctl[i].Description));
355
356 *status = TdiIoctl[i].pfRoutine(pIrp, pIrpStack, &Callback, DeviceType);
357
358 break;
359 }
360 }
361
362 break;
363 }
364
365 case IRP_MJ_CLEANUP:
366 LOG(LOG_SS_NETWORK, LOG_PRIORITY_VERBOSE, ("IRP_MJ_CLEANUP\n"));
367 break;
368
369 case IRP_MJ_CLOSE:
370 LOG(LOG_SS_NETWORK, LOG_PRIORITY_VERBOSE, ("IRP_MJ_CLOSE\n"));
371 break;
372
373 default:
374 LOG(LOG_SS_NETWORK, LOG_PRIORITY_VERBOSE, ("TDIDispatch: default switch case triggered\n"));
375 break;
376 }
377
378
379 if (*status == STATUS_ACCESS_DENIED)
380 {
381 pIrp->IoStatus.Status = STATUS_ACCESS_DENIED;
382 IoCompleteRequest (pIrp, IO_NO_INCREMENT);
383
384 HOOK_TDI_EXIT(TRUE);
385 }
386
387
388 if (Callback.Routine)
389 {
390 LOG(LOG_SS_NETWORK, LOG_PRIORITY_DEBUG, ("TDI Callback.Routine\n"));
391
392 //XXX IoCopyCurrentIrpStackLocationToNext()
393 IoSetCompletionRoutine(pIrp, Callback.Routine, Callback.Context, TRUE, TRUE, TRUE);
394 }
395 else
396 {
397 // Set up a completion routine to handle the bubbling of the "pending" mark of an IRP
398// IoSetCompletionRoutine(pIrp, GenericCompletion, NULL, TRUE, TRUE, TRUE);
399
400 IoSkipCurrentIrpStackLocation(pIrp);
401 }
402
403
404 if (DeviceType == NET_DEVICE_TYPE_TCP)
405 {
406 *status = IoCallDriver(pTcpDeviceOriginal, pIrp);
407 }
408 else if (DeviceType == NET_DEVICE_TYPE_UDP)
409 {
410 *status = IoCallDriver(pUdpDeviceOriginal, pIrp);
411 }
412 else if (DeviceType == NET_DEVICE_TYPE_IP)
413 {
414 *status = IoCallDriver(pIpDeviceOriginal, pIrp);
415 }
416 else
417 {
418 LOG(LOG_SS_NETWORK, LOG_PRIORITY_DEBUG, ("TDIDispatch: Unknown device type\n"));
419 }
420
421
422 HOOK_TDI_EXIT(TRUE);
423}
424
425
426
427NTSTATUS
428TDICreateAddressCompletion(IN PDEVICE_OBJECT DeviceObject, IN PIRP pIrp, IN PVOID Context)
429{
430 return STATUS_SUCCESS;
431}
432
433
434
435NTSTATUS
436TDICreate(IN PDEVICE_OBJECT pDeviceObject, IN PIRP pIrp, IN PIO_STACK_LOCATION pIrpStack, OUT PTDI_CALLBACK pCompletion)
437{
438 FILE_FULL_EA_INFORMATION *ea = (FILE_FULL_EA_INFORMATION *) pIrp->AssociatedIrp.SystemBuffer;
439
440
441 HOOK_ROUTINE_ENTER();
442
443
444 LOG(LOG_SS_NETWORK, LOG_PRIORITY_VERBOSE, ("TDICreate(%x %x %x)\n", pIrp, pIrpStack, ea));
445
446
447 /*
448 * From DDK (TdiDispatchCreate):
449 *
450 * Irp->AssociatedIrp.SystemBuffer
451 *
452 * Pointer to a FILE_FULL_EA_INFORMATION-structured buffer if the file object represents an address or a
453 * connection endpoint to be opened.
454 * For an address, the EaName member is set to the system-defined constant TdiTransportAddress and the EA value
455 * following the EaName array is of type TRANSPORT_ADDRESS, set up by the client to specify the address to be
456 * opened. For some transports, this value can be a symbolic netBIOS or DNS name to be translated by the transport.
457 *
458 * For a connection endpoint, the EaName member is set to the system-defined constant TdiConnectionContext and
459 * the EA value following the EaName array is a client-supplied handle, opaque to the transport driver. The
460 * transport must save this handle and subsequently pass it back to the client's registered event handlers for
461 * this connection.
462 *
463 * If the given file object represents a control channel, this member is NULL.
464 */
465
466 if (ea == NULL)
467 {
468 LOG(LOG_SS_NETWORK, LOG_PRIORITY_VERBOSE, ("TDICreate: Control channel\n"));
469 HOOK_ROUTINE_EXIT(STATUS_SUCCESS);
470 }
471
472
473 if (! MmIsAddressValid(ea) || ea->EaName == NULL || ! MmIsAddressValid(ea->EaName))
474 {
475 LOG(LOG_SS_NETWORK, LOG_PRIORITY_DEBUG, ("TDICreate: MmIsAddressValid() failed\n"));
476 HOOK_ROUTINE_EXIT(STATUS_SUCCESS);
477 }
478
479
480 if (ea->EaNameLength == TDI_CONNECTION_CONTEXT_LENGTH &&
481 memcmp(ea->EaName, TdiConnectionContext, TDI_CONNECTION_CONTEXT_LENGTH) == 0)
482 {
483 CONNECTION_CONTEXT conn_ctx = *(CONNECTION_CONTEXT *) (ea->EaName + ea->EaNameLength + 1);
484
485 if (conn_ctx)
486 LOG(LOG_SS_NETWORK, LOG_PRIORITY_VERBOSE, ("TDI Connection object 0x%x %x\n", conn_ctx, * (PULONG) conn_ctx));
487
488 HOOK_ROUTINE_EXIT(STATUS_SUCCESS);
489 }
490
491
492 // NOTE: for RawIp you can extract protocol number from irps->FileObject->FileName
493
494 if (ea->EaNameLength == TDI_TRANSPORT_ADDRESS_LENGTH &&
495 memcmp(ea->EaName, TdiTransportAddress, TDI_TRANSPORT_ADDRESS_LENGTH) == 0)
496 {
497 PTRANSPORT_ADDRESS pTransportAddress;
498 PTA_ADDRESS pAddress;
499 PIRP QueryIrp;
500 int i;
501
502
503 pTransportAddress = (PTRANSPORT_ADDRESS) (ea->EaName + ea->EaNameLength + 1);
504 pAddress = pTransportAddress->Address;
505
506 LOG(LOG_SS_NETWORK, LOG_PRIORITY_VERBOSE, ("TDICreate: TDI Address object. Num %d\n", pTransportAddress->TAAddressCount));
507
508
509 for (i = 0; i < pTransportAddress->TAAddressCount; i++)
510 {
511 LOG(LOG_SS_NETWORK, LOG_PRIORITY_VERBOSE, ("TDICreate: TDI Address %d: %x %x\n", i, pAddress->AddressLength, pAddress->AddressType));
512
513
514 if (pAddress->AddressType == TDI_ADDRESS_TYPE_IP)
515 {
516 PTDI_ADDRESS_IP ip = (PTDI_ADDRESS_IP) &pAddress->Address;
517 CHAR NETWORKNAME[MAX_PATH];
518 PCHAR FunctionName = "TDICreate";
519
520
521 if (ip->sin_port != 0)
522 {
523 LOG(LOG_SS_NETWORK, LOG_PRIORITY_DEBUG, ("%d TDICreate: Bind IP %x:%u (%s)\n", (ULONG) PsGetCurrentProcessId(), ntohl(ip->in_addr), ntohs(ip->sin_port), inet_ntoa2(ip->in_addr)));
524
525 itoa( ntohs(ip->sin_port), NETWORKNAME, 10 );
526 //inet_ntoa(ip->in_addr, NETWORKNAME);
527
528 if (LearningMode == FALSE)
529 {
530 POLICY_CHECK_OPTYPE_NAME(NETWORK, OP_BIND);
531 }
532 else
533 {
534 // learning mode
535 AddRule(RULE_NETWORK, NETWORKNAME, OP_BIND);
536 }
537 }
538 else
539 {
540 LOG(LOG_SS_NETWORK, LOG_PRIORITY_VERBOSE, ("%d TDICreate: IP & port are both zero\n", (ULONG) PsGetCurrentProcessId()));
541 }
542 }
543 else
544 {
545 //XXX fail if only IP network addresses are allowed.
546 }
547
548 pAddress += 1;
549 }
550
551 //XXX reread WDM ch 5.3 "COmpleting I/O requests"
552/*
553 QueryIrp = TdiBuildInternalDeviceControlIrp(TDI_QUERY_INFORMATION, pDeviceObject,
554 pIrpStack->FileObject, NULL, NULL);
555 if (QueryIrp == NULL)
556 {
557 LOG(LOG_SS_NETWORK, LOG_PRIORITY_DEBUG, ("TDICreate: QueryIrp is NULL\n"));
558 return FALSE;
559 }
560
561 pCompletion->Routine = TDICreateAddressCompletion;
562 pCompletion->Context = QueryIrp;
563*/
564 }
565
566
567 HOOK_ROUTINE_EXIT(STATUS_SUCCESS);
568}
569
570
571
572/*
573 * InstallNetworkHooks()
574 *
575 * Description:
576 * .
577 *
578 * NOTE: Called once during driver initialization (DriverEntry()).
579 * There is no need to cleanup in case a failure since RemoveNetworkHooks() will be called later.
580 *
581 * Parameters:
582 * pDriverObject - pointer to a driver object that represents this driver.
583 *
584 * Returns:
585 * STATUS_SUCCESS to indicate success or an NTSTATUS error code if failed.
586 */
587
588NTSTATUS
589InstallNetworkHooks(PDRIVER_OBJECT pDriverObject)
590{
591 UNICODE_STRING Name;
592 NTSTATUS status;
593
594
595 status = IoCreateDevice(pDriverObject, 0, NULL, FILE_DEVICE_UNKNOWN, 0, TRUE, &pTcpDevice);
596 if (! NT_SUCCESS(status))
597 {
598 LOG(LOG_SS_NETWORK, LOG_PRIORITY_DEBUG, ("InstallNetworkHooks: IoCreateDevice(tcp) failed\n"));
599 return status;
600 }
601
602
603 status = IoCreateDevice(pDriverObject, 0, NULL, FILE_DEVICE_UNKNOWN, 0, TRUE, &pUdpDevice);
604 if (! NT_SUCCESS(status))
605 {
606 LOG(LOG_SS_NETWORK, LOG_PRIORITY_DEBUG, ("InstallNetworkHooks: IoCreateDevice(udp) failed\n"));
607 return status;
608 }
609
610
611 status = IoCreateDevice(pDriverObject, 0, NULL, FILE_DEVICE_UNKNOWN, 0, TRUE, &pIpDevice);
612 if (! NT_SUCCESS(status))
613 {
614 LOG(LOG_SS_NETWORK, LOG_PRIORITY_DEBUG, ("InstallNetworkHooks: IoCreateDevice(udp) failed\n"));
615 return status;
616 }
617
618
619 RtlInitUnicodeString(&Name, L"\\Device\\Tcp");
620
621 status = IoAttachDevice(pTcpDevice, &Name, &pTcpDeviceOriginal);
622 if (! NT_SUCCESS(status))
623 {
624 LOG(LOG_SS_NETWORK, LOG_PRIORITY_DEBUG, ("InstallNetworkHooks: IoAttachDevice(\\Device\\Tcp) failed\n"));
625 return status;
626 }
627
628
629 RtlInitUnicodeString(&Name, L"\\Device\\Udp");
630
631 status = IoAttachDevice(pUdpDevice, &Name, &pUdpDeviceOriginal);
632 if (! NT_SUCCESS(status))
633 {
634 LOG(LOG_SS_NETWORK, LOG_PRIORITY_DEBUG, ("InstallNetworkHooks: IoAttachDevice(\\Device\\Udp) failed\n"));
635 return status;
636 }
637
638
639 RtlInitUnicodeString(&Name, L"\\Device\\Ip");
640
641 status = IoAttachDevice(pIpDevice, &Name, &pIpDeviceOriginal);
642 if (! NT_SUCCESS(status))
643 {
644 LOG(LOG_SS_NETWORK, LOG_PRIORITY_DEBUG, ("InstallNetworkHooks: IoAttachDevice(\\Device\\Ip) failed\n"));
645 return status;
646 }
647
648
649 pTcpDevice->StackSize = pTcpDeviceOriginal->StackSize + 1;
650 // XXX Flags &= ~DO_DEVICE_INITIALIZING;
651 pTcpDevice->Flags |= pTcpDeviceOriginal->Flags & (DO_BUFFERED_IO | DO_DIRECT_IO | DO_POWER_PAGABLE | DO_POWER_INRUSH) & ~DO_DEVICE_INITIALIZING;
652 pTcpDevice->DeviceType = pTcpDeviceOriginal->DeviceType;
653 pTcpDevice->Characteristics = pTcpDeviceOriginal->Characteristics;
654
655
656 pUdpDevice->StackSize = pUdpDeviceOriginal->StackSize + 1;
657 pUdpDevice->Flags |= pUdpDeviceOriginal->Flags & (DO_BUFFERED_IO | DO_DIRECT_IO | DO_POWER_PAGABLE | DO_POWER_INRUSH) & ~DO_DEVICE_INITIALIZING;
658 pUdpDevice->DeviceType = pUdpDeviceOriginal->DeviceType;
659 pUdpDevice->Characteristics = pUdpDeviceOriginal->Characteristics;
660
661
662 pIpDevice->StackSize = pIpDeviceOriginal->StackSize + 1;
663 pIpDevice->Flags |= pIpDeviceOriginal->Flags & (DO_BUFFERED_IO | DO_DIRECT_IO | DO_POWER_PAGABLE | DO_POWER_INRUSH) & ~DO_DEVICE_INITIALIZING;
664 pIpDevice->DeviceType = pIpDeviceOriginal->DeviceType;
665 pIpDevice->Characteristics = pIpDeviceOriginal->Characteristics;
666
667
668 return STATUS_SUCCESS;
669}
670
671
672
673/*
674 * RemoveNetworkHooks()
675 *
676 * Description:
677 * Detach from all network devices.
678 *
679 * Parameters:
680 * pDriverObject - pointer to a driver object that represents this driver.
681 *
682 * Returns:
683 * Nothing.
684 */
685
686void
687RemoveNetworkHooks(PDRIVER_OBJECT pDriverObject)
688{
689// int i;
690
691 //XXX is this necessary? we detach so we should not receive any network IRPs
692// if (pDriverObject && pTcpDevice && pTcpDeviceOriginal)
693// for (i = 0; i < IRP_MJ_MAXIMUM_FUNCTION; i++)
694// pDriverObject->MajorFunction[i] = pTcpDeviceOriginal->DriverObject->MajorFunction[i];
695
696
697 if (pTcpDeviceOriginal != NULL)
698 IoDetachDevice(pTcpDeviceOriginal);
699
700 if (pUdpDeviceOriginal != NULL)
701 IoDetachDevice(pUdpDeviceOriginal);
702
703 if (pIpDeviceOriginal != NULL)
704 IoDetachDevice(pIpDeviceOriginal);
705
706
707 if (pTcpDevice != NULL)
708 IoDeleteDevice(pTcpDevice);
709
710 if (pUdpDevice != NULL)
711 IoDeleteDevice(pUdpDevice);
712
713 if (pIpDevice != NULL)
714 IoDeleteDevice(pIpDevice);
715}
diff --git a/network.h b/network.h
new file mode 100644
index 0000000..012bc8a
--- /dev/null
+++ b/network.h
@@ -0,0 +1,57 @@
1/*
2 * Copyright (c) 2004 Security Architects Corporation. All rights reserved.
3 *
4 * Module Name:
5 *
6 * network.h
7 *
8 * Abstract:
9 *
10 * This module defines various types used by the Transport Driver Interface (TDI) network hooking routines.
11 *
12 * Author:
13 *
14 * Eugene Tsyrklevich 12-Mar-2004
15 *
16 * Revision History:
17 *
18 * None.
19 */
20
21
22#ifndef __NETWORK_H__
23#define __NETWORK_H__
24
25
26
27#define NET_DEVICE_TYPE_TCP 1
28#define NET_DEVICE_TYPE_UDP 2
29#define NET_DEVICE_TYPE_IP 3
30
31
32typedef struct _TDI_CALLBACK
33{
34 PIO_COMPLETION_ROUTINE Routine;
35 PVOID Context;
36
37} TDI_CALLBACK, *PTDI_CALLBACK;
38
39
40typedef int (*TDI_IOCTL_PFUNC) (IN PIRP pIrp, IN PIO_STACK_LOCATION pIrpStack, OUT PTDI_CALLBACK pCompletion, IN ULONG DeviceType);
41
42typedef struct _TDI_IOCTL
43{
44 UCHAR MinorFunction;
45 PCHAR Description;
46 TDI_IOCTL_PFUNC pfRoutine;
47
48} TDI_IOCTL, PTDI_IOCTL;
49
50
51BOOLEAN TDIDispatch(PDEVICE_OBJECT pDeviceObject, PIRP pIrp, NTSTATUS *status);
52NTSTATUS TDICreate(IN PDEVICE_OBJECT pDeviceObject, IN PIRP pIrp, IN PIO_STACK_LOCATION pIrpStack, OUT PTDI_CALLBACK pCompletion);
53NTSTATUS InstallNetworkHooks(PDRIVER_OBJECT pDriverObject);
54void RemoveNetworkHooks(PDRIVER_OBJECT pDriverObject);
55
56
57#endif /* __NETWORK_H__ */
diff --git a/ntproto.h b/ntproto.h
new file mode 100644
index 0000000..ddb3d76
--- /dev/null
+++ b/ntproto.h
@@ -0,0 +1,289 @@
1/*
2 * Copyright (c) 2004 Security Architects Corporation. All rights reserved.
3 *
4 * Module Name:
5 *
6 * ntproto.h
7 *
8 * Abstract:
9 *
10 * This module defines various types defined in WINNT.H and used by hooking routines.
11 *
12 * Author:
13 *
14 * Eugene Tsyrklevich 04-Mar-2004
15 */
16
17#ifndef __NTPROTO_H__
18#define __NTPROTO_H__
19
20
21
22typedef struct _SYSTEM_MODULE_INFORMATION {
23 ULONG Reserved[2];
24 PVOID Base;
25 ULONG Size;
26 ULONG Flags;
27 USHORT Index;
28 USHORT Unknown;
29 USHORT LoadCount;
30 USHORT ModuleNameOffset;
31 CHAR ImageName[256];
32} SYSTEM_MODULE_INFORMATION, *PSYSTEM_MODULE_INFORMATION;
33
34
35
36/*
37 * from WINNT.H
38 */
39
40#ifndef _WINNT_
41
42typedef unsigned short WORD;
43typedef unsigned long DWORD;
44typedef unsigned char BYTE;
45
46#define IMAGE_DOS_SIGNATURE 0x5A4D
47
48typedef struct _IMAGE_DOS_HEADER { // DOS .EXE header
49 WORD e_magic; // Magic number
50 WORD e_cblp; // Bytes on last page of file
51 WORD e_cp; // Pages in file
52 WORD e_crlc; // Relocations
53 WORD e_cparhdr; // Size of header in paragraphs
54 WORD e_minalloc; // Minimum extra paragraphs needed
55 WORD e_maxalloc; // Maximum extra paragraphs needed
56 WORD e_ss; // Initial (relative) SS value
57 WORD e_sp; // Initial SP value
58 WORD e_csum; // Checksum
59 WORD e_ip; // Initial IP value
60 WORD e_cs; // Initial (relative) CS value
61 WORD e_lfarlc; // File address of relocation table
62 WORD e_ovno; // Overlay number
63 WORD e_res[4]; // Reserved words
64 WORD e_oemid; // OEM identifier (for e_oeminfo)
65 WORD e_oeminfo; // OEM information; e_oemid specific
66 WORD e_res2[10]; // Reserved words
67 LONG e_lfanew; // File address of new exe header
68} IMAGE_DOS_HEADER, *PIMAGE_DOS_HEADER;
69
70
71typedef struct _IMAGE_FILE_HEADER {
72 WORD Machine;
73 WORD NumberOfSections;
74 DWORD TimeDateStamp;
75 DWORD PointerToSymbolTable;
76 DWORD NumberOfSymbols;
77 WORD SizeOfOptionalHeader;
78 WORD Characteristics;
79
80} IMAGE_FILE_HEADER, *PIMAGE_FILE_HEADER;
81
82
83typedef struct _IMAGE_DATA_DIRECTORY {
84 DWORD VirtualAddress;
85 DWORD Size;
86
87} IMAGE_DATA_DIRECTORY, *PIMAGE_DATA_DIRECTORY;
88
89
90#define IMAGE_NUMBEROF_DIRECTORY_ENTRIES 16
91
92typedef struct _IMAGE_OPTIONAL_HEADER {
93 //
94 // Standard fields.
95 //
96
97 WORD Magic;
98 BYTE MajorLinkerVersion;
99 BYTE MinorLinkerVersion;
100 DWORD SizeOfCode;
101 DWORD SizeOfInitializedData;
102 DWORD SizeOfUninitializedData;
103 DWORD AddressOfEntryPoint;
104 DWORD BaseOfCode;
105 DWORD BaseOfData;
106
107 //
108 // NT additional fields.
109 //
110
111 DWORD ImageBase;
112 DWORD SectionAlignment;
113 DWORD FileAlignment;
114 WORD MajorOperatingSystemVersion;
115 WORD MinorOperatingSystemVersion;
116 WORD MajorImageVersion;
117 WORD MinorImageVersion;
118 WORD MajorSubsystemVersion;
119 WORD MinorSubsystemVersion;
120 DWORD Win32VersionValue;
121 DWORD SizeOfImage;
122 DWORD SizeOfHeaders;
123 DWORD CheckSum;
124 WORD Subsystem;
125 WORD DllCharacteristics;
126 DWORD SizeOfStackReserve;
127 DWORD SizeOfStackCommit;
128 DWORD SizeOfHeapReserve;
129 DWORD SizeOfHeapCommit;
130 DWORD LoaderFlags;
131 DWORD NumberOfRvaAndSizes;
132 IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES];
133
134} IMAGE_OPTIONAL_HEADER32, *PIMAGE_OPTIONAL_HEADER32;
135
136
137// "PE\0\0"
138#define IMAGE_PE_SIGNATURE 0x00004550
139
140typedef struct _IMAGE_NT_HEADERS {
141 DWORD Signature;
142 IMAGE_FILE_HEADER FileHeader;
143 IMAGE_OPTIONAL_HEADER32 OptionalHeader;
144
145} IMAGE_NT_HEADERS32, *PIMAGE_NT_HEADERS32;
146
147
148#ifdef _WIN64
149#error Win64 not supported
150#else
151typedef IMAGE_NT_HEADERS32 IMAGE_NT_HEADERS;
152typedef PIMAGE_NT_HEADERS32 PIMAGE_NT_HEADERS;
153#endif
154
155typedef struct _IMAGE_EXPORT_DIRECTORY {
156 DWORD Characteristics;
157 DWORD TimeDateStamp;
158 WORD MajorVersion;
159 WORD MinorVersion;
160 DWORD Name;
161 DWORD OrdinalBase;
162 DWORD NumberOfFunctions;
163 DWORD NumberOfNames;
164 DWORD AddressOfFunctions; // RVA from base of image
165 DWORD AddressOfNames; // RVA from base of image
166 DWORD AddressOfNameOrdinals; // RVA from base of image
167
168} IMAGE_EXPORT_DIRECTORY, *PIMAGE_EXPORT_DIRECTORY;
169
170
171#define IMAGE_DIRECTORY_ENTRY_EXPORT 0 // Export Directory
172#define IMAGE_DIRECTORY_ENTRY_IMPORT 1 // Import Directory
173#define IMAGE_DIRECTORY_ENTRY_RESOURCE 2 // Resource Directory
174#define IMAGE_DIRECTORY_ENTRY_EXCEPTION 3 // Exception Directory
175#define IMAGE_DIRECTORY_ENTRY_SECURITY 4 // Security Directory
176#define IMAGE_DIRECTORY_ENTRY_BASERELOC 5 // Base Relocation Table
177#define IMAGE_DIRECTORY_ENTRY_DEBUG 6 // Debug Directory
178// IMAGE_DIRECTORY_ENTRY_COPYRIGHT 7 // (X86 usage)
179#define IMAGE_DIRECTORY_ENTRY_ARCHITECTURE 7 // Architecture Specific Data
180#define IMAGE_DIRECTORY_ENTRY_GLOBALPTR 8 // RVA of GP
181#define IMAGE_DIRECTORY_ENTRY_TLS 9 // TLS Directory
182#define IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG 10 // Load Configuration Directory
183#define IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT 11 // Bound Import Directory in headers
184#define IMAGE_DIRECTORY_ENTRY_IAT 12 // Import Address Table
185#define IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT 13 // Delay Load Import Descriptors
186#define IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR 14 // COM Runtime descriptor
187
188
189typedef struct _SID_AND_ATTRIBUTES
190{
191 PSID Sid;
192 DWORD Attributes;
193
194} SID_AND_ATTRIBUTES, *PSID_AND_ATTRIBUTES;
195
196 // Query Set
197typedef enum _TOKEN_INFORMATION_CLASS
198{
199 TokenUser = 1, // 1 Y N
200 TokenGroups, // 2 Y N
201 TokenPrivileges, // 3 Y N
202 TokenOwner, // 4 Y Y
203 TokenPrimaryGroup, // 5 Y Y
204 TokenDefaultDacl, // 6 Y Y
205 TokenSource, // 7 Y N
206 TokenType, // 8 Y N
207 TokenImpersonationLevel, // 9 Y N
208 TokenStatistics, // 10 Y N
209 TokenRestrictedSids, // 11 Y N
210 TokenSessionId // 12 Y Y
211
212} TOKEN_INFORMATION_CLASS;
213
214
215/* Information Class 1 */
216
217typedef struct _TOKEN_USER
218{
219 SID_AND_ATTRIBUTES User;
220
221} TOKEN_USER, *PTOKEN_USER;
222
223
224#define JOB_OBJECT_ASSIGN_PROCESS (0x0001)
225#define JOB_OBJECT_SET_ATTRIBUTES (0x0002)
226#define JOB_OBJECT_QUERY (0x0004)
227#define JOB_OBJECT_TERMINATE (0x0008)
228#define JOB_OBJECT_SET_SECURITY_ATTRIBUTES (0x0010)
229#define JOB_OBJECT_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0x1F)
230
231#define MUTANT_QUERY_STATE (0x0001)
232#define MUTANT_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | MUTANT_QUERY_STATE)
233
234
235#define TIMER_QUERY_STATE (0x0001)
236#define TIMER_MODIFY_STATE (0x0002)
237#define TIMER_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED|SYNCHRONIZE|TIMER_QUERY_STATE|TIMER_MODIFY_STATE)
238
239
240#define PROCESS_TERMINATE (0x0001)
241#define PROCESS_CREATE_THREAD (0x0002)
242#define PROCESS_SET_SESSIONID (0x0004)
243#define PROCESS_VM_OPERATION (0x0008)
244#define PROCESS_VM_READ (0x0010)
245#define PROCESS_VM_WRITE (0x0020)
246#define PROCESS_DUP_HANDLE (0x0040)
247#define PROCESS_CREATE_PROCESS (0x0080)
248#define PROCESS_SET_QUOTA (0x0100)
249#define PROCESS_SET_INFORMATION (0x0200)
250#define PROCESS_QUERY_INFORMATION (0x0400)
251#define PROCESS_SUSPEND_RESUME (0x0800)
252#define PROCESS_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0xFFF)
253
254
255#define THREAD_TERMINATE (0x0001)
256#define THREAD_SUSPEND_RESUME (0x0002)
257#define THREAD_GET_CONTEXT (0x0008)
258#define THREAD_SET_CONTEXT (0x0010)
259#define THREAD_SET_INFORMATION (0x0020)
260#define THREAD_QUERY_INFORMATION (0x0040)
261#define THREAD_SET_THREAD_TOKEN (0x0080)
262#define THREAD_IMPERSONATE (0x0100)
263#define THREAD_DIRECT_IMPERSONATION (0x0200)
264#define THREAD_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0x3FF)
265
266
267/*
268 * Token Specific Access Rights.
269 */
270
271#define TOKEN_ASSIGN_PRIMARY (0x0001)
272#define TOKEN_DUPLICATE (0x0002)
273#define TOKEN_IMPERSONATE (0x0004)
274#define TOKEN_QUERY (0x0008)
275#define TOKEN_QUERY_SOURCE (0x0010)
276#define TOKEN_ADJUST_PRIVILEGES (0x0020)
277#define TOKEN_ADJUST_GROUPS (0x0040)
278#define TOKEN_ADJUST_DEFAULT (0x0080)
279#define TOKEN_ADJUST_SESSIONID (0x0100)
280
281
282#define CURRENT_THREAD ((HANDLE) -2)
283#define CURRENT_PROCESS ((HANDLE) -1)
284
285
286#endif _WINNT_
287
288
289#endif /* __NTPROTO_H__ */ \ No newline at end of file
diff --git a/pathproc.c b/pathproc.c
new file mode 100644
index 0000000..8778868
--- /dev/null
+++ b/pathproc.c
@@ -0,0 +1,1093 @@
1/*
2 * Copyright (c) 2004 Security Architects Corporation. All rights reserved.
3 *
4 * Module Name:
5 *
6 * pathproc.c
7 *
8 * Abstract:
9 *
10 * This module implements various pathname handling routines.
11 *
12 * Author:
13 *
14 * Eugene Tsyrklevich 19-Feb-2004
15 *
16 * Revision History:
17 *
18 * None.
19 */
20
21
22#include "pathproc.h"
23#include "procname.h"
24#include "policy.h"
25#include "learn.h"
26#include "log.h"
27
28
29/*
30 * ResolveFilename() XXX rewrite
31 *
32 * Description:
33 * Get canonical name for a file by resolving symbolic links.
34 *
35 * Parameters:
36 * szFileName - filename to resolve.
37 * szResult - output buffer.
38 * szResultSize - size of an output buffer.
39 *
40 * Returns:
41 * TRUE to indicate success, FALSE if failed.
42 */
43
44BOOLEAN
45ResolveFilename(IN PCHAR szFileName, OUT PCHAR szResult, IN USHORT szResultSize)
46{
47 CHAR *p, c;
48 OBJECT_ATTRIBUTES oa;
49 ANSI_STRING FileNameAnsi;
50 UNICODE_STRING FileNameUnicode;
51 HANDLE hLink;
52 NTSTATUS rc;
53 int NumberOfLinks = 0;
54 WCHAR buffer[chMAX_PATH];
55 CHAR buffer2[chMAX_PATH];
56
57
58restart:
59
60 *szResult = '\0';
61
62 if (szFileName[0] == '\\' && szFileName[1] == '\\')
63 szFileName++;
64
65 /* move to the end of the object name */
66 for (p = szFileName; *p != '\0'; p++)
67 ;
68
69 /* process the object name from end to the beginning */
70 while (p != szFileName)
71 {
72 /* find the last slash */
73 if (*p != '\\' && *p != '\0')
74 {
75 p--;
76 continue;
77 }
78
79 c = *p;
80 *p = '\0';
81
82
83 RtlInitAnsiString(&FileNameAnsi, szFileName);
84 RtlAnsiStringToUnicodeString(&FileNameUnicode, &FileNameAnsi, TRUE);
85
86 InitializeObjectAttributes(&oa, &FileNameUnicode, OBJ_CASE_INSENSITIVE|OBJ_KERNEL_HANDLE, NULL, NULL);
87
88 rc = ZwOpenSymbolicLinkObject(&hLink, GENERIC_READ, &oa);
89
90 if (NT_SUCCESS(rc))
91 {
92 UNICODE_STRING target;
93 ANSI_STRING targeta;
94
95
96 target.Buffer = buffer;
97 target.MaximumLength = bMAX_PATH;
98 target.Length = 0;
99
100 rc = ZwQuerySymbolicLinkObject(hLink, &target, NULL);
101
102 ZwClose(hLink);
103
104
105 if (NT_SUCCESS(rc))
106 {
107 targeta.Length = 0;
108 targeta.MaximumLength = szResultSize;
109 targeta.Buffer = szResult;
110
111 RtlUnicodeStringToAnsiString(&targeta, &target, FALSE);
112 targeta.Buffer[targeta.Length] = '\0';
113
114//XXX szResultSize -= targeta.Length;
115
116 RtlFreeUnicodeString(&FileNameUnicode);
117 *p = c;
118
119//XXX can we have circular links?
120 if (NumberOfLinks++ < MAX_NUMBER_OF_LINKS)
121 {
122 strncat(szResult, p, szResultSize);
123
124// if (NumberOfLinks > 1)
125// LOG(LOG_SS_PATHPROC, LOG_PRIORITY_DEBUG, ("ResolveFilename: NumberOfLinks=%d. Resolved %s to %s. Restarting.\n", NumberOfLinks, szFileName, szResult));
126
127 /*
128 * switch szFileName to a different buffer. we cannot reuse szFileName buffer
129 * since the resolved link might end up being longer than the original buffer
130 */
131
132 szFileName = (PCHAR) buffer2;
133 strcpy(szFileName, szResult);
134
135 goto restart;
136 }
137
138 LOG(LOG_SS_PATHPROC, LOG_PRIORITY_DEBUG, ("ResolveFilename: NumberOfLinks=%d. bailing out. %s\n", NumberOfLinks, szResult));
139
140 break;
141 }
142 }
143
144 RtlFreeUnicodeString(&FileNameUnicode);
145
146 *p-- = c;
147 }
148
149 strncat(szResult, p, szResultSize);
150
151
152// LOG(LOG_SS_PATHPROC, LOG_PRIORITY_VERBOSE, ("ResolveFilename: name=%s number of links=%d\n", szResult, NumberOfLinks));
153
154
155 return TRUE;
156}
157
158
159
160BOOLEAN
161ResolveFilenameW(IN PUNICODE_STRING szFileName, OUT PCHAR szResult, IN USHORT szResultSize)
162{
163 WCHAR *p, c;
164 OBJECT_ATTRIBUTES oa;
165 ANSI_STRING FileNameAnsi;
166 UNICODE_STRING FileNameUnicode;
167 HANDLE hLink;
168 NTSTATUS rc;
169 int NumberOfLinks = 0;
170 WCHAR buffer[chMAX_PATH];
171 USHORT OriginalLength;
172 UNICODE_STRING target;
173 ANSI_STRING targeta;
174
175
176
177 ASSERT(szFileName);
178 ASSERT(szResult);
179
180 OriginalLength = szFileName->Length;
181
182
183restart:
184
185 *szResult = '\0';
186
187 /* move to the end of the object name */
188 p = (PWCHAR) ((PCHAR)szFileName->Buffer + szFileName->Length);
189
190 /* process the object name from end to the beginning */
191 while (p != szFileName->Buffer)
192 {
193 /* find the last slash */
194// p = wcsrchr(p, L'\\');
195/*
196 if (p == NULL)
197 {
198 p = szFileName->Buffer;
199 break;
200 }
201*/
202 if (*p != L'\\' && *p != L'\0')
203 {
204 p--;
205 continue;
206 }
207
208
209 c = *p;
210 *p = L'\0';
211// szFileName->Length = OriginalLength - (p - szFileName->Buffer);
212
213
214// RtlInitAnsiString(&FileNameAnsi, szFileName);
215// RtlAnsiStringToUnicodeString(&FileNameUnicode, &FileNameAnsi, TRUE);
216// InitializeObjectAttributes(&oa, &FileNameUnicode, OBJ_CASE_INSENSITIVE|OBJ_KERNEL_HANDLE, NULL, NULL);
217
218 InitializeObjectAttributes(&oa, szFileName, OBJ_CASE_INSENSITIVE|OBJ_KERNEL_HANDLE, NULL, NULL);
219
220 rc = ZwOpenSymbolicLinkObject(&hLink, GENERIC_READ, &oa);
221
222 if (! NT_SUCCESS(rc))
223 {
224 *p-- = c;
225 continue;
226 }
227
228 target.Buffer = buffer;
229 target.MaximumLength = bMAX_PATH;
230 target.Length = 0;
231
232 rc = ZwQuerySymbolicLinkObject(hLink, &target, NULL);
233
234 ZwClose(hLink);
235
236
237 if (! NT_SUCCESS(rc))
238 {
239 *p-- = c;
240 continue;
241 }
242
243
244 *p = c;
245
246
247//XXX can we have circular links?
248 if (NumberOfLinks++ < MAX_NUMBER_OF_LINKS)
249 {
250 wcscat(buffer, p);
251 RtlInitUnicodeString(szFileName, buffer);
252
253 goto restart;
254 }
255
256 LOG(LOG_SS_PATHPROC, LOG_PRIORITY_DEBUG, ("ResolveFilename: NumberOfLinks=%d. bailing out. %s\n", NumberOfLinks, szResult));
257
258 break;
259 }
260
261
262// wcscat(szResult, p);
263
264
265// LOG(LOG_SS_PATHPROC, LOG_PRIORITY_VERBOSE, ("ResolveFilename: name=%s number of links=%d\n", szResult, NumberOfLinks));
266
267
268 return TRUE;
269}
270
271
272
273/*
274 * GetPathFromOA()
275 *
276 * Description:
277 * Resolve an object handle to an object name.
278 *
279 * Parameters:
280 * ObjectAttributes - opaque structure describing an object handle.
281 * OutBuffer - output buffer where an object name will be saved to.
282 * OutBufferSize - size of an output buffer.
283 * ResolveLinks - do symbolic links need to be resolved?
284 *
285 * Returns:
286 * TRUE to indicate success, FALSE if failed.
287 */
288
289#define FINISH_GetPathFromOA(msg) \
290 do { \
291 LOG(LOG_SS_PATHPROC, LOG_PRIORITY_DEBUG, msg); \
292 return FALSE; \
293 } while(0)
294
295BOOLEAN
296GetPathFromOA(IN POBJECT_ATTRIBUTES ObjectAttributes, OUT PCHAR OutBuffer, IN USHORT OutBufferSize, IN BOOLEAN ResolveLinks)
297{
298 NTSTATUS rc;
299 PVOID Object = NULL;
300 ULONG len;
301 CHAR Buffer[sizeof(OBJECT_NAME_INFORMATION) + bMAX_PATH];
302 POBJECT_NAME_INFORMATION pONI = (POBJECT_NAME_INFORMATION) Buffer;
303 BOOLEAN ret = FALSE;
304 UNICODE_STRING ObjectName;
305
306 PUNICODE_STRING pusFilename = NULL;
307 ANSI_STRING name;
308
309
310 if (! ARGUMENT_PRESENT(ObjectAttributes) || OutBuffer == NULL)
311
312 return(FALSE);
313
314
315 try
316 {
317 if (KeGetPreviousMode() != KernelMode)
318
319 ProbeForRead(ObjectAttributes, sizeof(OBJECT_ATTRIBUTES), sizeof(ULONG));
320
321
322 if (ObjectAttributes->Length != sizeof(OBJECT_ATTRIBUTES))
323
324 FINISH_GetPathFromOA(("GetPathFromOA: Invalid ObjectAttributes length %d\n", ObjectAttributes->Length));
325
326
327 if (! ARGUMENT_PRESENT(ObjectAttributes->ObjectName) )
328
329 return FALSE;
330
331
332 if (KeGetPreviousMode() != KernelMode)
333 {
334 ProbeForRead(ObjectAttributes->ObjectName, sizeof(UNICODE_STRING), sizeof(ULONG));
335
336 ObjectName = ProbeAndReadUnicodeString(ObjectAttributes->ObjectName);
337 }
338 else
339 {
340 ObjectName = *ObjectAttributes->ObjectName;
341 }
342
343
344 if (ObjectName.Length == 0)
345
346 return FALSE;
347
348
349 if (((ObjectName.Length & (sizeof(WCHAR) - 1)) != 0) ||
350 (ObjectName.Length > bMAX_PATH - sizeof(WCHAR)) )
351
352 FINISH_GetPathFromOA(("GetPathFromOA: invalid wchar string length = %d\n", ObjectName.Length));
353
354
355 if (KeGetPreviousMode() != KernelMode)
356
357 ProbeForRead(ObjectName.Buffer, ObjectName.Length, sizeof(WCHAR));
358 }
359
360 except(EXCEPTION_EXECUTE_HANDLER)
361 {
362 NTSTATUS status = GetExceptionCode();
363
364 LOG(LOG_SS_PATHPROC, LOG_PRIORITY_DEBUG, ("GetPathFromOA(): caught an exception. status = 0x%x\n", status));
365
366 return FALSE;
367 }
368
369
370 pusFilename = &ObjectName;
371
372
373 /*
374 * is the filename referenced in relation to some directory?
375 * if so, append the filename to a specified directory name
376 */
377
378 if (ARGUMENT_PRESENT(ObjectAttributes->RootDirectory))
379 {
380 if (! NT_SUCCESS( ObReferenceObjectByHandle(ObjectAttributes->RootDirectory, 0, 0,
381 KernelMode, &Object, NULL) ))
382 {
383 FINISH_GetPathFromOA(("GetPathFromOA(): ObReferenceObjectByHandle() failed. Object = %x\n", Object));
384 }
385
386 if (Object == NULL)
387 {
388 FINISH_GetPathFromOA(("GetPathFromOA(): Object = NULL\n"));
389 }
390
391
392 if (! NT_SUCCESS( ObQueryNameString(Object, pONI, bMAX_PATH, &len) ))
393 {
394 ObDereferenceObject(Object);
395 FINISH_GetPathFromOA(("GetPathFromOA(): ObQueryNameString() failed\n"));
396 }
397
398
399 ObDereferenceObject(Object);
400 Object = NULL;
401
402
403 /* extracted directory name */
404 pusFilename = &pONI->Name;
405
406
407 /* is the directory name too long? */
408
409 if (pusFilename->Length >= bMAX_PATH - sizeof(WCHAR))
410 FINISH_GetPathFromOA(("GetPathFromOA(): directory name is too long\n"));
411
412
413 /*
414 * pusFilename points to a buffer of MAX_PATH size, ObQueryNameString() sets MaximumLength to the length
415 * of the directory name, we need to reset this back to MAX_PATH to be able to append a filename
416 * (reusing the same buffer)
417 */
418 pusFilename->MaximumLength = bMAX_PATH;
419
420
421 if (pusFilename->Buffer[ (pusFilename->Length / sizeof(WCHAR)) - 1 ] != L'\\')
422 {
423 pusFilename->Buffer[ pusFilename->Length / sizeof(WCHAR) ] = L'\\';
424 pusFilename->Length += sizeof(WCHAR);
425 }
426
427 if (RtlAppendUnicodeStringToString(pusFilename, ObjectAttributes->ObjectName) == STATUS_BUFFER_TOO_SMALL)
428 {
429 LOG(LOG_SS_PATHPROC, LOG_PRIORITY_VERBOSE, ("GetPathFromOA: 1 %S\n", pusFilename->Buffer));
430 LOG(LOG_SS_PATHPROC, LOG_PRIORITY_VERBOSE, ("GetPathFromOA: 2 %S\n", ObjectAttributes->ObjectName->Buffer));
431 FINISH_GetPathFromOA(("GetPathFromOA(): RtlAppendUnicodeStringToString() = STATUS_BUFFER_TOO_SMALL\n"));
432 }
433 }
434
435
436 if (NT_SUCCESS(RtlUnicodeStringToAnsiString(&name, pusFilename, TRUE)))
437 {
438 if (ResolveLinks == TRUE)
439 {
440 ret = ResolveFilename(name.Buffer, OutBuffer, OutBufferSize);
441 }
442 else
443 {
444 if (name.Length >= OutBufferSize - 1)
445 {
446 LOG(LOG_SS_PATHPROC, LOG_PRIORITY_DEBUG, ("GetPathFromOA: Pathname too long %d\n", name.Length));
447
448 OutBuffer[0] = 0;
449
450 ret = FALSE;
451 }
452 else
453 {
454 strcpy(OutBuffer, name.Buffer);
455
456 ret = TRUE;
457 }
458 }
459
460 RtlFreeAnsiString(&name);
461 }
462
463
464// LOG(LOG_SS_PATHPROC, LOG_PRIORITY_VERBOSE, ("%d GetPathFromOA: %s (%S)\n", (ULONG) PsGetCurrentProcessId(), OutBuffer, pusFilename->Buffer));
465
466
467 return ret;
468}
469
470
471
472
473BOOLEAN
474GetPathFromOAW(IN POBJECT_ATTRIBUTES ObjectAttributes, OUT PCHAR OutBuffer, IN USHORT OutBufferSize, IN BOOLEAN ResolveLinks)
475{
476 NTSTATUS rc;
477 PVOID Object = NULL;
478 ULONG len;
479 CHAR Buffer[sizeof(OBJECT_NAME_INFORMATION) + bMAX_PATH];
480 POBJECT_NAME_INFORMATION pONI = (POBJECT_NAME_INFORMATION) Buffer;
481 BOOLEAN ret = FALSE;
482 UNICODE_STRING ObjectName;
483
484 PUNICODE_STRING pusFilename = NULL;
485 ANSI_STRING name;
486
487
488 if (! ARGUMENT_PRESENT(ObjectAttributes) || OutBuffer == NULL)
489
490 return(FALSE);
491
492
493 try
494 {
495 if (KeGetPreviousMode() != KernelMode)
496
497 ProbeForRead(ObjectAttributes, sizeof(OBJECT_ATTRIBUTES), sizeof(ULONG));
498
499
500 if (ObjectAttributes->Length != sizeof(OBJECT_ATTRIBUTES))
501
502 FINISH_GetPathFromOA(("GetPathFromOA: Invalid ObjectAttributes length %d\n", ObjectAttributes->Length));
503
504
505 if (! ARGUMENT_PRESENT(ObjectAttributes->ObjectName) )
506
507 return FALSE;
508
509
510 if (KeGetPreviousMode() != KernelMode)
511 {
512 ProbeForRead(ObjectAttributes->ObjectName, sizeof(UNICODE_STRING), sizeof(ULONG));
513
514 ObjectName = ProbeAndReadUnicodeString(ObjectAttributes->ObjectName);
515 }
516 else
517 {
518 ObjectName = *ObjectAttributes->ObjectName;
519 }
520
521
522 if (ObjectName.Length == 0)
523
524 return FALSE;
525
526
527 if (((ObjectName.Length & (sizeof(WCHAR) - 1)) != 0) ||
528 (ObjectName.Length > bMAX_PATH - sizeof(WCHAR)) )
529
530 FINISH_GetPathFromOA(("GetPathFromOA: invalid wchar string length = %d\n", ObjectName.Length));
531
532
533 if (KeGetPreviousMode() != KernelMode)
534
535 ProbeForRead(ObjectName.Buffer, ObjectName.Length, sizeof(WCHAR));
536 }
537
538 except(EXCEPTION_EXECUTE_HANDLER)
539 {
540 NTSTATUS status = GetExceptionCode();
541
542 LOG(LOG_SS_PATHPROC, LOG_PRIORITY_DEBUG, ("GetPathFromOA(): caught an exception. status = 0x%x\n", status));
543
544 return FALSE;
545 }
546
547
548 pusFilename = &ObjectName;
549
550
551 /*
552 * is the filename referenced in relation to some directory?
553 * if so, append the filename to a specified directory name
554 */
555
556 if (ARGUMENT_PRESENT(ObjectAttributes->RootDirectory))
557 {
558 if (! NT_SUCCESS( ObReferenceObjectByHandle(ObjectAttributes->RootDirectory, 0, 0,
559 KernelMode, &Object, NULL) ))
560 {
561 ObDereferenceObject(Object);
562 FINISH_GetPathFromOA(("GetPathFromOA(): ObReferenceObjectByHandle() failed\n"));
563 }
564
565
566 if (Object == NULL)
567 {
568 ObDereferenceObject(Object);
569 FINISH_GetPathFromOA(("GetPathFromOA(): Object = NULL\n"));
570 }
571
572
573 if (! NT_SUCCESS( ObQueryNameString(Object, pONI, bMAX_PATH, &len) ))
574 {
575 ObDereferenceObject(Object);
576 FINISH_GetPathFromOA(("GetPathFromOA(): ObQueryNameString() failed\n"));
577 }
578
579
580 ObDereferenceObject(Object);
581 Object = NULL;
582
583
584 /* extracted directory name */
585 pusFilename = &pONI->Name;
586
587
588 /* is the directory name too long? */
589
590 if (pusFilename->Length >= bMAX_PATH - sizeof(WCHAR))
591 FINISH_GetPathFromOA(("GetPathFromOA(): directory name is too long\n"));
592
593
594 /*
595 * pusFilename points to a buffer of MAX_PATH size, ObQueryNameString() sets MaximumLength to the length
596 * of the directory name, we need to reset this back to MAX_PATH to be able to append a filename
597 * (reusing the same buffer)
598 */
599 pusFilename->MaximumLength = bMAX_PATH;
600
601
602 pusFilename->Buffer[ pusFilename->Length / sizeof(WCHAR) ] = L'\\';
603 pusFilename->Length += sizeof(WCHAR);
604
605
606 if (RtlAppendUnicodeStringToString(pusFilename, ObjectAttributes->ObjectName) == STATUS_BUFFER_TOO_SMALL)
607 {
608 LOG(LOG_SS_PATHPROC, LOG_PRIORITY_VERBOSE, ("GetPathFromOA: 1 %S\n", pusFilename->Buffer));
609 LOG(LOG_SS_PATHPROC, LOG_PRIORITY_VERBOSE, ("GetPathFromOA: 2 %S\n", ObjectAttributes->ObjectName->Buffer));
610 FINISH_GetPathFromOA(("GetPathFromOA(): RtlAppendUnicodeStringToString() = STATUS_BUFFER_TOO_SMALL\n"));
611 }
612 }
613
614
615 if (ResolveLinks == TRUE)
616 {
617 ret = ResolveFilenameW(pusFilename, OutBuffer, OutBufferSize);
618 }
619
620//XXX
621 if (NT_SUCCESS(RtlUnicodeStringToAnsiString(&name, pusFilename, TRUE)))
622 {
623 if (ResolveLinks == TRUE)
624 {
625 ret = ResolveFilename(name.Buffer, OutBuffer, OutBufferSize);
626 }
627 else
628 {
629 if (name.Length >= OutBufferSize - 1)
630 {
631 LOG(LOG_SS_PATHPROC, LOG_PRIORITY_DEBUG, ("GetPathFromOA: Pathname too long %d\n", name.Length));
632
633 OutBuffer[0] = 0;
634
635 ret = FALSE;
636 }
637 else
638 {
639 strcpy(OutBuffer, name.Buffer);
640
641 ret = TRUE;
642 }
643 }
644
645 RtlFreeAnsiString(&name);
646 }
647
648
649// LOG(LOG_SS_PATHPROC, LOG_PRIORITY_VERBOSE, ("%d GetPathFromOA: %s (%S)\n", (ULONG) PsGetCurrentProcessId(), OutBuffer, pusFilename->Buffer));
650
651
652 return ret;
653}
654
655
656/*
657 * ConvertLongFileNameToShort()
658 *
659 * Description:
660 * Converts long windows filenames to their DOS short equivalent filenames
661 * (i.e. c:\program files to c:\progra~1).
662 *
663 * Parameters:
664 * LongFileName - long filename buffer.
665 * ShortFileName - output buffer where a short filename is written to.
666 * ShortFileNameSize - size of an output buffer (in bytes).
667 *
668 * Returns:
669 * TRUE to indicate success, FALSE if failed.
670 */
671
672#if 0
673
674BOOLEAN
675ConvertLongFileNameToShort(IN PCHAR LongFileName, OUT PCHAR ShortFileName, IN USHORT ShortFileNameSize)
676{
677 int LongFileNameIndex = 0, ShortFileNameIndex = 0, CurrentFileNameLength, TotalLength, ExtensionLength, NumberOfSpaces;
678 BOOLEAN ProcessingExtension = FALSE;
679 CHAR ch, Extension[3];
680
681
682 if (LongFileName == NULL)
683 return FALSE;
684
685 TotalLength = strlen(LongFileName);
686
687
688 /* if the filename does not start with X:\ then assume \device\blah\ format and skip over the first 2 slashes */
689 if (LongFileName[0] == '\\')
690 {
691 int Slashes = 0;
692
693 do
694 {
695 if ( (ch = ShortFileName[ShortFileNameIndex++] = LongFileName[LongFileNameIndex++]) == '\0') return TRUE;
696 if (ch == '\\') ++Slashes;
697 } while (Slashes != 3);
698 }
699
700 for (NumberOfSpaces = ExtensionLength = CurrentFileNameLength = 0; ; LongFileNameIndex++)
701 {
702 /* if we finished traversing the entire directory path or reached a '\' then process the filename (append the extension if necessary) */
703 if (LongFileNameIndex == TotalLength || LongFileName[LongFileNameIndex] == '\\')
704 {
705 /*
706 * if the filename is longer than 8 chars or extension is longer than 3 chars then we need
707 * to create a 6 char filename followed by a '~1' and the first 3 chars of the last extension
708 */
709
710 if (CurrentFileNameLength > 8 || ExtensionLength > 3 || NumberOfSpaces > 0)
711 {
712 CurrentFileNameLength -= NumberOfSpaces;
713
714 if (CurrentFileNameLength > 7)
715 {
716 ShortFileName[ShortFileNameIndex - 2] = '~';
717 ShortFileName[ShortFileNameIndex - 1] = '1';
718 }
719 else if (CurrentFileNameLength == 7)
720 {
721 ShortFileName[ShortFileNameIndex - 1] = '~';
722 ShortFileName[ShortFileNameIndex++] = '1';
723 }
724 else
725 {
726 ShortFileName[ShortFileNameIndex++] = '~';
727 ShortFileName[ShortFileNameIndex++] = '1';
728 }
729 }
730
731 if (ExtensionLength > 0)
732 {
733 ShortFileName[ShortFileNameIndex++] = '.';
734 ShortFileName[ShortFileNameIndex++] = Extension[0];
735
736 if (ExtensionLength > 1)
737 {
738 ShortFileName[ShortFileNameIndex++] = Extension[1];
739
740 if (ExtensionLength > 2)
741 ShortFileName[ShortFileNameIndex++] = Extension[2];
742 }
743
744 ExtensionLength = 0;
745 ProcessingExtension = FALSE;
746 }
747
748 /* if we are done traversing the entire path than we can bail */
749 if (LongFileNameIndex == TotalLength)
750 break;
751
752 ShortFileName[ShortFileNameIndex++] = '\\';
753 NumberOfSpaces = CurrentFileNameLength = 0;
754
755 continue;
756 }
757
758 if (LongFileName[LongFileNameIndex] == '.')
759 {
760 ProcessingExtension = TRUE;
761 ExtensionLength = 0;
762 continue;
763 }
764
765 if (ProcessingExtension == TRUE)
766 {
767 if (ExtensionLength++ < 3)
768 Extension[ExtensionLength - 1] = LongFileName[LongFileNameIndex];
769
770 continue;
771 }
772
773 if (((CurrentFileNameLength++) - NumberOfSpaces) < 8)
774 {
775 if (LongFileName[LongFileNameIndex] != ' ')
776 ShortFileName[ShortFileNameIndex++] = LongFileName[LongFileNameIndex];
777 else
778 ++NumberOfSpaces;
779 }
780 }
781
782
783 ShortFileName[ShortFileNameIndex++] = 0;
784
785
786 return TRUE;
787}
788
789#endif
790
791
792
793/*
794 * GetNameFromHandle()
795 *
796 * Description:
797 * Resolve an object handle to an object name.
798 *
799 * Parameters:
800 * ObjectHandle - handle of an object whose name we are trying to obtain.
801 * OutBuffer - output buffer where an object name will be saved to.
802 * OutBufferSize - size of an output buffer (in bytes).
803 *
804 * Returns:
805 * TRUE to indicate success, FALSE if failed.
806 */
807
808PWSTR
809GetNameFromHandle(IN HANDLE ObjectHandle, OUT PWSTR OutBuffer, IN USHORT OutBufferSize)
810{
811 PVOID Object = NULL;
812 NTSTATUS rc;
813 POBJECT_NAME_INFORMATION pONI = (POBJECT_NAME_INFORMATION) OutBuffer;
814 ULONG len;
815
816
817 rc = ObReferenceObjectByHandle(ObjectHandle, GENERIC_READ, NULL, KernelMode, &Object, NULL);
818 if (! NT_SUCCESS(rc))
819 {
820 LOG(LOG_SS_PATHPROC, LOG_PRIORITY_DEBUG, ("%d GetNameFromHandle: ObReferenceObjectByHandle failed\n", (ULONG) PsGetCurrentProcessId()));
821 return NULL;
822 }
823
824
825 rc = ObQueryNameString(Object, pONI, OutBufferSize - sizeof(OBJECT_NAME_INFORMATION)*sizeof(WCHAR), &len);
826 if (! NT_SUCCESS(rc))
827 {
828 LOG(LOG_SS_PATHPROC, LOG_PRIORITY_VERBOSE, ("%d GetNameFromHandle: ObQueryNameString failed\n", (ULONG) PsGetCurrentProcessId()));
829 return NULL;
830 }
831
832
833// _snprintf(OutBuffer, OutBufferSize, "%S", pONI->Name.Buffer);
834// OutBuffer[OutBufferSize - 1] = 0;
835
836// LOG(LOG_SS_PATHPROC, LOG_PRIORITY_DEBUG, ("%S (%s)\n", pONI->Name.Buffer, OutBuffer));
837
838
839 ObDereferenceObject(Object);
840
841
842 return pONI->Name.Buffer;
843// return TRUE;
844}
845
846
847
848/*
849 * StripFileMacros()
850 *
851 * Description:
852 * Strip file names of %SystemRoot% and %SystemDrive% macros as well as any specifications.
853 *
854 * Parameters:
855 * Path - ASCII file path to parse.
856 * Buffer - pointer to an Object where the final result will be saved.
857 * BufferSize - size of the output Buffer.
858 *
859 * Returns:
860 * Pointer to a stripped ASCII path.
861 */
862
863PCHAR
864StripFileMacros(IN PCHAR Path, OUT PCHAR Buffer, IN USHORT BufferSize)
865{
866 if (_strnicmp(Path, "%systemdrive%:", 14) == 0)
867 {
868 return Path + 14;
869 }
870
871
872 if (_strnicmp(Path, "%systemroot%\\", 13) == 0)
873 {
874 if (_snprintf(Buffer, MAX_PATH, "%s%s", SystemRootUnresolved, Path + 12) < 0)
875 return NULL;
876
877 Path = Buffer;
878 }
879
880
881 if (Path[1] == ':' && Path[2] == '\\' && (isalpha(Path[0]) || Path[0] == '?' || Path[0] == '*'))
882 {
883 Path += 2;
884 }
885
886
887 return Path;
888}
889
890
891
892/*
893 * FixupFilename()
894 *
895 * Description:
896 * Get canonical name for a file (without the drive specification, i.e. \windows\blah.exe)
897 *
898 * Parameters:
899 * szFileName - filename to resolve.
900 * szResult - output buffer.
901 * szResultSize - size of an output buffer.
902 *
903 * Returns:
904 * TRUE to indicate success, FALSE if failed.
905 */
906
907BOOLEAN
908FixupFilename(IN PCHAR szFileName, OUT PCHAR szResult, IN USHORT szResultSize)
909{
910 /* skip over \??\ */
911 if (_strnicmp(szFileName, "\\??\\", 4) == 0)
912 {
913 szFileName += 4;
914 }
915
916
917 /* replace "\SystemRoot" references with the actual system root directory */
918 if (_strnicmp(szFileName, "\\SystemRoot\\", 12) == 0)
919 {
920 _snprintf(szResult, szResultSize, "%s\\%s", SystemRootDirectory, szFileName + 12);
921 szResult[ szResultSize - 1 ] = 0;
922
923 return TRUE;
924 }
925
926
927 /* skip over X: drive specifications */
928 if (isalpha(szFileName[0]) && szFileName[1] == ':' && szFileName[2] == '\\')
929 {
930 szFileName += 2;
931 }
932
933
934 strncpy(szResult, szFileName, szResultSize);
935 szResult[ szResultSize - 1 ] = 0;
936
937
938 return TRUE;
939}
940
941
942
943/*
944 * AreMalformedExtensionsAllowed()
945 *
946 * Description:
947 * Check whether the current process is allowed to run binaries with malformed file extensions.
948 *
949 * Parameters:
950 * None.
951 *
952 * Returns:
953 * FALSE if binaries with malformed extensions are not allowed to run. TRUE otherwise.
954 */
955
956BOOLEAN
957AreMalformedExtensionsAllowed()
958{
959 PIMAGE_PID_ENTRY CurrentProcess;
960 BOOLEAN MalformedExtensionsAllowed = FALSE;
961
962
963 /* check the global policy first */
964 if (! IS_EXTENSION_PROTECTION_ON(gSecPolicy))
965 return TRUE;
966
967
968 /* now check the process specific policy */
969 CurrentProcess = FindImagePidEntry(CURRENT_PROCESS_PID, 0);
970
971 if (CurrentProcess != NULL)
972 {
973 MalformedExtensionsAllowed = ! IS_EXTENSION_PROTECTION_ON(CurrentProcess->SecPolicy);
974 }
975 else
976 {
977 LOG(LOG_SS_PATHPROC, LOG_PRIORITY_DEBUG, ("%d AreMalformedExtensionsAllowed: CurrentProcess = NULL!\n", (ULONG) PsGetCurrentProcessId()));
978 }
979
980
981 return MalformedExtensionsAllowed;
982}
983
984
985
986/*
987 * VerifyExecutableName()
988 *
989 * Description:
990 * Make sure the executed binary does not have a funny filename.
991 * Look out for non-standard extensions (.exe, etc) and double
992 * extensions that are commonly "ab"used by malware.
993 *
994 * Parameters:
995 * szFileName - filename to verify.
996 *
997 * Returns:
998 * TRUE to indicate success, FALSE if failed.
999 */
1000
1001#define CHECK_LEARNING_MODE() \
1002 if (LearningMode == TRUE) \
1003 { \
1004 TURN_EXTENSION_PROTECTION_OFF(NewPolicy); \
1005 return TRUE; \
1006 }
1007
1008BOOLEAN
1009VerifyExecutableName(IN PCHAR szFileName)
1010{
1011 SHORT i, len;
1012 BOOLEAN FirstExtension = TRUE;
1013
1014
1015 if (LearningMode == FALSE && AreMalformedExtensionsAllowed() == TRUE)
1016 {
1017 /* no need to check anything further, malformed extensions are allowed */
1018 return TRUE;
1019 }
1020
1021
1022 if ((len = (SHORT) strlen(szFileName)) == 0)
1023 return TRUE;
1024
1025
1026 for (i = len - 1; i >= 0; i--)
1027 {
1028 /* bail out once we reach the end of the filename */
1029 if (szFileName[i] == '\\')
1030 break;
1031
1032 if (szFileName[i] == '.')
1033 {
1034 if (FirstExtension == FALSE)
1035 {
1036 CHECK_LEARNING_MODE();
1037
1038 LOG(LOG_SS_PATHPROC, LOG_PRIORITY_DEBUG, ("VerifyExecutableName: Executing a binary with more than one extension '%s'\n", szFileName));
1039
1040 LogAlert(ALERT_SS_PROCESS, OP_PROC_EXECUTE, ALERT_RULE_PROCESS_EXEC_2EXTS, ACTION_LOG, ALERT_PRIORITY_HIGH, NULL, 0, szFileName);
1041
1042 return FALSE;
1043 }
1044
1045 if (len - i != 4)
1046 {
1047 CHECK_LEARNING_MODE();
1048
1049 LOG(LOG_SS_PATHPROC, LOG_PRIORITY_DEBUG, ("VerifyExecutableName: Executing a binary with an unknown extension '%s'\n", szFileName));
1050
1051 LogAlert(ALERT_SS_PROCESS, OP_PROC_EXECUTE, ALERT_RULE_PROCESS_EXEC_UNKNOWN, ACTION_LOG, ALERT_PRIORITY_HIGH, NULL, 0, szFileName);
1052
1053 return FALSE;
1054 }
1055 else
1056 {
1057 if (_stricmp(szFileName + i + 1, "exe") != 0 &&
1058 _stricmp(szFileName + i + 1, "com") != 0 &&
1059 _stricmp(szFileName + i + 1, "bat") != 0 &&
1060 _stricmp(szFileName + i + 1, "scr") != 0 &&
1061 _stricmp(szFileName + i + 1, "dir") != 0 &&
1062 _stricmp(szFileName + i + 1, "tmp") != 0 &&
1063 _stricmp(szFileName + i + 1, "_mp") != 0)
1064 {
1065 CHECK_LEARNING_MODE();
1066
1067 LOG(LOG_SS_PATHPROC, LOG_PRIORITY_DEBUG, ("VerifyExecutableName: Executing a binary with an unknown extension '%s'\n", szFileName));
1068
1069 LogAlert(ALERT_SS_PROCESS, OP_PROC_EXECUTE, ALERT_RULE_PROCESS_EXEC_UNKNOWN, ACTION_LOG, ALERT_PRIORITY_HIGH, NULL, 0, szFileName);
1070
1071 return FALSE;
1072 }
1073 }
1074
1075 FirstExtension = FALSE;
1076 }
1077 }
1078
1079
1080 if (FirstExtension == TRUE)
1081 {
1082 CHECK_LEARNING_MODE();
1083
1084 LOG(LOG_SS_PATHPROC, LOG_PRIORITY_DEBUG, ("VerifyExecutableName: Executing binary without an extension '%s'\n", szFileName));
1085
1086 LogAlert(ALERT_SS_PROCESS, OP_PROC_EXECUTE, ALERT_RULE_PROCESS_EXEC_NOEXT, ACTION_LOG, ALERT_PRIORITY_HIGH, NULL, 0, szFileName);
1087
1088 return FALSE;
1089 }
1090
1091
1092 return TRUE;
1093}
diff --git a/pathproc.h b/pathproc.h
new file mode 100644
index 0000000..9a6c049
--- /dev/null
+++ b/pathproc.h
@@ -0,0 +1,67 @@
1/*
2 * Copyright (c) 2004 Security Architects Corporation. All rights reserved.
3 *
4 * Module Name:
5 *
6 * pathproc.h
7 *
8 * Abstract:
9 *
10 * This module definies various types used by pathname handling routines.
11 *
12 * Author:
13 *
14 * Eugene Tsyrklevich 19-Feb-2004
15 *
16 * Revision History:
17 *
18 * None.
19 */
20
21
22#ifndef __PATHPROC_H__
23#define __PATHPROC_H__
24
25
26#include <NTDDK.h>
27#include "log.h"
28
29
30// some registry keys are actually longer than 260 chars!
31// HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Control\DeviceClasses\{6994AD04-93EF-11D0-A3CC-00A0C9223196}\##?#Root#SYSTEM#0000#{6994ad04-93ef-11d0-a3cc-00a0c9223196}\#{2f412ab5-ed3a-4590-ab24-b0ce2aa77d3c}&{9B365890-165F-11D0-A195-0020AFD156E4}\Device Parameters
32//#define MAX_PATH 260
33
34#define MAX_PATH 300
35#define chMAX_PATH MAX_PATH
36#define bMAX_PATH (MAX_PATH * sizeof(WCHAR))
37
38
39/* maximum number of links to follow */
40#define MAX_NUMBER_OF_LINKS 3
41
42
43#define DO_NOT_RESOLVE_LINKS 0
44#define RESOLVE_LINKS 1
45
46
47BOOLEAN GetPathFromOA(IN POBJECT_ATTRIBUTES ObjectAttributes, OUT PCHAR OutBuffer, IN USHORT OutBufferSize, IN BOOLEAN ResolveLinks);
48BOOLEAN GetPathFromOAW(IN POBJECT_ATTRIBUTES ObjectAttributes, OUT PCHAR OutBuffer, IN USHORT OutBufferSize, IN BOOLEAN ResolveLinks);
49BOOLEAN ResolveFilename(IN PCHAR szFileName, OUT PCHAR szResult, IN USHORT szResultSize);
50BOOLEAN ResolveFilenameW(IN PUNICODE_STRING szFileName, OUT PCHAR szResult, IN USHORT szResultSize);
51PWSTR GetNameFromHandle(IN HANDLE ObjectHandle, OUT PWSTR OutBuffer, IN USHORT OutBufferSize);
52BOOLEAN FixupFilename(IN PCHAR szFileName, OUT PCHAR szResult, IN USHORT szResultSize);
53BOOLEAN VerifyExecutableName(IN PCHAR szFileName);
54PCHAR StripFileMacros(IN PCHAR Path, OUT PCHAR Buffer, IN USHORT BufferSize);
55BOOLEAN ConvertLongFileNameToShort(IN PCHAR LongFileName, OUT PCHAR ShortFileName, IN USHORT ShortFileNameSize);
56
57
58NTSTATUS
59ObQueryNameString(
60 IN PVOID Object,
61 OUT POBJECT_NAME_INFORMATION ObjectNameInfo,
62 IN ULONG Length,
63 OUT PULONG ReturnLength
64 );
65
66
67#endif /* __PATHPROC_H__ */ \ No newline at end of file
diff --git a/policy.c b/policy.c
new file mode 100644
index 0000000..be08a81
--- /dev/null
+++ b/policy.c
@@ -0,0 +1,3243 @@
1/*
2 * Copyright (c) 2004 Security Architects Corporation. All rights reserved.
3 *
4 * Module Name:
5 *
6 * policy.c
7 *
8 * Abstract:
9 *
10 * This module implements various security policy parsing and enforcement routines.
11 *
12 * Author:
13 *
14 * Eugene Tsyrklevich 16-Feb-2004
15 *
16 * Revision History:
17 *
18 * None.
19 */
20
21// XXX rename all funcs as SpYYY ? (same for other modules?)
22
23#include <NTDDK.h>
24#include "policy.h"
25#include "pathproc.h"
26#include "procname.h"
27#include "hookproc.h"
28#include "media.h"
29#include "learn.h"
30#include "misc.h"
31#include "i386.h"
32
33
34#include "process.h"
35#include "log.h"
36
37
38BOOLEAN PolicyParseRule(OUT PSECURITY_POLICY pSecPolicy, IN PCHAR rule, OUT BOOLEAN *Critical);
39BOOLEAN PolicyParsePolicyRule(OUT PSECURITY_POLICY pSecPolicy, IN PCHAR Operation, IN PCHAR rule, OUT BOOLEAN *Critical);
40BOOLEAN PolicyParseObjectRule(PSECURITY_POLICY pSecPolicy, RULE_TYPE RuleType, PCHAR Operation, PCHAR rule);
41BOOLEAN PolicyParseSyscallRule(PSECURITY_POLICY pSecPolicy, PCHAR SyscallName, PCHAR rule);
42BOOLEAN PolicyParseProtectionRule(PSECURITY_POLICY pSecPolicy, PCHAR Operation, PCHAR rule);
43BOOLEAN PolicyParseMediaRule(PSECURITY_POLICY pSecPolicy, PCHAR Operation, PCHAR rule);
44
45
46#ifdef ALLOC_PRAGMA
47#pragma alloc_text (INIT, InitPolicy)
48#pragma alloc_text (PAGE, PolicyPostBootup)
49#pragma alloc_text (PAGE, PolicyRemove)
50#endif
51
52
53/*
54 * example:
55 *
56 * SystemRoot - \device\harddisk1\windows
57 * SystemRootUnresolved - c:\windows
58 * SystemRootDirectory - \windows
59 * CDrive - \device\harddisk1
60 */
61
62CHAR SystemDrive, SystemRoot[MAX_PATH], SystemRootUnresolved[MAX_PATH], *SystemRootDirectory, CDrive[MAX_PATH];
63USHORT SystemRootLength = 0, SystemRootUnresolvedLength = 0, SystemRootDirectoryLength = 0, CDriveLength = 0;
64
65USHORT gPolicyLineNumber;
66PWSTR gPolicyFilename, gFilePath;
67
68// to be portable on 32 & 64 bit platforms
69ULONG NumberOfBitsInUlong, UlongBitShift;
70
71/* LoadPolicy() can be used by only one thread at a time due to use of global variables */
72KMUTEX LoadPolicyMutex;
73
74/* Global Security Policy */
75SECURITY_POLICY gSecPolicy;
76
77
78
79/*
80 * InitPolicy()
81 *
82 * Description:
83 * Initialize the policy engine. Load the global policy.
84 *
85 * NOTE: Called once during driver initialization (DriverEntry()).
86 *
87 * Parameters:
88 * None.
89 *
90 * Returns:
91 * TRUE if everything is OK, FALSE if failed.
92 */
93
94BOOLEAN
95InitPolicy()
96{
97 NumberOfBitsInUlong = sizeof(ULONG) * 8;
98 UlongBitShift = sizeof(ULONG) == 4 ? 5 : 6;
99
100
101 /* gets reinitialized correctly once bootup is complete (see PolicyPostBootup) */
102 SystemDrive = 'C';
103
104 if (ReadSymlinkValue(L"\\SystemRoot", SystemRootUnresolved, MAX_PATH) == FALSE)
105 {
106 LOG(LOG_SS_POLICY, LOG_PRIORITY_DEBUG, ("InitPolicy: ReadSymlinkValue failed\n"));
107 return FALSE;
108 }
109
110 SystemRootUnresolvedLength = (USHORT) strlen(SystemRootUnresolved);
111
112 ResolveFilename(SystemRootUnresolved, SystemRoot, MAX_PATH);
113
114
115 /* extract the system directory name by itself (i.e. \windows) */
116 SystemRootDirectory = strrchr(SystemRoot, '\\');
117
118 if (SystemRootDirectory == NULL)
119 {
120 LOG(LOG_SS_POLICY, LOG_PRIORITY_DEBUG, ("InitPolicy: SystemRootDirectory is NULL\n"));
121 return FALSE;
122 }
123
124 SystemRootDirectoryLength = (USHORT) strlen(SystemRootDirectory);
125
126
127 if (ReadSymlinkValue(L"\\??\\C:", CDrive, MAX_PATH) == FALSE)
128 {
129 LOG(LOG_SS_POLICY, LOG_PRIORITY_DEBUG, ("InitPolicy: Failed to open C: symbolic link\n"));
130 return FALSE;
131 }
132
133 CDriveLength = (USHORT) strlen(CDrive);
134
135
136 if (PolicyPostBootup() == FALSE)
137 {
138 /*
139 * if boot process is not complete yet then we cannot get SystemRootUnresolved (i.e. c:\windows)
140 * because parts of registry are not initialized yet (see PolicyPostBootup)
141 *
142 * In that case, try to assemble SystemRootUnresolved manually
143 */
144
145 SystemRootUnresolved[0] = SystemDrive;
146 SystemRootUnresolved[1] = ':';
147
148 strcpy(SystemRootUnresolved + 2, SystemRootDirectory);
149 }
150
151
152 LOG(LOG_SS_POLICY, LOG_PRIORITY_VERBOSE, ("InitPolicy: SystemRoot=%s (%s, %s)\n", SystemRoot, SystemRootUnresolved, SystemRootDirectory));
153
154
155 KeInitializeMutex(&LoadPolicyMutex, 0);
156
157 RtlZeroMemory(&gSecPolicy, sizeof(gSecPolicy));
158
159 KeInitializeSpinLock(&gSecPolicy.SpinLock);
160
161
162 if (LearningMode == TRUE)
163
164 return TRUE;
165
166
167 if (FindAndLoadSecurityPolicy(&gSecPolicy, L"computer", NULL) == FALSE)
168 {
169 LOG(LOG_SS_POLICY, LOG_PRIORITY_WARNING, ("InitPolicy: LoadSecurityPolicy(computer.policy) failed\n"));
170 gSecPolicy.DefaultPolicyAction = ACTION_PERMIT_DEFAULT;
171 }
172
173
174 if (gSecPolicy.DefaultPolicyAction != ACTION_PERMIT_DEFAULT)
175 {
176 LOG(LOG_SS_POLICY, LOG_PRIORITY_WARNING, ("InitPolicy: Global policy default action must be permit\n"));
177 gSecPolicy.DefaultPolicyAction = ACTION_PERMIT_DEFAULT;
178 }
179
180
181 return TRUE;
182}
183
184
185
186/*
187 * PolicyPostBootup()
188 *
189 * Description:
190 * Finish initializing system variables once the bootup process is complete.
191 * We are unable to read the SystemRoot registry value before the bootup is complete since
192 * that part of the registry has not been initialized yet.
193 *
194 * Parameters:
195 * None.
196 *
197 * Returns:
198 * TRUE to indicate success, FALSE if failed.
199 */
200
201BOOLEAN
202PolicyPostBootup()
203{
204 ASSERT(BootingUp == FALSE);
205
206
207 if (ReadStringRegistryValueA(L"\\Registry\\Machine\\Software\\Microsoft\\Windows NT\\CurrentVersion", L"SystemRoot", SystemRootUnresolved, MAX_PATH) == FALSE)
208 {
209 LOG(LOG_SS_POLICY, LOG_PRIORITY_DEBUG, ("PolicyPostBootup: Failed to open SystemRoot registry key\n"));
210 return FALSE;
211 }
212
213 SystemRootUnresolvedLength = (USHORT) strlen(SystemRootUnresolved);
214
215 SystemDrive = (CHAR) toupper(SystemRootUnresolved[0]);
216
217
218 return TRUE;
219}
220
221
222
223/*
224 * PolicyRemove()
225 *
226 * Description:
227 * Shutdown the policy engine. Delete the global policy
228 *
229 * Parameters:
230 * None.
231 *
232 * Returns:
233 * Nothing.
234 */
235
236void
237PolicyRemove()
238{
239 PolicyDelete(&gSecPolicy);
240}
241
242
243
244/*
245 * PolicyDelete()
246 *
247 * Description:
248 * Delete a security policy. Free all the rules associated with a policy.
249 *
250 * Parameters:
251 * pSecPolicy - pointer to a security policy to delete.
252 *
253 * Returns:
254 * Nothing.
255 */
256
257void
258PolicyDelete(IN PSECURITY_POLICY pSecPolicy)
259{
260 PPOLICY_RULE r, tmp;
261 KIRQL irql;
262 UCHAR i;
263
264
265 if (pSecPolicy == NULL)
266 {
267 LOG(LOG_SS_POLICY, LOG_PRIORITY_DEBUG, ("PolicyDelete: pSecPolicy is NULL\n"));
268 return;
269 }
270
271
272 if (pSecPolicy->Initialized == FALSE)
273 {
274 LOG(LOG_SS_POLICY, LOG_PRIORITY_VERBOSE, ("PolicyDelete: pSecPolicy is not initialized\n"));
275 return;
276 }
277
278
279 KeAcquireSpinLock(&pSecPolicy->SpinLock, &irql);
280
281 for (i = 0; i < RULE_LASTONE; i++)
282 {
283 r = pSecPolicy->RuleList[i];
284
285 while (r)
286 {
287 tmp = r;
288 r = (PPOLICY_RULE) r->Next;
289
290 ExFreePoolWithTag(tmp, _POOL_TAG);
291 }
292 }
293
294 if (pSecPolicy->Name)
295 {
296 ExFreePoolWithTag(pSecPolicy->Name, _POOL_TAG);
297 pSecPolicy->Name = NULL;
298 }
299
300 pSecPolicy->Initialized = FALSE;
301
302 RtlZeroMemory(pSecPolicy->RuleList, sizeof(pSecPolicy->RuleList));
303
304
305 KeReleaseSpinLock(&pSecPolicy->SpinLock, irql);
306}
307
308
309
310/*
311 * LoadSecurityPolicy()
312 *
313 * Description:
314 * Parses and loads a security policy.
315 *
316 * Parameters:
317 * pSecPolicy - pointer to a security policy to initialize.
318 * PolicyFile - string containing the policy filename to parse
319 * FilePath - string containing full program path of the file we are loading policy for
320 *
321 * Returns:
322 * TRUE if security policy was successfully parsed and loaded, FALSE otherwise.
323 */
324
325BOOLEAN
326LoadSecurityPolicy(OUT PSECURITY_POLICY pSecPolicy, IN PWSTR PolicyFile, IN PWSTR FilePath)
327{
328 OBJECT_ATTRIBUTES oa;
329 HANDLE hFile = 0;
330 UNICODE_STRING usPolicyFile;
331 ULONG size;
332 NTSTATUS status;
333 IO_STATUS_BLOCK isb;
334 CHAR *p, buffer[POLICY_MAX_RULE_LENGTH];
335 INT64 offset;
336 BOOLEAN ret = TRUE, Critical = FALSE;
337
338
339 if (pSecPolicy == NULL || PolicyFile == NULL)
340 {
341 LOG(LOG_SS_POLICY, LOG_PRIORITY_DEBUG, ("LoadSecurityPolicy(%x, %x, %x): NULL parameter\n", pSecPolicy, PolicyFile, FilePath));
342 return FALSE;
343 }
344
345
346 pSecPolicy->Initialized = FALSE;
347 pSecPolicy->DefaultPolicyAction = ACTION_NONE;
348 pSecPolicy->ProtectionFlags = BootingUp ? PROTECTION_ALL_OFF : PROTECTION_ALL_ON;
349
350
351 RtlInitUnicodeString(&usPolicyFile, PolicyFile);
352
353 LOG(LOG_SS_POLICY, LOG_PRIORITY_VERBOSE, ("LoadSecurityPolicy: Parsing %S\n", usPolicyFile.Buffer));
354
355
356 InitializeObjectAttributes(&oa, &usPolicyFile, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL);
357
358 if (!NT_SUCCESS(ZwCreateFile(&hFile, GENERIC_READ, &oa, &isb,
359 NULL, 0, FILE_SHARE_READ, FILE_OPEN,
360 FILE_SYNCHRONOUS_IO_NONALERT, NULL, 0)))
361 {
362 LOG(LOG_SS_POLICY, LOG_PRIORITY_VERBOSE, ("LoadSecurityPolicy: Failed to open file %S\n", usPolicyFile.Buffer));
363 return FALSE;
364 }
365
366
367 offset = 0;
368 buffer[0] = 0;
369
370
371 /* only one thread at a time can use LoadPolicyMutex due to use of global variables (PolicyLineNumber, buffer) */
372 KeWaitForMutexObject(&LoadPolicyMutex, Executive, KernelMode, FALSE, NULL);
373
374
375 gPolicyLineNumber = 1;
376 gPolicyFilename = usPolicyFile.Buffer;
377 gFilePath = FilePath;
378
379 while (1)
380 {
381 status = ZwReadFile(hFile, NULL, NULL, NULL, &isb, (PVOID) buffer, sizeof(buffer) - 1,
382 (PLARGE_INTEGER) &offset, NULL);
383
384 if (! NT_SUCCESS(status))
385 {
386 if (status != STATUS_END_OF_FILE)
387 {
388 LOG(LOG_SS_POLICY, LOG_PRIORITY_DEBUG, ("LoadSecurityPolicy: ZwReadFile failed rc=%x\n", status));
389 ret = FALSE;
390 PolicyDelete(pSecPolicy);
391 }
392
393 break;
394 }
395
396 if (isb.Information == 0)
397 break;
398
399 buffer[isb.Information] = '\0';
400
401 /*
402 * strchr() will return NULL when the line we read exceeds the size of the buffer or
403 * the last line was not '\n' terminated
404 */
405
406 if ((p = strchr(buffer, '\n')) == NULL)
407 {
408 /* don't try to parse very long lines */
409
410 if (isb.Information == sizeof(buffer) - 1)
411 {
412 LOG(LOG_SS_POLICY_PARSER, LOG_PRIORITY_WARNING, ("LoadSecurityPolicy(%s:%d): Rule is too long\n", gPolicyFilename, gPolicyLineNumber));
413
414 PolicyDelete(pSecPolicy);
415
416 ret = FALSE;
417 break;
418 }
419
420
421 /* the last rule was not '\n' terminated */
422
423 if (PolicyParseRule(pSecPolicy, buffer, &Critical) == FALSE)
424 {
425 if (Critical == TRUE)
426 {
427 LOG(LOG_SS_POLICY_PARSER, LOG_PRIORITY_DEBUG, ("LoadSecurityPolicy(%S:%d): Encountered a critical error. Aborting.\n", gPolicyFilename, gPolicyLineNumber));
428
429 PolicyDelete(pSecPolicy);
430
431 ret = FALSE;
432 break;
433 }
434 }
435
436 ret = TRUE;
437
438 break;
439 }
440
441 *p = 0;
442
443 if (p != buffer && *(p - 1) == '\r')
444 *(p - 1) = 0;
445
446
447 if (PolicyParseRule(pSecPolicy, buffer, &Critical) == FALSE)
448 {
449 if (Critical == TRUE)
450 {
451 LOG(LOG_SS_POLICY_PARSER, LOG_PRIORITY_DEBUG, ("LoadSecurityPolicy(%S:%d): Encountered a critical error. Aborting.\n", gPolicyFilename, gPolicyLineNumber));
452
453 PolicyDelete(pSecPolicy);
454
455 ret = FALSE;
456 break;
457 }
458 }
459
460
461 offset += p - buffer + 1;
462
463
464 if (++gPolicyLineNumber > 10000)
465 {
466 LOG(LOG_SS_POLICY_PARSER, LOG_PRIORITY_WARNING, ("LoadSecurityPolicy: Policy '%S' is too long. Maximum number of lines is 10000.\n", gPolicyFilename));
467
468 PolicyDelete(pSecPolicy);
469
470 ret = FALSE;
471 break;
472 }
473 }
474
475 ZwClose(hFile);
476
477
478 if (ret != FALSE)
479 {
480 pSecPolicy->Initialized = TRUE;
481
482 if (pSecPolicy->DefaultPolicyAction == ACTION_NONE)
483 pSecPolicy->DefaultPolicyAction = DEFAULT_POLICY_ACTION;
484 }
485
486
487 LOG(LOG_SS_POLICY, LOG_PRIORITY_VERBOSE, ("LoadSecurityPolicy: Done Parsing %S. Total number of lines %d. (ret=%d)\n", usPolicyFile.Buffer, gPolicyLineNumber, ret));
488
489
490 KeReleaseMutex(&LoadPolicyMutex, FALSE);
491
492
493 return ret;
494}
495
496
497
498/*
499 * FindAndLoadSecurityPolicy()
500 *
501 * Description:
502 * Finds and loads a security policy associated with a specified executable filename.
503 *
504 * Parameters:
505 * pSecPolicy - pointer to a security policy to initialize.
506 * FilePath - string specifying the complete path to an executable
507 * UserName - optional username, if specified check for a policy in "username" directory first
508 *
509 * Returns:
510 * TRUE if security policy was successfully parsed and loaded, FALSE otherwise.
511 */
512
513BOOLEAN
514FindAndLoadSecurityPolicy(OUT PSECURITY_POLICY pSecPolicy, IN PWSTR FilePath, IN PWSTR UserName)
515{
516 PWSTR filename;
517 WCHAR PolicyPath[MAX_PATH];
518 BOOLEAN ret;
519 int len;
520
521
522 if (pSecPolicy == NULL || FilePath == NULL)
523 {
524 LOG(LOG_SS_POLICY, LOG_PRIORITY_DEBUG, ("FindAndLoadSecurityPolicy: NULL argument %x %x\n", pSecPolicy, FilePath));
525 return FALSE;
526 }
527
528
529 if (KeGetCurrentIrql() != 0)
530 {
531 LOG(LOG_SS_POLICY, LOG_PRIORITY_DEBUG, ("FindAndLoadSecurityPolicy(): irql=%d\n", KeGetCurrentIrql()));
532 return FALSE;
533 }
534
535
536 filename = wcsrchr(FilePath, L'\\');
537
538 if (filename == NULL)
539 filename = FilePath;
540 else
541 ++filename;
542
543
544 /* if user policy load fails, we loop here again to load the global policy */
545ReloadPolicy:
546
547 if (UserName != NULL)
548 _snwprintf(PolicyPath, MAX_PATH, L"\\??\\%s\\policy\\%s\\%s.policy", OzoneInstallPath, UserName, filename);
549 else
550 _snwprintf(PolicyPath, MAX_PATH, L"\\??\\%s\\policy\\%s.policy", OzoneInstallPath, filename);
551
552 PolicyPath[MAX_PATH - 1] = 0;
553
554
555 LOG(LOG_SS_POLICY, LOG_PRIORITY_VERBOSE, ("FindAndLoadSecurityPolicy: Loading policy for %S (%S)\n", PolicyPath, FilePath));
556
557
558 ret = LoadSecurityPolicy(pSecPolicy, PolicyPath, FilePath);
559 if (ret == FALSE)
560 {
561 /* If we can't find a policy specific to a user, try to load a global policy instead */
562 if (UserName != NULL)
563 {
564 LOG(LOG_SS_POLICY, LOG_PRIORITY_DEBUG, ("FindAndLoadSecurityPolicy: Cannot find '%S' policy for user '%S'. Looking for a global policy..\n", filename, UserName));
565
566 UserName = NULL;
567
568 goto ReloadPolicy;
569 }
570
571 return FALSE;
572 }
573
574
575 /* allocate extra space for ".policy" string */
576 len = wcslen(filename) + 7 + 1;
577
578 pSecPolicy->Name = ExAllocatePoolWithTag(NonPagedPool, len * sizeof(WCHAR), _POOL_TAG);
579
580 if (pSecPolicy->Name != NULL)
581 {
582 _snwprintf(pSecPolicy->Name, len, L"%s.policy", filename);
583 }
584 else
585 {
586 PolicyDelete(pSecPolicy);
587 ret = FALSE;
588 }
589
590 return ret;
591}
592
593
594
595/*
596 * PolicyParseRule()
597 *
598 * Description:
599 * Parses a specified rule.
600 *
601 * Parameters:
602 * pSecPolicy - pointer to a security policy that will contain the parsed rule.
603 * rule - string buffer containing a rule to parse.
604 * Critical - Boolean indicating whether the parser should abort parsing the policy due to a critical error.
605 *
606 * Returns:
607 * TRUE if the policy rule was successfully parsed and loaded, FALSE otherwise.
608 */
609
610#define SKIP_WHITESPACE(str) do { while(*(str) == ' ' || *(str) == '\t') ++(str); } while(0)
611#define IS_WHITESPACE(c) ((c) == ' ' || (c) == '\t')
612
613/* macro shortcut for bailing out of PolicyParseRule() in case of an error */
614
615#define ABORT_PolicyParseRule(msg) \
616 do { \
617 LOG(LOG_SS_POLICY_PARSER, LOG_PRIORITY_WARNING, ("Encountered an error while parsing %S:%d :\n", gPolicyFilename, gPolicyLineNumber)); \
618 LOG(LOG_SS_POLICY_PARSER, LOG_PRIORITY_WARNING, msg); \
619 return FALSE; \
620 } while (0)
621
622
623static BOOLEAN
624PolicyParseRule(OUT PSECURITY_POLICY pSecPolicy, IN PCHAR rule, OUT BOOLEAN *Critical)
625{
626 CHAR ServiceName[POLICY_MAX_SERVICE_NAME_LENGTH];
627 PCHAR OriginalRule = rule;
628 int i = 0, SawSpace = 0, SawUnderscore = 0;
629
630
631 *Critical = FALSE;
632
633
634 SKIP_WHITESPACE(rule);
635
636
637 /* skip empty lines */
638
639 if (*rule == 0)
640 return TRUE;
641
642
643 /* comments start with '#' */
644
645 if (*rule == '#')
646 return TRUE;
647
648
649 /*
650 * Parse the service name. Format: "ServiceName:" or "ServiceName_OperationType:"
651 * where ServiceName can be "file", "registry", "event", "memory", etc
652 * and OperationType can be "read", "write", "rw"
653 */
654
655 while (*rule != 0 && *rule != ':')
656 {
657 /* is the specified syscall name too long? */
658
659 if (i > POLICY_MAX_SERVICE_NAME_LENGTH - 1)
660 ABORT_PolicyParseRule(("Rule type specification is too long. Maximum rule type specification length is %d characters.\n", POLICY_MAX_SERVICE_NAME_LENGTH));
661
662
663 /* allow whitespace before the colon */
664
665 if (IS_WHITESPACE(*rule))
666 {
667 ++rule;
668
669 SawSpace = 1;
670
671 continue;
672 }
673
674
675 /* Service Names are not allowed to contain a space */
676
677 if (SawSpace)
678 ABORT_PolicyParseRule(("Rule type specification cannot contain a space\n"));
679
680
681 /* Expecting to see 1 underscore '_' */
682
683 if (*rule == '_')
684 {
685 /* There can be only be 1 underscore char. and it cannot be the first char. */
686 if (i == 0 || SawUnderscore)
687 ABORT_PolicyParseRule(("Rule type specification cannot contain multiple underscore characters\n"));
688
689 /* remember the underscore position */
690 SawUnderscore = i;
691 }
692
693
694 ServiceName[i++] = *rule++;
695 }
696
697
698 /* Expecting to have read more than 1 character, finishing with a ':' */
699 if (i == 0 || *rule++ != ':')
700 ABORT_PolicyParseRule(("Colon not found. Rule type specification must end with a colon ':'.\n"));
701
702
703 ServiceName[i] = 0;
704
705
706 SKIP_WHITESPACE(rule);
707
708
709 /* didn't see any underscores. assume "system_call_name:" format */
710
711 if (SawUnderscore == 0)
712 ABORT_PolicyParseRule(("Underscore not found. Rule type specification must contain an underscore.\n"));
713
714
715 ServiceName[SawUnderscore] = 0;
716
717
718 // file operation
719 if (strlen(ServiceName) == 4 && _stricmp(ServiceName, "file") == 0)
720 return PolicyParseObjectRule(pSecPolicy, RULE_FILE, ServiceName + SawUnderscore + 1, rule);
721
722 // directory operation
723 if (strlen(ServiceName) == 9 && _stricmp(ServiceName, "directory") == 0)
724 return PolicyParseObjectRule(pSecPolicy, RULE_DIRECTORY, ServiceName + SawUnderscore + 1, rule);
725
726 // registry operation
727 if (strlen(ServiceName) == 8 && _stricmp(ServiceName, "registry") == 0)
728 return PolicyParseObjectRule(pSecPolicy, RULE_REGISTRY, ServiceName + SawUnderscore + 1, rule);
729
730 // memory section operation
731 if (strlen(ServiceName) == 7 && _stricmp(ServiceName, "section") == 0)
732 return PolicyParseObjectRule(pSecPolicy, RULE_SECTION, ServiceName + SawUnderscore + 1, rule);
733
734 // memory section / dll operation
735 if (strlen(ServiceName) == 3 && _stricmp(ServiceName, "dll") == 0)
736 return PolicyParseObjectRule(pSecPolicy, RULE_DLL, ServiceName + SawUnderscore + 1, rule);
737
738 // event operation
739 if (strlen(ServiceName) == 5 && _stricmp(ServiceName, "event") == 0)
740 return PolicyParseObjectRule(pSecPolicy, RULE_EVENT, ServiceName + SawUnderscore + 1, rule);
741
742 // semaphore operation
743 if (strlen(ServiceName) == 9 && _stricmp(ServiceName, "semaphore") == 0)
744 return PolicyParseObjectRule(pSecPolicy, RULE_SEMAPHORE, ServiceName + SawUnderscore + 1, rule);
745
746 // mailslot operation
747 if (strlen(ServiceName) == 8 && _stricmp(ServiceName, "mailslot") == 0)
748 return PolicyParseObjectRule(pSecPolicy, RULE_MAILSLOT, ServiceName + SawUnderscore + 1, rule);
749
750 // named pipe operation
751 if (strlen(ServiceName) == 9 && _stricmp(ServiceName, "namedpipe") == 0)
752 return PolicyParseObjectRule(pSecPolicy, RULE_NAMEDPIPE, ServiceName + SawUnderscore + 1, rule);
753
754 // job object operation
755 if (strlen(ServiceName) == 3 && _stricmp(ServiceName, "job") == 0)
756 return PolicyParseObjectRule(pSecPolicy, RULE_JOB, ServiceName + SawUnderscore + 1, rule);
757
758 // mutant operation
759 if (strlen(ServiceName) == 5 && _stricmp(ServiceName, "mutex") == 0)
760 return PolicyParseObjectRule(pSecPolicy, RULE_MUTANT, ServiceName + SawUnderscore + 1, rule);
761
762 // port operation
763 if (strlen(ServiceName) == 4 && _stricmp(ServiceName, "port") == 0)
764 return PolicyParseObjectRule(pSecPolicy, RULE_PORT, ServiceName + SawUnderscore + 1, rule);
765
766 // symlink operation
767 if (strlen(ServiceName) == 7 && _stricmp(ServiceName, "symlink") == 0)
768 return PolicyParseObjectRule(pSecPolicy, RULE_SYMLINK, ServiceName + SawUnderscore + 1, rule);
769
770 // timer operation
771 if (strlen(ServiceName) == 5 && _stricmp(ServiceName, "timer") == 0)
772 return PolicyParseObjectRule(pSecPolicy, RULE_TIMER, ServiceName + SawUnderscore + 1, rule);
773
774 // process operation
775 if (strlen(ServiceName) == 7 && _stricmp(ServiceName, "process") == 0)
776 return PolicyParseObjectRule(pSecPolicy, RULE_PROCESS, ServiceName + SawUnderscore + 1, rule);
777
778 // driver operation
779 if (strlen(ServiceName) == 6 && _stricmp(ServiceName, "driver") == 0)
780 return PolicyParseObjectRule(pSecPolicy, RULE_DRIVER, ServiceName + SawUnderscore + 1, rule);
781
782 // object directory operation
783 if (strlen(ServiceName) == 6 && _stricmp(ServiceName, "dirobj") == 0)
784 return PolicyParseObjectRule(pSecPolicy, RULE_DIROBJ, ServiceName + SawUnderscore + 1, rule);
785
786 // atom operation
787 if (strlen(ServiceName) == 4 && _stricmp(ServiceName, "atom") == 0)
788 return PolicyParseObjectRule(pSecPolicy, RULE_ATOM, ServiceName + SawUnderscore + 1, rule);
789
790 // network operation
791 if (strlen(ServiceName) == 7 && _stricmp(ServiceName, "network") == 0)
792 return PolicyParseObjectRule(pSecPolicy, RULE_NETWORK, ServiceName + SawUnderscore + 1, rule);
793
794 // service operation
795 if (strlen(ServiceName) == 7 && _stricmp(ServiceName, "service") == 0)
796 return PolicyParseObjectRule(pSecPolicy, RULE_SERVICE, ServiceName + SawUnderscore + 1, rule);
797
798 // time operation
799 if (strlen(ServiceName) == 4 && _stricmp(ServiceName, "time") == 0)
800 return PolicyParseObjectRule(pSecPolicy, RULE_TIME, ServiceName + SawUnderscore + 1, rule);
801
802 // token operation
803 if (strlen(ServiceName) == 5 && _stricmp(ServiceName, "token") == 0)
804 return PolicyParseObjectRule(pSecPolicy, RULE_TOKEN, ServiceName + SawUnderscore + 1, rule);
805
806
807 /*
808 * non object rules
809 */
810
811 // syscall
812 if (strlen(ServiceName) == 7 && _stricmp(ServiceName, "syscall") == 0)
813 return PolicyParseSyscallRule(pSecPolicy, ServiceName + SawUnderscore + 1, rule);
814
815 // policy
816 if (strlen(ServiceName) == 6 && _stricmp(ServiceName, "policy") == 0)
817 return PolicyParsePolicyRule(pSecPolicy, ServiceName + SawUnderscore + 1, rule, Critical);
818
819 // protection
820 if (strlen(ServiceName) == 10 && _stricmp(ServiceName, "protection") == 0)
821 return PolicyParseProtectionRule(pSecPolicy, ServiceName + SawUnderscore + 1, rule);
822
823 // media
824 if (strlen(ServiceName) == 5 && _stricmp(ServiceName, "media") == 0)
825 return PolicyParseMediaRule(pSecPolicy, ServiceName + SawUnderscore + 1, rule);
826
827
828
829 ABORT_PolicyParseRule(("Invalid rule type specification: '%s'.\n", ServiceName));
830}
831
832
833
834/*
835 * ParseDllOperation()
836 *
837 * Description:
838 * Parses an operation (i.e. "load" in "dll_load") specified for a DLL object rule.
839 *
840 * Parameters:
841 * Operation - specified operation.
842 *
843 * Returns:
844 * OP_INVALID if a specified operation is invalid or an OP_* value corresponding to the parsed operation.
845 */
846
847UCHAR
848ParseDllOperation(IN PCHAR Operation)
849{
850 if (strlen(Operation) == 4 && _stricmp(Operation, "load") == 0)
851 return OP_LOAD;
852
853 if (strlen(Operation) == 3 && _stricmp(Operation, "all") == 0)
854 return OP_ALL;
855
856 return OP_INVALID;
857}
858
859
860
861/*
862 * ParseTimeOperation()
863 *
864 * Description:
865 * Parses an operation (i.e. "change" in "time_change") specified for a Time object rule.
866 *
867 * Parameters:
868 * Operation - specified operation.
869 *
870 * Returns:
871 * OP_INVALID if a specified operation is invalid or an OP_* value corresponding to the parsed operation.
872 */
873
874UCHAR
875ParseTimeOperation(IN PCHAR Operation)
876{
877 if (strlen(Operation) == 6 && _stricmp(Operation, "change") == 0)
878 return OP_LOAD;
879
880 if (strlen(Operation) == 3 && _stricmp(Operation, "all") == 0)
881 return OP_ALL;
882
883 return OP_INVALID;
884}
885
886
887
888/*
889 * ParseTokenOperation()
890 *
891 * Description:
892 * Parses an operation (i.e. "modify" in "token_modify") specified for a Token object rule.
893 *
894 * Parameters:
895 * Operation - specified operation.
896 *
897 * Returns:
898 * OP_INVALID if a specified operation is invalid or an OP_* value corresponding to the parsed operation.
899 */
900
901UCHAR
902ParseTokenOperation(IN PCHAR Operation)
903{
904 if (strlen(Operation) == 6 && _stricmp(Operation, "modify") == 0)
905 return OP_TOKEN_MODIFY;
906
907 if (strlen(Operation) == 3 && _stricmp(Operation, "all") == 0)
908 return OP_ALL;
909
910 return OP_INVALID;
911}
912
913
914
915/*
916 * ParsePortOperation()
917 *
918 * Description:
919 * Parses an operation (i.e. "create" in "port_create") specified for a port object rule.
920 *
921 * Parameters:
922 * Operation - specified operation.
923 *
924 * Returns:
925 * OP_INVALID if a specified operation is invalid or an OP_* value corresponding to the parsed operation.
926 */
927
928UCHAR
929ParsePortOperation(IN PCHAR Operation)
930{
931 if (strlen(Operation) == 6 && _stricmp(Operation, "create") == 0)
932 return OP_PORT_CREATE;
933
934 if (strlen(Operation) == 7 && _stricmp(Operation, "connect") == 0)
935 return OP_PORT_CONNECT;
936
937 if (strlen(Operation) == 3 && _stricmp(Operation, "all") == 0)
938 return OP_ALL;
939
940
941 return OP_INVALID;
942}
943
944
945
946/*
947 * ParseCreateOpenOperation()
948 *
949 * Description:
950 * Parses a create or an open operation (i.e. "create" in "dirobj_create").
951 *
952 * Parameters:
953 * Operation - specified operation.
954 *
955 * Returns:
956 * OP_INVALID if a specified operation is invalid or an OP_* value corresponding to the parsed operation.
957 */
958
959UCHAR
960ParseCreateOpenOperation(IN PCHAR Operation)
961{
962 if (strlen(Operation) == 6 && _stricmp(Operation, "create") == 0)
963 return OP_CREATE;
964
965 if (strlen(Operation) == 4 && _stricmp(Operation, "open") == 0)
966 return OP_OPEN;
967
968 if (strlen(Operation) == 3 && _stricmp(Operation, "all") == 0)
969 return OP_ALL;
970
971
972 return OP_INVALID;
973}
974
975
976
977/*
978 * ParseAtomOperation()
979 *
980 * Description:
981 * Parses an operation (i.e. "find" in "atom_find") specified for an atom object rule.
982 *
983 * Parameters:
984 * Operation - specified operation.
985 *
986 * Returns:
987 * OP_INVALID if a specified operation is invalid or an OP_* value corresponding to the parsed operation.
988 */
989
990UCHAR
991ParseAtomOperation(IN PCHAR Operation)
992{
993 if (strlen(Operation) == 4 && _stricmp(Operation, "find") == 0)
994 return OP_FIND;
995
996 if (strlen(Operation) == 3 && _stricmp(Operation, "add") == 0)
997 return OP_ADD;
998
999 if (strlen(Operation) == 3 && _stricmp(Operation, "all") == 0)
1000 return OP_ALL;
1001
1002
1003 return OP_INVALID;
1004}
1005
1006
1007
1008/*
1009 * ParseDriverOperation()
1010 *
1011 * Description:
1012 * Parses an operation (i.e. "load" in "driver_load") specified for a driver object rule.
1013 *
1014 * Parameters:
1015 * Operation - specified operation.
1016 *
1017 * Returns:
1018 * OP_INVALID if a specified operation is invalid or an OP_* value corresponding to the parsed operation.
1019 */
1020
1021UCHAR
1022ParseDriverOperation(IN PCHAR Operation)
1023{
1024 if (strlen(Operation) == 4 && _stricmp(Operation, "load") == 0)
1025 return OP_LOAD;
1026
1027 if (strlen(Operation) == 7 && _stricmp(Operation, "regload") == 0)
1028 return OP_REGLOAD;
1029
1030 if (strlen(Operation) == 3 && _stricmp(Operation, "all") == 0)
1031 return OP_ALL;
1032
1033 return OP_INVALID;
1034}
1035
1036
1037
1038/*
1039 * ParseDirectoryOperation()
1040 *
1041 * Description:
1042 * Parses an operation (i.e. "create" in "directory_create") specified for a directory object rule.
1043 *
1044 * Parameters:
1045 * Operation - specified operation.
1046 *
1047 * Returns:
1048 * OP_INVALID if a specified operation is invalid or an OP_* value corresponding to the parsed operation.
1049 */
1050
1051UCHAR
1052ParseDirectoryOperation(IN PCHAR Operation)
1053{
1054 if (strlen(Operation) == 6 && _stricmp(Operation, "create") == 0)
1055 return OP_DIR_CREATE;
1056
1057 if (strlen(Operation) == 3 && _stricmp(Operation, "all") == 0)
1058 return OP_ALL;
1059
1060 return OP_INVALID;
1061}
1062
1063
1064
1065/*
1066 * ParseObjectOperation()
1067 *
1068 * Description:
1069 * Parses an operation (i.e. "read" in "file_read") specified for an object (file, registry, etc) rule.
1070 *
1071 * Parameters:
1072 * Operation - specified operation.
1073 *
1074 * Returns:
1075 * OP_INVALID if a specified operation is invalid or an OP_* value corresponding to the parsed operation.
1076 */
1077
1078UCHAR
1079ParseObjectOperation(IN PCHAR Operation)
1080{
1081 if (strlen(Operation) == 4 && _stricmp(Operation, "read") == 0)
1082 return OP_READ;
1083
1084 if (strlen(Operation) == 5 && _stricmp(Operation, "write") == 0)
1085 return OP_WRITE;
1086
1087 if (strlen(Operation) == 2 && _stricmp(Operation, "rw") == 0)
1088 return (OP_READ | OP_WRITE);
1089
1090 if (strlen(Operation) == 3 && _stricmp(Operation, "all") == 0)
1091 return OP_ALL;
1092
1093 //XXX valid for files only
1094// if (strlen(Operation) == 6 && _stricmp(Operation, "append") == 0)
1095// return OP_APPEND;
1096
1097 if (strlen(Operation) == 7 && _stricmp(Operation, "execute") == 0)
1098 return OP_EXECUTE;
1099
1100 if (strlen(Operation) == 6 && _stricmp(Operation, "delete") == 0)
1101 return OP_DELETE;
1102
1103
1104 return OP_INVALID;
1105}
1106
1107
1108
1109/*
1110 * ParseProcessOperation()
1111 *
1112 * Description:
1113 * Parses an operation (i.e. "execute" in "process_execute") specified for a process rule.
1114 *
1115 * Parameters:
1116 * Operation - specified operation.
1117 *
1118 * Returns:
1119 * OP_INVALID if a specified operation is invalid or an OP_* value corresponding to the parsed operation.
1120 */
1121
1122UCHAR
1123ParseProcessOperation(IN PCHAR Operation)
1124{
1125 if (strlen(Operation) == 3 && _stricmp(Operation, "all") == 0)
1126 return OP_ALL;
1127
1128 if (strlen(Operation) == 7 && _stricmp(Operation, "execute") == 0)
1129 return OP_PROC_EXECUTE;
1130
1131 if (strlen(Operation) == 4 && _stricmp(Operation, "open") == 0)
1132 return OP_PROC_OPEN;
1133
1134
1135 return OP_INVALID;
1136}
1137
1138
1139
1140/*
1141 * ParseServiceOperation()
1142 *
1143 * Description:
1144 * Parses an operation (i.e. "start" in "service_start") specified for a service object rule.
1145 *
1146 * Parameters:
1147 * Operation - specified operation.
1148 *
1149 * Returns:
1150 * OP_INVALID if a specified operation is invalid or an OP_* value corresponding to the parsed operation.
1151 */
1152
1153UCHAR
1154ParseServiceOperation(IN PCHAR Operation)
1155{
1156 if (strlen(Operation) == 3 && _stricmp(Operation, "all") == 0)
1157 return OP_ALL;
1158
1159 /*
1160 * We cannot distinguish between various service operations since service rules are actually
1161 * enforced by the registry rules. Thus convert all operations to OP_ALL for now.
1162 */
1163
1164 if (strlen(Operation) == 5 && _stricmp(Operation, "start") == 0)
1165 return OP_ALL;//OP_SERVICE_START;
1166
1167 if (strlen(Operation) == 4 && _stricmp(Operation, "stop") == 0)
1168 return OP_ALL;//OP_SERVICE_STOP;
1169
1170 if (strlen(Operation) == 6 && _stricmp(Operation, "create") == 0)
1171 return OP_ALL;//OP_SERVICE_CREATE;
1172
1173 if (strlen(Operation) == 6 && _stricmp(Operation, "delete") == 0)
1174 return OP_ALL;//OP_SERVICE_DELETE;
1175
1176 return OP_INVALID;
1177}
1178
1179
1180
1181/*
1182 * ParseNetworkOperation()
1183 *
1184 * Description:
1185 * Parses an operation (i.e. "bind" in "network_bind") specified for a network object rule.
1186 *
1187 * Parameters:
1188 * Operation - specified operation.
1189 *
1190 * Returns:
1191 * OP_INVALID if a specified operation is invalid or an OP_* value corresponding to the parsed operation.
1192 */
1193
1194UCHAR
1195ParseNetworkOperation(IN PCHAR Operation)
1196{
1197 if (strlen(Operation) == 3 && _stricmp(Operation, "all") == 0)
1198 return OP_ALL;
1199
1200 if (strlen(Operation) == 10 && _stricmp(Operation, "tcpconnect") == 0)
1201 return OP_TCPCONNECT;
1202
1203 if (strlen(Operation) == 10 && _stricmp(Operation, "udpconnect") == 0)
1204 return OP_UDPCONNECT;
1205
1206 if (strlen(Operation) == 7 && _stricmp(Operation, "connect") == 0)
1207 return OP_CONNECT;
1208
1209 if (strlen(Operation) == 4 && _stricmp(Operation, "bind") == 0)
1210 return OP_BIND;
1211
1212 return OP_INVALID;
1213}
1214
1215
1216
1217
1218/*****************************************************************************/
1219
1220
1221
1222
1223/*
1224 * ParseNetworkObject()
1225 *
1226 * Description:
1227 * Parses the specified network address (i.e. "127.0.0.1:443").
1228 *
1229 * Parameters:
1230 * name - string value to parse.
1231 * Object - pointer to an Object where the final result will be saved
1232 * wildcard - pointer to a BOOLEAN that will indicate whether the specified value contained any regular expressions.
1233 *
1234 * Returns:
1235 * INVALID_OBJECT_SIZE if the specified network address is invalid. 0 to indicate SUCCESS.
1236 * Network addresses do not require any additional memory to be allocated thus the returned size is 0.
1237 */
1238
1239size_t
1240ParseNetworkObject(IN PCHAR name, OUT PCHAR *Object, OUT BOOLEAN *wildcard)
1241{
1242 PCHAR colon;
1243
1244
1245 //XXX
1246 // for now connect format is "ipaddr" while bind format is "ipaddr:port"
1247
1248 colon = strchr(name, ':');
1249
1250 if (colon)
1251 {
1252 *Object = colon + 1;
1253// if ((*Object = (PVOID) atoi(colon + 1)) == 0)
1254// return INVALID_OBJECT_SIZE;
1255 }
1256 else
1257 {
1258 *Object = name;
1259// if ((*Object = (PVOID) inet_addr(name)) == 0)
1260// return INVALID_OBJECT_SIZE;
1261 }
1262
1263
1264 return strlen(*Object);
1265}
1266
1267
1268
1269/*
1270 * ParseStub()
1271 *
1272 * Description:
1273 * Parse stub for strings that do no require any further parsing.
1274 *
1275 * Parameters:
1276 * name - string value to parse.
1277 * Object - pointer to an Object where the final result will be saved.
1278 * wildcard - pointer to a BOOLEAN that will indicate whether the specified value contained any regular expressions.
1279 *
1280 * Returns:
1281 * Length of the specified string value.
1282 */
1283
1284size_t
1285ParseStub(IN PCHAR name, OUT PCHAR *ObjectName, OUT BOOLEAN *wildcard)
1286{
1287 *ObjectName = name;
1288
1289 return strlen(name);
1290}
1291
1292
1293
1294/*
1295 * ParseRegistryObject()
1296 *
1297 * Description:
1298 * Convert user land registry object names into their kernel land equivalents.
1299 *
1300 * Parameters:
1301 * name - string value to parse.
1302 * Object - pointer to an Object where the final result will be saved.
1303 * wildcard - pointer to a BOOLEAN that will indicate whether the specified value contained any regular expressions.
1304 *
1305 * Returns:
1306 * Length of the specified string value.
1307 */
1308
1309size_t
1310ParseRegistryObject(IN PCHAR name, OUT PCHAR *ObjectName, OUT BOOLEAN *wildcard)
1311{
1312 PCHAR key;
1313 static CHAR buffer[MAX_PATH] = { 0 };
1314
1315
1316 if (_strnicmp(name, "HKEY_LOCAL_MACHINE\\", 19) == 0)
1317 {
1318 /* replace HKEY_LOCAL_MACHINE\ with kernel equivalent of \REGISTRY\MACHINE\ */
1319
1320 strcpy(name + 1, "\\REGISTRY\\MACHINE");
1321 name[18] = '\\';
1322
1323 key = name + 1;
1324 }
1325 else if (_strnicmp(name, "HKEY_USERS\\", 11) == 0)
1326 {
1327 /* replace HKEY_USERS\ with kernel equivalent of \REGISTRY\USER\ */
1328
1329 strcpy(buffer, "\\REGISTRY\\USER\\");
1330 strncat(buffer, name + 11, MAX_PATH - 12);
1331
1332 key = buffer;
1333 }
1334 else
1335 {
1336 key = name;
1337 }
1338
1339
1340 *ObjectName = key;
1341
1342
1343 return strlen(key);
1344}
1345
1346
1347
1348/*
1349 * ParseFileObject()
1350 *
1351 * Description:
1352 * Convert user land file object names into their kernel land equivalents.
1353 *
1354 * Parameters:
1355 * name - string value to parse.
1356 * Object - pointer to an Object where the final result will be saved.
1357 * wildcard - pointer to a BOOLEAN that will indicate whether the specified value contained any regular expressions.
1358 *
1359 * Returns:
1360 * Length of the specified string value.
1361 */
1362
1363size_t
1364ParseFileObject(IN PCHAR name, OUT PCHAR *Object, OUT BOOLEAN *wildcard)
1365{
1366 PCHAR filename;
1367 static CHAR buffer[MAX_PATH] = { 0 }; //XXX not SMP safe
1368
1369
1370 if (_strnicmp(name, "%systemdrive%:", 14) == 0)
1371 {
1372 name[12] = SystemDrive;
1373
1374 name += 12;
1375 }
1376
1377
1378 // match drive wildcards such as "?:" and "*:" with "\Device\*"
1379 if (name[1] == ':' && name[2] == '\\' && (name[0] == '?' || name[0] == '*'))
1380 {
1381#if 0
1382 ConvertLongFileNameToShort(name, buffer + 7, MAX_PATH - 7);
1383
1384 strcpy(buffer, "\\Device\\*");
1385 buffer[9] = '\\'; /* replace the zero terminator */
1386
1387 filename = buffer;
1388#endif
1389
1390 strcpy(name - 7, "\\Device\\*");
1391
1392 /*
1393 * replace "\Device\*" terminating zero with a '\'
1394 * since name is just a pointer to FullName+7, FullName now contains
1395 * \Device\*\<user specified path>
1396 */
1397
1398 name[2] = '\\';
1399
1400 filename = name - 7;
1401
1402
1403 // mark the rule as wildcard even if the user (mistakenly) used "eq"
1404 // XXX or should we throw an error if wildcard==0?
1405 *wildcard = TRUE;
1406 }
1407 else if (isalpha(name[0]) && name[1] == ':')
1408 {
1409#if 0
1410 CHAR buffer2[MAX_PATH];
1411
1412
1413 ConvertLongFileNameToShort(name, buffer2 + 4, MAX_PATH - 4);
1414
1415 buffer2[0] = '\\';
1416 buffer2[1] = '?';
1417 buffer2[2] = '?';
1418 buffer2[3] = '\\';
1419
1420 if (ResolveFilename(buffer2, buffer, MAX_PATH) == FALSE)
1421 LOG(LOG_SS_POLICY, LOG_PRIORITY_DEBUG, ("ParseFileObject: ResolveFilename(%s) failed\n", name - 4));
1422#endif
1423
1424
1425 // match <letter>: drive specifications and prepend "\??\" to them
1426
1427 *(name - 4) = '\\';
1428 *(name - 3) = '?';
1429 *(name - 2) = '?';
1430 *(name - 1) = '\\';
1431
1432 if (ResolveFilename(name - 4, buffer, MAX_PATH) == FALSE)
1433 LOG(LOG_SS_POLICY, LOG_PRIORITY_DEBUG, ("ParseFileObject: ResolveFilename(%s) failed\n", name - 4));
1434
1435 filename = buffer;
1436 }
1437 else if (_strnicmp(name, "%systemroot%\\", 13) == 0)
1438 {
1439 strcpy(buffer, SystemRoot);
1440 strcat(buffer, name + 12);
1441
1442 filename = buffer;
1443 }
1444 else if (_strnicmp(name, "\\pipe\\", 6) == 0)
1445 {
1446 strcpy(buffer, "\\device\\namedpipe");
1447 strcat(buffer, name + 5);
1448
1449 filename = buffer;
1450 }
1451 else
1452 {
1453 filename = name;
1454 }
1455
1456
1457 *Object = filename;
1458
1459 return strlen(filename);
1460}
1461
1462
1463
1464/*
1465 * ParseProcessObject()
1466 *
1467 * Description:
1468 * Convert user land process object names into their kernel land equivalents (strip the drive specification).
1469 *
1470 * Parameters:
1471 * name - string value to parse.
1472 * Object - pointer to an Object where the final result will be saved.
1473 * wildcard - pointer to a BOOLEAN that will indicate whether the specified value contained any regular expressions.
1474 *
1475 * Returns:
1476 * Length of the specified string value.
1477 */
1478
1479size_t
1480ParseProcessObject(IN PCHAR name, OUT PCHAR *Object, OUT BOOLEAN *wildcard)
1481{
1482 static CHAR buffer[MAX_PATH] = { 0 };
1483
1484
1485 if ((name = StripFileMacros(name, buffer, MAX_PATH)) == NULL)
1486 return INVALID_OBJECT_SIZE;
1487
1488
1489 *Object = name;
1490
1491 return strlen(name);
1492}
1493
1494
1495
1496/*
1497 * ParseBaseNamedObjectsObject()
1498 *
1499 * Description:
1500 * Convert user land object names into their kernel land equivalents.
1501 *
1502 * Parameters:
1503 * name - string value to parse.
1504 * Object - pointer to an Object where the final result will be saved.
1505 * wildcard - pointer to a BOOLEAN that will indicate whether the specified value contained any regular expressions.
1506 *
1507 * Returns:
1508 * Length of the specified string value.
1509 */
1510
1511size_t
1512ParseBaseNamedObjectsObject(IN PCHAR name, OUT PCHAR *Object, OUT BOOLEAN *wildcard)
1513{
1514 PCHAR ObjectName;
1515
1516
1517 /*
1518 * if an object name does not start with a slash '\' then prepend '\BaseNamedObjects\' to it
1519 */
1520
1521 if (name[0] != '\\')
1522 {
1523 //XXX this is a hack, we are prepending to our buffer, knowing that there is space there
1524 strcpy(name - 18, "\\BaseNamedObjects");
1525
1526 *(name - 1) = '\\';
1527
1528 ObjectName = name - 18;
1529 }
1530 else
1531 {
1532 ObjectName = name;
1533 }
1534
1535
1536 *Object = ObjectName;
1537
1538 return strlen(ObjectName);
1539}
1540
1541
1542
1543/*
1544 * ParseMailslotObject()
1545 *
1546 * Description:
1547 * Convert user land mailslot object names into their kernel land equivalents.
1548 *
1549 * Parameters:
1550 * name - string value to parse.
1551 * Object - pointer to an Object where the final result will be saved.
1552 * wildcard - pointer to a BOOLEAN that will indicate whether the specified value contained any regular expressions.
1553 *
1554 * Returns:
1555 * Length of the specified string value.
1556 */
1557
1558size_t
1559ParseMailslotObject(IN PCHAR name, OUT PCHAR *Object, OUT BOOLEAN *wildcard)
1560{
1561 PCHAR MailslotName;
1562
1563
1564 /*
1565 * if the mailslot name does not start with a slash '\' then prepend '\Device\Mailslot\' to the name
1566 */
1567
1568 if (name[0] != '\\')
1569 {
1570 //XXX this is a hack, we are prepending to our buffer, knowing that there is space there
1571 strcpy(name - 17, "\\Device\\Mailslot");
1572
1573 *(name - 1) = '\\';
1574
1575 MailslotName = name - 17;
1576 }
1577 else
1578 {
1579 MailslotName = name;
1580 }
1581
1582
1583 *Object = MailslotName;
1584
1585 return strlen(MailslotName);
1586}
1587
1588
1589
1590/*
1591 * ParseNamedpipeObject()
1592 *
1593 * Description:
1594 * Convert user land namedpipe object names into their kernel land equivalents.
1595 *
1596 * Parameters:
1597 * name - string value to parse.
1598 * Object - pointer to an Object where the final result will be saved.
1599 * wildcard - pointer to a BOOLEAN that will indicate whether the specified value contained any regular expressions.
1600 *
1601 * Returns:
1602 * Length of the specified string value.
1603 */
1604
1605size_t
1606ParseNamedpipeObject(IN PCHAR name, OUT PCHAR *Object, OUT BOOLEAN *wildcard)
1607{
1608 PCHAR NamedpipeName;
1609
1610
1611 /*
1612 * if the namedpipe name does not start with a slash '\' then prepend '\Device\Namedpipe\' to the name
1613 */
1614
1615 if (name[0] != '\\')
1616 {
1617 //XXX this is a hack, we are prepending to our buffer, knowing that there is space there
1618 strcpy(name - 18, "\\Device\\Namedpipe");
1619
1620 *(name - 1) = '\\';
1621
1622 NamedpipeName = name - 18;
1623 }
1624 else
1625 {
1626 NamedpipeName = name;
1627 }
1628
1629
1630 *Object = NamedpipeName;
1631
1632 return strlen(NamedpipeName);
1633}
1634
1635
1636
1637/*
1638 * ParseDllObject()
1639 *
1640 * Description:
1641 * Convert user land DLL object names into their kernel land equivalents.
1642 * Since DLL rules are actually enforced by section rules, we just append DLL names to
1643 * '\KnownDlls\' string which is used by section rules.
1644 *
1645 * Parameters:
1646 * name - string value to parse.
1647 * Object - pointer to an Object where the final result will be saved.
1648 * wildcard - pointer to a BOOLEAN that will indicate whether the specified value contained any regular expressions.
1649 *
1650 * Returns:
1651 * Length of the specified string value.
1652 */
1653
1654size_t
1655ParseDllObject(IN PCHAR name, OUT PCHAR *Object, OUT BOOLEAN *wildcard)
1656{
1657 PCHAR DllName;
1658
1659
1660 /*
1661 * if the DLL name does not start with a slash '\' then prepend '\KnownDlls\' to the name
1662 */
1663
1664 if (name[0] != '\\')
1665 {
1666 strcpy(name - 11, "\\KnownDlls");
1667
1668 *(name - 1) = '\\';
1669
1670 DllName = name - 11;
1671 }
1672 else
1673 {
1674 DllName = name;
1675 }
1676
1677
1678 *Object = DllName;
1679
1680 return strlen(DllName);
1681}
1682
1683
1684
1685/*
1686 * ParseTimeObject()
1687 *
1688 * Description:
1689 * Time rule specifications are not supposed to have any object names specified.
1690 * Return an error.
1691 *
1692 * Parameters:
1693 * name - string value to parse.
1694 * Object - pointer to an Object where the final result will be saved.
1695 * wildcard - pointer to a BOOLEAN that will indicate whether the specified value contained any regular expressions.
1696 *
1697 * Returns:
1698 * An error.
1699 */
1700
1701size_t
1702ParseTimeObject(IN PCHAR name, OUT PCHAR *Object, OUT BOOLEAN *wildcard)
1703{
1704 return INVALID_OBJECT_SIZE;
1705}
1706
1707
1708
1709/*
1710 * ParseServiceObject()
1711 *
1712 * Description:
1713 * Convert user land service object names into their kernel land equivalents.
1714 * Since service rules are actually enforced by registry rules, we just append service names
1715 * to '\Registry\Machine\System\*ControlSet*\Services\' string which is used by registry rules.
1716 *
1717 * Parameters:
1718 * name - string value to parse.
1719 * Object - pointer to an Object where the final result will be saved.
1720 * wildcard - pointer to a BOOLEAN that will indicate whether the specified value contained any regular expressions.
1721 *
1722 * Returns:
1723 * Length of the specified string value.
1724 * INVALID_OBJECT_SIZE is service name is too long.
1725 */
1726
1727size_t
1728ParseServiceObject(IN PCHAR name, OUT PCHAR *Object, OUT BOOLEAN *wildcard)
1729{
1730 static CHAR buffer[MAX_PATH] = { 0 }; //XXX not SMP safe
1731
1732
1733 if (strlen(name) > 64)
1734 {
1735 return INVALID_OBJECT_SIZE;
1736 }
1737
1738 strcpy(buffer, "\\Registry\\Machine\\System\\*ControlSet*\\Services\\");
1739 strcat(buffer, name);
1740
1741 *wildcard = TRUE;
1742
1743 *Object = buffer;
1744
1745
1746 return strlen(buffer);
1747}
1748
1749
1750
1751typedef size_t (*OBJECT_PARSER)(IN PCHAR name, OUT PCHAR *Object, OUT BOOLEAN *wildcard);
1752typedef UCHAR (*OPERATION_TYPE_PARSER)(IN PCHAR name);
1753
1754
1755/* in C++ these would be member methods */
1756
1757struct _ObjectParseOps
1758{
1759 RULE_TYPE RuleType;
1760 OBJECT_PARSER ObjectNameParser;
1761 OPERATION_TYPE_PARSER OperationTypeParser;
1762
1763} ObjectParseOps[] =
1764{
1765 { RULE_FILE, ParseFileObject, ParseObjectOperation },
1766 { RULE_DIRECTORY, ParseFileObject, ParseDirectoryOperation },
1767 { RULE_MAILSLOT, ParseMailslotObject, ParseObjectOperation },
1768 { RULE_NAMEDPIPE, ParseNamedpipeObject, ParseObjectOperation },
1769 { RULE_REGISTRY, ParseRegistryObject, ParseObjectOperation },
1770 { RULE_SECTION, ParseBaseNamedObjectsObject, ParseObjectOperation },
1771 { RULE_DLL, ParseDllObject, ParseDllOperation },
1772 { RULE_EVENT, ParseBaseNamedObjectsObject, ParseCreateOpenOperation },
1773 { RULE_SEMAPHORE, ParseBaseNamedObjectsObject, ParseCreateOpenOperation },
1774 { RULE_JOB, ParseBaseNamedObjectsObject, ParseCreateOpenOperation },
1775 { RULE_MUTANT, ParseBaseNamedObjectsObject, ParseCreateOpenOperation },
1776 { RULE_PORT, ParseStub, ParsePortOperation },
1777 { RULE_SYMLINK, ParseStub, ParseCreateOpenOperation },
1778 { RULE_TIMER, ParseBaseNamedObjectsObject, ParseCreateOpenOperation },
1779 { RULE_PROCESS, ParseProcessObject, ParseProcessOperation },
1780 { RULE_DRIVER, ParseProcessObject, ParseDriverOperation },
1781 { RULE_DIROBJ, ParseStub, ParseCreateOpenOperation },
1782 { RULE_ATOM, ParseStub, ParseAtomOperation },
1783 { RULE_NETWORK, ParseNetworkObject, ParseNetworkOperation },
1784 { RULE_SERVICE, ParseServiceObject, ParseServiceOperation },
1785 { RULE_TIME, ParseTimeObject, ParseTimeOperation },
1786 { RULE_TOKEN, ParseTimeObject, ParseTokenOperation },
1787};
1788
1789
1790
1791/*
1792 * PolicyParseActionClause()
1793 *
1794 * Description:
1795 * .
1796 *
1797 * Parameters:
1798 * .
1799 *
1800 * Returns:
1801 * .
1802 */
1803
1804BOOLEAN
1805PolicyParseActionClause(PCHAR rule, ACTION_TYPE *ActionType, UCHAR *RuleNumber)
1806{
1807 UCHAR len = 0, num = 0;
1808
1809
1810 SKIP_WHITESPACE(rule);
1811
1812
1813 if (_strnicmp(rule, "permit", 6) == 0)
1814 {
1815 rule += 6;
1816
1817 *ActionType = ACTION_PERMIT;
1818 }
1819 else if (_strnicmp(rule, "deny", 4) == 0)
1820 {
1821 rule += 4;
1822
1823 *ActionType = ACTION_DENY;
1824 }
1825 else if (_strnicmp(rule, "quietdeny", 9) == 0)
1826 {
1827 rule += 9;
1828
1829 *ActionType = ACTION_QUIETDENY;
1830 }
1831 else if (_strnicmp(rule, "log", 3) == 0)
1832 {
1833 rule += 3;
1834
1835 *ActionType = ACTION_LOG;
1836 }
1837 else if (_strnicmp(rule, "ask", 3) == 0)
1838 {
1839 rule += 3;
1840
1841 *ActionType = ACTION_ASK;
1842 }
1843 else
1844 {
1845 ABORT_PolicyParseRule(("Expecting to see 'permit', 'deny', 'quitedeny', 'log' or 'ask' clause. Got '%s'\n", rule));
1846 }
1847
1848
1849 SKIP_WHITESPACE(rule);
1850
1851
1852 /* EOL? */
1853 if (*rule == 0)
1854 {
1855 if (RuleNumber)
1856 *RuleNumber = 0;
1857
1858 return TRUE;
1859 }
1860
1861
1862 /* if it is not EOL then we expect to see "[rule DIGIT]" clause */
1863 if (_strnicmp(rule, "[rule", 5) == 0)
1864 {
1865 rule += 5;
1866 }
1867 else
1868 {
1869 ABORT_PolicyParseRule(("Expecting to see a rule clause. Got '%s'\n", rule));
1870 }
1871
1872
1873 if (! IS_WHITESPACE(*rule))
1874 {
1875 ABORT_PolicyParseRule(("Expecting to see white space. Got '%s'\n", rule));
1876 }
1877
1878 SKIP_WHITESPACE(rule);
1879
1880
1881 /* parse the rule number (a decimal digit) */
1882 while (*rule >= '0' && *rule <= '9')
1883 {
1884 /* don't overflow UCHAR values */
1885 if (++len > 2)
1886 {
1887 ABORT_PolicyParseRule(("The rule number is too long.\n"));
1888 }
1889
1890 num = num*10 + (*rule - '0');
1891
1892 ++rule;
1893 }
1894
1895
1896 SKIP_WHITESPACE(rule);
1897
1898
1899 if (*rule != ']')
1900 {
1901 ABORT_PolicyParseRule(("Invalid rule clause: '%s'\n", rule));
1902 }
1903
1904
1905 ++rule;
1906 SKIP_WHITESPACE(rule);
1907
1908
1909 /* expecting an EOL */
1910 if (*rule != 0)
1911 {
1912 ABORT_PolicyParseRule(("Expecting to see end of line. Got '%s'\n", rule));
1913 }
1914
1915
1916 if (RuleNumber)
1917 *RuleNumber = num;
1918
1919
1920 return TRUE;
1921}
1922
1923
1924
1925/*
1926 * PolicyParseOnOffClause()
1927 *
1928 * Description:
1929 * .
1930 *
1931 * Parameters:
1932 * .
1933 *
1934 * Returns:
1935 * .
1936 */
1937
1938BOOLEAN
1939PolicyParseOnOffClause(PCHAR rule, BOOLEAN *OnOff)
1940{
1941 SKIP_WHITESPACE(rule);
1942
1943
1944 if (_strnicmp(rule, "on", 2) == 0)
1945 {
1946 rule += 2;
1947
1948 *OnOff = TRUE;
1949 }
1950 else if (_strnicmp(rule, "off", 3) == 0)
1951 {
1952 rule += 3;
1953
1954 *OnOff = FALSE;
1955 }
1956 else
1957 {
1958 ABORT_PolicyParseRule(("Expecting to see 'on' or 'off' clause. Got '%s'\n", rule));
1959 }
1960
1961
1962 SKIP_WHITESPACE(rule);
1963
1964 /* expecting an EOL */
1965 if (*rule != 0)
1966 {
1967 ABORT_PolicyParseRule(("Expecting to see end of line. Got '%s'\n", rule));
1968 }
1969
1970 return TRUE;
1971}
1972
1973
1974
1975/*
1976 * VerifyToken2()
1977 *
1978 * Description:
1979 * .
1980 *
1981 * Parameters:
1982 * .
1983 *
1984 * Returns:
1985 * .
1986 */
1987
1988UCHAR
1989VerifyToken2(PCHAR *rule, PCHAR token1, PCHAR token2)
1990{
1991 USHORT Token1Length, Token2Length;
1992
1993
1994 ASSERT(rule && *rule);
1995 ASSERT(token1);
1996 ASSERT(token2);
1997
1998
1999 SKIP_WHITESPACE(*rule);
2000
2001
2002 Token1Length = (USHORT) strlen(token1);
2003 Token2Length = (USHORT) strlen(token2);
2004
2005 if (_strnicmp(*rule, token1, Token1Length) == 0)
2006 {
2007 *rule += Token1Length;
2008
2009 if (! IS_WHITESPACE(**rule))
2010 {
2011// LOG(LOG_SS_POLICY_PARSER, LOG_PRIORITY_WARNING, ("Expecting to see whitespace. Got '%s'\n", *rule));
2012 return FALSE;
2013 }
2014
2015 SKIP_WHITESPACE(*rule);
2016
2017 return 1;
2018 }
2019
2020
2021 if (_strnicmp(*rule, token2, Token2Length) == 0)
2022 {
2023 *rule += Token2Length;
2024
2025 if (! IS_WHITESPACE(**rule))
2026 {
2027// LOG(LOG_SS_POLICY_PARSER, LOG_PRIORITY_WARNING, ("Expecting to see whitespace. Got '%s'\n", *rule));
2028 return FALSE;
2029 }
2030
2031 SKIP_WHITESPACE(*rule);
2032
2033 return 2;
2034 }
2035
2036
2037 return 0;
2038}
2039
2040
2041
2042/*
2043 * PolicyParsePolicyRule()
2044 *
2045 * Description:
2046 * Parse a policy rule and adjust the policy default action.
2047 *
2048 * Parameters:
2049 * pSecPolicy - security policy that the rule is going to be added to.
2050 * Operation - ASCII operation (valid options are 'default' and 'path').
2051 * Rule - ASCII rule to parse.
2052 * Critical - Boolean indicating whether the parser should abort parsing the policy due to a critical error.
2053 *
2054 * Returns:
2055 * Nothing.
2056 */
2057
2058BOOLEAN
2059PolicyParsePolicyRule(OUT PSECURITY_POLICY pSecPolicy, IN PCHAR Operation, IN PCHAR rule, OUT BOOLEAN *Critical)
2060{
2061 ACTION_TYPE ActionType;
2062 UCHAR RuleNumber;
2063
2064
2065 *Critical = FALSE;
2066
2067
2068 if (strlen(Operation) == 7 && _stricmp(Operation, "default") == 0)
2069 {
2070 if (PolicyParseActionClause(rule, &ActionType, &RuleNumber) == FALSE)
2071
2072 ABORT_PolicyParseRule(("Invalid default policy action specification. Format: \"policy_default: (permit|deny|quietdeny|log|ask)\"\n"));
2073
2074
2075 /* did we initialize default policy action already? */
2076 if (pSecPolicy->DefaultPolicyAction != ACTION_NONE)
2077
2078 ABORT_PolicyParseRule(("Duplicate default policy action specification.\n"));
2079
2080
2081 /* this still allows "policy_default: permit [rule 0]", oh well */
2082 if (RuleNumber != 0)
2083
2084 ABORT_PolicyParseRule(("Rule clause cannot appear in default policy action specification.\n"));
2085
2086
2087 pSecPolicy->DefaultPolicyAction = ActionType | ACTION_DEFAULT;
2088
2089 return TRUE;
2090 }
2091
2092
2093 if (strlen(Operation) == 4 && _stricmp(Operation, "path") == 0)
2094 {
2095 CHAR szPath[MAX_PATH];
2096 CHAR szPolicyPath[MAX_PATH];
2097
2098
2099 _snprintf(szPath, MAX_PATH, "%S", gFilePath);
2100 szPath[MAX_PATH - 1] = 0;
2101
2102
2103 rule = StripFileMacros(rule, szPolicyPath, MAX_PATH);
2104
2105
2106 KdPrint(("%s\n%s\n", szPath, rule));
2107
2108 if (WildcardMatch(szPath, rule) == WILDCARD_MATCH)
2109 {
2110 KdPrint(("paths match\n"));
2111 return TRUE;
2112 }
2113
2114
2115 if (LearningMode == FALSE)
2116 *Critical = TRUE;
2117
2118 KdPrint(("paths do not match\n"));
2119
2120
2121 return FALSE;
2122 }
2123
2124
2125 ABORT_PolicyParseRule(("Invalid policy operation '%s'. Valid options are 'default' and 'path'.\n", Operation));
2126}
2127
2128
2129
2130/*
2131 * PolicyParseProtectionRule()
2132 *
2133 * Description:
2134 * Parse a protection rule and adjust the protection options such as buffer overflow protection
2135 * and userland (dll injection) protection being on and off
2136 *
2137 * Parameters:
2138 * pSecPolicy - security policy that the rule is going to be added to.
2139 * Operation - ASCII operation. Valid options are 'overflow', 'userland', 'debugging', 'dos16', 'keyboard', 'modem', 'sniffer', 'extension' and 'all'.
2140 * Rule - ASCII rule to parse.
2141 *
2142 * Returns:
2143 * Nothing.
2144 */
2145
2146BOOLEAN
2147PolicyParseProtectionRule(PSECURITY_POLICY pSecPolicy, PCHAR Operation, PCHAR rule)
2148{
2149 BOOLEAN OnOff;
2150
2151
2152 if (strlen(Operation) == 8 && _stricmp(Operation, "overflow") == 0)
2153 {
2154 if (PolicyParseOnOffClause(rule, &OnOff) == FALSE)
2155 return FALSE;
2156
2157 LOG(LOG_SS_POLICY_PARSER, LOG_PRIORITY_VERBOSE, ("PolicyParseProtectionRule: Turning overflow protection %s\n", OnOff ? "on" : "off"));
2158
2159 if (OnOff)
2160 pSecPolicy->ProtectionFlags |= PROTECTION_OVERFLOW;
2161 else
2162 pSecPolicy->ProtectionFlags &= ~PROTECTION_OVERFLOW;
2163
2164 return TRUE;
2165 }
2166
2167
2168 if (strlen(Operation) == 8 && _stricmp(Operation, "userland") == 0)
2169 {
2170 if (PolicyParseOnOffClause(rule, &OnOff) == FALSE)
2171 return FALSE;
2172
2173 LOG(LOG_SS_POLICY_PARSER, LOG_PRIORITY_VERBOSE, ("PolicyParseProtectionRule: Turning userland protection %s\n", OnOff ? "on" : "off"));
2174
2175 if (OnOff)
2176 pSecPolicy->ProtectionFlags |= PROTECTION_USERLAND;
2177 else
2178 pSecPolicy->ProtectionFlags &= ~PROTECTION_USERLAND;
2179
2180 return TRUE;
2181 }
2182
2183
2184 if (strlen(Operation) == 9 && _stricmp(Operation, "debugging") == 0)
2185 {
2186 if (PolicyParseOnOffClause(rule, &OnOff) == FALSE)
2187 return FALSE;
2188
2189 LOG(LOG_SS_POLICY_PARSER, LOG_PRIORITY_VERBOSE, ("PolicyParseProtectionRule: Turning debugging protection %s\n", OnOff ? "on" : "off"));
2190
2191 if (OnOff)
2192 pSecPolicy->ProtectionFlags |= PROTECTION_DEBUGGING;
2193 else
2194 pSecPolicy->ProtectionFlags &= ~PROTECTION_DEBUGGING;
2195
2196 return TRUE;
2197 }
2198
2199
2200 if (strlen(Operation) == 5 && _stricmp(Operation, "dos16") == 0)
2201 {
2202 if (PolicyParseOnOffClause(rule, &OnOff) == FALSE)
2203 return FALSE;
2204
2205 LOG(LOG_SS_POLICY_PARSER, LOG_PRIORITY_VERBOSE, ("PolicyParseProtectionRule: Turning dos16/vdm protection %s\n", OnOff ? "on" : "off"));
2206
2207 if (OnOff)
2208 pSecPolicy->ProtectionFlags |= PROTECTION_VDM;
2209 else
2210 pSecPolicy->ProtectionFlags &= ~PROTECTION_VDM;
2211
2212 return TRUE;
2213 }
2214
2215
2216 if (strlen(Operation) == 8 && _stricmp(Operation, "keyboard") == 0)
2217 {
2218 if (PolicyParseOnOffClause(rule, &OnOff) == FALSE)
2219 return FALSE;
2220
2221 LOG(LOG_SS_POLICY_PARSER, LOG_PRIORITY_VERBOSE, ("PolicyParseProtectionRule: Turning keyboard logger protection %s\n", OnOff ? "on" : "off"));
2222
2223 if (OnOff)
2224 pSecPolicy->ProtectionFlags |= PROTECTION_KEYBOARD;
2225 else
2226 pSecPolicy->ProtectionFlags &= ~PROTECTION_KEYBOARD;
2227
2228 return TRUE;
2229 }
2230
2231
2232 if (strlen(Operation) == 5 && _stricmp(Operation, "modem") == 0)
2233 {
2234 if (PolicyParseOnOffClause(rule, &OnOff) == FALSE)
2235 return FALSE;
2236
2237 LOG(LOG_SS_POLICY_PARSER, LOG_PRIORITY_VERBOSE, ("PolicyParseProtectionRule: Turning modem protection %s\n", OnOff ? "on" : "off"));
2238
2239 if (OnOff)
2240 pSecPolicy->ProtectionFlags |= PROTECTION_MODEM;
2241 else
2242 pSecPolicy->ProtectionFlags &= ~PROTECTION_MODEM;
2243
2244 return TRUE;
2245 }
2246
2247
2248 if (strlen(Operation) == 7 && _stricmp(Operation, "sniffer") == 0)
2249 {
2250 if (PolicyParseOnOffClause(rule, &OnOff) == FALSE)
2251 return FALSE;
2252
2253 LOG(LOG_SS_POLICY_PARSER, LOG_PRIORITY_VERBOSE, ("PolicyParseProtectionRule: Turning sniffer protection %s\n", OnOff ? "on" : "off"));
2254
2255 if (OnOff)
2256 pSecPolicy->ProtectionFlags |= PROTECTION_SNIFFER;
2257 else
2258 pSecPolicy->ProtectionFlags &= ~PROTECTION_SNIFFER;
2259
2260 return TRUE;
2261 }
2262
2263
2264 if (strlen(Operation) == 9 && _stricmp(Operation, "extension") == 0)
2265 {
2266 if (PolicyParseOnOffClause(rule, &OnOff) == FALSE)
2267 return FALSE;
2268
2269 LOG(LOG_SS_POLICY_PARSER, LOG_PRIORITY_VERBOSE, ("PolicyParseProtectionRule: Turning extension protection %s\n", OnOff ? "on" : "off"));
2270
2271 if (OnOff)
2272 pSecPolicy->ProtectionFlags |= PROTECTION_EXTENSION;
2273 else
2274 pSecPolicy->ProtectionFlags &= ~PROTECTION_EXTENSION;
2275
2276 return TRUE;
2277 }
2278
2279
2280 if (strlen(Operation) == 3 && _stricmp(Operation, "all") == 0)
2281 {
2282 if (PolicyParseOnOffClause(rule, &OnOff) == FALSE)
2283 return FALSE;
2284
2285 LOG(LOG_SS_POLICY_PARSER, LOG_PRIORITY_VERBOSE, ("PolicyParseProtectionRule: Turning all protection %s\n", OnOff ? "on" : "off"));
2286
2287 pSecPolicy->ProtectionFlags = OnOff == TRUE ? PROTECTION_ALL_ON : PROTECTION_ALL_OFF;
2288
2289 return TRUE;
2290 }
2291
2292
2293 ABORT_PolicyParseRule(("Invalid protection operation '%s'. Valid options are 'overflow', 'userland', 'debugging', 'dos16', 'keyboard', 'modem', 'sniffer', 'extension' and 'all'.\n", Operation));
2294}
2295
2296
2297
2298/*
2299 * PolicyParseMediaRule()
2300 *
2301 * Description:
2302 * Parse a media rule.
2303 *
2304 * Parameters:
2305 * pSecPolicy - security policy that the rule is going to be added to.
2306 * Operation - ASCII operation. The only valid option is 'access'.
2307 * Rule - ASCII rule to parse.
2308 *
2309 * Returns:
2310 * Nothing.
2311 */
2312
2313BOOLEAN
2314PolicyParseMediaRule(PSECURITY_POLICY pSecPolicy, PCHAR Operation, PCHAR rule)
2315{
2316 if (pSecPolicy != &gSecPolicy)
2317 {
2318 LOG(LOG_SS_POLICY_PARSER, LOG_PRIORITY_WARNING, ("PolicyParseMediaRule: Media rules can be setup only in a global policy\n"));
2319 return TRUE;
2320 }
2321
2322
2323 if (strlen(Operation) != 6 || _stricmp(Operation, "access") != 0)
2324 ABORT_PolicyParseRule(("Invalid media operation '%s'. The only valid option is 'access'.\n", Operation));
2325
2326
2327 if (strlen(rule) == 6 && _stricmp(rule, "permit") == 0)
2328 {
2329 MediaRemovableFlags = MEDIA_REMOVABLE_PERMIT;
2330 return TRUE;
2331 }
2332
2333 if (strlen(rule) == 4 && _stricmp(rule, "deny") == 0)
2334 {
2335 MediaRemovableFlags |= MEDIA_REMOVABLE_DISABLE;
2336 return TRUE;
2337 }
2338
2339 if (strlen(rule) == 8 && _stricmp(rule, "readonly") == 0)
2340 {
2341 MediaRemovableFlags |= MEDIA_REMOVABLE_READONLY;
2342 return TRUE;
2343 }
2344
2345 if (strlen(rule) == 9 && _stricmp(rule, "noexecute") == 0)
2346 {
2347 MediaRemovableFlags |= MEDIA_REMOVABLE_NOEXECUTE;
2348 return TRUE;
2349 }
2350
2351
2352 ABORT_PolicyParseRule(("Expecting to see 'permit', 'deny', 'readonly', or 'noexecute' action. Got '%s'\n", rule));
2353}
2354
2355
2356
2357/*
2358 * InsertPolicyRule()
2359 *
2360 * Description:
2361 * Adds a rule to a specified security policy (FIFO order).
2362 *
2363 * Parameters:
2364 * pSecPolicy - security policy that the rule is going to be added to.
2365 * PolicyRule - rule to add.
2366 * RuleType - rule type (file, network, etc).
2367 *
2368 * Returns:
2369 * Nothing.
2370 */
2371
2372VOID
2373InsertPolicyRule(PSECURITY_POLICY pSecPolicy, PPOLICY_RULE PolicyRule, RULE_TYPE RuleType)
2374{
2375 KIRQL irql;
2376 PPOLICY_RULE tmp;
2377
2378
2379 ASSERT(RuleType < RULE_LASTONE);
2380
2381
2382 KeAcquireSpinLock(&pSecPolicy->SpinLock, &irql);
2383
2384
2385 if (pSecPolicy->RuleList[RuleType] == NULL)
2386 {
2387 pSecPolicy->RuleList[RuleType] = PolicyRule;
2388
2389 KeReleaseSpinLock(&pSecPolicy->SpinLock, irql);
2390
2391 return;
2392 }
2393
2394 /* find the last rule and link the new rule to it */
2395 tmp = pSecPolicy->RuleList[RuleType];
2396
2397 while (tmp->Next)
2398 {
2399 tmp = tmp->Next;
2400 }
2401
2402 tmp->Next = PolicyRule;
2403
2404
2405 KeReleaseSpinLock(&pSecPolicy->SpinLock, irql);
2406}
2407
2408
2409
2410/*
2411 * PolicyParseObjectRule()
2412 *
2413 * Description:
2414 * Parse an object rule of the following format:
2415 * (name|address) (eq|match) "<objectname>" then (deny|quitedeny|permit|log)
2416 * Rule can also consist of just (deny|quitedeny|permit|log)
2417 *
2418 * example1: name match "c:\file*" then deny
2419 * example2: address eq "192.168.0.1" then log
2420 * example3: quietdeny
2421 *
2422 * Parameters:
2423 * pSecPolicy - security policy that the rule is going to be added to.
2424 * RuleType - rule type (file, network, etc).
2425 * Operation - ASCII operation (read, write, etc).
2426 * Rule - ASCII rule to parse. NOTE: this field gets clobbered.
2427 *
2428 * Returns:
2429 * Nothing.
2430 */
2431
2432BOOLEAN
2433PolicyParseObjectRule(PSECURITY_POLICY pSecPolicy, RULE_TYPE RuleType, PCHAR Operation, PCHAR rule)
2434{
2435 PCHAR name = NULL;
2436 PCHAR OriginalRule = rule;
2437 int i, TotalStars;
2438 BOOLEAN wildcard, WildcardWarning = FALSE;
2439 BOOLEAN ParseLastToken = FALSE;
2440 ACTION_TYPE ActionType;
2441 MATCH_TYPE MatchType;
2442 PPOLICY_RULE PolicyRule;
2443 UCHAR OperationType;
2444 PCHAR ObjectName = NULL;
2445 size_t ObjectSize = 0;
2446 UCHAR RuleNumber;
2447
2448
2449 LOG(LOG_SS_POLICY_PARSER, LOG_PRIORITY_VERBOSE, ("PolicyParseObjectRule: Parsing rule '%s': '%s'\n", Operation, rule));
2450
2451
2452 /*
2453 * First token can be "name" or "address" for network rules
2454 * Alternatively, the entire rule can consist of an action clause (such as permit, deny, quietdeny or log)
2455 */
2456
2457 switch (VerifyToken2(&rule, "name", "address"))
2458 {
2459 /* matched token1 - "name" */
2460 case 1: break;
2461
2462 /* matched token2 - "address" */
2463 case 2:
2464 {
2465 /* only network rules can substitute "address" for "name" */
2466
2467 if (RuleType != RULE_NETWORK)
2468
2469 ABORT_PolicyParseRule(("Expecting to see 'name'. Got 'address'\n"));
2470
2471 break;
2472 }
2473
2474 /* didn't match "name" or "address". try to parse as an action clause */
2475 default:
2476 {
2477 ParseLastToken = TRUE;
2478 goto ParseLastToken;
2479 }
2480 }
2481
2482
2483 /*
2484 * Second token should be "eq" or "match"
2485 */
2486
2487 switch (VerifyToken2(&rule, "eq", "match"))
2488 {
2489 /* matched token1 - "eq" */
2490 case 1: wildcard = FALSE; break;
2491
2492 /* matched token2 - "match" */
2493 case 2: wildcard = TRUE; break;
2494
2495 /* didn't match "eq" or "match" */
2496 default: ABORT_PolicyParseRule(("Expecting to see 'eq' or 'match'. Got '%s'\n", rule));
2497 }
2498
2499
2500 /*
2501 * Third token is the object names in quotes
2502 */
2503
2504 /* parse the object name surrounded by quotes: "<object name>" */
2505
2506 if (*rule++ != '"')
2507 ABORT_PolicyParseRule(("Initial quote character not found. Object names should be surrounded by quotes.\n"));
2508
2509
2510 name = rule;
2511
2512 TotalStars = i = 0;
2513
2514
2515 while (*rule != 0 && *rule != '"')
2516 {
2517 if (i >= POLICY_MAX_OBJECT_NAME_LENGTH-1)
2518 ABORT_PolicyParseRule(("Object name '%s' is too long.\nMaximum name length is %d characters.\n", rule - POLICY_MAX_OBJECT_NAME_LENGTH, POLICY_MAX_OBJECT_NAME_LENGTH));
2519
2520 // fail bad regexes
2521 if (*rule == '*')
2522 {
2523 if (++TotalStars > POLICY_TOTAL_NUMBER_OF_STARS)
2524 ABORT_PolicyParseRule(("Invalid regular expression. Maximum of %d stars are allowed\n", POLICY_TOTAL_NUMBER_OF_STARS));
2525 }
2526
2527
2528 if (wildcard == FALSE && (*rule == '*' || *rule == '?') && WildcardWarning == FALSE)
2529 {
2530 LOG(LOG_SS_POLICY_PARSER, LOG_PRIORITY_WARNING, ("%S:%d:\n", gPolicyFilename, gPolicyLineNumber));
2531 LOG(LOG_SS_POLICY_PARSER, LOG_PRIORITY_WARNING, ("Found a regular expression with an 'eq' operator. Use 'match' operator to enable regular expressions.\n"));
2532 WildcardWarning = TRUE;
2533 }
2534
2535
2536 ++i;
2537 ++rule;
2538 }
2539
2540
2541 if (i == 0 || *rule++ != '"')
2542 ABORT_PolicyParseRule(("Final quote character not found. Object names should be surrounded by quotes.\n"));
2543
2544 name[i] = 0;
2545
2546
2547 if (! IS_WHITESPACE(*rule))
2548 {
2549 ABORT_PolicyParseRule(("Expecting to see white space. Got '%s'\n", rule));
2550 }
2551
2552 SKIP_WHITESPACE(rule);
2553
2554
2555 /*
2556 * Fourth token is "then"
2557 */
2558
2559 if (VerifyToken2(&rule, "then", "") != 1)
2560 ABORT_PolicyParseRule(("Expecting to see 'then'. Got '%s'\n", rule));
2561
2562 /*
2563 * Fifth/Last token is "permit", "deny", "quietdeny", "log" or "ask"
2564 */
2565
2566ParseLastToken:
2567
2568 if (PolicyParseActionClause(rule, &ActionType, &RuleNumber) == FALSE)
2569
2570 return FALSE;
2571
2572
2573 /*
2574 * Rule parsed ok. Create a new rule.
2575 */
2576
2577 if (RuleType > sizeof(ObjectParseOps) / sizeof(ObjectParseOps[0]))
2578 ABORT_PolicyParseRule(("Invalid rule type\n"));
2579
2580
2581 if (name)
2582 {
2583 if ((ObjectSize = ObjectParseOps[RuleType].ObjectNameParser(name, &ObjectName, &wildcard)) == INVALID_OBJECT_SIZE)
2584 ABORT_PolicyParseRule(("Invalid object name '%s'\n", name));
2585
2586 MatchType = (wildcard == TRUE ? MATCH_WILDCARD : MATCH_SINGLE);
2587 }
2588 else
2589 {
2590 ObjectSize = 0;
2591 MatchType = MATCH_ALL;
2592 }
2593
2594
2595 if ((OperationType = ObjectParseOps[RuleType].OperationTypeParser(Operation)) == OP_INVALID)
2596 ABORT_PolicyParseRule(("Invalid operation '%s'\n", Operation));
2597
2598
2599 /* POLICY_RULE already includes 1 character for the name buffer */
2600
2601 PolicyRule = ExAllocatePoolWithTag(NonPagedPool, sizeof(POLICY_RULE) + ObjectSize, _POOL_TAG);
2602 if (PolicyRule == NULL)
2603 {
2604 LOG(LOG_SS_POLICY_PARSER, LOG_PRIORITY_WARNING, ("Object policy parser is out of memory\n"));
2605 return FALSE;
2606 }
2607
2608 RtlZeroMemory(PolicyRule, sizeof(POLICY_RULE));
2609
2610 PolicyRule->ActionType = ActionType;
2611 PolicyRule->MatchType = MatchType;
2612 PolicyRule->OperationType = OperationType;
2613
2614 PolicyRule->RuleNumber = RuleNumber;
2615 PolicyRule->PolicyLineNumber = gPolicyLineNumber;
2616 PolicyRule->pSecurityPolicy = pSecPolicy;
2617
2618
2619 /* ObjectSize can be 0 for MATCH_ALL rules */
2620 if (ObjectSize)
2621 {
2622 PolicyRule->NameLength = (USHORT) ObjectSize;
2623 strcpy(PolicyRule->Name, (PCHAR) ObjectName);
2624 }
2625
2626
2627 /*
2628 * Some rules (such as DLL) are actually enforced by different rules (i.e. section).
2629 * If LearningMode = TRUE then there is no need to convert
2630 */
2631
2632 if (LearningMode == FALSE)
2633 {
2634 /* DLL rules are enforced by section rules. */
2635 if (RuleType == RULE_DLL)
2636 RuleType = RULE_SECTION;
2637
2638 /* Service rules are enforced by registry rules. */
2639 if (RuleType == RULE_SERVICE)
2640 RuleType = RULE_REGISTRY;
2641 }
2642
2643
2644 InsertPolicyRule(pSecPolicy, PolicyRule, RuleType);
2645
2646
2647 return TRUE;
2648}
2649
2650
2651
2652/*
2653 * PolicyParseSyscallRule()
2654 *
2655 * Description:
2656 * .
2657 *
2658 * Parameters:
2659 * .
2660 *
2661 * Returns:
2662 * Nothing.
2663 */
2664
2665BOOLEAN
2666PolicyParseSyscallRule(PSECURITY_POLICY pSecPolicy, PCHAR SyscallName, PCHAR rule)
2667{
2668 PPOLICY_RULE PolicyRule;
2669 KIRQL irql;
2670 ACTION_TYPE ActionType;
2671 ULONG SyscallNameIndex;
2672 BOOLEAN AcceptAll = FALSE;
2673
2674
2675#if HOOK_SYSCALLS
2676
2677 LOG(LOG_SS_POLICY_PARSER, LOG_PRIORITY_VERBOSE, ("PolicyParseSyscallRule: Parsing syscall '%s' rule: '%s'\n", SyscallName, rule));
2678
2679
2680 /* expecting to see "permit", "deny", "quietdeny" or "log" */
2681 if (PolicyParseActionClause(rule, &ActionType, NULL) == FALSE)
2682 {
2683// LOG(LOG_SS_POLICY_PARSER, LOG_PRIORITY_DEBUG, ("PolicyParseSyscallRule: PolicyParseActionClause failed\n"));
2684 return FALSE;
2685 }
2686
2687#if 0
2688 /*
2689 * all the special system calls such as OpenFile and CreateProcess have already been hooked, it should
2690 * be safe to hook everything else. If a special system call is specified then HookSystemServiceByName
2691 * will just silently fail since it's already hooked.
2692 */
2693
2694 if (HookSystemServiceByName(SyscallName, NULL/*USE_DEFAULT_HOOK_FUNCTION*/) == FALSE)
2695 {
2696 LOG(LOG_SS_POLICY_PARSER, LOG_PRIORITY_WARNING, ("Unknown syscall '%s'\n", SyscallName));
2697 return FALSE;
2698 }
2699#endif
2700
2701
2702 if (strlen(SyscallName) == 3 && _stricmp(SyscallName, "all") == 0)
2703 {
2704 AcceptAll = TRUE;
2705 }
2706 else
2707 {
2708 SyscallNameIndex = FindSystemServiceNumber(SyscallName);
2709 if (SyscallNameIndex == -1)
2710 {
2711 LOG(LOG_SS_POLICY_PARSER, LOG_PRIORITY_DEBUG, ("PolicyParseSyscallRule: Syscall name '%s' not found\n", SyscallName));
2712 return FALSE;
2713 }
2714 }
2715
2716
2717 /* allocate enough memory to hold a bit array for all existing system calls */
2718
2719 if (pSecPolicy->RuleList[ RULE_SYSCALL ] == NULL)
2720 {
2721 /*
2722 * Take into account 1 ULONG that is already preallocated in POLICY_RULE.
2723 */
2724
2725 USHORT Size = 1 + (USHORT) (ZwCallsNumber - NumberOfBitsInUlong) / 8;
2726
2727
2728 PolicyRule = ExAllocatePoolWithTag(NonPagedPool, sizeof(POLICY_RULE) + Size, _POOL_TAG);
2729 if (rule == NULL)
2730 {
2731 LOG(LOG_SS_POLICY_PARSER, LOG_PRIORITY_WARNING, ("Policy parser is out of memory\n"));
2732 return FALSE;
2733 }
2734
2735 RtlZeroMemory(PolicyRule, sizeof(POLICY_RULE) + Size);
2736
2737
2738 /* if default action is permit, then fill the entire bit array with 1's */
2739 if (pSecPolicy->DefaultPolicyAction == ACTION_PERMIT)
2740 {
2741 RtlFillMemory(&PolicyRule->ServiceBitArray, sizeof(PolicyRule->ServiceBitArray) + Size, 0xFF);
2742 }
2743
2744
2745 KeAcquireSpinLock(&pSecPolicy->SpinLock, &irql);
2746
2747 pSecPolicy->RuleList[ RULE_SYSCALL ] = PolicyRule;
2748
2749 KeReleaseSpinLock(&pSecPolicy->SpinLock, irql);
2750 }
2751 else
2752 {
2753 PolicyRule = pSecPolicy->RuleList[ RULE_SYSCALL ];
2754 }
2755
2756
2757 // syscall_all: permit
2758 // syscall_all: deny
2759
2760 // syscall_blah: permit
2761 // syscall_all: deny
2762
2763 if (AcceptAll == TRUE)
2764 ;//XXX
2765
2766 {
2767 /* Calculate the bit array ULONG we need to modify (bit array consists of a bunch of ULONGs) */
2768 ULONG UlongCount = SyscallNameIndex >> UlongBitShift;
2769
2770 /* Choose the correct bit array ULONG */
2771 PULONG BitArray = &PolicyRule->ServiceBitArray[0] + UlongCount;
2772
2773
2774 //XXX what about log?
2775 if (ActionType == ACTION_PERMIT)
2776 {
2777 /* set the bit */
2778 *BitArray |= 1 << (SyscallNameIndex - (UlongCount << UlongBitShift));
2779 }
2780 else if (ActionType >= ACTION_DENY)
2781 {
2782 /* reset the bit */
2783 *BitArray &= ~( 1 << (SyscallNameIndex - (UlongCount << UlongBitShift)) );
2784 }
2785 }
2786
2787#endif
2788
2789
2790 return TRUE;
2791}
2792
2793
2794
2795/*
2796 * WildcardMatch()
2797 *
2798 * Description:
2799 * Simple regex algorithm. Supports '?' for a single character match (does not match EOF) and
2800 * '*' for multiple characters (must reside in the same directory).
2801 *
2802 * i.e. c:\temp\*\blah will match c:\temp\temp2\blah but not c:\temp\temp2\temp3\blah
2803 *
2804 * NOTE: WildcardMatch() is at least 10x slower than simple _stricmp().
2805 *
2806 * Parameters:
2807 * path - ASCII pathname.
2808 * regex - regular expression to match
2809 *
2810 * Returns:
2811 * WILDCARD_MATCH (0) in case of a match, WILDCARD_NO_MATCH (1) otherwise.
2812 */
2813
2814int
2815WildcardMatch(PCHAR path, PCHAR regex)
2816{
2817 BOOLEAN MultipleDirectoryMatch = FALSE, SkippedOverWhitespace = FALSE, ShortFileName = FALSE;
2818
2819
2820 if (path == NULL || regex == NULL)
2821 return WILDCARD_NO_MATCH;
2822
2823
2824 while (*regex)
2825 {
2826 /*
2827 * SPECIAL CASE.
2828 * Try to deal with short names (longna~1.txt vs long name.txt).
2829 * when we encounter a ~X where X is a digit we skip over it and rewind regex
2830 * to either the next '\' or whatever the next path character is.
2831 *
2832 * The reason for this is when we encounter a long directory it will be abbreviated as follows
2833 * c:\Documents and Settings\... -> c:\DOCUME~1\...
2834 * Thus by matching "DOCUME" and then skipping over ~1 in the pathname and by rewinding regex
2835 * until the next '\' we match the two directories.
2836 *
2837 * The long filenames are matched and abbreviated as follows
2838 * c:\longfilename.txt -> c:\longfi~1.txt
2839 * Thus we match "longfi", skip over ~1 in the pathname and rewind regex until we match
2840 * the next path character which is '.', then we match ".txt"
2841 *
2842 * The following scheme was mostly designed to deal with "c:\documents and settings" and
2843 * "c:\program files" directories since they are two very common long names. It breaks
2844 * in a lot of different cases. Consider the following abbreviation list
2845 *
2846 * LONGNA~1 long name1
2847 * LONGNA~2 long name2
2848 * LONGNA~3 long name3
2849 * LONGNA~4 long name4
2850 * LOA926~1 long name5
2851 * LOB926~1 long name6
2852 *
2853 * When more than four names match to the same short name prefix, Windows switches to an
2854 * alternative hash based schemes which is not handled by our code.
2855 *
2856 * Another restriction (there are probably more) has to do with long extensions which are abbreviated
2857 * as follows: file.html.text -> filete~1.htm. The following code does not handle this case either.
2858 *
2859 * All in all, the following code is an ugly hack that is designed to work for most common cases
2860 * with a least amount of effort.
2861 */
2862
2863 if (*path == '~' && isdigit(*(path + 1)))
2864 {
2865 /* rewind regex until we see '\' or whichever character (ie '.' as in ~1.txt) follows ~X in the path */
2866 while (*regex && *regex != '\\' && *regex != *(path + 2) /*&& *regex != '*' && *regex != '?'*/)
2867 ++regex;
2868
2869 /* skip over ~X */
2870 path += 2;
2871
2872 ShortFileName = TRUE;
2873 }
2874
2875
2876 if (*regex == '*')
2877 {
2878 PCHAR str;
2879
2880 /*
2881 * match one or more characters
2882 */
2883
2884 /* if regular expression ends with '*', automatically match the rest of the pathname */
2885 if (*(regex + 1) == 0)
2886 return WILDCARD_MATCH;
2887
2888 if (*(regex + 1) == '*')
2889 {
2890 ++regex;
2891 MultipleDirectoryMatch = TRUE;
2892 }
2893
2894 str = path;
2895 while (*str)
2896 {
2897 if (WildcardMatch(str, regex+1) == WILDCARD_MATCH)
2898 return WILDCARD_MATCH;
2899
2900 if (MultipleDirectoryMatch == FALSE && *str == '\\')
2901 break;
2902
2903 ++str;
2904 }
2905 }
2906 else if (*regex == '?')
2907 {
2908 /*
2909 * match one character
2910 */
2911
2912 if (*path == 0 || *path == '\\')
2913 return WILDCARD_NO_MATCH;
2914
2915 ++path;
2916 }
2917 else if (*regex == '\\')
2918 {
2919 /* if we skipped over whitespace but did not match a short name then bail out as not skipping over
2920 whitespace would not get us this far anyway */
2921 if (SkippedOverWhitespace == TRUE && ShortFileName == FALSE)
2922 return WILDCARD_NO_MATCH;
2923
2924 ShortFileName = FALSE;
2925 SkippedOverWhitespace = FALSE;
2926
2927 /*
2928 * match one or more slashes
2929 */
2930
2931 if (*path++ != '\\')
2932 return WILDCARD_NO_MATCH;
2933
2934 while (*path == '\\')
2935 ++path;
2936 }
2937 else
2938 {
2939 /*
2940 * match all other characters
2941 */
2942
2943// if (toupper(*path++) != toupper(*regex))
2944// return WILDCARD_NO_MATCH;
2945
2946 if (toupper(*path) != toupper(*regex))
2947 {
2948 /*
2949 * Skip over whitespace to match long filenames which are abbreviated with all
2950 * whitespace stripped. In order not to match two filenames with different amount
2951 * of whitespace, we insert an additional check when we reach '\' once we found out
2952 * whether we are working with an abbreviated name.
2953 */
2954 if (*regex == ' ')
2955 SkippedOverWhitespace = TRUE;
2956 else
2957 return WILDCARD_NO_MATCH;
2958 }
2959 else
2960 {
2961 ++path;
2962 }
2963 }
2964
2965 ++regex;
2966 }
2967
2968
2969 /* make sure pathname is not longer than the regex */
2970 return *path == 0 ? WILDCARD_MATCH : WILDCARD_NO_MATCH;
2971}
2972
2973
2974
2975/*
2976 * PolicyCheckPolicy()
2977 *
2978 * Description:
2979 * .
2980 *
2981 * Parameters:
2982 * .
2983 *
2984 * Returns:
2985 * .
2986 */
2987
2988ACTION_TYPE
2989PolicyCheckPolicy(PSECURITY_POLICY pSecPolicy, RULE_TYPE RuleType, PCHAR Object, UCHAR OperationType, ACTION_TYPE DefaultAction, UCHAR *RuleNumber, PWSTR *PolicyFilename, USHORT *PolicyLineNumber)
2990{
2991 PPOLICY_RULE r;
2992 ACTION_TYPE ret = DefaultAction;
2993 KIRQL irql;
2994 size_t len;
2995
2996
2997 ASSERT(pSecPolicy);
2998 ASSERT(PolicyFilename && PolicyLineNumber);
2999 ASSERT(RuleNumber);
3000
3001
3002 if (Object)
3003 len = strlen(Object);
3004
3005 *PolicyFilename = NULL;
3006 *PolicyLineNumber = 0;
3007 *RuleNumber = 0;
3008
3009
3010 if (pSecPolicy->Initialized == FALSE)
3011
3012 return ACTION_NONE;
3013
3014
3015 KeAcquireSpinLock(&pSecPolicy->SpinLock, &irql);
3016
3017
3018 *PolicyFilename = pSecPolicy->Name;
3019
3020
3021 r = pSecPolicy->RuleList[RuleType];
3022
3023 while (r)
3024 {
3025//XXX at least for registry keys there is no point in comparing the first 10 characters since they will always be \Registry\ ?
3026
3027 if ( (r->MatchType == MATCH_ALL) ||
3028 (r->MatchType == MATCH_SINGLE && len == r->NameLength && _stricmp(Object, r->Name) == 0) ||
3029 (r->MatchType == MATCH_WILDCARD && WildcardMatch(Object, r->Name) == WILDCARD_MATCH) )
3030 {
3031 if (Object)
3032 LOG(LOG_SS_POLICY, LOG_PRIORITY_VERBOSE, ("%d PolicyCheckPolicy: matched '%s' (%s) (%x %x %x)\n", CURRENT_PROCESS_PID, Object, r->Name, r->MatchType, r->OperationType, OperationType));
3033 else
3034 LOG(LOG_SS_POLICY, LOG_PRIORITY_VERBOSE, ("%d PolicyCheckPolicy: matched RuleType %d MatchType %d OpType %d\n", CURRENT_PROCESS_PID, RuleType, r->MatchType, r->OperationType));
3035
3036
3037// if (r->OperationType == OP_APPEND)
3038// {
3039// ret = ACTION_PROCESS;
3040// break;
3041// }
3042
3043
3044 /*
3045 * (r->OperationType & OperationType) == r->OperationType
3046 * (r->OperationType & OperationType)
3047 *
3048 * policy_default: deny
3049 * file_read: file.txt
3050 *
3051 * del file.txt (opens file for read + write)
3052 *
3053 * (read & read_write) = read
3054 *
3055 * successfully overwrites the file!
3056 */
3057
3058 /*
3059 * (r->OperationType & OperationType) == OperationType
3060 *
3061 * policy_default: permit
3062 * file_write: file.txt deny
3063 * file_read: file.txt
3064 *
3065 * del file.txt (opens file for read + write)
3066 *
3067 * (write & read_write) != read_write
3068 *
3069 * successfully deletes the file!
3070 */
3071
3072 // XXX if we only allow reading but both read+execute are requested, the following
3073 // if will match! (bad in deny all scenario!)
3074 if (r->OperationType == OP_ALL || r->OperationType & OperationType)
3075// if (r->OperationType == OP_ALL || (r->OperationType & OperationType) == r->OperationType)
3076// if (r->OperationType == OP_ALL || (r->OperationType & OperationType) == OperationType)
3077 {
3078 ret = r->ActionType;
3079
3080
3081 /* remember which rule caused this alert */
3082 *PolicyLineNumber = r->PolicyLineNumber;
3083 *RuleNumber = r->RuleNumber;
3084
3085
3086 LOG(LOG_SS_POLICY, LOG_PRIORITY_VERBOSE, ("%d PolicyCheckPolicy: %s access to %d\n",
3087 CURRENT_PROCESS_PID, ret >= ACTION_DENY ? "deny" : "permit",
3088 (ULONG) PsGetCurrentProcessId()));
3089
3090 break;
3091 }
3092 }
3093
3094 r = (PPOLICY_RULE) r->Next;
3095 }
3096
3097 KeReleaseSpinLock(&pSecPolicy->SpinLock, irql);
3098
3099
3100 return ret;
3101}
3102
3103
3104
3105/*
3106 * PolicyCheck()
3107 *
3108 * Description:
3109 * Verifies whether a specified action (rule (RuleType) + object (arg) ) are allowed
3110 * by a global and current process security policies.
3111 *
3112 * Parameters:
3113 * RuleType - rule type (file rule, registry, etc).
3114 * Object - Object name.
3115 * OperationType - type of operation carried out (read, write, etc).
3116 * RuleNumber - number of the rule that triggered the alert (if it did)
3117 * PolicyFilename - name of the policy where the rule, that triggered the alert, was specified
3118 * PolicyLineNumber - policy line where the rule, that triggered the alert, was specified
3119 *
3120 * Returns:
3121 * ACCESS_NONE, ACCESS_PERMIT, ACCESS_DENY or ACCESS_QUIETDENY depending on a security policy.
3122 */
3123
3124ACTION_TYPE
3125PolicyCheck(RULE_TYPE RuleType, PCHAR Object, UCHAR OperationType, UCHAR *RuleNumber, PWSTR *PolicyFilename, USHORT *PolicyLineNumber)
3126{
3127 PIMAGE_PID_ENTRY p, prev;
3128 PWSTR GlobalPolicyFilename, ProcessPolicyFilename;
3129 USHORT GlobalPolicyLineNumber, ProcessPolicyLineNumber;
3130 UCHAR GlobalRuleNumber, ProcessRuleNumber;
3131 ACTION_TYPE GlobalAction, ProcessAction = ACTION_PERMIT_DEFAULT, ReturnAction;
3132 ULONG ProcessId = CURRENT_PROCESS_PID;
3133
3134
3135 /* don't mess with kernel initiated calls */
3136
3137 if (KeGetPreviousMode() != UserMode || KeGetCurrentIrql() != PASSIVE_LEVEL)
3138
3139 return ACTION_PERMIT;
3140
3141
3142 /*
3143 * As most of system calls PolicyCheck() this is a convinient place to verify
3144 * user return address since it needs to be done for all calls
3145 */
3146
3147 VerifyUserReturnAddress();
3148
3149
3150 /*
3151 * First verify against the global security policy
3152 */
3153
3154 GlobalAction = PolicyCheckPolicy(&gSecPolicy, RuleType, Object, OperationType, gSecPolicy.DefaultPolicyAction, &GlobalRuleNumber, &GlobalPolicyFilename, &GlobalPolicyLineNumber);
3155
3156 /*
3157 * Then against process specific policy
3158 */
3159
3160 /* find the process specific policy */
3161
3162 p = FindImagePidEntry(ProcessId, 0);
3163
3164 if (p)
3165 {
3166 ProcessAction = PolicyCheckPolicy(&p->SecPolicy, RuleType, Object, OperationType, p->SecPolicy.DefaultPolicyAction, &ProcessRuleNumber, &ProcessPolicyFilename, &ProcessPolicyLineNumber);
3167 }
3168
3169
3170// KdPrint(("object %s %d %d action %x %x", Object, RuleType, OperationType, GlobalAction, ProcessAction));
3171
3172 /*
3173 * return the most stringent possible action
3174 */
3175
3176 /* Exception #1: explicit process permit/log overrides general global deny */
3177 if ((ProcessAction == ACTION_PERMIT || ProcessAction == ACTION_LOG) &&
3178 (GlobalAction & (ACTION_ASK | ACTION_DENY)))
3179 {
3180 *PolicyFilename = ProcessPolicyFilename;
3181 *PolicyLineNumber = ProcessPolicyLineNumber;
3182 *RuleNumber = ProcessRuleNumber;
3183 return ProcessAction;
3184 }
3185
3186 /* Exception #2: explicit global permit overrides process default deny */
3187 if (GlobalAction == ACTION_PERMIT && (ProcessAction & ACTION_DEFAULT))
3188 {
3189 *PolicyFilename = GlobalPolicyFilename;
3190 *PolicyLineNumber = GlobalPolicyLineNumber;
3191 *RuleNumber = GlobalRuleNumber;
3192 return GlobalAction;
3193 }
3194
3195 if (GlobalAction & ACTION_DENY)
3196 { *PolicyFilename = GlobalPolicyFilename; *PolicyLineNumber = GlobalPolicyLineNumber; *RuleNumber = GlobalRuleNumber; ReturnAction = GlobalAction; goto done; }
3197
3198 if (ProcessAction & ACTION_DENY)
3199 { *PolicyFilename = ProcessPolicyFilename; *PolicyLineNumber = ProcessPolicyLineNumber; *RuleNumber = ProcessRuleNumber; ReturnAction = ProcessAction; goto done; }
3200
3201
3202 if (GlobalAction & ACTION_LOG)
3203 { *PolicyFilename = GlobalPolicyFilename; *PolicyLineNumber = GlobalPolicyLineNumber; *RuleNumber = GlobalRuleNumber; ReturnAction = GlobalAction; goto done; }
3204
3205 if (ProcessAction & ACTION_LOG)
3206 { *PolicyFilename = ProcessPolicyFilename; *PolicyLineNumber = ProcessPolicyLineNumber; *RuleNumber = ProcessRuleNumber; ReturnAction = ProcessAction; goto done; }
3207
3208
3209 if (GlobalAction & ACTION_ASK)
3210 { *PolicyFilename = GlobalPolicyFilename; *PolicyLineNumber = GlobalPolicyLineNumber; *RuleNumber = GlobalRuleNumber; ReturnAction = GlobalAction; goto done; }
3211
3212 if (ProcessAction & ACTION_ASK)
3213 { *PolicyFilename = ProcessPolicyFilename; *PolicyLineNumber = ProcessPolicyLineNumber; *RuleNumber = ProcessRuleNumber; ReturnAction = ProcessAction; goto done; }
3214
3215
3216 if (GlobalAction & ACTION_PERMIT)
3217 { *PolicyFilename = GlobalPolicyFilename; *PolicyLineNumber = GlobalPolicyLineNumber; *RuleNumber = GlobalRuleNumber; ReturnAction = GlobalAction; goto done; }
3218
3219 if (ProcessAction & ACTION_PERMIT)
3220 { *PolicyFilename = ProcessPolicyFilename; *PolicyLineNumber = ProcessPolicyLineNumber; *RuleNumber = ProcessRuleNumber; ReturnAction = ProcessAction; goto done; }
3221
3222
3223 LOG(LOG_SS_POLICY, LOG_PRIORITY_DEBUG, ("object %s %d %d action %x %x\n", Object, RuleType, OperationType, GlobalAction, ProcessAction));
3224
3225 *PolicyFilename = NULL;
3226 *PolicyLineNumber = 0;
3227
3228
3229 return ProcessAction;
3230
3231
3232done:
3233
3234 /*
3235 * if we are booting up then don't deny any system calls to prevent a machine
3236 * from not booting up
3237 */
3238
3239 if (BootingUp == TRUE && (ReturnAction == ACTION_ASK || (ReturnAction & ACTION_DENY)))
3240 ReturnAction = ACTION_LOG;
3241
3242 return ReturnAction;
3243}
diff --git a/policy.h b/policy.h
new file mode 100644
index 0000000..a85c4fc
--- /dev/null
+++ b/policy.h
@@ -0,0 +1,344 @@
1/*
2 * Copyright (c) 2004 Security Architects Corporation. All rights reserved.
3 *
4 * Module Name:
5 *
6 * policy.h
7 *
8 * Abstract:
9 *
10 * This module defines various types used by security policy related routines.
11 *
12 * Author:
13 *
14 * Eugene Tsyrklevich 16-Feb-2004
15 *
16 * Revision History:
17 *
18 * None.
19 */
20
21
22#ifndef __POLICY_H__
23#define __POLICY_H__
24
25
26#define POLICY_MAX_SERVICE_NAME_LENGTH 64
27#define POLICY_MAX_OBJECT_NAME_LENGTH 192
28#define POLICY_MAX_RULE_LENGTH 256
29
30// maximum number of '*' characters in a regex
31#define POLICY_TOTAL_NUMBER_OF_STARS 5
32
33#define isalpha(c) ( ((c) >= 'a' && (c) <= 'z') || ((c) >= 'A' && (c) <= 'Z') )
34
35#if 0
36typedef enum _ActionType
37{
38 ACTION_NONE=0,
39 ACTION_PERMIT,
40 ACTION_PERMIT_DEFAULT,
41 ACTION_LOG,
42 ACTION_LOG_DEFAULT,
43 ACTION_PROCESS, /* further processing is required */
44 ACTION_RESERVED1,
45 ACTION_RESERVED2,
46 ACTION_RESERVED3,
47 ACTION_TERMINATE, /* terminate process */
48 ACTION_ASK, /* XXX user prompt (interactive session only?) */
49 ACTION_ASK_PERMIT, /* User chose permit */
50 ACTION_ASK_LOG, /* User chose log */
51 ACTION_ASK_TERMINATE, /* User chose terminate */
52 ACTION_DENY, /* all actions listed after ACTION_DENY are treated as DENY actions */
53 ACTION_ASK_DENY, /* User chose deny */
54 ACTION_DENY_DEFAULT, /* default deny policy action, used to distinguish between default and explicit deny actions */
55 ACTION_QUIETDENY, /* deny but do not log */
56 ACTION_QUIETDENY_DEFAULT, /* deny but do not log (default action) */
57
58} ACTION_TYPE;
59#endif
60
61
62typedef unsigned char ACTION_TYPE;
63
64#define ACTION_DEFAULT (1 << 7)
65#define ACTION_DENY (1 << 6)
66#define ACTION_PERMIT (1 << 5)
67#define ACTION_LOG (1 << 4)
68#define ACTION_TERMINATE (1 << 3)
69
70#define ACTION_NONE 0
71#define ACTION_ASK 1
72#define ACTION_ASK_PERMIT (ACTION_ASK | ACTION_PERMIT)
73#define ACTION_ASK_LOG (ACTION_ASK | ACTION_LOG)
74#define ACTION_ASK_TERMINATE (ACTION_ASK | ACTION_TERMINATE)
75#define ACTION_ASK_DENY (ACTION_ASK | ACTION_DENY)
76#define ACTION_QUIETDENY (2 | ACTION_DENY)
77#define ACTION_PROCESS 3
78#define ACTION_RESERVED1 4
79#define ACTION_RESERVED2 5
80#define ACTION_RESERVED3 6
81#define ACTION_RESERVED4 7
82
83#define ACTION_DENY_DEFAULT (ACTION_DENY | ACTION_DEFAULT)
84#define ACTION_PERMIT_DEFAULT (ACTION_PERMIT | ACTION_DEFAULT)
85#define ACTION_LOG_DEFAULT (ACTION_LOG | ACTION_DEFAULT)
86#define ACTION_QUIETDENY_DEFAULT (ACTION_QUIETDENY | ACTION_DEFAULT)
87#define ACTION_ASK_DEFAULT (ACTION_ASK | ACTION_DEFAULT)
88
89
90#define DEFAULT_POLICY_ACTION ACTION_PERMIT_DEFAULT
91
92
93/*
94 * WARNING: ObjectParseOps (policy.c) && RuleTypeData (learn.c) structures depend on the order of the
95 * following enum values
96 *
97 * RuleType enumerates all possible object types.
98 * (in C++ we would have a separate class for each)
99 */
100
101typedef enum _RuleType
102{
103 RULE_FILE = 0,
104 RULE_DIRECTORY,
105 RULE_MAILSLOT,
106 RULE_NAMEDPIPE,
107 RULE_REGISTRY,
108 RULE_SECTION,
109 RULE_DLL,
110 RULE_EVENT,
111 RULE_SEMAPHORE,
112 RULE_JOB,
113 RULE_MUTANT,
114 RULE_PORT,
115 RULE_SYMLINK,
116 RULE_TIMER,
117 RULE_PROCESS,
118 RULE_DRIVER,
119 RULE_DIROBJ,
120 RULE_ATOM,
121
122 RULE_NETWORK,
123 RULE_SERVICE,
124 RULE_TIME,
125 RULE_TOKEN,
126 RULE_SYSCALL,
127 RULE_LASTONE, /* not a real rule, just a convinient way of iterating through all rules (i < RULE_LASTONE) */
128
129} RULE_TYPE;
130
131
132typedef enum _MatchType
133{
134 MATCH_SINGLE = 0,
135 MATCH_WILDCARD,
136 MATCH_ALL,
137 MATCH_NONE
138
139} MATCH_TYPE;
140
141
142typedef enum _AlertPriority
143{
144 ALERT_PRIORITY_HIGH = 1,
145 ALERT_PRIORITY_MEDIUM,
146 ALERT_PRIORITY_LOW,
147 ALERT_PRIORITY_INFO,
148
149} ALERT_PRIORITY;
150
151
152/*
153 * Operation Types
154 */
155
156
157#define OP_INVALID 0x00
158#define OP_NONE 0x00
159
160// file ops
161
162#define OP_READ 0x01
163#define OP_WRITE 0x02
164#define OP_READ_WRITE (OP_READ | OP_WRITE)
165#define OP_EXECUTE 0x04
166#define OP_DELETE 0x08
167#define OP_APPEND 0x10
168
169// dirobj & job ops
170#define OP_CREATE 0x01
171#define OP_OPEN 0x02
172
173// directory ops
174
175#define OP_DIR_TRAVERSE 0x01
176#define OP_DIR_CREATE 0x02
177
178// process ops
179
180#define OP_PROC_EXECUTE 0x01
181#define OP_PROC_OPEN 0x02
182
183// port ops
184
185#define OP_PORT_CONNECT 0x01
186#define OP_PORT_CREATE 0x02
187
188// network ops
189
190#define OP_TCPCONNECT 0x01
191#define OP_UDPCONNECT 0x02
192#define OP_CONNECT 0x03
193#define OP_BIND 0x04
194
195// atom ops
196
197#define OP_FIND 0x01
198#define OP_ADD 0x02
199
200// service ops
201
202#define OP_SERVICE_START 0x01
203#define OP_SERVICE_STOP 0x02
204#define OP_SERVICE_CREATE 0x03
205#define OP_SERVICE_DELETE 0x04
206
207// dll/driver ops
208
209#define OP_LOAD 0x01
210#define OP_REGLOAD 0x02
211#define OP_UNLOAD 0x03 // XXX 0x04?
212
213// time change op
214
215#define OP_TIME_CHANGE 0x01
216
217// vdm ops
218
219#define OP_VDM_USE 0x01
220
221// debug ops
222
223#define OP_DEBUG 0x01
224
225// token ops
226
227#define OP_TOKEN_MODIFY 0x01
228
229// buffer overflow protection "virtual op"
230
231#define OP_INVALIDCALL 0x01
232
233
234#define OP_ALL 0xFF
235
236
237// forward declaration
238typedef struct _SECURITY_POLICY SECURITY_POLICY, *PSECURITY_POLICY;
239
240
241/* Rule should really be a class */
242
243typedef struct _POLICY_RULE
244{
245 struct _POLICY_RULE *Next;
246
247 PSECURITY_POLICY pSecurityPolicy;
248
249 ACTION_TYPE ActionType;
250 MATCH_TYPE MatchType;
251 UCHAR OperationType;
252
253 UCHAR RuleNumber; /* is used to associate text descriptions with certain rules */
254
255 USHORT PolicyLineNumber; /* line number in the policy file */
256
257 /*
258 * the majority of rules use the struct below to hold information about string objects they represent
259 * RULE_SYSCALL though does not have any names associated with it and uses ServiceBitArray to create
260 * a bit index for all system calls. Both Name & ServiceBitArray are allocated dynamically.
261 * (in C++ we would have 2 different classes for this)
262 */
263 union
264 {
265 struct
266 {
267 USHORT NameLength;
268 CHAR Name[ANYSIZE_ARRAY];
269 };
270
271 ULONG ServiceBitArray[ANYSIZE_ARRAY];
272 };
273
274} POLICY_RULE, *PPOLICY_RULE;
275
276
277
278typedef struct _SECURITY_POLICY
279{
280 PPOLICY_RULE RuleList[RULE_LASTONE];
281
282 KSPIN_LOCK SpinLock;
283
284 BOOLEAN Initialized; /* Has this policy been initialized already? */
285
286
287#define PROTECTION_OVERFLOW (1 << 0)
288#define PROTECTION_USERLAND (1 << 1)
289#define PROTECTION_DEBUGGING (1 << 2)
290#define PROTECTION_VDM (1 << 3)
291#define PROTECTION_KEYBOARD (1 << 4)
292#define PROTECTION_MODEM (1 << 5)
293#define PROTECTION_SNIFFER (1 << 6)
294#define PROTECTION_EXTENSION (1 << 7)
295
296 USHORT ProtectionFlags;
297
298 ACTION_TYPE DefaultPolicyAction;
299
300 PWSTR Name;
301
302} SECURITY_POLICY, *PSECURITY_POLICY;
303
304
305#define IS_OVERFLOW_PROTECTION_ON(SecPolicy) (((SecPolicy).ProtectionFlags & PROTECTION_OVERFLOW) == PROTECTION_OVERFLOW)
306#define IS_USERLAND_PROTECTION_ON(SecPolicy) (((SecPolicy).ProtectionFlags & PROTECTION_USERLAND) == PROTECTION_USERLAND)
307#define IS_DEBUGGING_PROTECTION_ON(SecPolicy) (((SecPolicy).ProtectionFlags & PROTECTION_DEBUGGING) == PROTECTION_DEBUGGING)
308#define IS_VDM_PROTECTION_ON(SecPolicy) (((SecPolicy).ProtectionFlags & PROTECTION_VDM) == PROTECTION_VDM)
309#define IS_EXTENSION_PROTECTION_ON(SecPolicy) (((SecPolicy).ProtectionFlags & PROTECTION_EXTENSION) == PROTECTION_EXTENSION)
310
311#define TURN_DEBUGGING_PROTECTION_OFF(SecPolicy) ((SecPolicy).ProtectionFlags &= ~PROTECTION_DEBUGGING)
312#define TURN_VDM_PROTECTION_OFF(SecPolicy) ((SecPolicy).ProtectionFlags &= ~PROTECTION_VDM)
313#define TURN_EXTENSION_PROTECTION_OFF(SecPolicy) ((SecPolicy).ProtectionFlags &= ~PROTECTION_EXTENSION)
314
315
316#define PROTECTION_ALL_ON 0xFFFF
317#define PROTECTION_ALL_OFF 0x0000
318
319#define INVALID_OBJECT_SIZE (-1)
320
321
322extern SECURITY_POLICY gSecPolicy;
323extern CHAR SystemDrive, SystemRoot[], SystemRootUnresolved[], *SystemRootDirectory, CDrive[];
324extern USHORT SystemRootLength, SystemRootUnresolvedLength, SystemRootDirectoryLength, CDriveLength;
325extern ULONG NumberOfBitsInUlong, UlongBitShift;
326
327
328#define WILDCARD_MATCH 1
329#define WILDCARD_NO_MATCH 0
330
331
332BOOLEAN InitPolicy();
333void PolicyRemove();
334void PolicyDelete(IN PSECURITY_POLICY pSecPolicy);
335BOOLEAN LoadSecurityPolicy(OUT PSECURITY_POLICY pSecPolicy, IN PWSTR PolicyFile, IN PWSTR FilePath);
336BOOLEAN FindAndLoadSecurityPolicy(OUT PSECURITY_POLICY pSecPolicy, IN PWSTR filename, IN PWSTR UserName);
337ACTION_TYPE PolicyCheck(RULE_TYPE RuleType, PCHAR Object, UCHAR OperationType, UCHAR *RuleNumber, PWSTR *PolicyFilename, USHORT *PolicyLineNumber);
338BOOLEAN PolicyParseObjectRule(PSECURITY_POLICY pSecPolicy, RULE_TYPE RuleType, PCHAR Operation, PCHAR rule);
339VOID InsertPolicyRule(PSECURITY_POLICY pSecPolicy, PPOLICY_RULE PolicyRule, RULE_TYPE RuleType);
340BOOLEAN PolicyPostBootup();
341int WildcardMatch(PCHAR path, PCHAR regex);
342
343
344#endif /* __POLICY_H__ */
diff --git a/port.c b/port.c
new file mode 100644
index 0000000..bd99908
--- /dev/null
+++ b/port.c
@@ -0,0 +1,318 @@
1/*
2 * Copyright (c) 2004 Security Architects Corporation. All rights reserved.
3 *
4 * Module Name:
5 *
6 * port.c
7 *
8 * Abstract:
9 *
10 * This module implements various port object hooking routines.
11 *
12 * Author:
13 *
14 * Eugene Tsyrklevich 25-Mar-2004
15 *
16 * Revision History:
17 *
18 * None.
19 */
20
21
22#include "port.h"
23
24
25#ifdef ALLOC_PRAGMA
26#pragma alloc_text (INIT, InitPortHooks)
27#endif
28
29
30fpZwCreatePort OriginalNtCreatePort = NULL;
31fpZwCreateWaitablePort OriginalNtCreateWaitablePort = NULL;
32
33fpZwConnectPort OriginalNtConnectPort = NULL;
34fpZwSecureConnectPort OriginalNtSecureConnectPort = NULL;
35
36
37/*
38 * HookedNtCreatePort()
39 *
40 * Description:
41 * This function mediates the NtCreatePort() system service and checks the
42 * provided port name against the global and current process security policies.
43 *
44 * NOTE: ZwCreatePort creates a port object. [NAR]
45 *
46 * Parameters:
47 * Those of NtCreatePort().
48 *
49 * Returns:
50 * STATUS_ACCESS_DENIED if the call does not pass the security policy check.
51 * Otherwise, NTSTATUS returned by NtCreatePort().
52 */
53
54NTSTATUS
55NTAPI
56HookedNtCreatePort
57(
58 OUT PHANDLE PortHandle,
59 IN POBJECT_ATTRIBUTES ObjectAttributes,
60 IN ULONG MaxDataSize,
61 IN ULONG MaxMessageSize,
62 IN ULONG Reserved
63)
64{
65 PCHAR FunctionName = "HookedNtCreatePort";
66
67
68 HOOK_ROUTINE_START_OPTYPE(PORT, OP_PORT_CREATE);
69
70
71 ASSERT(OriginalNtCreatePort);
72
73 rc = OriginalNtCreatePort(PortHandle, ObjectAttributes, MaxDataSize, MaxMessageSize, Reserved);
74
75
76 HOOK_ROUTINE_FINISH_OPTYPE(PORT, OP_PORT_CREATE);
77}
78
79
80
81/*
82 * HookedNtCreateWaitablePort()
83 *
84 * Description:
85 * This function mediates the NtCreateWaitablePort() system service and checks the
86 * provided port name against the global and current process security policies.
87 *
88 * NOTE: ZwCreateWaitablePort creates a waitable port object. [NAR]
89 *
90 * Parameters:
91 * Those of NtCreateWaitablePort().
92 *
93 * Returns:
94 * STATUS_ACCESS_DENIED if the call does not pass the security policy check.
95 * Otherwise, NTSTATUS returned by NtCreateWaitablePort().
96 */
97
98NTSTATUS
99NTAPI
100HookedNtCreateWaitablePort
101(
102 OUT PHANDLE PortHandle,
103 IN POBJECT_ATTRIBUTES ObjectAttributes,
104 IN ULONG MaxDataSize,
105 IN ULONG MaxMessageSize,
106 IN ULONG Reserved
107)
108{
109 PCHAR FunctionName = "HookedNtCreateWaitablePort";
110
111
112 HOOK_ROUTINE_START_OPTYPE(PORT, OP_PORT_CREATE);
113
114
115 ASSERT(OriginalNtCreateWaitablePort);
116
117 rc = OriginalNtCreateWaitablePort(PortHandle, ObjectAttributes, MaxDataSize, MaxMessageSize, Reserved);
118
119
120 HOOK_ROUTINE_FINISH_OPTYPE(PORT, OP_PORT_CREATE);
121}
122
123
124
125/*
126 * HookedNtConnectPort()
127 *
128 * Description:
129 * This function mediates the NtConnectPort() system service and checks the
130 * provided port name against the global and current process security policies.
131 *
132 * NOTE: ZwConnectPort creates a port connected to a named port. [NAR]
133 *
134 * Parameters:
135 * Those of NtConnectPort().
136 *
137 * Returns:
138 * STATUS_ACCESS_DENIED if the call does not pass the security policy check.
139 * Otherwise, NTSTATUS returned by NtConnectPort().
140 */
141
142NTSTATUS
143NTAPI
144HookedNtConnectPort
145(
146 OUT PHANDLE PortHandle,
147 IN PUNICODE_STRING PortName,
148 IN PSECURITY_QUALITY_OF_SERVICE SecurityQos,
149 IN OUT PPORT_SECTION_WRITE WriteSection OPTIONAL,
150 IN OUT PPORT_SECTION_READ ReadSection OPTIONAL,
151 OUT PULONG MaxMessageSize OPTIONAL,
152 IN OUT PVOID ConnectData OPTIONAL,
153 IN OUT PULONG ConnectDataLength OPTIONAL
154)
155{
156 PCHAR FunctionName = "HookedNtConnectPort";
157 UNICODE_STRING usInputPortName;
158 CHAR PORTNAME[MAX_PATH];
159 ANSI_STRING asPortName;
160
161
162 HOOK_ROUTINE_ENTER();
163
164
165 if (!VerifyUnicodeString(PortName, &usInputPortName))
166 {
167 LOG(LOG_SS_PORT, LOG_PRIORITY_DEBUG, ("HookedNtConnectPort: VerifyUnicodeString failed\n"));
168 HOOK_ROUTINE_EXIT( STATUS_ACCESS_DENIED );
169 }
170
171
172 if (_snprintf(PORTNAME, MAX_PATH, "%S", usInputPortName.Buffer) < 0)
173 {
174 LOG(LOG_SS_PORT, LOG_PRIORITY_DEBUG, ("%s: Port name '%S' is too long\n", FunctionName, usInputPortName.Buffer));
175 HOOK_ROUTINE_EXIT( STATUS_ACCESS_DENIED );
176 }
177
178
179 if (LearningMode == FALSE)
180 {
181 POLICY_CHECK_OPTYPE_NAME(PORT, OP_PORT_CONNECT);
182 }
183
184
185 ASSERT(OriginalNtConnectPort);
186
187 rc = OriginalNtConnectPort(PortHandle, PortName, SecurityQos, WriteSection, ReadSection, MaxMessageSize,
188 ConnectData, ConnectDataLength);
189
190
191 HOOK_ROUTINE_FINISH_OBJECTNAME_OPTYPE(PORT, PORTNAME, OP_PORT_CONNECT);
192}
193
194
195
196/*
197 * HookedNtSecureConnectPort()
198 *
199 * Description:
200 * This function mediates the NtSecureConnectPort() system service and checks the
201 * provided port name against the global and current process security policies.
202 *
203 * NOTE: ZwSecureConnectPort creates a port connected to a named port. [NAR]
204 *
205 * Parameters:
206 * Those of NtSecureConnectPort().
207 *
208 * Returns:
209 * STATUS_ACCESS_DENIED if the call does not pass the security policy check.
210 * Otherwise, NTSTATUS returned by NtSecureConnectPort().
211 */
212
213NTSTATUS
214NTAPI
215HookedNtSecureConnectPort
216(
217 OUT PHANDLE PortHandle,
218 IN PUNICODE_STRING PortName,
219 IN PSECURITY_QUALITY_OF_SERVICE SecurityQos,
220 IN OUT PPORT_SECTION_WRITE WriteSection OPTIONAL,
221 IN PSID ServerSid OPTIONAL,
222 IN OUT PPORT_SECTION_READ ReadSection OPTIONAL,
223 OUT PULONG MaxMessageSize OPTIONAL,
224 IN OUT PVOID ConnectData OPTIONAL,
225 IN OUT PULONG ConnectDataLength OPTIONAL
226)
227{
228 PCHAR FunctionName = "HookedNtSecureConnectPort";
229 UNICODE_STRING usInputPortName;
230 CHAR PORTNAME[MAX_PATH];
231 ANSI_STRING asPortName;
232
233
234 HOOK_ROUTINE_ENTER();
235
236
237 if (!VerifyUnicodeString(PortName, &usInputPortName))
238 {
239 LOG(LOG_SS_PORT, LOG_PRIORITY_DEBUG, ("HookedNtSecureConnectPort: VerifyUnicodeString failed\n"));
240 HOOK_ROUTINE_EXIT( STATUS_ACCESS_DENIED );
241 }
242
243
244 asPortName.Length = 0;
245 asPortName.MaximumLength = MAX_PATH - 1;
246 asPortName.Buffer = PORTNAME;
247
248 if (! NT_SUCCESS(RtlUnicodeStringToAnsiString(&asPortName, &usInputPortName, FALSE)))
249 {
250 LOG(LOG_SS_PORT, LOG_PRIORITY_DEBUG, ("HookedNtSecureConnectPort: RtlUnicodeStringToAnsiString failed\n"));
251 HOOK_ROUTINE_EXIT( STATUS_ACCESS_DENIED );
252 }
253
254 PORTNAME[asPortName.Length] = 0;
255
256
257 if (LearningMode == FALSE)
258 {
259 POLICY_CHECK_OPTYPE_NAME(PORT, OP_PORT_CONNECT);
260 }
261
262
263 ASSERT(OriginalNtSecureConnectPort);
264
265 rc = OriginalNtSecureConnectPort(PortHandle, PortName, SecurityQos, WriteSection, ServerSid, ReadSection,
266 MaxMessageSize, ConnectData, ConnectDataLength);
267
268
269 HOOK_ROUTINE_FINISH_OBJECTNAME_OPTYPE(PORT, PORTNAME, OP_PORT_CONNECT);
270}
271
272
273
274/*
275 * InitPortHooks()
276 *
277 * Description:
278 * Initializes all the mediated port operation pointers. The "OriginalFunction" pointers
279 * are initialized by InstallSyscallsHooks() that must be called prior to this function.
280 *
281 * NOTE: Called once during driver initialization (DriverEntry()).
282 *
283 * Parameters:
284 * None.
285 *
286 * Returns:
287 * TRUE to indicate success, FALSE if failed.
288 */
289
290BOOLEAN
291InitPortHooks()
292{
293 if ( (OriginalNtCreatePort = (fpZwCreatePort) ZwCalls[ZW_CREATE_PORT_INDEX].OriginalFunction) == NULL)
294 {
295 LOG(LOG_SS_PORT, LOG_PRIORITY_DEBUG, ("InitPortHooks: OriginalNtCreatePort is NULL\n"));
296 return FALSE;
297 }
298
299 if ( (OriginalNtCreateWaitablePort = (fpZwCreateWaitablePort) ZwCalls[ZW_CREATE_WAITPORT_INDEX].OriginalFunction) == NULL)
300 {
301 LOG(LOG_SS_PORT, LOG_PRIORITY_DEBUG, ("InitPortHooks: OriginalNtCreateWaitablePort is NULL\n"));
302 return FALSE;
303 }
304
305 if ( (OriginalNtConnectPort = (fpZwConnectPort) ZwCalls[ZW_CONNECT_PORT_INDEX].OriginalFunction) == NULL)
306 {
307 LOG(LOG_SS_PORT, LOG_PRIORITY_DEBUG, ("InitPortHooks: OriginalNtConnectPort is NULL\n"));
308 return FALSE;
309 }
310
311 if ( (OriginalNtSecureConnectPort = (fpZwSecureConnectPort) ZwCalls[ZW_SECURECONNECT_PORT_INDEX].OriginalFunction) == NULL)
312 {
313 LOG(LOG_SS_PORT, LOG_PRIORITY_DEBUG, ("InitPortHooks: OriginalNtSecureConnectPort is NULL\n"));
314 return FALSE;
315 }
316
317 return TRUE;
318}
diff --git a/port.h b/port.h
new file mode 100644
index 0000000..dfa5747
--- /dev/null
+++ b/port.h
@@ -0,0 +1,162 @@
1/*
2 * Copyright (c) 2004 Security Architects Corporation. All rights reserved.
3 *
4 * Module Name:
5 *
6 * port.h
7 *
8 * Abstract:
9 *
10 * This module defines various types used by port object hooking routines.
11 *
12 * Author:
13 *
14 * Eugene Tsyrklevich 25-Mar-2004
15 *
16 * Revision History:
17 *
18 * None.
19 */
20
21
22#ifndef __PORT_H__
23#define __PORT_H__
24
25
26#include <NTDDK.h>
27#include "policy.h"
28#include "pathproc.h"
29#include "hookproc.h"
30#include "accessmask.h"
31#include "learn.h"
32#include "log.h"
33
34
35/*
36 * ZwCreatePort creates a port object. [NAR]
37 */
38
39typedef NTSTATUS (*fpZwCreatePort) (
40 OUT PHANDLE PortHandle,
41 IN POBJECT_ATTRIBUTES ObjectAttributes,
42 IN ULONG MaxDataSize,
43 IN ULONG MaxMessageSize,
44 IN ULONG Reserved
45 );
46
47NTSTATUS
48NTAPI
49HookedNtCreatePort(
50 OUT PHANDLE PortHandle,
51 IN POBJECT_ATTRIBUTES ObjectAttributes,
52 IN ULONG MaxDataSize,
53 IN ULONG MaxMessageSize,
54 IN ULONG Reserved
55 );
56
57
58/*
59 * ZwCreateWaitablePort creates a waitable port object. [NAR]
60 */
61
62typedef NTSTATUS (*fpZwCreateWaitablePort) (
63 OUT PHANDLE PortHandle,
64 IN POBJECT_ATTRIBUTES ObjectAttributes,
65 IN ULONG MaxDataSize,
66 IN ULONG MaxMessageSize,
67 IN ULONG Reserved
68 );
69
70NTSTATUS
71NTAPI
72HookedNtCreateWaitablePort(
73 OUT PHANDLE PortHandle,
74 IN POBJECT_ATTRIBUTES ObjectAttributes,
75 IN ULONG MaxDataSize,
76 IN ULONG MaxMessageSize,
77 IN ULONG Reserved
78 );
79
80
81
82typedef struct _PORT_SECTION_READ {
83 ULONG Length;
84 ULONG ViewSize;
85 ULONG ViewBase;
86} PORT_SECTION_READ, *PPORT_SECTION_READ;
87
88typedef struct _PORT_SECTION_WRITE {
89 ULONG Length;
90 HANDLE SectionHandle;
91 ULONG SectionOffset;
92 ULONG ViewSize;
93 PVOID ViewBase;
94 PVOID TargetViewBase;
95} PORT_SECTION_WRITE, *PPORT_SECTION_WRITE;
96
97
98/*
99 * ZwConnectPort creates a port connected to a named port. [NAR]
100 */
101
102typedef NTSTATUS (*fpZwConnectPort) (
103 OUT PHANDLE PortHandle,
104 IN PUNICODE_STRING PortName,
105 IN PSECURITY_QUALITY_OF_SERVICE SecurityQos,
106 IN OUT PPORT_SECTION_WRITE WriteSection OPTIONAL,
107 IN OUT PPORT_SECTION_READ ReadSection OPTIONAL,
108 OUT PULONG MaxMessageSize OPTIONAL,
109 IN OUT PVOID ConnectData OPTIONAL,
110 IN OUT PULONG ConnectDataLength OPTIONAL
111 );
112
113NTSTATUS
114NTAPI
115HookedNtConnectPort(
116 OUT PHANDLE PortHandle,
117 IN PUNICODE_STRING PortName,
118 IN PSECURITY_QUALITY_OF_SERVICE SecurityQos,
119 IN OUT PPORT_SECTION_WRITE WriteSection OPTIONAL,
120 IN OUT PPORT_SECTION_READ ReadSection OPTIONAL,
121 OUT PULONG MaxMessageSize OPTIONAL,
122 IN OUT PVOID ConnectData OPTIONAL,
123 IN OUT PULONG ConnectDataLength OPTIONAL
124 );
125
126
127/*
128 * ZwSecureConnectPort creates a port connected to a named port. [NAR]
129 */
130
131typedef NTSTATUS (*fpZwSecureConnectPort) (
132 OUT PHANDLE PortHandle,
133 IN PUNICODE_STRING PortName,
134 IN PSECURITY_QUALITY_OF_SERVICE SecurityQos,
135 IN OUT PPORT_SECTION_WRITE WriteSection OPTIONAL,
136 IN PSID ServerSid OPTIONAL,
137 IN OUT PPORT_SECTION_READ ReadSection OPTIONAL,
138 OUT PULONG MaxMessageSize OPTIONAL,
139 IN OUT PVOID ConnectData OPTIONAL,
140 IN OUT PULONG ConnectDataLength OPTIONAL
141 );
142
143NTSTATUS
144NTAPI
145HookedNtSecureConnectPort(
146 OUT PHANDLE PortHandle,
147 IN PUNICODE_STRING PortName,
148 IN PSECURITY_QUALITY_OF_SERVICE SecurityQos,
149 IN OUT PPORT_SECTION_WRITE WriteSection OPTIONAL,
150 IN PSID ServerSid OPTIONAL,
151 IN OUT PPORT_SECTION_READ ReadSection OPTIONAL,
152 OUT PULONG MaxMessageSize OPTIONAL,
153 IN OUT PVOID ConnectData OPTIONAL,
154 IN OUT PULONG ConnectDataLength OPTIONAL
155 );
156
157
158
159BOOLEAN InitPortHooks();
160
161
162#endif /* __PORT_H__ */
diff --git a/process.c b/process.c
new file mode 100644
index 0000000..c83603f
--- /dev/null
+++ b/process.c
@@ -0,0 +1,1270 @@
1/*
2 * Copyright (c) 2004 Security Architects Corporation. All rights reserved.
3 *
4 * Module Name:
5 *
6 * process.c
7 *
8 * Abstract:
9 *
10 * This module defines various types used by process and thread hooking routines.
11 *
12 * Author:
13 *
14 * Eugene Tsyrklevich 23-Feb-2004
15 *
16 * Revision History:
17 *
18 * None.
19 */
20
21
22#include <NTDDK.h>
23#include "process.h"
24#include "driver.h"
25#include "policy.h"
26#include "hookproc.h"
27#include "userland.h"
28#include "procname.h"
29#include "accessmask.h"
30#include "learn.h"
31#include "misc.h"
32#include "i386.h"
33#include "log.h"
34
35
36#ifdef ALLOC_PRAGMA
37#pragma alloc_text (INIT, InitProcessEntries)
38#pragma alloc_text (PAGE, ProcessPostBootup)
39#endif
40
41
42fpZwCreateProcess OriginalNtCreateProcess = NULL;
43fpZwCreateProcessEx OriginalNtCreateProcessEx = NULL;
44fpZwOpenProcess OriginalNtOpenProcess = NULL;
45
46fpZwCreateThread OriginalNtCreateThread = NULL;
47fpZwOpenThread OriginalNtOpenThread = NULL;
48
49
50BOOLEAN AllowProcessesWithPoliciesOnly = FALSE;
51
52WCHAR OzoneInstallPath[MAX_PATH];
53USHORT OzoneInstallPathSize = 0;
54
55
56/* XXX this will not work on 64-bit architectures, due to assumption of size of ulong, pointers, etc */
57typedef struct _CONTROL_AREA { // must be quadword sized.
58 ULONG data[9];
59 PFILE_OBJECT FilePointer;
60} CONTROL_AREA, *PCONTROL_AREA;
61
62typedef struct _SEGMENT {
63 struct _CONTROL_AREA *ControlArea;
64} SEGMENT, *PSEGMENT;
65
66typedef struct _SECTION {
67 ULONG_PTR data[5];
68 PSEGMENT Segment;
69} SECTION, *PSECTION;
70
71
72
73/*
74 * rand()
75 *
76 * Description:
77 * Returns a random number that is calculated by XOR'ing together often changing system values.
78 *
79 * Parameters:
80 * randval - An optional random value.
81 *
82 * Returns:
83 * A random ULONG value.
84 */
85
86ULONG
87rand(ULONG randval)
88{
89 LARGE_INTEGER perf, TickCount;
90 ULONG r;
91
92
93 KeQueryPerformanceCounter(&perf);
94// KdPrint(("perf: %d %d\n", perf.LowPart, perf.HighPart));
95
96 KeQueryTickCount(&TickCount);
97// KdPrint(("tick: %d %d\n", TickCount.LowPart, TickCount.HighPart));
98
99// KdPrint(("int: %I64d\n", KeQueryInterruptTime()));
100
101 r = randval ^
102 perf.LowPart ^ perf.HighPart ^
103 TickCount.HighPart ^ TickCount.LowPart ^
104 (ULONG) KeQueryInterruptTime();
105
106// KdPrint(("rand = %x\n", r));
107
108
109 return r;
110}
111
112
113
114/*
115 * PostProcessNtCreateProcess()
116 *
117 * Description:
118 * This function is called by the mediated NtCreateProcess() system service.
119 * It is responsible for saving the information about the newly created process in a
120 * global process hash table.
121 *
122 * Parameters:
123 * ProcessHandle - process object handle initialized by NtCreateProcess().
124 * SectionHandle - specifies a handle to an image section that grants SECTION_MAP_EXECUTE
125 * access. If this value is zero, the new process inherits the address space from the process
126 * referred to by InheritFromProcessHandle. In Windows 2000 the lowest bit specifies
127 * (when set) that the process should not be associated with the job of the
128 * InheritFromProcessHandle process.
129 *
130 * Returns:
131 * ULONG indicating an action to take (ACTION_DENY to disallow process createion, ACTION_PERMIT to allow).
132 */
133
134ULONG
135PostProcessNtCreateProcess(PHANDLE ProcessHandle, HANDLE SectionHandle)
136{
137 NTSTATUS status, rc;
138 PIMAGE_PID_ENTRY p, prev, NewProcess;
139 ULONG ProcessId, Size;
140 PULONG_PTR Base;
141 UNICODE_STRING usPath;
142 ANSI_STRING asPath;
143 KIRQL irql;
144 PROCESS_BASIC_INFORMATION ProcessBasicInfo;
145 CHAR ProcessPathUnresolved[MAX_PATH];
146 CHAR PROCESSNAME[MAX_PATH];
147 PCHAR FunctionName = "PostProcessNtCreateProcess";
148
149
150 if (ProcessHandle == NULL)
151 {
152 LOG(LOG_SS_PROCESS, LOG_PRIORITY_WARNING, ("%s: ProcessHandle is NULL\n", FunctionName));
153 return ACTION_NONE;
154 }
155
156
157 /*
158 * Try to retrieve the image name from a section object
159 */
160
161 if (!SectionHandle)
162 {
163 LOG(LOG_SS_PROCESS, LOG_PRIORITY_WARNING, ("%s: SectionHandle is NULL\n", FunctionName));
164 return ACTION_NONE;
165 }
166
167
168 do
169 {
170 PSECTION SectionToMap;
171 PSEGMENT seg;
172 PCONTROL_AREA pca;
173 PFILE_OBJECT pfo;
174
175
176 status = ObReferenceObjectByHandle(
177 SectionHandle,
178 0,
179 0,
180 KernelMode,
181 (PSECTION *) &SectionToMap,
182 NULL
183 );
184
185/* macro shortcut for bailing out of PostProcessNtCreateProcess do {} while loop in case of an error */
186
187#define ABORT_PostProcessNtCreateProcess(msg) \
188 { \
189 LOG(LOG_SS_PROCESS, LOG_PRIORITY_DEBUG, ("Error occurred in %s:", FunctionName)); \
190 LOG(LOG_SS_PROCESS, LOG_PRIORITY_DEBUG, (msg)); \
191 return ACTION_NONE; /* XXX */ \
192 }
193
194 if (! NT_SUCCESS(status))
195
196 ABORT_PostProcessNtCreateProcess(("ObReferenceObjectByHandle(SectionHandle) failed"));
197
198
199 if (SectionToMap == NULL)
200
201 ABORT_PostProcessNtCreateProcess(("SectionToMap is NULL"));
202
203
204 if ( (seg = ((PSECTION)SectionToMap)->Segment) == NULL)
205
206 ABORT_PostProcessNtCreateProcess(("Segment is NULL"));
207
208 if ( (pca = seg->ControlArea) == NULL)
209
210 ABORT_PostProcessNtCreateProcess(("ControlArea is NULL"));
211
212
213 if ( (pfo = pca->FilePointer) == NULL)
214
215 ABORT_PostProcessNtCreateProcess(("FilePointer is NULL"));
216
217
218 usPath = pfo->FileName;
219
220 if (usPath.Length == 0)
221
222 ABORT_PostProcessNtCreateProcess(("FileName length is 0"));
223
224
225 _snprintf(ProcessPathUnresolved, MAX_PATH, "%S", usPath.Buffer);
226 ProcessPathUnresolved[MAX_PATH - 1] = 0;
227
228
229 ObDereferenceObject(SectionToMap);
230
231 } while (0);
232
233
234 /*
235 * Now verify the executable name against the security policy
236 */
237
238 VerifyExecutableName(ProcessPathUnresolved);
239
240
241 if (LearningMode == FALSE)
242 {
243 ACTION_TYPE Action;
244
245
246 VerifyUserReturnAddress();
247
248
249 FixupFilename(ProcessPathUnresolved, PROCESSNAME, MAX_PATH);
250
251
252 /*
253 * We manually inc/dec HookedRoutineRunning since POLICY_CHECK_OPTYPE_NAME() can call
254 * HOOK_ROUTINE_EXIT() which will decrement HookedRoutineRunning and then it will get
255 * decremented the second time in HookedNtCreateProcess()
256 */
257
258#if DBG
259 InterlockedIncrement(&HookedRoutineRunning);
260#endif
261
262 POLICY_CHECK_OPTYPE_NAME(PROCESS, OP_PROC_EXECUTE);
263
264#if DBG
265 InterlockedDecrement(&HookedRoutineRunning);
266#endif
267 }
268 else
269 {
270 // learning mode
271 AddRule(RULE_PROCESS, ProcessPathUnresolved, OP_PROC_EXECUTE);
272 }
273
274
275 /*
276 * retrieve the Process ID
277 */
278
279 status = ZwQueryInformationProcess(*ProcessHandle, ProcessBasicInformation, &ProcessBasicInfo, sizeof(ProcessBasicInfo), &Size);
280
281 if (! NT_SUCCESS(status))
282 {
283 LOG(LOG_SS_PROCESS, LOG_PRIORITY_DEBUG, ("PostProcessNtCreateProcess: ZwQueryInformationProcess failed with status %x\n", status));
284 return ACTION_NONE;
285 }
286
287 ProcessId = ProcessBasicInfo.UniqueProcessId;
288
289 /*
290 * On win2k ProcessId is not available at this stage yet.
291 * ProcessId of 0 will get replaced by a real value in CreateProcessNotifyProc.
292 */
293
294
295 /* once winlogon.exe executes, we consider the boot process to be complete */
296 if (BootingUp == TRUE)
297 {
298 PCHAR ProcessName;
299
300
301 ProcessName = strrchr(ProcessPathUnresolved, '\\');
302
303 if (ProcessName == NULL)
304 ProcessName = ProcessPathUnresolved;
305 else
306 ++ProcessName; /* skip past the slash */
307
308 if (_strnicmp(ProcessName, "winlogon.exe", 12) == 0)
309 {
310 BootingUp = FALSE;
311 InitPostBootup();
312 }
313 }
314
315
316 /*
317 * Now create a new process entry and load the associated security policy (if any)
318 */
319
320 NewProcess = CreateNewProcessEntry(ProcessId, CURRENT_PROCESS_PID, &usPath, TRUE);
321
322
323 if (ProcessInsertImagePidEntry(ProcessId, NewProcess) == FALSE)
324 {
325 ExFreePoolWithTag(NewProcess, _POOL_TAG);
326
327 return ACTION_NONE;
328 }
329
330
331 /*
332 * Now find and load appropriate security policy.
333 *
334 * Look for a per-user policy first. To do that, we send an SID resolve request
335 * to userland Ozone Agent Service.
336 */
337
338 if (LearningMode == FALSE)
339 {
340 PSID_RESOLVE_REPLY pSidResolveReply = NULL;
341 PWSTR UserName = NULL;
342
343
344 if (IssueUserlandSidResolveRequest(NewProcess) != FALSE)
345 {
346 if (NewProcess->UserlandReply)
347 {
348 pSidResolveReply = (PSID_RESOLVE_REPLY) NewProcess->UserlandReply;
349
350 if (pSidResolveReply->UserNameLength)
351 {
352 LOG(LOG_SS_PROCESS, LOG_PRIORITY_DEBUG, ("PostProcessNtCreateProcess: SID resolved to %S\n", pSidResolveReply->UserName));
353 UserName = pSidResolveReply->UserName;
354 }
355 else
356 {
357 LOG(LOG_SS_PROCESS, LOG_PRIORITY_DEBUG, ("PostProcessNtCreateProcess(): SID resolve error\n"));
358 }
359 }
360 }
361
362
363 if (! FindAndLoadSecurityPolicy(&NewProcess->SecPolicy, usPath.Buffer, UserName))
364 {
365 LOG(LOG_SS_PROCESS, LOG_PRIORITY_WARNING, ("%d PostProcessNtCreateProcess(): no policy, %d, %S\n", CURRENT_PROCESS_PID, ProcessId, usPath.Buffer));
366
367 //XXX have an option where only processes with existing policies (even if they are empty.. policy_default: allow) are allowed to run
368 //interactive session is excluded?!?!
369 if (AllowProcessesWithPoliciesOnly == TRUE)
370 {
371 ExFreePoolWithTag(NewProcess, _POOL_TAG);
372 return ACTION_DENY;
373 }
374 }
375 else
376 {
377 LOG(LOG_SS_PROCESS, LOG_PRIORITY_WARNING, ("%d PostProcessNtCreateProcess(): with policy, %d, %S\n", CURRENT_PROCESS_PID, ProcessId, usPath.Buffer));
378 }
379
380
381 if (NewProcess->UserlandReply)
382 {
383 ExFreePoolWithTag(NewProcess->UserlandReply, _POOL_TAG);
384 NewProcess->UserlandReply = NULL;
385 }
386 }
387
388
389 /*
390 * Stack Buffer Overflow Protection (Part 1).
391 *
392 * 1. Allocate/reserve a random (< 0x4000000) chunk of virtual memory starting at 0xFFFF.
393 * This causes the stack of the main thread to be moved by a random amount.
394 *
395 * (note1: first 64K of memory are allocated as a guard against NULL pointers dereferencing).
396 * (note2: main() is mapped at 0x4000000 and thus we cannot allocate anything that will cause the
397 * stack of the main thread to move past the 0x400000 boundary).
398 *
399 *
400 * Stack Buffer Overflow Protection (Part 2).
401 *
402 * 2. Allocate a random (> 4 Megs && < 10 Megs) chunk of virtual memory after the process code segment.
403 * This causes the heap and stacks non-main threads to be moved by a random amount.
404 *
405 * (note: as mentioned above, main() is mapped at 0x4000000, by reserving a large chunk of virtual
406 * we force Windows to find the first available address beyond the code segment and reserve
407 * a random amount of memory past it causing other thread stacks and heaps to shift).
408 */
409
410#define ONE_MEGABYTE (1024 * 1024)
411
412 if (IS_OVERFLOW_PROTECTION_ON(gSecPolicy) && IS_OVERFLOW_PROTECTION_ON(NewProcess->SecPolicy) && LearningMode == FALSE && BootingUp == FALSE)
413 {
414//XXX verify that the image entry is actually at 4 meg (not true for most of system processes)
415
416 /*
417 * allocate up to 3 megs of virtual address space before the code segment,
418 * this affects main thread stack as well as some heaps
419 */
420
421#define FIRST_AVAILABLE_ADDRESS 0xFFFF
422
423 Size = PAGE_SIZE + (rand(ProcessId) % (3 * ONE_MEGABYTE));
424 Base = (PULONG_PTR) FIRST_AVAILABLE_ADDRESS;
425
426 status = ZwAllocateVirtualMemory(*ProcessHandle, &Base, 0L, &Size, MEM_RESERVE, PAGE_NOACCESS);
427
428 if (! NT_SUCCESS(status))
429 LOG(LOG_SS_PROCESS, LOG_PRIORITY_DEBUG, ("PostProcessNtCreateProcess: ZwAllocateVirtualMemory1(%x, %x) failed with status %x\n", Base, Size, status));
430 else
431 LOG(LOG_SS_PROCESS, LOG_PRIORITY_VERBOSE, ("PostProcessNtCreateProcess: size=%u base=%x status=%d\n", Size, Base, status));
432
433 /*
434 * allocate up to 10 megs of virtual address space after the code segment,
435 * this affects non-main thread stack as well as some heaps
436 */
437
438#define IMAGE_BASE (4 * ONE_MEGABYTE)
439
440 Size = IMAGE_BASE + (rand(ProcessId) % (10 * ONE_MEGABYTE));
441 Base = (PULONG_PTR) NULL;
442
443 status = ZwAllocateVirtualMemory(*ProcessHandle, &Base, 0L, &Size, MEM_RESERVE, PAGE_NOACCESS);
444
445 LOG(LOG_SS_PROCESS, LOG_PRIORITY_VERBOSE, ("PostProcessNtCreateProcess: size=%u base=%x status=%d\n", Size, Base, status));
446
447 if (! NT_SUCCESS(status))
448 LOG(LOG_SS_PROCESS, LOG_PRIORITY_DEBUG, ("PostProcessNtCreateProcess: ZwAllocateVirtualMemory2(%x, %x) failed with status %x\n", Base, Size, status));
449
450
451
452 /*
453 * allocate the entire KnownDll space
454 */
455//#if 0
456// Size = (4 * ONE_MEGABYTE) + (rand(ProcessId) % (100 * ONE_MEGABYTE));
457// Base = (PULONG_PTR) 0x71bf0000;
458
459// Size = 0x7000000;//(125 * ONE_MEGABYTE);
460// Base = (PULONG_PTR) 0x70000000;
461
462#if HOOK_BOPROT
463 if (strstr(ProcessPathUnresolved, "stack.exe") != NULL)
464 {
465 Size = PAGE_SIZE;
466 // Base = (PULONG_PTR) 0x77d00000; //user32
467 Base = (PULONG_PTR) 0x77e30000; //kernel32 on win2k3
468// Base = (PULONG_PTR) 0x77e80000; //kernel32 on win2k
469
470 status = ZwAllocateVirtualMemory(*ProcessHandle, &Base, 0L, &Size, MEM_RESERVE, PAGE_NOACCESS);
471
472 LOG(LOG_SS_PROCESS, LOG_PRIORITY_DEBUG, ("PostProcessNtCreateProcess: kernel32.dll size=%u base=%x status=%d\n", Size, Base, status));
473
474 if (! NT_SUCCESS(status))
475 LOG(LOG_SS_PROCESS, LOG_PRIORITY_DEBUG, ("PostProcessNtCreateProcess: ZwAllocateVirtualMemory1(%x, %x) failed with status %x\n", Base, Size, status));
476 }
477 else
478 NewProcess->FirstThread = FALSE;//XXX remove
479#endif
480 }
481
482
483 return ACTION_PERMIT;
484}
485
486
487
488/*
489 * HookedNtCreateProcess()
490 *
491 * Description:
492 * This function mediates the NtCreateProcess() system service in order to keep track of all
493 * the newly created processes.
494 *
495 * NOTE: ZwCreateProcess creates a process object. [NAR]
496 *
497 * Parameters:
498 * Those of NtCreateProcess().
499 *
500 * Returns:
501 * NTSTATUS returned by NtCreateProcess().
502 */
503
504NTSTATUS
505NTAPI
506HookedNtCreateProcess
507(
508 OUT PHANDLE ProcessHandle,
509 IN ACCESS_MASK DesiredAccess,
510 IN POBJECT_ATTRIBUTES ObjectAttributes,
511 IN HANDLE InheritFromProcessHandle,
512 IN BOOLEAN InheritHandles,
513 IN HANDLE SectionHandle OPTIONAL,
514 IN HANDLE DebugPort OPTIONAL,
515 IN HANDLE ExceptionPort OPTIONAL
516)
517{
518 HOOK_ROUTINE_ENTER();
519
520
521 ASSERT(OriginalNtCreateProcess);
522
523 rc = OriginalNtCreateProcess(ProcessHandle, DesiredAccess, ObjectAttributes, InheritFromProcessHandle,
524 InheritHandles, SectionHandle, DebugPort, ExceptionPort);
525
526
527 if (NT_SUCCESS(rc))
528 {
529 ULONG ret = PostProcessNtCreateProcess(ProcessHandle, SectionHandle);
530
531 if (ret == ACTION_DENY || ret == STATUS_ACCESS_DENIED)
532 {
533 ZwClose(*ProcessHandle);
534 rc = STATUS_ACCESS_DENIED;
535 }
536 }
537
538
539 HOOK_ROUTINE_EXIT(rc);
540}
541
542
543
544/*
545 * HookedNtCreateProcessEx()
546 *
547 * Description:
548 * This function mediates the NtCreateProcessEx() system service in order to keep track of all
549 * the newly created processes.
550 *
551 * NOTE: ZwCreateProcessEx creates a process object. [NAR]
552 *
553 * Parameters:
554 * Those of NtCreateProcessEx().
555 *
556 * Returns:
557 * NTSTATUS returned by NtCreateProcessEx().
558 */
559
560NTSTATUS
561NTAPI
562HookedNtCreateProcessEx
563(
564 OUT PHANDLE ProcessHandle,
565 IN ACCESS_MASK DesiredAccess,
566 IN POBJECT_ATTRIBUTES ObjectAttributes,
567 IN HANDLE InheritFromProcessHandle,
568 IN ULONG Unknown1,
569 IN HANDLE SectionHandle OPTIONAL,
570 IN HANDLE DebugPort OPTIONAL,
571 IN HANDLE ExceptionPort OPTIONAL,
572 IN ULONG Unknown2
573)
574{
575 HOOK_ROUTINE_ENTER();
576
577
578 ASSERT(OriginalNtCreateProcessEx);
579
580 rc = OriginalNtCreateProcessEx(ProcessHandle, DesiredAccess, ObjectAttributes, InheritFromProcessHandle,
581 Unknown1, SectionHandle, DebugPort, ExceptionPort, Unknown2);
582
583
584 if (NT_SUCCESS(rc))
585 {
586 ULONG ret = PostProcessNtCreateProcess(ProcessHandle, SectionHandle);
587
588 if (ret == ACTION_DENY || ret == STATUS_ACCESS_DENIED)
589 {
590 ZwClose(*ProcessHandle);
591 rc = STATUS_ACCESS_DENIED;
592 }
593 }
594
595
596 HOOK_ROUTINE_EXIT(rc);
597}
598
599
600
601/*
602 * HookedNtOpenProcess()
603 *
604 * Description:
605 * This function mediates the NtOpenProcess() system service and disallows certain operations such as
606 * PROCESS_VM_WRITE and PROCESS_CREATE_THREAD.
607 *
608 * NOTE: ZwOpenProcess opens a process object. [NAR]
609 *
610 * Parameters:
611 * Those of NtOpenProcess().
612 *
613 * Returns:
614 * NTSTATUS returned by NtOpenProcess().
615 */
616
617NTSTATUS
618NTAPI
619HookedNtOpenProcess
620(
621 OUT PHANDLE ProcessHandle,
622 IN ACCESS_MASK DesiredAccess,
623 IN POBJECT_ATTRIBUTES ObjectAttributes,
624 IN PCLIENT_ID ClientId OPTIONAL
625)
626{
627 PCHAR FunctionName = "HookedNtOpenProcess";
628 CHAR PROCESSNAME[MAX_PATH];
629
630
631//taskmgr uses PROCESS_TERMINATE to kill processes
632//XXX IPD disallows PROCESS_CREATE_THREAD|PROCESS_VM_WRITE
633
634/*
635PROCESS_TERMINATE Terminate process
636PROCESS_CREATE_THREAD Create threads in process
637PROCESS_SET_SESSIONID Set process session id
638PROCESS_VM_OPERATION Protect and lock memory of process
639PROCESS_VM_READ Read memory of process
640PROCESS_VM_WRITE Write memory of process
641PROCESS_DUP_HANDLE Duplicate handles of process
642PROCESS_CREATE_PROCESS Bequeath address space and handles to new process
643PROCESS_SET_QUOTA Set process quotas
644PROCESS_SET_INFORMATION Set information about process
645PROCESS_QUERY_INFORMATION Query information about process
646PROCESS_SET_PORT Set process exception or debug port
647PROCESS_ALL_ACCESS All of the preceding
648
649find out who uses which flags, i.e. VM_READ, etc.. filter out accordingly
650*/
651
652 HOOK_ROUTINE_ENTER();
653
654
655// if (! IS_BIT_SET(DesiredAccess, PROCESS_QUERY_INFORMATION) &&
656// ! IS_BIT_SET(DesiredAccess, PROCESS_DUP_HANDLE) &&
657// ! IS_BIT_SET(DesiredAccess, SYNCHRONIZE) )
658
659
660 if (! ARGUMENT_PRESENT(ClientId) || KeGetPreviousMode() != UserMode || KeGetCurrentIrql() != PASSIVE_LEVEL)
661 goto done;
662
663
664 __try
665 {
666 ProbeForRead(ClientId, sizeof(*ClientId), sizeof(PULONG_PTR));
667 }
668
669 __except(EXCEPTION_EXECUTE_HANDLER)
670 {
671 NTSTATUS status = GetExceptionCode();
672
673 LOG(LOG_SS_MISC, LOG_PRIORITY_DEBUG, ("%s: caught an exception. address=%x, status = 0x%x\n", FunctionName, ClientId, status));
674
675 goto done;
676 }
677
678
679 if (PsGetCurrentProcessId() != ClientId->UniqueProcess &&
680 (ULONG) PsGetCurrentProcessId() != SystemProcessId &&
681 ClientId->UniqueProcess != 0)
682 {
683 PIMAGE_PID_ENTRY p;
684
685 /* can't access ClientId (pageable memory) while holding spinlonk */
686 ULONG RequestedProcessId = (ULONG) ClientId->UniqueProcess;
687
688
689 //XXX
690/*
691 if (RequestedProcessId == UserAgentServicePid)
692 {
693 LOG(LOG_SS_PROCESS, LOG_PRIORITY_VERBOSE, ("%s: FindImagePidEntry(%d) UserAgent %x\n", FunctionName, RequestedProcessId, DesiredAccess));
694
695 if (IS_BIT_SET(DesiredAccess, PROCESS_TERMINATE))
696 {
697 HOOK_ROUTINE_EXIT( STATUS_ACCESS_DENIED );
698 }
699 }
700*/
701
702
703 p = FindImagePidEntry(RequestedProcessId, 0);
704
705 if (p == NULL)
706 {
707 LOG(LOG_SS_PROCESS, LOG_PRIORITY_DEBUG, ("%d %s: FindImagePidEntry(%d) failed\n", CURRENT_PROCESS_PID, FunctionName, RequestedProcessId));
708 goto done;
709 }
710
711/*
712 if (DesiredAccess & PROCESS_CREATE_THREAD)
713 {
714 LOG(LOG_SS_PROCESS, LOG_PRIORITY_DEBUG, ("%d %s(%d): %x (PROCESS_CREATE_THREAD). (%S)\n", CURRENT_PROCESS_PID, FunctionName, RequestedProcessId, DesiredAccess, p->ImageName));
715 }
716 else if (DesiredAccess & PROCESS_VM_WRITE)
717 {
718 LOG(LOG_SS_PROCESS, LOG_PRIORITY_DEBUG, ("%d %s(%d): %x (PROCESS_VM_WRITE). (%S)\n", CURRENT_PROCESS_PID, FunctionName, RequestedProcessId, DesiredAccess, p->ImageName));
719 }
720 else
721 {
722 LOG(LOG_SS_PROCESS, LOG_PRIORITY_VERBOSE, ("%d %s(%d): %x. (%S)\n", CURRENT_PROCESS_PID, FunctionName, RequestedProcessId, DesiredAccess, p->ImageName));
723 }
724*/
725
726
727 if (LearningMode == FALSE)
728 {
729 CHAR ProcessPathUnresolved[MAX_PATH];
730
731
732 _snprintf(ProcessPathUnresolved, MAX_PATH, "%S", p->ImageName);
733 ProcessPathUnresolved[ MAX_PATH - 1 ] = 0;
734
735
736 FixupFilename(ProcessPathUnresolved, PROCESSNAME, MAX_PATH);
737
738
739 POLICY_CHECK_OPTYPE_NAME(PROCESS, OP_PROC_OPEN);
740 }
741 else
742 {
743 // learning mode
744 _snprintf(PROCESSNAME, MAX_PATH, "%S", p->ImageName);
745 PROCESSNAME[ MAX_PATH - 1 ] = 0;
746
747 AddRule(RULE_PROCESS, PROCESSNAME, OP_PROC_OPEN);
748 }
749 }
750
751
752 if (LearningMode == FALSE && GetPathFromOA(ObjectAttributes, PROCESSNAME, MAX_PATH, RESOLVE_LINKS))
753 {
754 LOG(LOG_SS_PROCESS, LOG_PRIORITY_DEBUG, ("%d %s: %s SPECIAL CASE\n", (ULONG) PsGetCurrentProcessId(), FunctionName, PROCESSNAME));
755 }
756
757
758done:
759
760 ASSERT(OriginalNtOpenProcess);
761
762 rc = OriginalNtOpenProcess(ProcessHandle, DesiredAccess, ObjectAttributes, ClientId);
763
764
765 HOOK_ROUTINE_EXIT(rc);
766}
767
768
769
770/*
771 * HookedNtCreateThread()
772 *
773 * Description:
774 * This function mediates the NtCreateThread() system service in order to randomize thread stack
775 * and inject userland dll into newly created main threads.
776 *
777 * NOTE: ZwCreateThread creates a thread in a process. [NAR]
778 *
779 * Parameters:
780 * Those of NtCreateThread().
781 *
782 * Returns:
783 * NTSTATUS returned by NtCreateThread().
784 */
785
786NTSTATUS
787NTAPI
788HookedNtCreateThread
789(
790 OUT PHANDLE ThreadHandle,
791 IN ACCESS_MASK DesiredAccess,
792 IN POBJECT_ATTRIBUTES ObjectAttributes,
793 IN HANDLE ProcessHandle,
794 OUT PCLIENT_ID ClientId,
795 IN PCONTEXT ThreadContext,
796 IN PUSER_STACK UserStack,
797 IN BOOLEAN CreateSuspended
798)
799{
800 PEPROCESS proc = NULL;
801 USHORT StackOffset = 0;
802 PCHAR FunctionName = "HookedNtCreateThread";
803
804
805 HOOK_ROUTINE_ENTER();
806
807
808 if (ARGUMENT_PRESENT(ThreadContext) && KeGetPreviousMode() == UserMode && LearningMode == FALSE && BootingUp == FALSE)
809 {
810 NTSTATUS status;
811 ULONG ProcessId;
812 PCHAR InstructionAddress;
813 ULONG Size;
814 PCHAR Base;
815 PROCESS_BASIC_INFORMATION ProcessBasicInfo;
816 ULONG ret;
817 PIMAGE_PID_ENTRY p;
818
819
820 VerifyUserReturnAddress();
821
822
823 /* verify userland parameter threadcontext */
824 __try
825 {
826 ProbeForRead(ThreadContext, sizeof(*ThreadContext), sizeof(ULONG));
827 ProbeForWrite(ThreadContext, sizeof(*ThreadContext), sizeof(ULONG));
828 }
829
830 __except(EXCEPTION_EXECUTE_HANDLER)
831 {
832 NTSTATUS status = GetExceptionCode();
833
834 LOG(LOG_SS_PROCESS, LOG_PRIORITY_DEBUG, ("%s: caught an exception. status = 0x%x\n", FunctionName, status));
835
836 goto done;
837 }
838
839
840 if (ThreadContext->Eax > SystemAddressStart)
841 {
842 LOG(LOG_SS_PROCESS, LOG_PRIORITY_DEBUG, ("%s: eax=%x > %x (SystemAddressStart)\n", FunctionName, ThreadContext->Eax, SystemAddressStart));
843 goto done;
844 }
845
846
847 /* retrieve the Process ID */
848 status = ZwQueryInformationProcess(ProcessHandle, ProcessBasicInformation, &ProcessBasicInfo, sizeof(ProcessBasicInfo), &Size);
849
850 if (! NT_SUCCESS(status))
851 {
852 LOG(LOG_SS_PROCESS, LOG_PRIORITY_DEBUG, ("%s: ZwQueryInformationProcess failed with status %x\n", FunctionName, status));
853 goto done;
854 }
855
856 ProcessId = ProcessBasicInfo.UniqueProcessId;
857
858 /*
859 * if ProcessId is 0 then the pid has not been assigned yet and we are the primary thread.
860 * in that case pass our pid (we are still running in the context of the parent process) as the ParentId
861 * to make sure we find the right process (since theoretically there can be more than one process with a
862 * pid of 0)
863 */
864 p = FindImagePidEntry(ProcessId, ProcessId == 0 ? CURRENT_PROCESS_PID : 0);
865
866 if (p == NULL)
867 {
868 LOG(LOG_SS_PROCESS, LOG_PRIORITY_DEBUG, ("%d %s: FindImagePidEntry(%d) failed\n", CURRENT_PROCESS_PID, FunctionName, ProcessId));
869 goto done;
870 }
871
872
873 /*
874 * Stack Buffer Overflow Protection (Part 3).
875 *
876 * Allocate/reserve a random (< 1024 bytes) part of a thread's stack space.
877 * This causes the least significant 10 bits to be randomized as well.
878 * (without this, the least significant 16 bits are always the same).
879 */
880
881 /* save the stackoffset for now since we are holding a spinlock and cannot touch pageable memory */
882//XXX we are not holding the spinlock here but are still accessing various p-> fields
883 if (IS_OVERFLOW_PROTECTION_ON(gSecPolicy) && IS_OVERFLOW_PROTECTION_ON(p->SecPolicy))
884
885 StackOffset = (USHORT) (16 + (rand(ThreadContext->Eax) % 63) * 16);
886
887
888 if (! IS_USERLAND_PROTECTION_ON(gSecPolicy) || ! IS_USERLAND_PROTECTION_ON(p->SecPolicy))
889 goto done;
890
891
892 /* Userland DLL needs to be loaded only once (by the first/main thread) */
893
894 if (p->FirstThread != TRUE)
895 goto done;
896
897 p->FirstThread = FALSE;
898
899//XXX investigate MEM_WRITE_WATCH (supported on i386?)
900
901
902 /*
903 * Inject the userland DLL into the process.
904 *
905 * This is achieved by allocating 1 page of memory in the address space of a "victim" process.
906 * Then the LdrLoadDll(our_dll) code is written to the allocated page and victim's thread EIP
907 * is changed to point to our code.
908 * As soon as the thread executes, it will load our DLL and then jump to the original entry point.
909 *
910 * When not given explicit directions, the Microsoft linker creates each DLL with a
911 * preferred load address of 0x10000000. By loading our DLL first, we cause the rest of
912 * the application DLLs to load at a different address.
913 */
914
915 /* allocate 1 page of commited rwx memory */
916
917 Size = PAGE_SIZE;
918 Base = NULL;
919
920 status = ZwAllocateVirtualMemory(ProcessHandle, &Base, 0L, &Size, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
921
922 if (! NT_SUCCESS(status))
923 {
924 LOG(LOG_SS_PROCESS, LOG_PRIORITY_DEBUG, ("%s: ZwAllocateVirtualMemory(%x, %x) failed with status %x\n", FunctionName, Base, Size, status));
925 goto done;
926 }
927
928
929 status = ObReferenceObjectByHandle(ProcessHandle, PROCESS_ALL_ACCESS, 0, KernelMode, &proc, NULL);
930
931 if (! NT_SUCCESS(status))
932 {
933 LOG(LOG_SS_PROCESS, LOG_PRIORITY_DEBUG, ("%s: ObReferenceObjectByHandle(ProcessHandle) failed with status %x\n", FunctionName, status));
934 goto done;
935 }
936
937
938 try
939 {
940 ULONG CodeAddress, DllPathAddress;
941 ULONG ThreadEntryPoint = ThreadContext->Eax; /* thread entry point is stored in the EAX register */
942 PWSTR InjectDllName = L"ozoneusr.dll";
943 USHORT InjectDllNameSize = (wcslen(InjectDllName) + 1) * sizeof(WCHAR);
944
945
946 /*
947 * Execute the DLL inject in the memory context of a "victim" process
948 */
949
950 KeAttachProcess(proc);
951 {
952 /* probe the memory, just in case */
953 ProbeForRead(Base, PAGE_SIZE, 1);
954 ProbeForWrite(Base, PAGE_SIZE, 1);
955
956
957 /*
958 * Memory Layout used for DLL injection
959 *
960 * Byte Value
961 *
962 * 0..4 Original EIP
963 * 4..8 LdrLoadDll() output handle
964 * 8..16 LdrLoadDll() DllName UNICODE_STRING structure
965 * 16..? DllName.Buffer WCHAR string
966 * ?..? DllPath WCHAR string
967 * .... assembler code (to call LdrLoadDll() and then jmp to the original EIP)
968 */
969
970#define BASE_PTR Base
971#define ADDRESS_ORIGINAL_EIP (BASE_PTR + 0)
972#define ADDRESS_DLL_HANDLE (BASE_PTR + 4)
973#define ADDRESS_DLL_NAME (BASE_PTR + 8)
974
975
976 /* save the original thread entry point */
977 * (PULONG) ADDRESS_ORIGINAL_EIP = ThreadEntryPoint;
978
979 /* skip past eip and output handle (8 bytes) */
980 InstructionAddress = ADDRESS_DLL_NAME;
981
982 /*
983 * Create a UNICODE_STRING structure
984 */
985
986 * ((PUSHORT) InstructionAddress)++ = InjectDllNameSize; /* UNICODE_STRING.Length */
987 * ((PUSHORT) InstructionAddress)++ = InjectDllNameSize; /* UNICODE_STRING.MaximumLength */
988
989 /* UNICODE_STRING.Buffer (points to unicode string directly following the buffer) */
990
991 * ((PULONG) InstructionAddress)++ = (ULONG) (InstructionAddress + sizeof(PWSTR));
992
993
994 /* the actual DllName.Buffer value */
995
996 wcscpy((PWSTR) InstructionAddress, InjectDllName);
997
998 InstructionAddress += InjectDllNameSize;
999
1000
1001 /* DllPathValue value */
1002
1003 DllPathAddress = (ULONG) InstructionAddress;
1004
1005 wcscpy((PWSTR) InstructionAddress, OzoneInstallPath);
1006
1007 InstructionAddress += OzoneInstallPathSize;
1008
1009
1010 CodeAddress = (ULONG) InstructionAddress;
1011
1012
1013 /*
1014 * Generate code that will call LdrLoadDll and then jmp to the original entry point.
1015 */
1016
1017 /*
1018 * NTSTATUS
1019 * LdrLoadDll (
1020 * IN PWSTR DllPath OPTIONAL,
1021 * IN PULONG DllCharacteristics OPTIONAL,
1022 * IN PUNICODE_STRING DllName,
1023 * OUT PVOID *DllHandle
1024 * );
1025 *
1026 * Save LdrLoadDll parameters on stack (last to first).
1027 */
1028
1029 ASM_PUSH(InstructionAddress, ADDRESS_DLL_HANDLE); /* DllHandle */
1030 ASM_PUSH(InstructionAddress, ADDRESS_DLL_NAME); /* DllName */
1031 ASM_PUSH(InstructionAddress, 0); /* DllCharacteristics */
1032// ASM_PUSH(InstructionAddress, NULL); /* DllPath */
1033 ASM_PUSH(InstructionAddress, DllPathAddress); /* DllPath */
1034
1035 ASM_CALL(InstructionAddress, FindFunctionBase(NTDLL_Base, "LdrLoadDll"));
1036
1037
1038 //XXX now clear out all the data up to this instruction
1039 //be careful first 4 bytes are used by the next instruction
1040 /*
1041 mov ecx, 16
1042 lea edi, Base + 4
1043 rep stosw
1044 */
1045
1046 ASM_JMP(InstructionAddress, Base);
1047 }
1048 KeDetachProcess();
1049
1050 LOG(LOG_SS_PROCESS, LOG_PRIORITY_DEBUG, ("%d %s: Replacing original thread entry point %x with %x\n", CURRENT_PROCESS_PID, FunctionName, ThreadContext->Eax, CodeAddress));
1051
1052 /* hijack the thread instruction pointer (saved in EAX) */
1053// LOG(LOG_SS_PROCESS, LOG_PRIORITY_DEBUG, ("eip %x eax %x\n", ThreadContext->Eip, ThreadContext->Eax));
1054
1055 ThreadContext->Eax = (ULONG) CodeAddress;
1056
1057 ThreadContext->Eip = ThreadContext->Eax;
1058
1059 ObDereferenceObject(proc);
1060 }
1061
1062 except(EXCEPTION_EXECUTE_HANDLER)
1063 {
1064 NTSTATUS status = GetExceptionCode();
1065
1066 LOG(LOG_SS_PROCESS, LOG_PRIORITY_DEBUG, ("%s: caught an exception. status = 0x%x\n", FunctionName, status));
1067
1068 KeDetachProcess();
1069
1070 ObDereferenceObject(proc);
1071 }
1072 }
1073
1074
1075done:
1076
1077 /*
1078 * finally adjust the stack.
1079 * could not have done it before since we were holding a spinlock and weren't allowed to access pageable memory
1080 */
1081
1082 if (StackOffset)
1083
1084 ThreadContext->Esp -= StackOffset;
1085
1086
1087 ASSERT(OriginalNtCreateThread);
1088
1089 rc = OriginalNtCreateThread(ThreadHandle, DesiredAccess, ObjectAttributes, ProcessHandle,
1090 ClientId, ThreadContext, UserStack, CreateSuspended);
1091
1092
1093 HOOK_ROUTINE_EXIT(rc);
1094}
1095
1096
1097
1098/*
1099 * HookedNtOpenThread()
1100 *
1101 * Description:
1102 * This function mediates the NtOpenThread() system service in order to XXX
1103 * .
1104 *
1105 * NOTE: ZwOpenThread opens a thread object. [NAR]
1106 *
1107 * Parameters:
1108 * Those of NtOpenThread().
1109 *
1110 * Returns:
1111 * NTSTATUS returned by NtOpenThread().
1112 */
1113
1114NTSTATUS
1115NTAPI
1116HookedNtOpenThread
1117(
1118 OUT PHANDLE ThreadHandle,
1119 IN ACCESS_MASK DesiredAccess,
1120 IN POBJECT_ATTRIBUTES ObjectAttributes,
1121 IN PCLIENT_ID ClientId
1122)
1123{
1124 CHAR THREADNAME[MAX_PATH];
1125
1126 HOOK_ROUTINE_ENTER();
1127
1128
1129 if (LearningMode == FALSE && GetPathFromOA(ObjectAttributes, THREADNAME, MAX_PATH, RESOLVE_LINKS))
1130 {
1131 LOG(LOG_SS_PROCESS, LOG_PRIORITY_DEBUG, ("%d HookedNtOpenThread: %s\n", (ULONG) PsGetCurrentProcessId(), THREADNAME));
1132 }
1133
1134
1135 if (! IS_BIT_SET(DesiredAccess, THREAD_QUERY_INFORMATION))
1136 {
1137 // ClientId->UniqueProcess = 0 if process opens a thread in the same process (wmplayer.exe)
1138 if (ClientId)
1139 LOG(LOG_SS_PROCESS, LOG_PRIORITY_DEBUG, ("%d HookedNtOpenThread(%d %d): %x\n", (ULONG) PsGetCurrentProcessId(), ClientId->UniqueProcess, ClientId->UniqueThread, DesiredAccess));
1140 else
1141 LOG(LOG_SS_PROCESS, LOG_PRIORITY_DEBUG, ("%d HookedNtOpenThread(): %x\n", (ULONG) PsGetCurrentProcessId(), DesiredAccess));
1142 }
1143
1144 ASSERT(OriginalNtOpenThread);
1145
1146 rc = OriginalNtOpenThread(ThreadHandle, DesiredAccess, ObjectAttributes, ClientId);
1147
1148
1149 HOOK_ROUTINE_EXIT(rc);
1150}
1151
1152
1153
1154/*
1155 * ProcessPostBootup()
1156 *
1157 * Description:
1158 * Find out where userland Ozone files are installed once the bootup process is complete.
1159 * We are unable to read some parts of the registry before the bootup is complete since
1160 * they have not been initialized yet.
1161 *
1162 * ProcessPostBootup() might run even before bootup is complete in order to setup up the
1163 * default values. When ProcessPostBootup() runs again after bootup, the default values
1164 * will be overwritten with the correct ones.
1165 *
1166 * Parameters:
1167 * None.
1168 *
1169 * Returns:
1170 * Nothing.
1171 */
1172
1173VOID
1174ProcessPostBootup()
1175{
1176 if (ReadStringRegistryValueW(L"\\Registry\\Machine\\Software\\Security Architects\\Ozone Agent", L"InstallPath", OzoneInstallPath, MAX_PATH) == FALSE)
1177 {
1178 LOG(LOG_SS_MISC, LOG_PRIORITY_DEBUG, ("ProcessPostBootup: Failed to open InstallPath registry key\n"));
1179
1180 // use the default path
1181 wcscpy(OzoneInstallPath, L"C:\\Program Files\\Security Architects\\Ozone Agent");
1182 }
1183
1184 OzoneInstallPathSize = (wcslen(OzoneInstallPath) + 1) * sizeof(WCHAR);
1185}
1186
1187
1188
1189/*
1190 * InitProcessEntries()
1191 *
1192 * Description:
1193 * Initializes all the mediated process operation pointers. The "OriginalFunction" pointers
1194 * are initialized by InstallSyscallsHooks() that must be called prior to this function.
1195 *
1196 * NOTE: Called once during driver initialization (DriverEntry()).
1197 *
1198 * Parameters:
1199 * None.
1200 *
1201 * Returns:
1202 * TRUE to indicate success, FALSE if failed.
1203 */
1204/*
1205VOID
1206LoadImageNotifyProc
1207(
1208 IN PUNICODE_STRING FullImageName,
1209 IN HANDLE ProcessId, // where image is mapped
1210 IN PIMAGE_INFO ImageInfo
1211)
1212{
1213 if (FullImageName && ImageInfo)
1214 {
1215 KdPrint(("LoadImageNotifyProc: %d %S %x %x\n", ProcessId, FullImageName->Buffer, ImageInfo->ImageBase, ImageInfo->ImageSize));
1216 }
1217 else
1218 {
1219 KdPrint(("LoadImageNotifyProc: NULL Pointer %x %x\n", FullImageName, ImageInfo));
1220 }
1221}
1222*/
1223
1224BOOLEAN
1225InitProcessEntries()
1226{
1227// PsSetLoadImageNotifyRoutine(LoadImageNotifyProc);
1228
1229 if ( (OriginalNtCreateProcess = (fpZwCreateProcess) ZwCalls[ZW_CREATE_PROCESS_INDEX].OriginalFunction) == NULL)
1230 {
1231 LOG(LOG_SS_PROCESS, LOG_PRIORITY_DEBUG, ("InitProcessEntries: OriginalNtCreateProcess is NULL\n"));
1232 return FALSE;
1233 }
1234
1235 if ( (OriginalNtCreateProcessEx = (fpZwCreateProcessEx) ZwCalls[ZW_CREATE_PROCESSEX_INDEX].OriginalFunction) == NULL)
1236 {
1237 /* does not exist on Win2K */
1238 LOG(LOG_SS_PROCESS, LOG_PRIORITY_DEBUG, ("InitProcessEntries: OriginalNtCreateProcessEx is NULL\n"));
1239 }
1240
1241 if ( (OriginalNtOpenProcess = (fpZwOpenProcess) ZwCalls[ZW_OPEN_PROCESS_INDEX].OriginalFunction) == NULL)
1242 {
1243 LOG(LOG_SS_PROCESS, LOG_PRIORITY_DEBUG, ("InitProcessEntries: OriginalNtOpenProcess is NULL\n"));
1244 return FALSE;
1245 }
1246
1247 if ( (OriginalNtCreateThread = (fpZwCreateThread) ZwCalls[ZW_CREATE_THREAD_INDEX].OriginalFunction) == NULL)
1248 {
1249 LOG(LOG_SS_PROCESS, LOG_PRIORITY_DEBUG, ("InitProcessEntries: OriginalNtCreateThread is NULL\n"));
1250 return FALSE;
1251 }
1252
1253 if ( (OriginalNtOpenThread = (fpZwOpenThread) ZwCalls[ZW_OPEN_THREAD_INDEX].OriginalFunction) == NULL)
1254 {
1255 LOG(LOG_SS_PROCESS, LOG_PRIORITY_DEBUG, ("InitProcessEntries: OriginalNtOpenThread is NULL\n"));
1256 return FALSE;
1257 }
1258
1259
1260 /*
1261 * run ProcessPostBootup() even if we are still booting up, this way we will at least setup
1262 * the default values. When ProcessPostBootup() runs again after bootup, the default values
1263 * will be overwritten with the correct ones.
1264 */
1265
1266 ProcessPostBootup();
1267
1268
1269 return TRUE;
1270}
diff --git a/process.h b/process.h
new file mode 100644
index 0000000..7bf4f08
--- /dev/null
+++ b/process.h
@@ -0,0 +1,215 @@
1/*
2 * Copyright (c) 2004 Security Architects Corporation. All rights reserved.
3 *
4 * Module Name:
5 *
6 * process.h
7 *
8 * Abstract:
9 *
10 * This module defines various types used by process and thread hooking routines.
11 *
12 * Author:
13 *
14 * Eugene Tsyrklevich 23-Feb-2004
15 *
16 * Revision History:
17 *
18 * None.
19 */
20
21#ifndef __PROCESS_H__
22#define __PROCESS_H__
23
24
25extern ULONG SystemProcessId;
26
27extern WCHAR OzoneInstallPath[];
28extern USHORT OzoneInstallPathSize;
29
30
31/*
32 * ZwCreateProcess creates a process object. [NAR]
33 */
34
35typedef NTSTATUS (*fpZwCreateProcess) (
36 OUT PHANDLE ProcessHandle,
37 IN ACCESS_MASK DesiredAccess,
38 IN POBJECT_ATTRIBUTES ObjectAttributes,
39 IN HANDLE InheritFromProcessHandle,
40 IN BOOLEAN InheritHandles,
41 IN HANDLE SectionHandle OPTIONAL,
42 IN HANDLE DebugPort OPTIONAL,
43 IN HANDLE ExceptionPort OPTIONAL
44 );
45
46NTSTATUS
47NTAPI
48HookedNtCreateProcess(
49 OUT PHANDLE ProcessHandle,
50 IN ACCESS_MASK DesiredAccess,
51 IN POBJECT_ATTRIBUTES ObjectAttributes,
52 IN HANDLE InheritFromProcessHandle,
53 IN BOOLEAN InheritHandles,
54 IN HANDLE SectionHandle OPTIONAL,
55 IN HANDLE DebugPort OPTIONAL,
56 IN HANDLE ExceptionPort OPTIONAL
57 );
58
59
60typedef NTSTATUS (*fpZwCreateProcessEx) (
61 OUT PHANDLE ProcessHandle,
62 IN ACCESS_MASK DesiredAccess,
63 IN POBJECT_ATTRIBUTES ObjectAttributes,
64 IN HANDLE InheritFromProcessHandle,
65 IN ULONG Unknown1,
66 IN HANDLE SectionHandle OPTIONAL,
67 IN HANDLE DebugPort OPTIONAL,
68 IN HANDLE ExceptionPort OPTIONAL,
69 IN ULONG Unknown2
70 );
71
72NTSTATUS
73NTAPI
74HookedNtCreateProcessEx(
75 OUT PHANDLE ProcessHandle,
76 IN ACCESS_MASK DesiredAccess,
77 IN POBJECT_ATTRIBUTES ObjectAttributes,
78 IN HANDLE InheritFromProcessHandle,
79 IN ULONG Unknown1,
80 IN HANDLE SectionHandle OPTIONAL,
81 IN HANDLE DebugPort OPTIONAL,
82 IN HANDLE ExceptionPort OPTIONAL,
83 IN ULONG Unknown2
84 );
85
86
87/*
88 * ZwOpenProcess opens a process object. [NAR]
89 */
90
91typedef NTSTATUS (*fpZwOpenProcess) (
92 OUT PHANDLE ProcessHandle,
93 IN ACCESS_MASK DesiredAccess,
94 IN POBJECT_ATTRIBUTES ObjectAttributes,
95 IN PCLIENT_ID ClientId OPTIONAL
96 );
97
98NTSTATUS
99NTAPI
100HookedNtOpenProcess(
101 OUT PHANDLE ProcessHandle,
102 IN ACCESS_MASK DesiredAccess,
103 IN POBJECT_ATTRIBUTES ObjectAttributes,
104 IN PCLIENT_ID ClientId OPTIONAL
105 );
106
107
108/*
109 * ZwCreateThread creates a thread in a process. [NAR]
110 */
111
112typedef struct _USER_STACK {
113 PVOID FixedStackBase;
114 PVOID FixedStackLimit;
115 PVOID ExpandableStackBase;
116 PVOID ExpandableStackLimit;
117 PVOID ExpandableStackBottom;
118} USER_STACK, *PUSER_STACK;
119
120typedef NTSTATUS (*fpZwCreateThread) (
121 OUT PHANDLE ThreadHandle,
122 IN ACCESS_MASK DesiredAccess,
123 IN POBJECT_ATTRIBUTES ObjectAttributes,
124 IN HANDLE ProcessHandle,
125 OUT PCLIENT_ID ClientId,
126 IN PCONTEXT ThreadContext,
127 IN PUSER_STACK UserStack,
128 IN BOOLEAN CreateSuspended
129 );
130
131NTSTATUS
132NTAPI
133HookedNtCreateThread(
134 OUT PHANDLE ThreadHandle,
135 IN ACCESS_MASK DesiredAccess,
136 IN POBJECT_ATTRIBUTES ObjectAttributes,
137 IN HANDLE ProcessHandle,
138 OUT PCLIENT_ID ClientId,
139 IN PCONTEXT ThreadContext,
140 IN PUSER_STACK UserStack,
141 IN BOOLEAN CreateSuspended
142 );
143
144
145/*
146 * ZwOpenThread opens a thread object. [NAR]
147 */
148
149typedef NTSTATUS (*fpZwOpenThread) (
150 OUT PHANDLE ThreadHandle,
151 IN ACCESS_MASK DesiredAccess,
152 IN POBJECT_ATTRIBUTES ObjectAttributes,
153 IN PCLIENT_ID ClientId
154 );
155
156NTSTATUS
157NTAPI
158HookedNtOpenThread(
159 OUT PHANDLE ThreadHandle,
160 IN ACCESS_MASK DesiredAccess,
161 IN POBJECT_ATTRIBUTES ObjectAttributes,
162 IN PCLIENT_ID ClientId
163 );
164
165
166/*
167 * ZwAllocateVirtualMemory allocates virtual memory in the user mode address range. [NAR]
168 */
169
170NTSYSAPI
171NTSTATUS
172NTAPI
173ZwAllocateVirtualMemory(
174 IN HANDLE ProcessHandle,
175 IN OUT PVOID *BaseAddress,
176 IN ULONG ZeroBits,
177 IN OUT PULONG AllocationSize,
178 IN ULONG AllocationType,
179 IN ULONG Protect
180 );
181
182
183/*
184 * ZwQueryInformationProcess retrieves information about a process object. [NAR]
185 */
186
187NTSYSAPI
188NTSTATUS
189NTAPI
190ZwQueryInformationProcess(
191 IN HANDLE ProcessHandle,
192 IN PROCESSINFOCLASS ProcessInformationClass,
193 OUT PVOID ProcessInformation,
194 IN ULONG ProcessInformationLength,
195 OUT PULONG ReturnLength OPTIONAL
196 );
197
198
199VOID
200KeAttachProcess(
201 IN /*PRKPROCESS*/ PVOID Process
202 );
203
204VOID
205KeDetachProcess (
206 VOID
207 );
208
209
210BOOLEAN InitProcessEntries();
211VOID RemoveProcessEntries();
212VOID ProcessPostBootup();
213
214
215#endif /* __PROCESS_H__ */ \ No newline at end of file
diff --git a/procname.c b/procname.c
new file mode 100644
index 0000000..05ba9be
--- /dev/null
+++ b/procname.c
@@ -0,0 +1,677 @@
1/*
2 * Copyright (c) 2004 Security Architects Corporation. All rights reserved.
3 *
4 * Module Name:
5 *
6 * procname.c
7 *
8 * Abstract:
9 *
10 * This module defines various types used by process id to process name conversion routines.
11 *
12 * All processes are tracked in a global hash table.
13 * At startup ZwQuerySystemInformation(SystemProcessesAndThreadsInformation..) is used to
14 * enumerate all the existing processes. After that NtCreateProcess() is hooked and used
15 * to keep track of newly created processes while PsSetCreateProcessNotifyRoutine()
16 * callbacks are used to keep track of terminating processes.
17 *
18 * See http://www.microsoft.com/msj/0199/nerd/nerd0199.aspx for more info.
19 *
20 * Author:
21 *
22 * Eugene Tsyrklevich 23-Feb-2004
23 *
24 * Revision History:
25 *
26 * 07-Apr-2004 ET - Copied from process.h
27 */
28
29
30#include <NTDDK.h>
31#include "procname.h"
32#include "hookproc.h"
33#include "process.h"
34#include "policy.h"
35#include "sysinfo.h"
36#include "learn.h"
37#include "misc.h"
38#include "log.h"
39
40
41void FindProcessNameOffset();
42
43
44#ifdef ALLOC_PRAGMA
45#pragma alloc_text (INIT, InitProcessNameEntries)
46#pragma alloc_text (INIT, FindProcessNameOffset)
47#pragma alloc_text (INIT, EnumerateExistingProcesses)
48#pragma alloc_text (PAGE, RemoveProcessNameEntries)
49#endif
50
51
52ULONG SystemProcessId;
53
54/* 67 * 144 = 10 kilobytes */
55IMAGE_PID_ENTRY gImagePidHtbl[IMAGE_PID_HASHTABLE_SIZE];
56
57//XXX investigate KeAcquireInStackQueuedSpinLock
58KSPIN_LOCK gImagePidHtblSpinLock;
59
60
61/*
62 * FindImagePidEntry()
63 *
64 * Description:
65 * Looks for a process entry in the global process hash table with a specified process id.
66 *
67 * Parameters:
68 * ProcessId - process id of the process to look for.
69 *
70 * Returns:
71 * Pointer to a process entry if one is found, NULL otherwise.
72 */
73
74PIMAGE_PID_ENTRY
75FindImagePidEntry(ULONG ProcessId, ULONG ParentId)
76{
77 PIMAGE_PID_ENTRY p;
78 KIRQL irql;
79
80
81//LOG(LOG_SS_PROCESS, LOG_PRIORITY_DEBUG, ("FindImagePidEntry(%d %d) 1\n", ProcessId, ParentId));
82 KeAcquireSpinLock(&gImagePidHtblSpinLock, &irql);
83//LOG(LOG_SS_PROCESS, LOG_PRIORITY_DEBUG, ("FindImagePidEntry 2\n"));
84
85
86 p = gImagePidHtbl[(ULONG) ProcessId % IMAGE_PID_HASHTABLE_SIZE].next;
87
88 while (p)
89 {
90 if (p->ProcessId == ProcessId)
91 {
92 if (ParentId == 0 || p->ParentId == ParentId)
93 {
94 if (ParentId != 0)
95 {
96 LOG(LOG_SS_PROCESS, LOG_PRIORITY_DEBUG, ("%d FindImagePidEntry(%d, %d) found an entry (%d)\n", CURRENT_PROCESS_PID, ProcessId, ParentId, p->ParentId));
97 }
98
99 KeReleaseSpinLock(&gImagePidHtblSpinLock, irql);
100 return p;
101 }
102
103 LOG(LOG_SS_PROCESS, LOG_PRIORITY_DEBUG, ("%d FindImagePidEntry: ProcessId %d clash. Parent id %d vs %d\n", CURRENT_PROCESS_PID, ProcessId, ParentId, p->ParentId));
104 }
105
106 p = p->next;
107 }
108
109
110 KeReleaseSpinLock(&gImagePidHtblSpinLock, irql);
111
112
113 return NULL;
114}
115
116
117
118/*
119 * ProcessInsertImagePidEntry()
120 *
121 * Description:
122 * Insert the new process entry into the global process hash table.
123 *
124 * Parameters:
125 * ProcessId - process id of the new process.
126 * NewProcessEntry - the entry to insert into the hash table.
127 *
128 * Returns:
129 * TRUE to indicate success, FALSE if failed.
130 */
131
132BOOLEAN
133ProcessInsertImagePidEntry(ULONG ProcessId, PIMAGE_PID_ENTRY NewProcessEntry)
134{
135 PIMAGE_PID_ENTRY p, prev;
136 KIRQL irql;
137
138
139//LOG(LOG_SS_PROCESS, LOG_PRIORITY_DEBUG, ("ProcessInsertImagePidEntry(%d %x) 1\n", ProcessId, NewProcessEntry));
140 KeAcquireSpinLock(&gImagePidHtblSpinLock, &irql);
141//LOG(LOG_SS_PROCESS, LOG_PRIORITY_DEBUG, ("ProcessInsertImagePidEntry 2\n"));
142
143 prev = &gImagePidHtbl[(ULONG) ProcessId % IMAGE_PID_HASHTABLE_SIZE];
144 p = prev->next;
145
146 while (p)
147 {
148 // if an entry with our ProcessId already exists, bail out
149
150 if (p->ProcessId == (ULONG) ProcessId)
151 {
152 LOG(LOG_SS_PROCESS, LOG_PRIORITY_DEBUG, ("%d ProcessInsertImagePidEntry: ProcessId (%d) clash. New image name is '%S' (%d). Old image name is '%S' (%d)\n", CURRENT_PROCESS_PID, ProcessId, NewProcessEntry->ImageName, NewProcessEntry->ParentId, p->ImageName, p->ParentId));
153
154 if (ProcessId != 0)
155 {
156 KeReleaseSpinLock(&gImagePidHtblSpinLock, irql);
157 return FALSE;
158 }
159 }
160
161 prev = p;
162 p = p->next;
163 }
164
165 prev->next = NewProcessEntry;
166
167
168 KeReleaseSpinLock(&gImagePidHtblSpinLock, irql);
169
170
171 return TRUE;
172}
173
174
175
176/*
177 * CreateNewProcessEntry()
178 *
179 * Description:
180 * Allocates and initializes a new process entry.
181 *
182 * Parameters:
183 * ProcessId - process id of the new process.
184 * ProcessName - process image name.
185 *
186 * Returns:
187 * Pointer to a heap allocated IMAGE_PID_ENTRY structure. NULL if failed.
188 */
189
190PIMAGE_PID_ENTRY
191CreateNewProcessEntry(ULONG ProcessId, ULONG ParentId, PUNICODE_STRING ProcessName, BOOLEAN NewProcess)
192{
193 PIMAGE_PID_ENTRY ProcessEntry;
194
195
196 ASSERT(ProcessName);
197
198
199 ProcessEntry = ExAllocatePoolWithTag(NonPagedPool, sizeof(IMAGE_PID_ENTRY) + ProcessName->Length, _POOL_TAG);
200 if (ProcessEntry == NULL)
201 {
202 LOG(LOG_SS_PROCESS, LOG_PRIORITY_DEBUG, ("CreateNewProcessEntry: Out of memory. Forgeting about process %d (%S)", ProcessId, ProcessName->Buffer));
203 return NULL;
204 }
205
206 RtlZeroMemory(ProcessEntry, sizeof(IMAGE_PID_ENTRY));
207
208 ProcessEntry->ProcessId = ProcessId;
209 ProcessEntry->ParentId = ParentId;
210 ProcessEntry->FirstThread = NewProcess;
211
212 KeInitializeEvent(&ProcessEntry->UserlandRequestDoneEvent, SynchronizationEvent, FALSE);
213
214 wcscpy(ProcessEntry->ImageName, ProcessName->Buffer);
215 ProcessEntry->ImageName[ ProcessName->Length/sizeof(WCHAR) ] = L'\0';
216
217 KeInitializeSpinLock(&ProcessEntry->SecPolicy.SpinLock);
218
219
220 return ProcessEntry;
221}
222
223
224
225/*
226 * CreateAndLoadNewProcessEntry()
227 *
228 * Description:
229 * Creates a new process entry and inserts it into the global process hash table.
230 *
231 * Parameters:
232 * ProcessId - process id of the new process.
233 * ProcessName - process image name.
234 *
235 * Returns:
236 * Pointer to a heap allocated IMAGE_PID_ENTRY structure. NULL if failed.
237 */
238
239PIMAGE_PID_ENTRY
240CreateAndLoadNewProcessEntry(ULONG ProcessId, PUNICODE_STRING ProcessName, BOOLEAN NewProcess)
241{
242 PIMAGE_PID_ENTRY ProcessEntry;
243
244
245 ASSERT(ProcessName);
246
247
248 ProcessEntry = CreateNewProcessEntry(ProcessId, 0, ProcessName, NewProcess);
249 if (ProcessEntry == NULL)
250 return NULL;
251
252
253 if (LearningMode == FALSE && FindAndLoadSecurityPolicy(&ProcessEntry->SecPolicy, ProcessName->Buffer, NULL) == FALSE)
254 {
255 LOG(LOG_SS_PROCESS, LOG_PRIORITY_VERBOSE, ("CreateAndLoadNewProcessEntry: Failed to load security policy for %S\n", ProcessName->Buffer));
256 }
257
258
259 if (ProcessInsertImagePidEntry(ProcessId, ProcessEntry) == FALSE)
260 {
261 ExFreePoolWithTag(ProcessEntry, _POOL_TAG);
262 return NULL;
263 }
264
265
266 return ProcessEntry;
267}
268
269
270
271/*
272 * CreateProcessNotifyProc()
273 *
274 * Description:
275 * PsSetCreateProcessNotifyRoutine() callback. Used to remove process entries from the global
276 * hashtable of currently running processes. On Windows 2000, this routine also replaces PIDs
277 * of 0 with the real PIDs. This is necessary since win2k does not assign PIDs at a point
278 * where process.c!PostProcessNtCreateProcess() is called.
279 *
280 * NOTE: PsSetCreateProcessNotifyRoutine() adds a driver-supplied callback routine to,
281 * or removes it from, a list of routines to be called whenever a process is created or deleted.
282 *
283 * Parameters:
284 * ParentId - the parent process ID.
285 * ProcessId - process ID that was created / deleted.
286 * Create - indicates whether the process was created (TRUE) or deleted (FALSE).
287 *
288 * Returns:
289 * Nothing.
290 */
291
292VOID
293CreateProcessNotifyProc
294(
295 IN HANDLE ParentId,
296 IN HANDLE ProcessId,
297 IN BOOLEAN Create
298)
299{
300 PIMAGE_PID_ENTRY p, prev, tmp;
301 ULONG RequiredPid;
302 BOOLEAN FoundNewProcess = FALSE;
303 KIRQL irql;
304
305
306 LOG(LOG_SS_PROCESS, LOG_PRIORITY_VERBOSE, ("%d CreateProccessNotifyProc(%d, %d, %d)\n", CURRENT_PROCESS_PID, ParentId, ProcessId, Create));
307
308
309 /* if the entry is being removed look for ProcessId, otherwise look for 0 */
310 RequiredPid = Create == FALSE ? (ULONG) ProcessId : 0;
311
312
313 /*
314 * find an entry with pid=ProcessId
315 */
316
317 KeAcquireSpinLock(&gImagePidHtblSpinLock, &irql);
318
319 prev = &gImagePidHtbl[(ULONG) RequiredPid % IMAGE_PID_HASHTABLE_SIZE];
320 p = prev->next;
321
322 while (p)
323 {
324 if (p->ProcessId != (ULONG) RequiredPid)
325 {
326 prev = p;
327 p = p->next;
328 continue;
329 }
330
331 if (p->ParentId != 0 && p->ParentId != (ULONG) ParentId)
332 {
333 LOG(LOG_SS_PROCESS, LOG_PRIORITY_DEBUG, ("%d CreateProccessNotifyProc(): ProcessId %d collision. %d vs %d\n", CURRENT_PROCESS_PID, p->ProcessId, p->ParentId, ParentId));
334
335 prev = p;
336 p = p->next;
337 continue;
338 }
339
340
341 /* found the necessary entry */
342 LOG(LOG_SS_PROCESS, LOG_PRIORITY_DEBUG, ("%d CreateProccessNotifyProc(): Found (%s) %d %x %S\n", CURRENT_PROCESS_PID, Create == FALSE ? "delete" : "fix", p->ProcessId, p->next, p->ImageName));
343
344 tmp = p;
345
346 /* unlink the found entry */
347 prev->next = p->next;
348
349 if (Create == FALSE)
350 {
351 /* if the process is being deleted then free the entry */
352 PolicyDelete(&tmp->SecPolicy);
353 ExFreePoolWithTag(tmp, _POOL_TAG);
354 }
355 else
356 {
357 /*
358 * if the process is being executed and we found an entry with PID of 0 then
359 * replace 0 with the real pid
360 */
361 tmp->ProcessId = (ULONG) ProcessId;
362 tmp->next = NULL;
363 FoundNewProcess = TRUE;
364 }
365
366 break;
367 }
368
369 KeReleaseSpinLock(&gImagePidHtblSpinLock, irql);
370
371
372 /*
373 * If necessary, reinsert the new entry that used to have a PID of 0.
374 * We need to reinsert since the hashtable is indexed by PIDs.
375 */
376 if (FoundNewProcess == TRUE)
377 {
378//XXX at this point no locks are held. if tmp->ProcessId process quits before ProcessInsertImagePidEntry()
379 // executes, we will get a zombie entry (will never be removed)
380 LOG(LOG_SS_PROCESS, LOG_PRIORITY_DEBUG, ("%d Replacing 0 with %d for %S\n", CURRENT_PROCESS_PID, tmp->ProcessId, tmp->ImageName));
381 ProcessInsertImagePidEntry(tmp->ProcessId, tmp);
382 LOG(LOG_SS_PROCESS, LOG_PRIORITY_DEBUG, ("%d Done replacing %d\n", CURRENT_PROCESS_PID, tmp->ProcessId, tmp->ImageName));
383 }
384}
385
386
387
388USHORT ProcessNameOffset = 0, ThreadServiceTableOffset = 0;
389
390
391/*
392 * FindProcessNameOffset()
393 *
394 * Description:
395 * Identifies process name offset in the EPROCESS structure.
396 *
397 * The name offset is identified by searching for "System" string in the System EPROCESS structure
398 * (this function is called when the driver is loaded and thus runs in the "System" context).
399 *
400 * ThreadServiceTableOffset is the offset of the pointer to a service descriptor table (syscall table)
401 * in the Thread Environment Block (TEB). Used to determine whether a thread is GUI based or not.
402 *
403 * Parameters:
404 * None.
405 *
406 * Returns:
407 * Nothing.
408 */
409
410void
411FindProcessNameOffset()
412{
413 PEPROCESS SystemProcess = PsGetCurrentProcess(); // current "System" process
414 PETHREAD SystemThread = PsGetCurrentThread(); // current "System" thread
415 USHORT i;
416
417
418 /* Search for "System" process name in the current system process Process Environment Block */
419
420 for (i = 0; i < 1024; i++) // 372 on Windows XP SP1
421 {
422 if (_strnicmp((PCHAR) SystemProcess + i, "System", 6) == 0)
423 {
424 ProcessNameOffset = i;
425 break;
426 }
427 }
428
429
430 /* Search for KeServiceDescriptorTable address in the current system thread's Thread Environment Block */
431
432 for (i = 0; i < 500; i++) // 292 on Win2k3
433 {
434 if (* (PULONG) ((PCHAR) SystemThread + i) == (ULONG) &KeServiceDescriptorTable[0])
435 {
436 ThreadServiceTableOffset = i;
437 break;
438 }
439 }
440}
441
442
443
444/*
445 * GetCurrentProcessName()
446 *
447 * Description:
448 * Returns the current process pathname.
449 *
450 * Parameters:
451 * None.
452 *
453 * Returns:
454 * Pointer to the current process pathname ("Unknown" if not found).
455 */
456
457PWCHAR
458GetCurrentProcessName()
459{
460 PIMAGE_PID_ENTRY p;
461 PWCHAR name = NULL;
462
463
464 p = FindImagePidEntry(CURRENT_PROCESS_PID, 0);
465
466 if (p != NULL)
467 /*
468 * NOTE: we are returning a pointer to a member of a structure which is not locked at this point!
469 * Should be ok though since this function is only called in the context of a current process which
470 * cannot disappear from underneath us.
471 */
472 name = p->ImageName;
473 else
474 name = L"(Unknown)";
475
476
477 return name;
478}
479
480
481
482/*
483 * FindExistingProcesses()
484 *
485 * Description:
486 * Enumerates all the existing processes using ZwQuerySystemInformation(SystemProcessesAndThreadsInformation)
487 * and creates IMAGE_PID_ENTRY for all of them. Called once at startup.
488 *
489 * Parameters:
490 * None.
491 *
492 * Returns:
493 * Nothing.
494 */
495
496VOID
497EnumerateExistingProcesses()
498{
499 ULONG size = 65535, i;
500 PUCHAR SystemInfo;
501 PSYSTEM_PROCESSES pSystemProcess;
502 NTSTATUS status;
503
504
505 /*
506 * The format of the data returned to the SystemInformation buffer is a sequence of
507 * SYSTEM_PROCESSES structures, chained together via the NextEntryDelta member.
508 * The Threads member of each SYSTEM_PROCESSES structure is an array of ThreadCount
509 * SYSTEM_THREADS structures.The end of the process chain is marked by a NextEntryDelta
510 * value of zero.
511 */
512
513 /* first, find out the total amount of SystemProcessesAndThreadsInformation to be returned */
514/*
515 status = ZwQuerySystemInformation(SystemProcessesAndThreadsInformation, &i, 0, &size);
516 if (size == 0 || size > 1024*1024)
517 {
518 LOG(LOG_SS_PROCESS, LOG_PRIORITY_DEBUG, ("FindExistingProcesses: ZwQuerySystemInformation failed. status=%x size=%d\n", status, size));
519 return;
520 }
521*/
522
523 /* second, allocate the required amount of memory */
524
525 SystemInfo = ExAllocatePoolWithTag(PagedPool, size, _POOL_TAG);
526 if (SystemInfo == NULL)
527 {
528 LOG(LOG_SS_PROCESS, LOG_PRIORITY_DEBUG, ("FindExistingProcesses: out of memory (requested %d bytes)\n", size));
529 return;
530 }
531
532 /* third, request the SystemProcessesAndThreadsInformation */
533
534 ZwQuerySystemInformation(SystemProcessesAndThreadsInformation, SystemInfo, size, &i);
535
536
537 pSystemProcess = (PSYSTEM_PROCESSES) SystemInfo;
538
539
540 i = 0;
541
542 while (pSystemProcess->NextEntryDelta != 0)
543 {
544 if (pSystemProcess->ProcessName.Length != 0)
545 {
546 /* create a new process entry and load the associated security policy (if any) */
547
548 CreateAndLoadNewProcessEntry(pSystemProcess->ProcessId, &pSystemProcess->ProcessName, FALSE);
549
550 ++i;
551 }
552
553 pSystemProcess = (PSYSTEM_PROCESSES) ( ((PUCHAR) pSystemProcess) + pSystemProcess->NextEntryDelta);
554 }
555
556 ExFreePoolWithTag(SystemInfo, _POOL_TAG);
557
558
559 /* if no processes exist, the computer must be booting up */
560 if (i == 0)
561 {
562 UNICODE_STRING System;
563
564
565 BootingUp = TRUE;
566
567 /*
568 * when booting up no processes are listed as existing even though "System" and "Idle"
569 * have already been initialized. Initialize "System" process entry since it will
570 * never be created otherwise.
571 */
572
573 RtlInitUnicodeString(&System, L"System");
574
575 CreateAndLoadNewProcessEntry(SystemProcessId, &System, FALSE);
576 }
577}
578
579
580
581/*
582 * InitProcessNameEntries()
583 *
584 * Description:
585 * Initializes process id to process name related data.
586 *
587 * NOTE: Called once during driver initialization (DriverEntry()).
588 *
589 * Parameters:
590 * None.
591 *
592 * Returns:
593 * TRUE to indicate success, FALSE if failed.
594 */
595
596BOOLEAN
597InitProcessNameEntries()
598{
599 memset(gImagePidHtbl, 0, sizeof(gImagePidHtbl));
600
601 KeInitializeSpinLock(&gImagePidHtblSpinLock);
602
603 SystemProcessId = (ULONG) PsGetCurrentProcessId();
604
605 FindProcessNameOffset();
606
607
608 /* XXX investigate
609A driver's process-notify routine is also called with Create set to FALSE, usually when the last thread within a process has terminated and the process address space is about to be deleted. In very rare circumstances, for processes in which no thread was ever created, a driver's process-notify routine is called only at the destruction of the process. */
610 if (! NT_SUCCESS( PsSetCreateProcessNotifyRoutine(CreateProcessNotifyProc, FALSE) ))
611 {
612 LOG(LOG_SS_PROCESS, LOG_PRIORITY_DEBUG, ("InitProcessNameEntries: PsSetCreateProcessNotifyRoutine() failed\n"));
613 return FALSE;
614 }
615
616
617 return TRUE;
618}
619
620
621
622/*
623 * RemoveProcessNameEntries()
624 *
625 * Description:
626 * Removes the global hash table process entries and PsSetCreateProcessNotifyRoutine() callback.
627 *
628 * NOTE: Called once during driver unload (DriverUnload()).
629 *
630 * Parameters:
631 * None.
632 *
633 * Returns:
634 * Nothing.
635 */
636
637VOID
638RemoveProcessNameEntries()
639{
640 int i;
641 PIMAGE_PID_ENTRY p, tmp;
642 KIRQL irql;
643
644
645#if HOOK_PROCESS
646
647 if (! NT_SUCCESS( PsSetCreateProcessNotifyRoutine(CreateProcessNotifyProc, TRUE) ))
648 LOG(LOG_SS_PROCESS, LOG_PRIORITY_DEBUG, ("RemoveProcessEntries: PsSetCreateProcessNotifyRoutine remove failed\n"));
649
650#endif
651
652
653 KeAcquireSpinLock(&gImagePidHtblSpinLock, &irql);
654
655 for (i = 0; i < IMAGE_PID_HASHTABLE_SIZE; i++)
656 {
657 p = gImagePidHtbl[i].next;
658
659 while (p)
660 {
661 LOG(LOG_SS_PROCESS, LOG_PRIORITY_VERBOSE, ("RemoveProcessEntries: Removing %d %x %S\n", p->ProcessId, p->next, p->ImageName));
662
663 tmp = p;
664 p = p->next;
665
666 if (tmp->WaitingForUserRequestId != 0)
667 {
668 LOG(LOG_SS_PROCESS, LOG_PRIORITY_DEBUG, ("RemoveProcessEntries: Process (pid=%d) is still waiting for a user request id %d!\n", tmp->ProcessId, tmp->WaitingForUserRequestId));
669 }
670
671 PolicyDelete(&tmp->SecPolicy);
672 ExFreePoolWithTag(tmp, _POOL_TAG);
673 }
674 }
675
676 KeReleaseSpinLock(&gImagePidHtblSpinLock, irql);
677}
diff --git a/procname.h b/procname.h
new file mode 100644
index 0000000..01145a9
--- /dev/null
+++ b/procname.h
@@ -0,0 +1,68 @@
1/*
2 * Copyright (c) 2004 Security Architects Corporation. All rights reserved.
3 *
4 * Module Name:
5 *
6 * procname.h
7 *
8 * Abstract:
9 *
10 * This module defines various types used by process id to process name conversion routines.
11 *
12 * Author:
13 *
14 * Eugene Tsyrklevich 23-Feb-2004
15 *
16 * Revision History:
17 *
18 * 07-Apr-2004 ET - Copied from process.h
19 */
20
21#ifndef __PROCNAME_H__
22#define __PROCNAME_H__
23
24
25#include "userland.h"
26
27
28typedef struct _IMAGE_PID_ENTRY
29{
30 struct _IMAGE_PID_ENTRY *next;
31 ULONG ProcessId;
32 ULONG ParentId;
33 BOOLEAN FirstThread; // Was more than one thread already created?
34 // (some actions need to take place only in the main thread)
35 UCHAR WaitingForUserRequestId; // contains the sequence id of the reply we are waiting for
36 KEVENT UserlandRequestDoneEvent;
37 PUSERLAND_REPLY_HEADER UserlandReply;
38 SECURITY_POLICY SecPolicy;
39 WCHAR ImageName[1];
40
41} IMAGE_PID_ENTRY, *PIMAGE_PID_ENTRY;
42
43
44/*
45 * 1. The following number should be prime.
46 * 2. It should also be slightly larger than the "average" number of processes of any given machine to
47 * minimize the number of hash table collisions (we want O(1) access) and at the same time not
48 * eating up too much memory (gImagePidHtbl[]).
49 */
50#define IMAGE_PID_HASHTABLE_SIZE 67
51
52extern IMAGE_PID_ENTRY gImagePidHtbl[IMAGE_PID_HASHTABLE_SIZE];
53
54extern USHORT ProcessNameOffset, ThreadServiceTableOffset;
55extern BOOLEAN BootingUp;
56
57
58BOOLEAN InitProcessNameEntries();
59VOID RemoveProcessNameEntries();
60PIMAGE_PID_ENTRY FindImagePidEntry(ULONG ProcessId, ULONG ParentId);
61BOOLEAN ProcessInsertImagePidEntry(ULONG ProcessId, PIMAGE_PID_ENTRY NewProcess);
62PIMAGE_PID_ENTRY CreateNewProcessEntry(ULONG ProcessId, ULONG ParentId, PUNICODE_STRING ProcessName, BOOLEAN NewProcess);
63//PIMAGE_PID_ENTRY CreateAndLoadNewProcessEntry(ULONG ProcessId, PUNICODE_STRING ProcessName, BOOLEAN NewProcess);
64VOID EnumerateExistingProcesses();
65PWCHAR GetCurrentProcessName();
66
67
68#endif /* __PROCNAME_H__ */ \ No newline at end of file
diff --git a/registry.c b/registry.c
new file mode 100644
index 0000000..c91b7da
--- /dev/null
+++ b/registry.c
@@ -0,0 +1,402 @@
1/*
2 * Copyright (c) 2004 Security Architects Corporation. All rights reserved.
3 *
4 * Module Name:
5 *
6 * registry.c
7 *
8 * Abstract:
9 *
10 * This module defines various types used by registry hooking routines.
11 *
12 * Author:
13 *
14 * Eugene Tsyrklevich 20-Feb-2004
15 *
16 * Revision History:
17 *
18 * None.
19 */
20
21
22#include <NTDDK.h>
23#include "registry.h"
24#include "policy.h"
25#include "pathproc.h"
26#include "hookproc.h"
27#include "accessmask.h"
28#include "learn.h"
29#include "misc.h"
30#include "log.h"
31
32
33#ifdef ALLOC_PRAGMA
34#pragma alloc_text (INIT, InitRegistryHooks)
35#endif
36
37
38fpZwCreateKey OriginalNtCreateKey = NULL;
39fpZwOpenKey OriginalNtOpenKey = NULL;
40
41fpZwDeleteKey OriginalNtDeleteKey = NULL;
42
43fpZwSetValueKey OriginalNtSetValueKey = NULL;
44fpZwQueryValueKey OriginalNtQueryValueKey = NULL;
45
46
47
48/*
49 * HookedNtCreateKey()
50 *
51 * Description:
52 * This function mediates the NtCreateKey() system service and checks the
53 * provided registry key against the global and current process security policies.
54 *
55 * NOTE: ZwCreateKey creates or opens a registry key object. [NAR]
56 *
57 * Parameters:
58 * Those of NtCreateKey().
59 *
60 * Returns:
61 * STATUS_ACCESS_DENIED if the call does not pass the security policy check.
62 * Otherwise, NTSTATUS returned by NtCreateKey().
63 */
64
65NTSTATUS
66NTAPI
67HookedNtCreateKey
68(
69 OUT PHANDLE KeyHandle,
70 IN ACCESS_MASK DesiredAccess,
71 IN POBJECT_ATTRIBUTES ObjectAttributes,
72 IN ULONG TitleIndex,
73 IN PUNICODE_STRING Class OPTIONAL,
74 IN ULONG CreateOptions,
75 OUT PULONG Disposition OPTIONAL
76)
77{
78 PCHAR FunctionName = "HookedNtCreateKey";
79
80
81 HOOK_ROUTINE_START(REGISTRY);
82
83
84 ASSERT(OriginalNtOpenKey);
85
86 rc = OriginalNtCreateKey(KeyHandle, DesiredAccess, ObjectAttributes, TitleIndex,
87 Class, CreateOptions, Disposition);
88
89
90 HOOK_ROUTINE_FINISH(REGISTRY);
91}
92
93
94
95/*
96 * HookedNtOpenKey()
97 *
98 * Description:
99 * This function mediates the NtOpenKey() system service and checks the
100 * provided registry key against the global and current process security policies.
101 *
102 * NOTE: ZwOpenKey opens a registry key object. [NAR]
103 *
104 * Parameters:
105 * Those of NtOpenKey().
106 *
107 * Returns:
108 * STATUS_ACCESS_DENIED if the call does not pass the security policy check.
109 * Otherwise, NTSTATUS returned by NtOpenKey().
110 */
111
112NTSTATUS
113NTAPI
114HookedNtOpenKey
115(
116 OUT PHANDLE KeyHandle,
117 IN ACCESS_MASK DesiredAccess,
118 IN POBJECT_ATTRIBUTES ObjectAttributes
119)
120{
121 PCHAR FunctionName = "HookedNtOpenKey";
122
123
124 HOOK_ROUTINE_START(REGISTRY);
125
126
127 ASSERT(OriginalNtOpenKey);
128
129 rc = OriginalNtOpenKey(KeyHandle, DesiredAccess, ObjectAttributes);
130
131
132 HOOK_ROUTINE_FINISH(REGISTRY);
133}
134
135
136
137/*
138 * HookedNtDeleteKey()
139 *
140 * Description:
141 * This function mediates the NtDeleteKey() system service and checks the
142 * provided registry key against the global and current process security policies.
143 *
144 * NOTE: ZwDeleteKey deletes a key in the registry. [NAR]
145 *
146 * Parameters:
147 * Those of NtDeleteKey().
148 *
149 * Returns:
150 * STATUS_ACCESS_DENIED if the call does not pass the security policy check.
151 * Otherwise, NTSTATUS returned by NtDeleteKey().
152 */
153
154NTSTATUS
155NTAPI
156HookedNtDeleteKey
157(
158 IN HANDLE KeyHandle
159)
160{
161 PCHAR FunctionName = "HookedNtDeleteKey";
162 CHAR REGISTRYNAME[MAX_PATH];
163 WCHAR REGISTRYNAMEW[MAX_PATH];
164 PWSTR KeyName = NULL;
165
166
167 HOOK_ROUTINE_ENTER();
168
169
170 if ((KeyName = GetNameFromHandle(KeyHandle, REGISTRYNAMEW, sizeof(REGISTRYNAMEW))) != NULL)
171 {
172 sprintf(REGISTRYNAME, "%S", KeyName);
173
174 LOG(LOG_SS_REGISTRY, LOG_PRIORITY_VERBOSE, ("%d %s: %s\n", (ULONG) PsGetCurrentProcessId(), FunctionName, REGISTRYNAME));
175
176
177 if (LearningMode == FALSE)
178 {
179 POLICY_CHECK_OPTYPE_NAME(REGISTRY, OP_DELETE);
180 }
181 }
182
183
184 ASSERT(OriginalNtDeleteKey);
185
186 rc = OriginalNtDeleteKey(KeyHandle);
187
188
189 if (KeyName)
190 {
191 HOOK_ROUTINE_FINISH_OBJECTNAME_OPTYPE(REGISTRY, REGISTRYNAME, OP_DELETE);
192 }
193 else
194 {
195 HOOK_ROUTINE_EXIT(rc);
196 }
197}
198
199
200
201/*
202 * HookedNtSetValueKey()
203 *
204 * Description:
205 * This function mediates the NtSetValueKey() system service and checks the
206 * provided registry key against the global and current process security policies.
207 *
208 * NOTE: ZwSetValueKey updates or adds a value to a key. [NAR]
209 *
210 * Parameters:
211 * Those of NtSetValueKey().
212 *
213 * Returns:
214 * STATUS_ACCESS_DENIED if the call does not pass the security policy check.
215 * Otherwise, NTSTATUS returned by NtSetValueKey().
216 */
217
218NTSTATUS
219NTAPI
220HookedNtSetValueKey
221(
222 IN HANDLE KeyHandle,
223 IN PUNICODE_STRING ValueName,
224 IN ULONG TitleIndex,
225 IN ULONG Type,
226 IN PVOID Data,
227 IN ULONG DataSize
228)
229{
230 CHAR REGISTRYNAME[MAX_PATH];
231 WCHAR REGISTRYNAMEW[MAX_PATH];
232 PCHAR FunctionName = "HookedNtSetValueKey";
233 UNICODE_STRING usValueName;
234 PWSTR KeyName = NULL;
235
236
237 HOOK_ROUTINE_ENTER();
238
239
240 if (VerifyUnicodeString(ValueName, &usValueName) == TRUE)
241 {
242 if ((KeyName = GetNameFromHandle(KeyHandle, REGISTRYNAMEW, sizeof(REGISTRYNAMEW))) != NULL)
243 {
244 _snprintf(REGISTRYNAME, MAX_PATH, "%S\\%S", KeyName, ValueName->Buffer);
245 REGISTRYNAME[MAX_PATH - 1] = 0;
246
247 LOG(LOG_SS_REGISTRY, LOG_PRIORITY_VERBOSE, ("%d %s: %s\n", (ULONG) PsGetCurrentProcessId(), FunctionName, REGISTRYNAME));
248
249
250 if (LearningMode == FALSE)
251 {
252 POLICY_CHECK_OPTYPE_NAME(REGISTRY, OP_WRITE);
253 }
254 }
255 }
256
257
258 ASSERT(OriginalNtSetValueKey);
259
260 rc = OriginalNtSetValueKey(KeyHandle, ValueName, TitleIndex, Type, Data, DataSize);
261
262
263 if (KeyName)
264 {
265 HOOK_ROUTINE_FINISH_OBJECTNAME_OPTYPE(REGISTRY, REGISTRYNAME, OP_WRITE);
266 }
267 else
268 {
269 HOOK_ROUTINE_EXIT(rc);
270 }
271}
272
273
274
275/*
276 * HookedNtQueryValueKey()
277 *
278 * Description:
279 * This function mediates the NtQueryValueKey() system service and checks the
280 * provided registry key against the global and current process security policies.
281 *
282 * NOTE: ZwQueryValueKey retrieves information about a key value. [NAR]
283 *
284 * Parameters:
285 * Those of NtQueryValueKey().
286 *
287 * Returns:
288 * STATUS_ACCESS_DENIED if the call does not pass the security policy check.
289 * Otherwise, NTSTATUS returned by NtQueryValueKey().
290 */
291
292NTSTATUS
293NTAPI
294HookedNtQueryValueKey
295(
296 IN HANDLE KeyHandle,
297 IN PUNICODE_STRING ValueName,
298 IN KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass,
299 OUT PVOID KeyValueInformation,
300 IN ULONG KeyValueInformationLength,
301 OUT PULONG ResultLength
302)
303{
304 CHAR REGISTRYNAME[MAX_PATH];
305 WCHAR REGISTRYNAMEW[MAX_PATH];
306 PCHAR FunctionName = "HookedNtQueryValueKey";
307 UNICODE_STRING usValueName;
308 PWSTR KeyName = NULL;
309
310
311 HOOK_ROUTINE_ENTER();
312
313
314 if (VerifyUnicodeString(ValueName, &usValueName) == TRUE)
315 {
316 if ((KeyName = GetNameFromHandle(KeyHandle, REGISTRYNAMEW, sizeof(REGISTRYNAMEW))) != NULL)
317 {
318 _snprintf(REGISTRYNAME, MAX_PATH, "%S\\%S", KeyName, ValueName->Buffer);
319 REGISTRYNAME[MAX_PATH - 1] = 0;
320
321 LOG(LOG_SS_REGISTRY, LOG_PRIORITY_VERBOSE, ("%d %s: %s\n", (ULONG) PsGetCurrentProcessId(), FunctionName, REGISTRYNAME));
322
323
324 if (LearningMode == FALSE)
325 {
326 POLICY_CHECK_OPTYPE_NAME(REGISTRY, OP_READ);
327 }
328 }
329 }
330
331
332 ASSERT(OriginalNtQueryValueKey);
333
334 rc = OriginalNtQueryValueKey(KeyHandle, ValueName, KeyValueInformationClass, KeyValueInformation,
335 KeyValueInformationLength, ResultLength);
336
337
338 if (KeyName)
339 {
340 HOOK_ROUTINE_FINISH_OBJECTNAME_OPTYPE(REGISTRY, REGISTRYNAME, OP_READ);
341 }
342 else
343 {
344 HOOK_ROUTINE_EXIT(rc);
345 }
346}
347
348
349
350/*
351 * InitRegistryHooks()
352 *
353 * Description:
354 * Initializes all the mediated registry operation pointers. The "OriginalFunction" pointers
355 * are initialized by InstallSyscallsHooks() that must be called prior to this function.
356 *
357 * NOTE: Called once during driver initialization (DriverEntry()).
358 *
359 * Parameters:
360 * None.
361 *
362 * Returns:
363 * TRUE to indicate success, FALSE if failed.
364 */
365
366BOOLEAN
367InitRegistryHooks()
368{
369 if ( (OriginalNtCreateKey = (fpZwCreateKey) ZwCalls[ZW_CREATE_KEY_INDEX].OriginalFunction) == NULL)
370 {
371 LOG(LOG_SS_REGISTRY, LOG_PRIORITY_DEBUG, ("InitRegistryHooks: OriginalNtCreateKey is NULL\n"));
372 return FALSE;
373 }
374
375 if ( (OriginalNtOpenKey = (fpZwOpenKey) ZwCalls[ZW_OPEN_KEY_INDEX].OriginalFunction) == NULL)
376 {
377 LOG(LOG_SS_REGISTRY, LOG_PRIORITY_DEBUG, ("InitRegistryHooks: OriginalNtOpenKey is NULL\n"));
378 return FALSE;
379 }
380
381 if ( (OriginalNtDeleteKey = (fpZwDeleteKey) ZwCalls[ZW_DELETE_KEY_INDEX].OriginalFunction) == NULL)
382 {
383 LOG(LOG_SS_REGISTRY, LOG_PRIORITY_DEBUG, ("InitRegistryHooks: OriginalNtDeleteKey is NULL\n"));
384 return FALSE;
385 }
386
387// XXX ZwDeleteValueKey
388/*
389 if ( (OriginalNtSetValueKey = (fpZwSetValueKey) ZwCalls[ZW_SET_VALUE_KEY_INDEX].OriginalFunction) == NULL)
390 {
391 LOG(LOG_SS_REGISTRY, LOG_PRIORITY_DEBUG, ("InitRegistryHooks: OriginalNtSetValueKey is NULL\n"));
392 return FALSE;
393 }
394
395 if ( (OriginalNtQueryValueKey = (fpZwQueryValueKey) ZwCalls[ZW_QUERY_VALUE_KEY_INDEX].OriginalFunction) == NULL)
396 {
397 LOG(LOG_SS_REGISTRY, LOG_PRIORITY_DEBUG, ("InitRegistryHooks: OriginalNtQueryValueKey is NULL\n"));
398 return FALSE;
399 }
400*/
401 return TRUE;
402}
diff --git a/registry.h b/registry.h
new file mode 100644
index 0000000..d4f5756
--- /dev/null
+++ b/registry.h
@@ -0,0 +1,140 @@
1/*
2 * Copyright (c) 2004 Security Architects Corporation. All rights reserved.
3 *
4 * Module Name:
5 *
6 * registry.h
7 *
8 * Abstract:
9 *
10 * This module defines various types used by registry hooking routines.
11 *
12 * Author:
13 *
14 * Eugene Tsyrklevich 20-Feb-2004
15 *
16 * Revision History:
17 *
18 * None.
19 */
20
21
22#ifndef __REGISTRY_H__
23#define __REGISTRY_H__
24
25
26/*
27 * ZwCreateKey creates or opens a registry key object. [NAR]
28 */
29
30typedef NTSTATUS (*fpZwCreateKey) (
31 OUT PHANDLE KeyHandle,
32 IN ACCESS_MASK DesiredAccess,
33 IN POBJECT_ATTRIBUTES ObjectAttributes,
34 IN ULONG TitleIndex,
35 IN PUNICODE_STRING Class OPTIONAL,
36 IN ULONG CreateOptions,
37 OUT PULONG Disposition OPTIONAL
38 );
39
40NTSTATUS
41NTAPI
42HookedNtCreateKey(
43 OUT PHANDLE KeyHandle,
44 IN ACCESS_MASK DesiredAccess,
45 IN POBJECT_ATTRIBUTES ObjectAttributes,
46 IN ULONG TitleIndex,
47 IN PUNICODE_STRING Class OPTIONAL,
48 IN ULONG CreateOptions,
49 OUT PULONG Disposition OPTIONAL
50 );
51
52
53/*
54 * ZwOpenKey opens a registry key object. [NAR]
55 */
56
57typedef NTSTATUS (*fpZwOpenKey) (
58 OUT PHANDLE KeyHandle,
59 IN ACCESS_MASK DesiredAccess,
60 IN POBJECT_ATTRIBUTES ObjectAttributes
61 );
62
63NTSTATUS
64NTAPI
65HookedNtOpenKey(
66 OUT PHANDLE KeyHandle,
67 IN ACCESS_MASK DesiredAccess,
68 IN POBJECT_ATTRIBUTES ObjectAttributes
69 );
70
71
72/*
73 * ZwSetValueKey updates or adds a value to a key. [NAR]
74 */
75
76typedef NTSTATUS (*fpZwSetValueKey) (
77 IN HANDLE KeyHandle,
78 IN PUNICODE_STRING ValueName,
79 IN ULONG TitleIndex,
80 IN ULONG Type,
81 IN PVOID Data,
82 IN ULONG DataSize
83 );
84
85NTSTATUS
86NTAPI
87HookedNtSetValueKey(
88 IN HANDLE KeyHandle,
89 IN PUNICODE_STRING ValueName,
90 IN ULONG TitleIndex,
91 IN ULONG Type,
92 IN PVOID Data,
93 IN ULONG DataSize
94 );
95
96
97/*
98 * ZwQueryValueKey retrieves information about a key value. [NAR]
99 */
100
101typedef NTSTATUS (*fpZwQueryValueKey) (
102 IN HANDLE KeyHandle,
103 IN PUNICODE_STRING ValueName,
104 IN KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass,
105 OUT PVOID KeyValueInformation,
106 IN ULONG KeyValueInformationLength,
107 OUT PULONG ResultLength
108 );
109
110NTSTATUS
111NTAPI
112HookedNtQueryValueKey(
113 IN HANDLE KeyHandle,
114 IN PUNICODE_STRING ValueName,
115 IN KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass,
116 OUT PVOID KeyValueInformation,
117 IN ULONG KeyValueInformationLength,
118 OUT PULONG ResultLength
119 );
120
121
122/*
123 * ZwDeleteKey deletes a key in the registry. [NAR]
124 */
125
126typedef NTSTATUS (*fpZwDeleteKey) (
127 IN HANDLE KeyHandle
128 );
129
130NTSTATUS
131NTAPI
132HookedNtDeleteKey(
133 IN HANDLE KeyHandle
134 );
135
136
137BOOLEAN InitRegistryHooks();
138
139
140#endif /* __REGISTRY_H__ */
diff --git a/resource.h b/resource.h
new file mode 100644
index 0000000..c2e26c9
--- /dev/null
+++ b/resource.h
@@ -0,0 +1,15 @@
1//{{NO_DEPENDENCIES}}
2// Microsoft Visual C++ generated include file.
3// Used by eugene.rc
4//
5
6// Next default values for new objects
7//
8#ifdef APSTUDIO_INVOKED
9#ifndef APSTUDIO_READONLY_SYMBOLS
10#define _APS_NEXT_RESOURCE_VALUE 102
11#define _APS_NEXT_COMMAND_VALUE 40001
12#define _APS_NEXT_CONTROL_VALUE 1000
13#define _APS_NEXT_SYMED_VALUE 101
14#endif
15#endif
diff --git a/section.c b/section.c
new file mode 100644
index 0000000..ba21b3c
--- /dev/null
+++ b/section.c
@@ -0,0 +1,285 @@
1/*
2 * Copyright (c) 2004 Security Architects Corporation. All rights reserved.
3 *
4 * Module Name:
5 *
6 * section.c
7 *
8 * Abstract:
9 *
10 * This module defines various routines used for hooking section objects related routines.
11 * Section objects are objects that can be mapped into the virtual address space of a process.
12 * The Win32 API refers to section objects as file-mapping objects.
13 *
14 * Hooked routines protect "\Device\PhysicalMemory" device from being accessed.
15 *
16 * Author:
17 *
18 * Eugene Tsyrklevich 29-Feb-2004
19 *
20 * Revision History:
21 *
22 * None.
23 */
24
25
26#include <NTDDK.h>
27#include "section.h"
28#include "hookproc.h"
29#include "pathproc.h"
30#include "process.h"
31#include "accessmask.h"
32#include "procname.h"
33#include "learn.h"
34#include "log.h"
35
36
37#ifdef ALLOC_PRAGMA
38#pragma alloc_text (INIT, InitSectionHooks)
39#endif
40
41
42fpZwCreateSection OriginalNtCreateSection = NULL;
43fpZwOpenSection OriginalNtOpenSection = NULL;
44fpZwMapViewOfSection OriginalNtMapViewOfSection = NULL;
45
46
47//XXX make sure people cannot create symlinks to physicalmemory or we at least resolve all of them!
48// http://www.blackhat.com/presentations/bh-usa-03/bh-us-03-rutkowski/bh-us-03-rutkowski-r2.pdf
49
50
51/*
52 * HookedNtCreateSection()
53 *
54 * Description:
55 * This function mediates the NtCreateSection() system service and checks the
56 * provided section name against the global and current process security policies.
57 *
58 * NOTE: ZwCreateSection creates a section object. [NAR]
59 *
60 * Parameters:
61 * Those of NtCreateSection().
62 *
63 * Returns:
64 * STATUS_ACCESS_DENIED if the call does not pass the security policy check.
65 * Otherwise, NTSTATUS returned by NtCreateSection().
66 */
67
68NTSTATUS
69NTAPI
70HookedNtCreateSection
71(
72 OUT PHANDLE SectionHandle,
73 IN ACCESS_MASK DesiredAccess,
74 IN POBJECT_ATTRIBUTES ObjectAttributes,
75 IN PLARGE_INTEGER SectionSize OPTIONAL,
76 IN ULONG Protect,
77 IN ULONG Attributes,
78 IN HANDLE FileHandle
79)
80{
81 PCHAR FunctionName = "HookedNtCreateSection";
82
83
84 HOOK_ROUTINE_START(SECTION);
85
86
87 ASSERT(OriginalNtCreateSection);
88
89 rc = OriginalNtCreateSection(SectionHandle, DesiredAccess, ObjectAttributes, SectionSize,
90 Protect, Attributes, FileHandle);
91
92
93// HOOK_ROUTINE_FINISH(SECTION);
94 if (LearningMode == TRUE)
95 {
96 if (GetPathFromOA(ObjectAttributes, SECTIONNAME, MAX_PATH, DO_NOT_RESOLVE_LINKS))
97 {
98 /*
99 * Special Case.
100 * \KnownDlls\* requests are processed as DLL rules.
101 *
102 * In addition, they are processed even if NtCreateSection() failed because not
103 * all the existing DLLs are "known".
104 */
105
106 if (_strnicmp(SECTIONNAME, "\\KnownDlls\\", 11) == 0)
107 {
108 AddRule(RULE_DLL, SECTIONNAME, Get_SECTION_OperationType(DesiredAccess));
109 }
110 else if (NT_SUCCESS(rc))
111 {
112 AddRule(RULE_SECTION, SECTIONNAME, Get_SECTION_OperationType(DesiredAccess));
113 }
114 }
115 }
116
117 HOOK_ROUTINE_EXIT(rc);
118}
119
120
121
122/*
123 * HookedNtOpenSection()
124 *
125 * Description:
126 * This function mediates the NtOpenSection() system service and checks the
127 * provided section name against the global and current process security policies.
128 *
129 * NOTE: ZwOpenSection opens a section object. [NAR]
130 *
131 * Parameters:
132 * Those of NtOpenSection().
133 *
134 * Returns:
135 * STATUS_ACCESS_DENIED if the call does not pass the security policy check.
136 * Otherwise, NTSTATUS returned by NtOpenSection().
137 */
138
139NTSTATUS
140NTAPI
141HookedNtOpenSection
142(
143 OUT PHANDLE SectionHandle,
144 IN ACCESS_MASK DesiredAccess,
145 IN POBJECT_ATTRIBUTES ObjectAttributes
146)
147{
148 PCHAR FunctionName = "HookedNtOpenSection";
149
150
151 HOOK_ROUTINE_START(SECTION);
152
153
154 ASSERT(OriginalNtOpenSection);
155
156 rc = OriginalNtOpenSection(SectionHandle, DesiredAccess, ObjectAttributes);
157
158
159// HOOK_ROUTINE_FINISH(SECTION);
160 if (LearningMode == TRUE)
161 {
162 if (GetPathFromOA(ObjectAttributes, SECTIONNAME, MAX_PATH, DO_NOT_RESOLVE_LINKS))
163 {
164 /*
165 * Special Case.
166 * \KnownDlls\* requests are processed as DLL rules.
167 *
168 * In addition, they are processed even if NtOpenSection() failed because not
169 * all the existing DLLs are "known".
170 */
171
172 if (_strnicmp(SECTIONNAME, "\\KnownDlls\\", 11) == 0)
173 {
174 AddRule(RULE_DLL, SECTIONNAME, Get_SECTION_OperationType(DesiredAccess));
175 }
176 else if (NT_SUCCESS(rc))
177 {
178 AddRule(RULE_SECTION, SECTIONNAME, Get_SECTION_OperationType(DesiredAccess));
179 }
180 }
181 }
182
183 HOOK_ROUTINE_EXIT(rc);
184}
185
186
187
188/*
189 * HookedNtMapViewOfSection()
190 *
191 * Description:
192 * This function mediates the NtMapViewOfSection() system service and checks the
193 * provided section name against the global and current process security policies.
194 *
195 * NOTE: ZwMapViewOfSection maps a view of a section to a range of virtual addresses. [NAR]
196 *
197 * Parameters:
198 * Those of NtMapViewOfSection().
199 *
200 * Returns:
201 * STATUS_ACCESS_DENIED if the call does not pass the security policy check.
202 * Otherwise, NTSTATUS returned by NtMapViewOfSection().
203 */
204
205NTSTATUS
206NTAPI
207HookedNtMapViewOfSection
208(
209 IN HANDLE SectionHandle,
210 IN HANDLE ProcessHandle,
211 IN OUT PVOID *BaseAddress,
212 IN ULONG ZeroBits,
213 IN ULONG CommitSize,
214 IN OUT PLARGE_INTEGER SectionOffset OPTIONAL,
215 IN OUT PULONG ViewSize,
216 IN SECTION_INHERIT InheritDisposition,
217 IN ULONG AllocationType,
218 IN ULONG Protect
219)
220{
221 CHAR section[512];
222
223
224 HOOK_ROUTINE_ENTER();
225
226// LOG(LOG_SS_SECTION, LOG_PRIORITY_DEBUG, ("%d HookedNtMapViewOfSection: %x %x %x %x\n", (ULONG) PsGetCurrentProcessId(), SectionHandle, ProcessHandle, BaseAddress, CommitSize));
227/*
228 if (GetPathFromOA(ObjectAttributes, section, RESOLVE_LINKS))
229 {
230 LOG(LOG_SS_SECTION, LOG_PRIORITY_DEBUG, ("HookedNtMapViewOfSection: %s\n", section));
231// if (PolicyCheck(&gSecPolicy, key, GetRegistryOperationType(DesiredAccess)) == STATUS_ACCESS_DENIED)
232
233// HOOK_ROUTINE_EXIT( STATUS_ACCESS_DENIED );
234 }
235*/
236
237 ASSERT(OriginalNtMapViewOfSection);
238
239 rc = OriginalNtMapViewOfSection(SectionHandle, ProcessHandle, BaseAddress, ZeroBits, CommitSize,
240 SectionOffset, ViewSize, InheritDisposition, AllocationType, Protect);
241
242 HOOK_ROUTINE_EXIT(rc);
243}
244
245
246
247/*
248 * InitSectionHooks()
249 *
250 * Description:
251 * Initializes all the mediated section object operation pointers. The "OriginalFunction" pointers
252 * are initialized by InstallSyscallsHooks() that must be called prior to this function.
253 *
254 * NOTE: Called once during driver initialization (DriverEntry()).
255 *
256 * Parameters:
257 * None.
258 *
259 * Returns:
260 * TRUE to indicate success, FALSE if failed.
261 */
262
263BOOLEAN
264InitSectionHooks()
265{
266 if ( (OriginalNtCreateSection = (fpZwCreateSection) ZwCalls[ZW_CREATE_SECTION_INDEX].OriginalFunction) == NULL)
267 {
268 LOG(LOG_SS_SECTION, LOG_PRIORITY_DEBUG, ("InitSectionHooks: OriginalNtCreateSection is NULL\n"));
269 return FALSE;
270 }
271
272 if ( (OriginalNtOpenSection = (fpZwOpenSection) ZwCalls[ZW_OPEN_SECTION_INDEX].OriginalFunction) == NULL)
273 {
274 LOG(LOG_SS_SECTION, LOG_PRIORITY_DEBUG, ("InitSectionHooks: OriginalNtOpenSection is NULL\n"));
275 return FALSE;
276 }
277/*
278 if ((OriginalNtMapViewOfSection = (fpZwMapViewOfSection) ZwCalls[ZW_MAPVIEW_SECTION_INDEX].OriginalFunction) == NULL)
279 {
280 LOG(LOG_SS_SECTION, LOG_PRIORITY_DEBUG, ("InitSectionHooks: OriginalNtMapViewOfSection is NULL\n"));
281 return FALSE;
282 }
283*/
284 return TRUE;
285}
diff --git a/section.h b/section.h
new file mode 100644
index 0000000..7e41076
--- /dev/null
+++ b/section.h
@@ -0,0 +1,112 @@
1/*
2 * Copyright (c) 2004 Security Architects Corporation. All rights reserved.
3 *
4 * Module Name:
5 *
6 * section.h
7 *
8 * Abstract:
9 *
10 * This module defines various types used by section hooking related routines.
11 *
12 * Author:
13 *
14 * Eugene Tsyrklevich 29-Feb-2004
15 *
16 * Revision History:
17 *
18 * None.
19 */
20
21#ifndef __MEMORY_H__
22#define __MEMORY_H__
23
24
25
26/*
27 * "Section objects are objects that can be mapped into the virtual address space of a process.
28 * The Win32 API refers to section objects as file-mapping objects.
29 *
30 * ZwOpenSection opens a section object." [NAR]
31 */
32
33typedef NTSTATUS (*fpZwOpenSection) (
34 OUT PHANDLE SectionHandle,
35 IN ACCESS_MASK DesiredAccess,
36 IN POBJECT_ATTRIBUTES ObjectAttributes
37 );
38
39
40NTSTATUS
41NTAPI
42HookedNtOpenSection(
43 OUT PHANDLE SectionHandle,
44 IN ACCESS_MASK DesiredAccess,
45 IN POBJECT_ATTRIBUTES ObjectAttributes
46 );
47
48
49/*
50 * ZwCreateSection creates a section object. [NAR]
51 */
52
53typedef NTSTATUS (*fpZwCreateSection) (
54 OUT PHANDLE SectionHandle,
55 IN ACCESS_MASK DesiredAccess,
56 IN POBJECT_ATTRIBUTES ObjectAttributes,
57 IN PLARGE_INTEGER SectionSize OPTIONAL,
58 IN ULONG Protect,
59 IN ULONG Attributes,
60 IN HANDLE FileHandle
61 );
62
63NTSTATUS
64NTAPI
65HookedNtCreateSection(
66 OUT PHANDLE SectionHandle,
67 IN ACCESS_MASK DesiredAccess,
68 IN POBJECT_ATTRIBUTES ObjectAttributes,
69 IN PLARGE_INTEGER SectionSize OPTIONAL,
70 IN ULONG Protect,
71 IN ULONG Attributes,
72 IN HANDLE FileHandle
73 );
74
75
76/*
77 * ZwMapViewOfSection maps a view of a section to a range of virtual addresses. [NAR]
78 */
79
80typedef NTSTATUS (*fpZwMapViewOfSection) (
81 IN HANDLE SectionHandle,
82 IN HANDLE ProcessHandle,
83 IN OUT PVOID *BaseAddress,
84 IN ULONG ZeroBits,
85 IN ULONG CommitSize,
86 IN OUT PLARGE_INTEGER SectionOffset OPTIONAL,
87 IN OUT PULONG ViewSize,
88 IN SECTION_INHERIT InheritDisposition,
89 IN ULONG AllocationType,
90 IN ULONG Protect
91 );
92
93NTSTATUS
94NTAPI
95HookedNtMapViewOfSection(
96 IN HANDLE SectionHandle,
97 IN HANDLE ProcessHandle,
98 IN OUT PVOID *BaseAddress,
99 IN ULONG ZeroBits,
100 IN ULONG CommitSize,
101 IN OUT PLARGE_INTEGER SectionOffset OPTIONAL,
102 IN OUT PULONG ViewSize,
103 IN SECTION_INHERIT InheritDisposition,
104 IN ULONG AllocationType,
105 IN ULONG Protect
106 );
107
108
109BOOLEAN InitSectionHooks();
110
111
112#endif /* __MEMORY_H__ */
diff --git a/semaphore.c b/semaphore.c
new file mode 100644
index 0000000..fe12258
--- /dev/null
+++ b/semaphore.c
@@ -0,0 +1,161 @@
1/*
2 * Copyright (c) 2004 Security Architects Corporation. All rights reserved.
3 *
4 * Module Name:
5 *
6 * semaphore.c
7 *
8 * Abstract:
9 *
10 * This module implements various semaphore hooking routines.
11 *
12 * Author:
13 *
14 * Eugene Tsyrklevich 09-Mar-2004
15 *
16 * Revision History:
17 *
18 * None.
19 */
20
21
22#include <NTDDK.h>
23#include "semaphore.h"
24#include "policy.h"
25#include "pathproc.h"
26#include "hookproc.h"
27#include "accessmask.h"
28#include "learn.h"
29#include "log.h"
30
31
32#ifdef ALLOC_PRAGMA
33#pragma alloc_text (INIT, InitSemaphoreHooks)
34#endif
35
36
37fpZwCreateSemaphore OriginalNtCreateSemaphore = NULL;
38fpZwOpenSemaphore OriginalNtOpenSemaphore = NULL;
39
40
41
42/*
43 * HookedNtCreateSemaphore()
44 *
45 * Description:
46 * This function mediates the NtCreateSemaphore() system service and checks the
47 * provided semaphore name against the global and current process security policies.
48 *
49 * NOTE: ZwOpenSemaphore opens a semaphore object. [NAR]
50 *
51 * Parameters:
52 * Those of NtCreateSemaphore().
53 *
54 * Returns:
55 * STATUS_ACCESS_DENIED if the call does not pass the security policy check.
56 * Otherwise, NTSTATUS returned by NtCreateSemaphore().
57 */
58
59NTSTATUS
60NTAPI
61HookedNtCreateSemaphore
62(
63 OUT PHANDLE SemaphoreHandle,
64 IN ACCESS_MASK DesiredAccess,
65 IN POBJECT_ATTRIBUTES ObjectAttributes,
66 IN LONG InitialCount,
67 IN LONG MaximumCount
68)
69{
70 PCHAR FunctionName = "HookedNtCreateSemaphore";
71
72
73 HOOK_ROUTINE_START(SEMAPHORE);
74
75
76 ASSERT(OriginalNtCreateSemaphore);
77
78 rc = OriginalNtCreateSemaphore(SemaphoreHandle, DesiredAccess, ObjectAttributes, InitialCount, MaximumCount);
79
80
81 HOOK_ROUTINE_FINISH(SEMAPHORE);
82}
83
84
85
86
87/*
88 * HookedNtOpenSemaphore()
89 *
90 * Description:
91 * This function mediates the NtOpenSemaphore() system service and checks the
92 * provided semaphore name against the global and current process security policies.
93 *
94 * NOTE: ZwOpenSemaphore opens a semaphore object. [NAR]
95 *
96 * Parameters:
97 * Those of NtOpenSemaphore().
98 *
99 * Returns:
100 * STATUS_ACCESS_DENIED if the call does not pass the security policy check.
101 * Otherwise, NTSTATUS returned by NtOpenSemaphore().
102 */
103
104NTSTATUS
105NTAPI
106HookedNtOpenSemaphore
107(
108 OUT PHANDLE SemaphoreHandle,
109 IN ACCESS_MASK DesiredAccess,
110 IN POBJECT_ATTRIBUTES ObjectAttributes
111)
112{
113 PCHAR FunctionName = "HookedNtOpenSemaphore";
114
115
116 HOOK_ROUTINE_START(SEMAPHORE);
117
118
119 ASSERT(OriginalNtOpenSemaphore);
120
121 rc = OriginalNtOpenSemaphore(SemaphoreHandle, DesiredAccess, ObjectAttributes);
122
123
124 HOOK_ROUTINE_FINISH(SEMAPHORE);
125}
126
127
128
129/*
130 * InitSemaphoreHooks()
131 *
132 * Description:
133 * Initializes all the mediated semaphore operation pointers. The "OriginalFunction" pointers
134 * are initialized by InstallSyscallsHooks() that must be called prior to this function.
135 *
136 * NOTE: Called once during driver initialization (DriverEntry()).
137 *
138 * Parameters:
139 * None.
140 *
141 * Returns:
142 * TRUE to indicate success, FALSE if failed.
143 */
144
145BOOLEAN
146InitSemaphoreHooks()
147{
148 if ( (OriginalNtCreateSemaphore = (fpZwCreateSemaphore) ZwCalls[ZW_CREATE_SEMAPHORE_INDEX].OriginalFunction) == NULL)
149 {
150 LOG(LOG_SS_SEMAPHORE, LOG_PRIORITY_DEBUG, ("InstallSemaphoreHooks: OriginalNtCreateSemaphore is NULL\n"));
151 return FALSE;
152 }
153
154 if ( (OriginalNtOpenSemaphore = (fpZwOpenSemaphore) ZwCalls[ZW_OPEN_SEMAPHORE_INDEX].OriginalFunction) == NULL)
155 {
156 LOG(LOG_SS_SEMAPHORE, LOG_PRIORITY_DEBUG, ("InstallSemaphoreHooks: OriginalNtOpenSemaphore is NULL\n"));
157 return FALSE;
158 }
159
160 return TRUE;
161}
diff --git a/semaphore.h b/semaphore.h
new file mode 100644
index 0000000..856095a
--- /dev/null
+++ b/semaphore.h
@@ -0,0 +1,69 @@
1/*
2 * Copyright (c) 2004 Security Architects Corporation. All rights reserved.
3 *
4 * Module Name:
5 *
6 * semaphore.h
7 *
8 * Abstract:
9 *
10 * This module defines various types used by semaphore hooking routines.
11 *
12 * Author:
13 *
14 * Eugene Tsyrklevich 09-Mar-2004
15 *
16 * Revision History:
17 *
18 * None.
19 */
20
21
22#ifndef __SEMAPHORE_H__
23#define __SEMAPHORE_H__
24
25
26
27/*
28 * ZwCreateSemaphore creates or opens a semaphore object. [NAR]
29 */
30
31typedef NTSTATUS (*fpZwCreateSemaphore) (
32 OUT PHANDLE SemaphoreHandle,
33 IN ACCESS_MASK DesiredAccess,
34 IN POBJECT_ATTRIBUTES ObjectAttributes,
35 IN LONG InitialCount,
36 IN LONG MaximumCount
37 );
38
39NTSTATUS HookedNtCreateSemaphore(
40 OUT PHANDLE SemaphoreHandle,
41 IN ACCESS_MASK DesiredAccess,
42 IN POBJECT_ATTRIBUTES ObjectAttributes,
43 IN LONG InitialCount,
44 IN LONG MaximumCount
45 );
46
47
48/*
49 * ZwOpenSemaphore opens a semaphore object. [NAR]
50 */
51
52typedef NTSTATUS (*fpZwOpenSemaphore) (
53 OUT PHANDLE SemaphoreHandle,
54 IN ACCESS_MASK DesiredAccess,
55 IN POBJECT_ATTRIBUTES ObjectAttributes
56 );
57
58NTSTATUS HookedNtOpenSemaphore(
59 OUT PHANDLE SemaphoreHandle,
60 IN ACCESS_MASK DesiredAccess,
61 IN POBJECT_ATTRIBUTES ObjectAttributes
62 );
63
64
65
66BOOLEAN InitSemaphoreHooks();
67
68
69#endif /* __SEMAPHORE_H__ */
diff --git a/symlink.c b/symlink.c
new file mode 100644
index 0000000..237ac97
--- /dev/null
+++ b/symlink.c
@@ -0,0 +1,185 @@
1/*
2 * Copyright (c) 2004 Security Architects Corporation. All rights reserved.
3 *
4 * Module Name:
5 *
6 * symlink.c
7 *
8 * Abstract:
9 *
10 * This module implements various symbolic link object hooking routines.
11 *
12 * Author:
13 *
14 * Eugene Tsyrklevich 25-Mar-2004
15 *
16 * Revision History:
17 *
18 * None.
19 */
20
21
22#include "symlink.h"
23#include "media.h"
24
25
26#ifdef ALLOC_PRAGMA
27#pragma alloc_text (INIT, InitSymlinkHooks)
28#endif
29
30
31fpZwCreateSymbolicLinkObject OriginalNtCreateSymbolicLinkObject = NULL;
32fpZwOpenSymbolicLinkObject OriginalNtOpenSymbolicLinkObject = NULL;
33
34
35/*
36 * HookedNtCreateSymbolicLinkObject()
37 *
38 * Description:
39 * This function mediates the NtCreateSymbolicLinkObject() system service and checks the
40 * provided symbolic link object name against the global and current process security policies.
41 *
42 * NOTE: ZwCreateSymbolicLinkObject creates or opens a symbolic link object. [NAR]
43 *
44 * Parameters:
45 * Those of NtCreateSymbolicLinkObject().
46 *
47 * Returns:
48 * STATUS_ACCESS_DENIED if the call does not pass the security policy check.
49 * Otherwise, NTSTATUS returned by NtCreateSymbolicLinkObject().
50 */
51
52NTSTATUS
53NTAPI
54HookedNtCreateSymbolicLinkObject
55(
56 OUT PHANDLE SymbolicLinkHandle,
57 IN ACCESS_MASK DesiredAccess,
58 IN POBJECT_ATTRIBUTES ObjectAttributes,
59 IN PUNICODE_STRING TargetName
60)
61{
62 PCHAR FunctionName = "HookedNtCreateSymbolicLinkObject";
63 CHAR SYMLINKNAME[MAX_PATH];
64
65
66 HOOK_ROUTINE_ENTER();
67
68
69 if (LearningMode == FALSE && GetPathFromOA(ObjectAttributes, SYMLINKNAME, MAX_PATH, RESOLVE_LINKS))
70 {
71 /* TargetName is not verified to be valid but it's ok as we don't use it for anything but printing (in debugging mode only) */
72 if (TargetName)
73 LOG(LOG_SS_SYMLINK, LOG_PRIORITY_VERBOSE, ("%d HookedNtCreateSymbolicLinkObject: %s -> %S\n", (ULONG) PsGetCurrentProcessId(), SYMLINKNAME, TargetName->Buffer));
74 else
75 LOG(LOG_SS_SYMLINK, LOG_PRIORITY_VERBOSE, ("%d HookedNtCreateSymbolicLinkObject: %s ->.\n", (ULONG) PsGetCurrentProcessId(), SYMLINKNAME));
76
77
78 POLICY_CHECK_OPTYPE_NAME(SYMLINK, Get_SYMLINK_OperationType(DesiredAccess));
79 }
80
81
82 ASSERT(OriginalNtCreateSymbolicLinkObject);
83
84 rc = OriginalNtCreateSymbolicLinkObject(SymbolicLinkHandle, DesiredAccess, ObjectAttributes, TargetName);
85
86
87#if HOOK_MEDIA
88 /* removable media hook */
89 if (LearningMode == FALSE && NT_SUCCESS(rc) && KeGetPreviousMode() == KernelMode)
90 {
91 MonitorDriveLinks(SYMLINKNAME);
92 }
93#endif
94
95
96 HOOK_ROUTINE_FINISH(SYMLINK);
97}
98
99
100
101/*
102 * HookedNtOpenSymbolicLinkObject()
103 *
104 * Description:
105 * This function mediates the NtOpenSymbolicLinkObject() system service and checks the
106 * provided symbolic link object name against the global and current process security policies.
107 *
108 * NOTE: ZwOpenSymbolicLinkObject opens a symbolic link object. [NAR]
109 *
110 * Parameters:
111 * Those of NtOpenSymbolicLinkObject().
112 *
113 * Returns:
114 * STATUS_ACCESS_DENIED if the call does not pass the security policy check.
115 * Otherwise, NTSTATUS returned by NtOpenSymbolicLinkObject().
116 */
117
118NTSTATUS
119NTAPI
120HookedNtOpenSymbolicLinkObject
121(
122 OUT PHANDLE SymbolicLinkHandle,
123 IN ACCESS_MASK DesiredAccess,
124 IN POBJECT_ATTRIBUTES ObjectAttributes
125)
126{
127 PCHAR FunctionName = "HookedNtOpenSymbolicLinkObject";
128 CHAR SYMLINKNAME[MAX_PATH];
129
130
131 HOOK_ROUTINE_ENTER();
132
133
134 /* Cannot use RESOLVE_LINKS! (to avoid infinite recursion) */
135 if (LearningMode == FALSE && GetPathFromOA(ObjectAttributes, SYMLINKNAME, MAX_PATH, DO_NOT_RESOLVE_LINKS))
136 {
137 POLICY_CHECK_OPTYPE_NAME(SYMLINK, Get_SYMLINK_OperationType(DesiredAccess));
138 }
139
140
141 ASSERT(OriginalNtOpenSymbolicLinkObject);
142
143 rc = OriginalNtOpenSymbolicLinkObject(SymbolicLinkHandle, DesiredAccess, ObjectAttributes);
144
145
146 HOOK_ROUTINE_FINISH(SYMLINK);
147}
148
149
150
151/*
152 * InitSymlinkHooks()
153 *
154 * Description:
155 * Initializes all the mediated symbolic link object operation pointers. The "OriginalFunction" pointers
156 * are initialized by InstallSyscallsHooks() that must be called prior to this function.
157 *
158 * NOTE: Called once during driver initialization (DriverEntry()).
159 *
160 * Parameters:
161 * None.
162 *
163 * Returns:
164 * TRUE to indicate success, FALSE if failed.
165 */
166
167BOOLEAN
168InitSymlinkHooks()
169{
170 if ( (OriginalNtCreateSymbolicLinkObject = (fpZwCreateSymbolicLinkObject) ZwCalls[ZW_CREATE_SYMLINK_INDEX].OriginalFunction) == NULL)
171 {
172 LOG(LOG_SS_SYMLINK, LOG_PRIORITY_DEBUG, ("InitSymlinkHooks: OriginalNtCreateSymbolicLinkObject is NULL\n"));
173 return FALSE;
174 }
175/*
176 disabled due to performance issues - this function is called by every system call (from ResolveFilename)
177
178 if ( (OriginalNtOpenSymbolicLinkObject = (fpZwOpenSymbolicLinkObject) ZwCalls[ZW_OPEN_SYMLINK_INDEX].OriginalFunction) == NULL)
179 {
180 LOG(LOG_SS_SYMLINK, LOG_PRIORITY_DEBUG, ("InitSymlinkHooks: OriginalNtOpenSymbolicLinkObject is NULL\n"));
181 return FALSE;
182 }
183*/
184 return TRUE;
185}
diff --git a/symlink.h b/symlink.h
new file mode 100644
index 0000000..2a6abf9
--- /dev/null
+++ b/symlink.h
@@ -0,0 +1,78 @@
1/*
2 * Copyright (c) 2004 Security Architects Corporation. All rights reserved.
3 *
4 * Module Name:
5 *
6 * symlink.h
7 *
8 * Abstract:
9 *
10 * This module defines various types used by symbolic link object hooking routines.
11 *
12 * Author:
13 *
14 * Eugene Tsyrklevich 25-Mar-2004
15 *
16 * Revision History:
17 *
18 * None.
19 */
20
21
22#ifndef __SYMLINK_H__
23#define __SYMLINK_H__
24
25
26#include <NTDDK.h>
27#include "policy.h"
28#include "pathproc.h"
29#include "hookproc.h"
30#include "accessmask.h"
31#include "learn.h"
32#include "log.h"
33
34
35/*
36 * ZwCreateSymbolicLinkObject creates or opens a symbolic link object. [NAR]
37 */
38
39typedef NTSTATUS (*fpZwCreateSymbolicLinkObject) (
40 OUT PHANDLE SymbolicLinkHandle,
41 IN ACCESS_MASK DesiredAccess,
42 IN POBJECT_ATTRIBUTES ObjectAttributes,
43 IN PUNICODE_STRING TargetName
44 );
45
46NTSTATUS
47NTAPI
48HookedNtCreateSymbolicLinkObject(
49 OUT PHANDLE SymbolicLinkHandle,
50 IN ACCESS_MASK DesiredAccess,
51 IN POBJECT_ATTRIBUTES ObjectAttributes,
52 IN PUNICODE_STRING TargetName
53 );
54
55
56/*
57 * ZwOpenSymbolicLinkObject opens a symbolic link object. [NAR]
58 */
59
60typedef NTSTATUS (*fpZwOpenSymbolicLinkObject) (
61 OUT PHANDLE SymbolicLinkHandle,
62 IN ACCESS_MASK DesiredAccess,
63 IN POBJECT_ATTRIBUTES ObjectAttributes
64 );
65
66NTSTATUS
67NTAPI
68HookedNtOpenSymbolicLinkObject(
69 OUT PHANDLE SymbolicLinkHandle,
70 IN ACCESS_MASK DesiredAccess,
71 IN POBJECT_ATTRIBUTES ObjectAttributes
72 );
73
74
75BOOLEAN InitSymlinkHooks();
76
77
78#endif /* __SYMLINK_H__ */
diff --git a/sysinfo.c b/sysinfo.c
new file mode 100644
index 0000000..5e08179
--- /dev/null
+++ b/sysinfo.c
@@ -0,0 +1,197 @@
1/*
2 * Copyright (c) 2004 Security Architects Corporation. All rights reserved.
3 *
4 * Module Name:
5 *
6 * sysinfo.c
7 *
8 * Abstract:
9 *
10 * This module defines various routines used for hooking ZwSetSystemInformation() routine.
11 * ZwSetSystemInformation's SystemLoadAndCallImage and SystemLoadImage parameters can be used
12 * to load code into kernel address space.
13 *
14 * Author:
15 *
16 * Eugene Tsyrklevich 01-Mar-2004
17 *
18 * Revision History:
19 *
20 * None.
21 */
22
23
24#include <NTDDK.h>
25#include "sysinfo.h"
26#include "hookproc.h"
27#include "procname.h"
28#include "learn.h"
29#include "time.h"
30#include "log.h"
31
32
33#ifdef ALLOC_PRAGMA
34#pragma alloc_text (INIT, InitSysInfoHooks)
35#endif
36
37
38fpZwSetSystemInformation OriginalNtSetSystemInformation = NULL;
39
40
41/*
42 * HookedNtSetSystemInformation()
43 *
44 * Description:
45 * This function mediates the NtSetSystemInformation() system service and disallows access to
46 * Information Classes 26 (SystemLoadImage) and 38 (SystemLoadAndCallImage) which allow
47 * applications to load code into kernel memory.
48 *
49 * NOTE: ZwSetSystemInformation sets information that affects the operation of the system. [NAR]
50 *
51 * Parameters:
52 * Those of NtSetSystemInformation().
53 *
54 * Returns:
55 * STATUS_ACCESS_DENIED if Information Class 26 or 38 is used.
56 * Otherwise, NTSTATUS returned by NtSetSystemInformation().
57 */
58
59NTSTATUS
60NTAPI
61HookedNtSetSystemInformation
62(
63 IN SYSTEM_INFORMATION_CLASS SystemInformationClass,
64 IN OUT PVOID SystemInformation,
65 IN ULONG SystemInformationLength
66)
67{
68 PCHAR FunctionName = "HookedNtSetSystemInformation";
69
70
71 HOOK_ROUTINE_ENTER();
72
73
74 if (SystemInformationClass == SystemLoadImage ||
75 SystemInformationClass == SystemLoadAndCallImage)
76 {
77 UNICODE_STRING usImageName;
78 ANSI_STRING asImageName;
79 CHAR DriverNameUnresolved[MAX_PATH];
80
81
82 if (!VerifyUnicodeString(SystemInformation, &usImageName))
83 {
84 LOG(LOG_SS_PORT, LOG_PRIORITY_DEBUG, ("%s: VerifyUnicodeString failed\n", FunctionName));
85 HOOK_ROUTINE_EXIT( STATUS_ACCESS_DENIED );
86 }
87
88
89 if (_snprintf(DriverNameUnresolved, MAX_PATH, "%S", usImageName.Buffer) < 0)
90 {
91 LOG(LOG_SS_DRIVER, LOG_PRIORITY_DEBUG, ("%s: Driver name '%S' is too long\n", FunctionName, usImageName.Buffer));
92 HOOK_ROUTINE_EXIT( STATUS_ACCESS_DENIED );
93 }
94
95
96 LOG(LOG_SS_SYSINFO, LOG_PRIORITY_VERBOSE, ("%d %s: SystemLoad %d %s\n", (ULONG) PsGetCurrentProcessId(), FunctionName, SystemInformationClass, DriverNameUnresolved));
97
98
99 /*
100 * Verify the image name against the security policy
101 */
102
103 if (LearningMode == FALSE)
104 {
105 CHAR DRIVERNAME[MAX_PATH];
106
107
108 FixupFilename(DriverNameUnresolved, DRIVERNAME, MAX_PATH);
109
110 LOG(LOG_SS_SYSINFO, LOG_PRIORITY_VERBOSE, ("%d %s: SystemLoad %d %s\n", (ULONG) PsGetCurrentProcessId(), FunctionName, SystemInformationClass, DRIVERNAME));
111
112 POLICY_CHECK_OPTYPE_NAME(DRIVER, OP_LOAD);
113 }
114 else
115 {
116 AddRule(RULE_DRIVER, DriverNameUnresolved, OP_LOAD);
117 }
118 }
119 else if (SystemInformationClass == SystemUnloadImage)
120 {
121 LOG(LOG_SS_SYSINFO, LOG_PRIORITY_VERBOSE, ("%d HookedNtSetSystemInformation: SystemUnloadImage %x\n", (ULONG) PsGetCurrentProcessId(), SystemInformation));
122 }
123 else if (SystemInformationClass == SystemTimeAdjustment)
124 {
125 LOG(LOG_SS_SYSINFO, LOG_PRIORITY_VERBOSE, ("%d HookedNtSetSystemInformation: SystemTimeAdjustment\n", (ULONG) PsGetCurrentProcessId()));
126
127
128 if (LearningMode == FALSE)
129 {
130 PCHAR TIMENAME = NULL; /* allow the use of POLICY_CHECK_OPTYPE_NAME() macro */
131
132 POLICY_CHECK_OPTYPE_NAME(TIME, OP_TIME_CHANGE);
133 }
134 else if (LearningMode == TRUE)
135 {
136 AddRule(RULE_TIME, NULL, OP_TIME_CHANGE);
137 }
138 }
139 else if (SystemInformationClass == SystemProcessesAndThreadsInformation)
140 {
141 LOG(LOG_SS_SYSINFO, LOG_PRIORITY_DEBUG, ("%d HookedNtSetSystemInformation: SystemProcessesAndThreadsInformation\n", (ULONG) PsGetCurrentProcessId()));
142 }
143 else if (SystemInformationClass == SystemModuleInformation)
144 {
145 LOG(LOG_SS_SYSINFO, LOG_PRIORITY_DEBUG, ("%d HookedNtSetSystemInformation: SystemModuleInformation\n", (ULONG) PsGetCurrentProcessId()));
146 }
147 else if (SystemInformationClass == SystemCreateSession)
148 {
149 LOG(LOG_SS_SYSINFO, LOG_PRIORITY_VERBOSE, ("%d HookedNtSetSystemInformation: SystemCreateSession %x %x\n", (ULONG) PsGetCurrentProcessId(), SystemInformation, *(PULONG) SystemInformation));
150 }
151 else if (SystemInformationClass == SystemDeleteSession)
152 {
153 LOG(LOG_SS_SYSINFO, LOG_PRIORITY_VERBOSE, ("%d HookedNtSetSystemInformation: SystemDeleteSession %x %x\n", (ULONG) PsGetCurrentProcessId(), SystemInformation, *(PULONG) SystemInformation));
154 }
155 else if (SystemInformationClass == SystemSessionProcessesInformation)
156 {
157 LOG(LOG_SS_SYSINFO, LOG_PRIORITY_DEBUG, ("%d HookedNtSetSystemInformation: SystemSessionProcessesInformation\n", (ULONG) PsGetCurrentProcessId()));
158 }
159
160
161 ASSERT(OriginalNtSetSystemInformation);
162
163 rc = OriginalNtSetSystemInformation(SystemInformationClass, SystemInformation, SystemInformationLength);
164
165
166 HOOK_ROUTINE_EXIT(rc);
167}
168
169
170
171/*
172 * InitSysInfoHooks()
173 *
174 * Description:
175 * Initializes all the mediated system information operation pointers. The "OriginalFunction" pointers
176 * are initialized by InstallSyscallsHooks() that must be called prior to this function.
177 *
178 * NOTE: Called once during driver initialization (DriverEntry()).
179 *
180 * Parameters:
181 * None.
182 *
183 * Returns:
184 * TRUE to indicate success, FALSE if failed.
185 */
186
187BOOLEAN
188InitSysInfoHooks()
189{
190 if ((OriginalNtSetSystemInformation = (fpZwSetSystemInformation) ZwCalls[ZW_SET_SYSTEM_INFORMATION_INDEX].OriginalFunction) == NULL)
191 {
192 LOG(LOG_SS_SYSINFO, LOG_PRIORITY_DEBUG, ("InitSysInfoHooks: OriginalNtSetSystemInformation is NULL\n"));
193 return FALSE;
194 }
195
196 return TRUE;
197}
diff --git a/sysinfo.h b/sysinfo.h
new file mode 100644
index 0000000..60a0a9a
--- /dev/null
+++ b/sysinfo.h
@@ -0,0 +1,190 @@
1/*
2 * Copyright (c) 2004 Security Architects Corporation. All rights reserved.
3 *
4 * Module Name:
5 *
6 * sysinfo.h
7 *
8 * Abstract:
9 *
10 * This module defines various types used by ZwSetSystemInformation() hooking routines.
11 * ZwSetSystemInformation's SystemLoadAndCallImage and SystemLoadImage parameters can be used
12 * to load code into kernel address space.
13 *
14 * Author:
15 *
16 * Eugene Tsyrklevich 01-Mar-2004
17 *
18 * Revision History:
19 *
20 * None.
21 */
22
23
24#ifndef __SYSINFO_H__
25#define __SYSINFO_H__
26
27
28
29/*
30 * ZwSetSystemInformation sets information that affects the operation of the system. [NAR]
31 */
32 // # Query Set
33typedef enum _SYSTEM_INFORMATION_CLASS {
34 SystemBasicInformation, // 0 Y N
35 SystemProcessorInformation, // 1 Y N
36 SystemPerformanceInformation, // 2 Y N
37 SystemTimeOfDayInformation, // 3 Y N
38 SystemNotImplemented1, // 4 Y N // SystemPathInformation
39 SystemProcessesAndThreadsInformation, // 5 Y N
40 SystemCallCounts, // 6 Y N
41 SystemConfigurationInformation, // 7 Y N
42 SystemProcessorTimes, // 8 Y N
43 SystemGlobalFlag, // 9 Y Y
44 SystemNotImplemented2, // 10 Y N // SystemCallTimeInformation
45 SystemModuleInformation, // 11 Y N
46 SystemLockInformation, // 12 Y N
47 SystemNotImplemented3, // 13 Y N // SystemStackTraceInformation
48 SystemNotImplemented4, // 14 Y N // SystemPagedPoolInformation
49 SystemNotImplemented5, // 15 Y N // SystemNonPagedPoolInformation
50 SystemHandleInformation, // 16 Y N
51 SystemObjectInformation, // 17 Y N
52 SystemPagefileInformation, // 18 Y N
53 SystemInstructionEmulationCounts, // 19 Y N
54 SystemInvalidInfoClass1, // 20
55 SystemCacheInformation, // 21 Y Y
56 SystemPoolTagInformation, // 22 Y N
57 SystemProcessorStatistics, // 23 Y N
58 SystemDpcInformation, // 24 Y Y
59 SystemNotImplemented6, // 25 Y N // SystemFullMemoryInformation
60 SystemLoadImage, // 26 N Y // SystemLoadGdiDriverInformation
61 SystemUnloadImage, // 27 N Y
62 SystemTimeAdjustment, // 28 Y Y
63 SystemNotImplemented7, // 29 Y N // SystemSummaryMemoryInformation
64 SystemNotImplemented8, // 30 Y N // SystemNextEventIdInformation
65 SystemNotImplemented9, // 31 Y N // SystemEventIdsInformation
66 SystemCrashDumpInformation, // 32 Y N
67 SystemExceptionInformation, // 33 Y N
68 SystemCrashDumpStateInformation, // 34 Y Y/N
69 SystemKernelDebuggerInformation, // 35 Y N
70 SystemContextSwitchInformation, // 36 Y N
71 SystemRegistryQuotaInformation, // 37 Y Y
72 SystemLoadAndCallImage, // 38 N Y // SystemExtendServiceTableInformation
73 SystemPrioritySeparation, // 39 N Y
74 SystemNotImplemented10, // 40 Y N // SystemPlugPlayBusInformation
75 SystemNotImplemented11, // 41 Y N // SystemDockInformation
76 SystemInvalidInfoClass2, // 42 // SystemPowerInformation
77 SystemInvalidInfoClass3, // 43 // SystemProcessorSpeedInformation
78 SystemTimeZoneInformation, // 44 Y N
79 SystemLookasideInformation, // 45 Y N
80 SystemSetTimeSlipEvent, // 46 N Y
81 SystemCreateSession, // 47 N Y
82 SystemDeleteSession, // 48 N Y
83 SystemInvalidInfoClass4, // 49
84 SystemRangeStartInformation, // 50 Y N
85 SystemVerifierInformation, // 51 Y Y
86 SystemAddVerifier, // 52 N Y
87 SystemSessionProcessesInformation // 53 Y N
88} SYSTEM_INFORMATION_CLASS;
89
90
91/*
92 * Information Class 5
93 */
94
95typedef enum {
96 StateInitialized,
97 StateReady,
98 StateRunning,
99 StateStandby,
100 StateTerminated,
101 StateWait,
102 StateTransition,
103 StateUnknown
104} THREAD_STATE;
105
106typedef struct _SYSTEM_THREADS {
107 LARGE_INTEGER KernelTime;
108 LARGE_INTEGER UserTime;
109 LARGE_INTEGER CreateTime;
110 ULONG WaitTime;
111 PVOID StartAddress;
112 CLIENT_ID ClientId;
113 KPRIORITY Priority;
114 KPRIORITY BasePriority;
115 ULONG ContextSwitchCount;
116 THREAD_STATE State;
117 KWAIT_REASON WaitReason;
118} SYSTEM_THREADS, *PSYSTEM_THREADS;
119
120typedef struct _SYSTEM_PROCESSES {
121 ULONG NextEntryDelta;
122 ULONG ThreadCount;
123 ULONG Reserved1[6];
124 LARGE_INTEGER CreateTime;
125 LARGE_INTEGER UserTime;
126 LARGE_INTEGER KernelTime;
127 UNICODE_STRING ProcessName;
128 KPRIORITY BasePriority;
129 ULONG ProcessId;
130 ULONG InheritedFromProcessId;
131 ULONG HandleCount;
132 ULONG Reserved2[2];
133 VM_COUNTERS VmCounters;
134 IO_COUNTERS IoCounters; // Windows 2000 only
135 SYSTEM_THREADS Threads[1];
136} SYSTEM_PROCESSES, *PSYSTEM_PROCESSES;
137
138
139NTSTATUS
140NTAPI
141HookedNtSetSystemInformation(
142 IN SYSTEM_INFORMATION_CLASS SystemInformationClass,
143 IN OUT PVOID SystemInformation,
144 IN ULONG SystemInformationLength
145 );
146
147
148/*
149 * ZwQuerySystemInformation queries information about the system. [NAR]
150 */
151
152NTSYSAPI
153NTSTATUS
154NTAPI
155ZwQuerySystemInformation(
156 IN SYSTEM_INFORMATION_CLASS SystemInformationClass,
157 IN OUT PVOID SystemInformation,
158 IN ULONG SystemInformationLength,
159 OUT PULONG ReturnLength OPTIONAL
160 );
161
162
163typedef NTSTATUS (*fpZwSetSystemInformation)
164(
165 IN SYSTEM_INFORMATION_CLASS SystemInformationClass,
166 IN OUT PVOID SystemInformation,
167 IN ULONG SystemInformationLength
168);
169
170
171/*
172 * Information Class 38
173 *
174 * "This information class can only be set. Rather than setting any information (in a narrow
175 * sense of “setting”), it performs the operation of loading a module into the kernel
176 * address space and calling its entry point." [NAR]
177 */
178
179typedef struct _SYSTEM_LOAD_AND_CALL_IMAGE {
180
181 UNICODE_STRING ModuleName; /* The full path in the native NT format of the module to load. */
182
183} SYSTEM_LOAD_AND_CALL_IMAGE, *PSYSTEM_LOAD_AND_CALL_IMAGE;
184
185
186
187BOOLEAN InitSysInfoHooks();
188
189
190#endif /* __SYSINFO_H__ */
diff --git a/time.c b/time.c
new file mode 100644
index 0000000..448fe7c
--- /dev/null
+++ b/time.c
@@ -0,0 +1,190 @@
1/*
2 * Copyright (c) 2004 Security Architects Corporation. All rights reserved.
3 *
4 * Module Name:
5 *
6 * time.c
7 *
8 * Abstract:
9 *
10 * This module defines various routines used for hooking time routines.
11 *
12 * Author:
13 *
14 * Eugene Tsyrklevich 10-Mar-2004
15 *
16 * Revision History:
17 *
18 * None.
19 */
20
21
22#include <NTDDK.h>
23#include "time.h"
24#include "hookproc.h"
25#include "procname.h"
26#include "learn.h"
27#include "misc.h"
28#include "log.h"
29
30
31#ifdef ALLOC_PRAGMA
32#pragma alloc_text (INIT, InitTimeHooks)
33#endif
34
35
36fpZwSetSystemTime OriginalNtSetSystemTime = NULL;
37fpZwSetTimerResolution OriginalNtSetTimerResolution = NULL;
38
39
40
41/*
42 * HookedNtSetSystemTime()
43 *
44 * Description:
45 * This function mediates the NtSetSystemTime() system service and disallows applications
46 * to change the system time.
47 *
48 * NOTE: ZwSetSystemTime sets the system time. [NAR]
49 *
50 * Parameters:
51 * Those of NtSetSystemTime().
52 *
53 * Returns:
54 * STATUS_ACCESS_DENIED if time changing is disabled.
55 * Otherwise, NTSTATUS returned by NtSetSystemTime().
56 */
57
58NTSTATUS
59NTAPI
60HookedNtSetSystemTime
61(
62 IN PLARGE_INTEGER NewTime,
63 OUT PLARGE_INTEGER OldTime OPTIONAL
64)
65{
66 PCHAR FunctionName = "HookedNtSetSystemTime";
67 PCHAR TIMENAME = NULL; /* allow the use of POLICY_CHECK_OPTYPE_NAME() macro */
68
69
70 HOOK_ROUTINE_ENTER();
71
72
73 LOG(LOG_SS_TIME, LOG_PRIORITY_DEBUG, ("%d (%S) HookedNtSetSystemTime\n", (ULONG) PsGetCurrentProcessId(), GetCurrentProcessName()));
74
75
76 /* NOTE: same code is replicated in sysinfo.c */
77
78 if (LearningMode == FALSE)
79 {
80 POLICY_CHECK_OPTYPE_NAME(TIME, OP_TIME_CHANGE);
81 }
82
83
84 ASSERT(OriginalNtSetSystemTime);
85
86 rc = OriginalNtSetSystemTime(NewTime, OldTime);
87
88
89 if (LearningMode == TRUE)
90 {
91 AddRule(RULE_TIME, NULL, OP_TIME_CHANGE);
92 }
93
94 HOOK_ROUTINE_EXIT(rc);
95}
96
97
98
99/*
100 * HookedNtSetTimerResolution()
101 *
102 * Description:
103 * This function mediates the NtSetTimerResolution() system service and disallows applications
104 * to change the system time.
105 *
106 * NOTE: ZwSetTimerResolution sets the resolution of the system timer. [NAR]
107 *
108 * Parameters:
109 * Those of NtSetTimerResolution().
110 *
111 * Returns:
112 * STATUS_ACCESS_DENIED if time changing is disabled.
113 * Otherwise, NTSTATUS returned by NtSetTimerResolution().
114 */
115
116NTSTATUS
117NTAPI
118HookedNtSetTimerResolution
119(
120 IN ULONG RequestedResolution,
121 IN BOOLEAN Set,
122 OUT PULONG ActualResolution
123)
124{
125 PCHAR FunctionName = "HookedNtSetTimerResolution";
126 PCHAR TIMENAME = NULL; /* allow the use of POLICY_CHECK_OPTYPE_NAME() macro */
127
128
129 HOOK_ROUTINE_ENTER();
130
131
132 LOG(LOG_SS_TIME, LOG_PRIORITY_DEBUG, ("%d (%S) HookedNtSetTimerResolution\n", (ULONG) PsGetCurrentProcessId(), GetCurrentProcessName()));
133
134
135 if (LearningMode == FALSE)
136 {
137 POLICY_CHECK_OPTYPE_NAME(TIME, OP_TIME_CHANGE);
138 }
139
140
141 ASSERT(OriginalNtSetTimerResolution);
142
143 rc = OriginalNtSetTimerResolution(RequestedResolution, Set, ActualResolution);
144
145
146 if (LearningMode == TRUE)
147 {
148 AddRule(RULE_TIME, NULL, OP_TIME_CHANGE);
149 }
150
151 HOOK_ROUTINE_EXIT(rc);
152}
153
154
155
156/*
157 * InitTimeHooks()
158 *
159 * Description:
160 * Initializes all the mediated time operation pointers. The "OriginalFunction" pointers
161 * are initialized by InstallSyscallsHooks() that must be called prior to this function.
162 *
163 * NOTE: Called once during driver initialization (DriverEntry()).
164 *
165 * Parameters:
166 * None.
167 *
168 * Returns:
169 * TRUE to indicate success, FALSE if failed.
170 */
171
172BOOLEAN
173InitTimeHooks()
174{
175 if ((OriginalNtSetSystemTime = (fpZwSetSystemTime) ZwCalls[ZW_SET_SYSTEM_TIME_INDEX].OriginalFunction) == NULL)
176 {
177 LOG(LOG_SS_TIME, LOG_PRIORITY_DEBUG, ("InitTimeHooks: OriginalNtSetSystemTime is NULL\n"));
178 return FALSE;
179 }
180
181 /* a lot of applications seem to be calling this function thus don't intercept it */
182/*
183 if ((OriginalNtSetTimerResolution = (fpZwSetTimerResolution) ZwCalls[ZW_SET_TIMER_RESOLUTION_INDEX].OriginalFunction) == NULL)
184 {
185 LOG(LOG_SS_TIME, LOG_PRIORITY_DEBUG, ("InitTimeHooks: OriginalNtSetTimerResolution is NULL\n"));
186 return FALSE;
187 }
188*/
189 return TRUE;
190}
diff --git a/time.h b/time.h
new file mode 100644
index 0000000..76ccc36
--- /dev/null
+++ b/time.h
@@ -0,0 +1,68 @@
1/*
2 * Copyright (c) 2004 Security Architects Corporation. All rights reserved.
3 *
4 * Module Name:
5 *
6 * time.h
7 *
8 * Abstract:
9 *
10 * This module defines various types used by time hooking routines.
11 *
12 * Author:
13 *
14 * Eugene Tsyrklevich 10-Mar-2004
15 *
16 * Revision History:
17 *
18 * None.
19 */
20
21
22#ifndef __TIME_H__
23#define __TIME_H__
24
25
26#include <NTDDK.h>
27
28
29/*
30 * ZwSetSystemTime sets the system time. [NAR]
31 */
32
33typedef NTSTATUS (*fpZwSetSystemTime)(
34 IN PLARGE_INTEGER NewTime,
35 OUT PLARGE_INTEGER OldTime OPTIONAL
36 );
37
38NTSTATUS
39NTAPI
40HookedNtSetSystemTime(
41 IN PLARGE_INTEGER NewTime,
42 OUT PLARGE_INTEGER OldTime OPTIONAL
43 );
44
45
46/*
47 * ZwSetTimerResolution sets the resolution of the system timer. [NAR]
48 */
49
50typedef NTSTATUS (*fpZwSetTimerResolution)(
51 IN ULONG RequestedResolution,
52 IN BOOLEAN Set,
53 OUT PULONG ActualResolution
54 );
55
56NTSTATUS
57NTAPI
58HookedNtSetTimerResolution(
59 IN ULONG RequestedResolution,
60 IN BOOLEAN Set,
61 OUT PULONG ActualResolution
62 );
63
64
65BOOLEAN InitTimeHooks();
66
67
68#endif /* __TIME_H__ */
diff --git a/timer.c b/timer.c
new file mode 100644
index 0000000..3210000
--- /dev/null
+++ b/timer.c
@@ -0,0 +1,151 @@
1/*
2 * Copyright (c) 2004 Security Architects Corporation. All rights reserved.
3 *
4 * Module Name:
5 *
6 * timer.c
7 *
8 * Abstract:
9 *
10 * This module implements various timer hooking routines.
11 *
12 * Author:
13 *
14 * Eugene Tsyrklevich 25-Mar-2004
15 *
16 * Revision History:
17 *
18 * None.
19 */
20
21
22#include "timer.h"
23
24
25#ifdef ALLOC_PRAGMA
26#pragma alloc_text (INIT, InitTimerHooks)
27#endif
28
29
30fpZwCreateTimer OriginalNtCreateTimer = NULL;
31fpZwOpenTimer OriginalNtOpenTimer = NULL;
32
33
34/*
35 * HookedNtCreateTimer()
36 *
37 * Description:
38 * This function mediates the NtCreateTimer() system service and checks the
39 * provided timer name against the global and current process security policies.
40 *
41 * NOTE: ZwCreateTimer creates or opens a timer object. [NAR]
42 *
43 * Parameters:
44 * Those of NtCreateTimer().
45 *
46 * Returns:
47 * STATUS_ACCESS_DENIED if the call does not pass the security policy check.
48 * Otherwise, NTSTATUS returned by NtCreateTimer().
49 */
50
51NTSTATUS
52NTAPI
53HookedNtCreateTimer
54(
55 OUT PHANDLE TimerHandle,
56 IN ACCESS_MASK DesiredAccess,
57 IN POBJECT_ATTRIBUTES ObjectAttributes,
58 IN TIMER_TYPE TimerType
59)
60{
61 PCHAR FunctionName = "HookedNtCreateTimer";
62
63
64 HOOK_ROUTINE_START(TIMER);
65
66
67 ASSERT(OriginalNtCreateTimer);
68
69 rc = OriginalNtCreateTimer(TimerHandle, DesiredAccess, ObjectAttributes, TimerType);
70
71
72 HOOK_ROUTINE_FINISH(TIMER);
73}
74
75
76
77/*
78 * HookedNtOpenTimer()
79 *
80 * Description:
81 * This function mediates the NtOpenTimer() system service and checks the
82 * provided timer name against the global and current process security policies.
83 *
84 * NOTE: ZwOpenTimer opens a timer object. [NAR]
85 *
86 * Parameters:
87 * Those of NtOpenTimer().
88 *
89 * Returns:
90 * STATUS_ACCESS_DENIED if the call does not pass the security policy check.
91 * Otherwise, NTSTATUS returned by NtOpenTimer().
92 */
93
94NTSTATUS
95NTAPI
96HookedNtOpenTimer
97(
98 OUT PHANDLE TimerHandle,
99 IN ACCESS_MASK DesiredAccess,
100 IN POBJECT_ATTRIBUTES ObjectAttributes
101)
102{
103 PCHAR FunctionName = "HookedNtOpenTimer";
104
105
106 HOOK_ROUTINE_START(TIMER);
107
108
109 ASSERT(OriginalNtOpenTimer);
110
111 rc = OriginalNtOpenTimer(TimerHandle, DesiredAccess, ObjectAttributes);
112
113
114 HOOK_ROUTINE_FINISH(TIMER);
115}
116
117
118
119/*
120 * InitTimerHooks()
121 *
122 * Description:
123 * Initializes all the mediated timer operation pointers. The "OriginalFunction" pointers
124 * are initialized by InstallSyscallsHooks() that must be called prior to this function.
125 *
126 * NOTE: Called once during driver initialization (DriverEntry()).
127 *
128 * Parameters:
129 * None.
130 *
131 * Returns:
132 * TRUE to indicate success, FALSE if failed.
133 */
134
135BOOLEAN
136InitTimerHooks()
137{
138 if ( (OriginalNtCreateTimer = (fpZwCreateTimer) ZwCalls[ZW_CREATE_TIMER_INDEX].OriginalFunction) == NULL)
139 {
140 LOG(LOG_SS_TIMER, LOG_PRIORITY_DEBUG, ("InitTimerHooks: OriginalNtCreateTimer is NULL\n"));
141 return FALSE;
142 }
143
144 if ( (OriginalNtOpenTimer = (fpZwOpenTimer) ZwCalls[ZW_OPEN_TIMER_INDEX].OriginalFunction) == NULL)
145 {
146 LOG(LOG_SS_TIMER, LOG_PRIORITY_DEBUG, ("InitTimerHooks: OriginalNtOpenTimer is NULL\n"));
147 return FALSE;
148 }
149
150 return TRUE;
151}
diff --git a/timer.h b/timer.h
new file mode 100644
index 0000000..9b0ae85
--- /dev/null
+++ b/timer.h
@@ -0,0 +1,78 @@
1/*
2 * Copyright (c) 2004 Security Architects Corporation. All rights reserved.
3 *
4 * Module Name:
5 *
6 * timer.h
7 *
8 * Abstract:
9 *
10 * This module defines various types used by timer object hooking routines.
11 *
12 * Author:
13 *
14 * Eugene Tsyrklevich 25-Mar-2004
15 *
16 * Revision History:
17 *
18 * None.
19 */
20
21
22#ifndef __TIMER_H__
23#define __TIMER_H__
24
25
26#include <NTDDK.h>
27#include "policy.h"
28#include "pathproc.h"
29#include "hookproc.h"
30#include "accessmask.h"
31#include "learn.h"
32#include "log.h"
33
34
35/*
36 * ZwCreateTimer creates or opens a timer object. [NAR]
37 */
38
39typedef NTSTATUS (*fpZwCreateTimer) (
40 OUT PHANDLE TimerHandle,
41 IN ACCESS_MASK DesiredAccess,
42 IN POBJECT_ATTRIBUTES ObjectAttributes,
43 IN TIMER_TYPE TimerType
44 );
45
46NTSTATUS
47NTAPI
48HookedNtCreateTimer(
49 OUT PHANDLE TimerHandle,
50 IN ACCESS_MASK DesiredAccess,
51 IN POBJECT_ATTRIBUTES ObjectAttributes,
52 IN TIMER_TYPE TimerType
53 );
54
55
56/*
57 * ZwOpenTimer opens a timer object. [NAR]
58 */
59
60typedef NTSTATUS (*fpZwOpenTimer) (
61 OUT PHANDLE TimerHandle,
62 IN ACCESS_MASK DesiredAccess,
63 IN POBJECT_ATTRIBUTES ObjectAttributes
64 );
65
66NTSTATUS
67NTAPI
68HookedNtOpenTimer(
69 OUT PHANDLE TimerHandle,
70 IN ACCESS_MASK DesiredAccess,
71 IN POBJECT_ATTRIBUTES ObjectAttributes
72 );
73
74
75BOOLEAN InitTimerHooks();
76
77
78#endif /* __TIMER_H__ */
diff --git a/token.c b/token.c
new file mode 100644
index 0000000..2f7e45b
--- /dev/null
+++ b/token.c
@@ -0,0 +1,250 @@
1/*
2 * Copyright (c) 2004 Security Architects Corporation. All rights reserved.
3 *
4 * Module Name:
5 *
6 * token.c
7 *
8 * Abstract:
9 *
10 * This module implements various token hooking routines.
11 * Token objects encapsulate the privileges and access rights of an agent
12 * (a thread or process).
13 *
14 * Author:
15 *
16 * Eugene Tsyrklevich 25-Mar-2004
17 *
18 * Revision History:
19 *
20 * None.
21 */
22
23
24#include "token.h"
25
26
27#ifdef ALLOC_PRAGMA
28#pragma alloc_text (INIT, InitTokenHooks)
29#endif
30
31
32fpZwAdjustPrivilegesToken OriginalNtAdjustPrivilegesToken = NULL;
33fpZwSetInformationToken OriginalNtSetInformationToken = NULL;
34
35
36
37/*
38 * HookedNtAdjustPrivilegesToken()
39 *
40 * Description:
41 * This function mediates the NtAdjustPrivilegesToken() system service and XXX.
42 *
43 * NOTE: ZwAdjustPrivilegesToken adjusts the attributes of the privileges in a token. [NAR]
44 *
45 * Parameters:
46 * Those of NtAdjustPrivilegesToken().
47 *
48 * Returns:
49 * STATUS_ACCESS_DENIED if the call does not pass the security policy check.
50 * Otherwise, NTSTATUS returned by NtAdjustPrivilegesToken().
51 */
52
53NTSTATUS
54NTAPI
55HookedNtAdjustPrivilegesToken
56(
57 IN HANDLE TokenHandle,
58 IN BOOLEAN DisableAllPrivileges,
59 IN PTOKEN_PRIVILEGES NewState,
60 IN ULONG BufferLength,
61 OUT PTOKEN_PRIVILEGES PreviousState OPTIONAL,
62 OUT PULONG ReturnLength
63)
64{
65 PCHAR FunctionName = "HookedNtAdjustPrivilegesToken";
66 PCHAR TOKENNAME = NULL; /* allow the use of POLICY_CHECK_OPTYPE_NAME() macro */
67 ULONG i;
68
69
70 HOOK_ROUTINE_ENTER();
71
72/*
73 if (LearningMode == FALSE && IsTokenModificationAllowed() == FALSE)
74 {
75 LOG(LOG_SS_TOKEN, LOG_PRIORITY_DEBUG, ("%d (%S) HookedNtAdjustPrivilegesToken: disallowing token modification\n", (ULONG) PsGetCurrentProcessId(), GetCurrentProcessName()));
76
77 LogAlert(ALERT_SS_TOKEN, OP_MODIFY, ALERT_RULE_NONE, ACTION_DENY, ALERT_PRIORITY_MEDIUM, NULL, 0, NULL);
78
79 HOOK_ROUTINE_EXIT( STATUS_ACCESS_DENIED );
80 }
81*/
82 if (LearningMode == FALSE)
83 {
84 POLICY_CHECK_OPTYPE_NAME(TOKEN, OP_TOKEN_MODIFY);
85 }
86
87
88 if (KeGetPreviousMode() != KernelMode && DisableAllPrivileges == FALSE && ARGUMENT_PRESENT(NewState))
89 {
90 BOOLEAN CaughtException;
91
92 __try
93 {
94 // Probe to make sure the first ULONG (PrivilegeCount) is accessible
95 ProbeForRead(NewState, sizeof(ULONG), sizeof(ULONG));
96
97 // Now probe the entire structure
98 ProbeForRead(NewState, sizeof(TOKEN_PRIVILEGES) +
99 (NewState->PrivilegeCount - ANYSIZE_ARRAY) * sizeof(LUID_AND_ATTRIBUTES),
100 sizeof(ULONG));
101 }
102
103 __except(EXCEPTION_EXECUTE_HANDLER)
104 {
105 NTSTATUS status = GetExceptionCode();
106
107 LOG(LOG_SS_TOKEN, LOG_PRIORITY_DEBUG, ("HookedNtAdjustPrivilegesToken(): caught an exception. status = 0x%x\n", status));
108
109 CaughtException = TRUE;
110 }
111
112
113 LOG(LOG_SS_TOKEN, LOG_PRIORITY_VERBOSE, ("%d HookedNtAdjustPrivilegesToken: %S\n", (ULONG) PsGetCurrentProcessId(), GetCurrentProcessName()));
114
115
116 //XXX replace with PID lookup
117/*
118 if (CaughtException == FALSE &&
119 wcsstr(GetCurrentProcessName(), L"svchost.exe") == 0 &&
120 wcsstr(GetCurrentProcessName(), L"services.exe") == 0)
121 {
122 LOG(LOG_SS_TOKEN, LOG_PRIORITY_DEBUG, ("%d HookedNtAdjustPrivilegesToken\n", (ULONG) PsGetCurrentProcessId()));
123
124 for (i = 0; i < NewState->PrivilegeCount; i++)
125 {
126 if (NewState->Privileges[i].Luid.LowPart == SE_AUDIT_PRIVILEGE && NewState->Privileges[i].Luid.HighPart == 0)
127 ;
128 else
129 KdPrint(("priv %d: %x %x %x\n", i, NewState->Privileges[i].Attributes, NewState->Privileges[i].Luid.LowPart, NewState->Privileges[i].Luid.HighPart));
130 }
131 }
132*/
133 }
134
135
136 ASSERT(OriginalNtAdjustPrivilegesToken);
137
138 rc = OriginalNtAdjustPrivilegesToken(TokenHandle, DisableAllPrivileges, NewState, BufferLength,
139 PreviousState, ReturnLength);
140
141
142 if (LearningMode == TRUE)
143 {
144 AddRule(RULE_TOKEN, NULL, OP_TOKEN_MODIFY);
145 }
146
147 HOOK_ROUTINE_EXIT(rc);
148}
149
150
151
152/*
153 * HookedNtSetInformationToken()
154 *
155 * Description:
156 * This function mediates the NtSetInformationToken() system service and XXX.
157 *
158 * NOTE: ZwSetInformationToken sets information affecting a token object. [NAR]
159 *
160 * Parameters:
161 * Those of NtSetInformationToken().
162 *
163 * Returns:
164 * STATUS_ACCESS_DENIED if the call does not pass the security policy check.
165 * Otherwise, NTSTATUS returned by NtSetInformationToken().
166 */
167
168NTSTATUS
169NTAPI
170HookedNtSetInformationToken
171(
172 IN HANDLE TokenHandle,
173 IN TOKEN_INFORMATION_CLASS TokenInformationClass,
174 IN PVOID TokenInformation,
175 IN ULONG TokenInformationLength
176)
177{
178 PCHAR FunctionName = "HookedNtSetInformationToken";
179 PCHAR TOKENNAME = NULL; /* allow the use of POLICY_CHECK_OPTYPE_NAME() macro */
180
181
182 HOOK_ROUTINE_ENTER();
183
184
185 LOG(LOG_SS_TOKEN, LOG_PRIORITY_VERBOSE, ("%d HookedNtSetInformationToken %S %x %x %x\n", (ULONG) PsGetCurrentProcessId(), GetCurrentProcessName(), TokenInformationClass, TokenInformation, TokenInformationLength));
186
187/*
188 if (LearningMode == FALSE && IsTokenModificationAllowed() == FALSE)
189 {
190 LOG(LOG_SS_TOKEN, LOG_PRIORITY_DEBUG, ("%d (%S) HookedNtSetInformationToken: disallowing token modification\n", (ULONG) PsGetCurrentProcessId(), GetCurrentProcessName()));
191
192 LogAlert(ALERT_SS_TOKEN, OP_MODIFY, ALERT_RULE_NONE, ACTION_DENY, ALERT_PRIORITY_MEDIUM, NULL, 0, NULL);
193
194 HOOK_ROUTINE_EXIT( STATUS_ACCESS_DENIED );
195 }
196*/
197 if (LearningMode == FALSE)
198 {
199 POLICY_CHECK_OPTYPE_NAME(TOKEN, OP_TOKEN_MODIFY);
200 }
201
202
203 ASSERT(OriginalNtSetInformationToken);
204
205 rc = OriginalNtSetInformationToken(TokenHandle, TokenInformationClass, TokenInformation, TokenInformationLength);
206
207
208 if (LearningMode == TRUE)
209 {
210 AddRule(RULE_TOKEN, NULL, OP_TOKEN_MODIFY);
211 }
212
213 HOOK_ROUTINE_EXIT(rc);
214}
215
216
217
218/*
219 * InitTokenHooks()
220 *
221 * Description:
222 * Initializes all the mediated token object operation pointers. The "OriginalFunction" pointers
223 * are initialized by InstallSyscallsHooks() that must be called prior to this function.
224 *
225 * NOTE: Called once during driver initialization (DriverEntry()).
226 *
227 * Parameters:
228 * None.
229 *
230 * Returns:
231 * TRUE to indicate success, FALSE if failed.
232 */
233
234BOOLEAN
235InitTokenHooks()
236{
237 if ( (OriginalNtAdjustPrivilegesToken = (fpZwAdjustPrivilegesToken) ZwCalls[ZW_ADJUST_TOKEN_INDEX].OriginalFunction) == NULL)
238 {
239 LOG(LOG_SS_TOKEN, LOG_PRIORITY_DEBUG, ("InitTokenHooks: OriginalNtAdjustPrivilegesToken is NULL\n"));
240 return FALSE;
241 }
242
243 if ( (OriginalNtSetInformationToken = (fpZwSetInformationToken) ZwCalls[ZW_SET_INFO_TOKEN_INDEX].OriginalFunction) == NULL)
244 {
245 LOG(LOG_SS_TOKEN, LOG_PRIORITY_DEBUG, ("InitTokenHooks: OriginalNtSetInformationToken is NULL\n"));
246 return FALSE;
247 }
248
249 return TRUE;
250}
diff --git a/token.h b/token.h
new file mode 100644
index 0000000..732ff56
--- /dev/null
+++ b/token.h
@@ -0,0 +1,145 @@
1/*
2 * Copyright (c) 2004 Security Architects Corporation. All rights reserved.
3 *
4 * Module Name:
5 *
6 * token.h
7 *
8 * Abstract:
9 *
10 * This module defines various types used by token hooking routines.
11 *
12 * Author:
13 *
14 * Eugene Tsyrklevich 25-Mar-2004
15 *
16 * Revision History:
17 *
18 * None.
19 */
20
21
22#ifndef __TOKEN_H__
23#define __TOKEN_H__
24
25
26#include <NTDDK.h>
27#include "policy.h"
28#include "pathproc.h"
29#include "hookproc.h"
30#include "procname.h"
31#include "learn.h"
32#include "log.h"
33
34
35/*
36ZwAdjustGroupsToken
37ZwCreateToken
38ZwOpenProcessToken
39ZwOpenProcessTokenEx
40ZwOpenThreadToken
41ZwOpenThreadTokenEx
42*/
43
44
45typedef struct _TOKEN_PRIVILEGES {
46 DWORD PrivilegeCount;
47 LUID_AND_ATTRIBUTES Privileges[ANYSIZE_ARRAY];
48} TOKEN_PRIVILEGES, *PTOKEN_PRIVILEGES;
49
50
51/*
52 * ZwAdjustPrivilegesToken adjusts the attributes of the privileges in a token. [NAR]
53 */
54
55typedef NTSTATUS (*fpZwAdjustPrivilegesToken) (
56 IN HANDLE TokenHandle,
57 IN BOOLEAN DisableAllPrivileges,
58 IN PTOKEN_PRIVILEGES NewState,
59 IN ULONG BufferLength,
60 OUT PTOKEN_PRIVILEGES PreviousState OPTIONAL,
61 OUT PULONG ReturnLength
62 );
63
64NTSTATUS
65NTAPI
66HookedNtAdjustPrivilegesToken(
67 IN HANDLE TokenHandle,
68 IN BOOLEAN DisableAllPrivileges,
69 IN PTOKEN_PRIVILEGES NewState,
70 IN ULONG BufferLength,
71 OUT PTOKEN_PRIVILEGES PreviousState OPTIONAL,
72 OUT PULONG ReturnLength
73 );
74
75
76/*
77 * ZwSetInformationToken sets information affecting a token object. [NAR]
78 */
79
80typedef NTSTATUS (*fpZwSetInformationToken) (
81 IN HANDLE TokenHandle,
82 IN TOKEN_INFORMATION_CLASS TokenInformationClass,
83 IN PVOID TokenInformation,
84 IN ULONG TokenInformationLength
85 );
86
87NTSTATUS
88NTAPI
89HookedNtSetInformationToken(
90 IN HANDLE TokenHandle,
91 IN TOKEN_INFORMATION_CLASS TokenInformationClass,
92 IN PVOID TokenInformation,
93 IN ULONG TokenInformationLength
94 );
95
96
97/*
98 * ZwOpenProcessToken opens the token of a process. [NAR]
99 */
100
101NTSYSAPI
102NTSTATUS
103NTAPI
104ZwOpenProcessToken(
105 IN HANDLE ProcessHandle,
106 IN ACCESS_MASK DesiredAccess,
107 OUT PHANDLE TokenHandle
108 );
109
110
111/*
112 * ZwOpenThreadToken opens the token of a thread. [NAR]
113 */
114
115NTSYSAPI
116NTSTATUS
117NTAPI
118ZwOpenThreadToken(
119 IN HANDLE ThreadHandle,
120 IN ACCESS_MASK DesiredAccess,
121 IN BOOLEAN OpenAsSelf,
122 OUT PHANDLE TokenHandle
123 );
124
125
126/*
127 * ZwQueryInformationToken retrieves information about a token object. [NAR]
128 */
129
130NTSYSAPI
131NTSTATUS
132NTAPI
133ZwQueryInformationToken(
134 IN HANDLE TokenHandle,
135 IN TOKEN_INFORMATION_CLASS TokenInformationClass,
136 OUT PVOID TokenInformation,
137 IN ULONG TokenInformationLength,
138 OUT PULONG ReturnLength
139 );
140
141
142BOOLEAN InitTokenHooks();
143
144
145#endif /* __TOKEN_H__ */
diff --git a/userland.c b/userland.c
new file mode 100644
index 0000000..805a413
--- /dev/null
+++ b/userland.c
@@ -0,0 +1,573 @@
1/*
2 * Copyright (c) 2004 Security Architects Corporation. All rights reserved.
3 *
4 * Module Name:
5 *
6 * userland.c
7 *
8 * Abstract:
9 *
10 * This module defines various types routines used to interact with userland agent service.
11 *
12 * Author:
13 *
14 * Eugene Tsyrklevich 18-Apr-2004
15 *
16 * Revision History:
17 *
18 * None.
19 */
20
21
22#include "userland.h"
23#include "procname.h"
24#include "process.h"
25
26
27#ifdef ALLOC_PRAGMA
28#pragma alloc_text (INIT, InitUserland)
29#pragma alloc_text (PAGE, ShutdownUserland)
30#pragma alloc_text (PAGE, UserlandPostBootup)
31#endif
32
33
34BOOLEAN ActiveUserAgent = FALSE;
35
36PKEVENT UserlandRequestUserEvent = NULL;
37HANDLE UserlandRequestUserEventHandle = NULL;
38
39PUSERLAND_REQUEST_HEADER UserlandRequestList = NULL;
40KSPIN_LOCK gUserlandRequestListSpinLock;
41
42BOOLEAN CacheSid = TRUE;
43ULONG CachedSidSize = 0, CachedSidReplySize = 0;
44PVOID CachedSid = NULL;
45PSID_RESOLVE_REPLY CachedSidReply = NULL;
46
47UCHAR SeqId = 0; /* global sequence id used for matching up userland requests & replies */
48
49
50
51/*
52 * UserlandPostBootup()
53 *
54 * Description:
55 * Initializes userland related data once computer is done booting up.
56 *
57 * \BaseNamedObjects object directory is not created until the Win32® system initializes.
58 * Therefore, drivers that are loaded at boot time cannot create event objects in their DriverEntry
59 * routines that are visible to user-mode programs.
60 *
61 * Parameters:
62 * None.
63 *
64 * Returns:
65 * TRUE to indicate success, FALSE if failed.
66 */
67
68BOOLEAN
69UserlandPostBootup()
70{
71 UNICODE_STRING uszUserlandRequestEvent;
72
73
74 ASSERT(BootingUp == FALSE);
75
76
77 KeInitializeSpinLock(&gUserlandRequestListSpinLock);
78
79
80 /* Create an event for userland agent service to monitor */
81#define USERLAND_REQUEST_EVENT_NAME L"\\BaseNamedObjects\\OzoneUserlandRequestEvent"
82
83 RtlInitUnicodeString(&uszUserlandRequestEvent, USERLAND_REQUEST_EVENT_NAME);
84
85
86 if ((UserlandRequestUserEvent = IoCreateNotificationEvent(&uszUserlandRequestEvent, &UserlandRequestUserEventHandle)) == NULL)
87 {
88 LOG(LOG_SS_MISC, LOG_PRIORITY_DEBUG, ("UserlandPostBootup: IoCreateNotificationEvent failed\n"));
89 return FALSE;
90 }
91
92 KeClearEvent(UserlandRequestUserEvent);
93
94
95 return TRUE;
96}
97
98
99
100/*
101 * IssueUserlandSidResolveRequest()
102 *
103 * Description:
104 * Resolves binary SID to its ASCII representation by querying a userland agent.
105 *
106 * Parameters:
107 * .
108 *
109 * Returns:
110 * TRUE to indicate success, FALSE otherwise.
111 */
112
113BOOLEAN
114IssueUserlandSidResolveRequest(PIMAGE_PID_ENTRY Process)
115{
116 PSID_RESOLVE_REQUEST pSidResolveRequest;
117 USHORT Size;
118 PCHAR UserSidBuffer;
119 KIRQL irql;
120 LARGE_INTEGER liDelay;
121 NTSTATUS status;
122
123
124 ASSERT(Process);
125
126
127 if (!ActiveUserAgent)
128 {
129 LOG(LOG_SS_MISC, LOG_PRIORITY_VERBOSE, ("IssueUserlandSidResolveRequest: no Agent Service\n"));
130 return FALSE;
131 }
132
133 if (KeGetCurrentIrql() != PASSIVE_LEVEL)
134 {
135 LOG(LOG_SS_MISC, LOG_PRIORITY_DEBUG, ("IssueUserlandSidResolveRequest: Running at high IRQL\n"));
136 return FALSE;
137 }
138
139 if (Process->ProcessId == SystemProcessId)
140 {
141 LOG(LOG_SS_MISC, LOG_PRIORITY_DEBUG, ("IssueUserlandSidResolveRequest: Cannot issue requests on behalf of SYSTEM process\n"));
142// return FALSE;
143 }
144
145
146 /*
147 * the following code assumes that SID_RESOLVE_REQUESTS consists of USERLAND_REQUEST_HEADER
148 * followed by PSID_AND_ATTRIBUTES.
149 *
150 * GetCurrentUserSid() allocates memory for user sid + PSID_AND_ATTRIBUTES and converts SID
151 * from absolute into relative format.
152 */
153
154 Size = sizeof(USERLAND_REQUEST_HEADER);
155 UserSidBuffer = GetCurrentUserSid(&Size);
156
157 if (UserSidBuffer == NULL)
158 {
159 LOG(LOG_SS_MISC, LOG_PRIORITY_DEBUG, ("IssueUserlandSidResolveRequest: out of memory\n"));
160 return FALSE;
161 }
162
163 /* check for a previously resolved cached SID */
164 while (CacheSid == TRUE)
165 {
166 int SidSize = Size - sizeof(USERLAND_REQUEST_HEADER);
167
168
169 /* cache hit? */
170 if (CachedSid && CachedSidReply &&
171 SidSize == CachedSidSize &&
172 memcmp(UserSidBuffer + sizeof(USERLAND_REQUEST_HEADER), CachedSid, CachedSidSize) == 0)
173 {
174 Process->WaitingForUserRequestId = 0;
175 Process->UserlandReply = ExAllocatePoolWithTag(PagedPool, CachedSidReplySize, _POOL_TAG);
176
177 if (Process->UserlandReply == NULL)
178 {
179 ExFreePoolWithTag(UserSidBuffer, _POOL_TAG);
180 return FALSE;
181 }
182
183 memcpy(Process->UserlandReply, CachedSidReply, CachedSidReplySize);
184
185 LOG(LOG_SS_MISC, LOG_PRIORITY_DEBUG, ("IssueUserlandSidResolveRequest: Cache hit. Returning username %S\n", CachedSidReply->UserName));
186
187 ExFreePoolWithTag(UserSidBuffer, _POOL_TAG);
188
189 return TRUE;
190 }
191
192
193 /* cache miss */
194 CachedSidSize = SidSize;
195
196 if (CachedSid)
197 ExFreePoolWithTag(CachedSid, _POOL_TAG);
198
199 CachedSid = ExAllocatePoolWithTag(PagedPool, SidSize, _POOL_TAG);
200
201 if (CachedSid == NULL)
202 {
203 ExFreePoolWithTag(UserSidBuffer, _POOL_TAG);
204 return FALSE;
205 }
206
207 memcpy(CachedSid, UserSidBuffer + sizeof(USERLAND_REQUEST_HEADER), SidSize);
208
209 if (CachedSidReply)
210 {
211 ExFreePoolWithTag(CachedSidReply, _POOL_TAG);
212 CachedSidReply = NULL;
213 }
214
215 break;
216 }
217
218
219 pSidResolveRequest = (PSID_RESOLVE_REQUEST) UserSidBuffer;
220
221
222 pSidResolveRequest->RequestHeader.RequestType = USERLAND_SID_RESOLVE_REQUEST;
223 pSidResolveRequest->RequestHeader.RequestSize = Size;
224 pSidResolveRequest->RequestHeader.ProcessId = Process->ProcessId;
225
226 if (++SeqId == 0) SeqId = 1;
227 pSidResolveRequest->RequestHeader.SeqId = SeqId;
228
229
230 KeAcquireSpinLock(&gUserlandRequestListSpinLock, &irql);
231 {
232 pSidResolveRequest->RequestHeader.Next = UserlandRequestList;
233 UserlandRequestList = (PUSERLAND_REQUEST_HEADER) pSidResolveRequest;
234 }
235 KeReleaseSpinLock(&gUserlandRequestListSpinLock, irql);
236
237
238 Process->WaitingForUserRequestId = SeqId;
239 Process->UserlandReply = NULL;
240
241
242 KeClearEvent(&Process->UserlandRequestDoneEvent);
243
244
245 /* signal the userland agent service */
246 if (UserlandRequestUserEvent)
247 {
248 /* pulse twice since userland sometimes misses single pulses */
249 KeSetEvent(UserlandRequestUserEvent, 0, FALSE);
250 KeClearEvent(UserlandRequestUserEvent);
251
252 KeSetEvent(UserlandRequestUserEvent, 0, FALSE);
253 KeClearEvent(UserlandRequestUserEvent);
254 }
255 else
256 {
257 LOG(LOG_SS_MISC, LOG_PRIORITY_DEBUG, ("IssueUserlandSidResolveRequest: UserlandRequestUserEvent is NULL\n"));
258 }
259
260
261 LOG(LOG_SS_MISC, LOG_PRIORITY_DEBUG, ("%d IssueUserlandSidResolveRequest: Waiting for agent service\n", CURRENT_PROCESS_PID));
262
263
264 /* wait for the userland service to reply (wait for maximum of USERLAND_REQUEST_TIMEOUT seconds) */
265 liDelay.QuadPart = SECONDS(USERLAND_REQUEST_TIMEOUT);
266
267 status = KeWaitForSingleObject(&Process->UserlandRequestDoneEvent, UserRequest, KernelMode, FALSE, &liDelay);
268
269
270 Process->WaitingForUserRequestId = 0;
271
272 if (status == STATUS_TIMEOUT)
273 {
274 LOG(LOG_SS_MISC, LOG_PRIORITY_DEBUG, ("IssueUserlandSidResolveRequest: KeWaitForSingleObject timed out\n"));
275 }
276 else
277 {
278 LOG(LOG_SS_MISC, LOG_PRIORITY_DEBUG, ("IssueUserlandSidResolveRequest: KeWaitForSingleObject returned\n"));
279
280 /* cache the resolved Sid */
281 if (CacheSid == TRUE && Process->UserlandReply != NULL)
282 {
283 CachedSidReply = ExAllocatePoolWithTag(PagedPool, Process->UserlandReply->ReplySize, _POOL_TAG);
284
285 if (CachedSidReply)
286 {
287 memcpy(CachedSidReply, Process->UserlandReply, Process->UserlandReply->ReplySize);
288
289 CachedSidReplySize = Process->UserlandReply->ReplySize;
290 }
291 }
292 }
293
294
295 /* at this point UserSidBuffer/pSidResolveRequest has already been deallocated in driver.c!DriverDeviceControl */
296
297
298 return TRUE;
299}
300
301
302
303/*
304 * IssueUserlandAskUserRequest()
305 *
306 * Description:
307 * .
308 *
309 * Parameters:
310 * .
311 *
312 * Returns:
313 * .
314 */
315
316ACTION_TYPE
317IssueUserlandAskUserRequest(RULE_TYPE RuleType, UCHAR OperationType, PCHAR ObjectName)
318{
319 ACTION_TYPE Action = ACTION_DENY_DEFAULT;
320 PIMAGE_PID_ENTRY Process;
321 PASK_USER_REQUEST pAskUserRequest;
322 USHORT Size;
323 KIRQL irql;
324 LARGE_INTEGER liDelay;
325 NTSTATUS status;
326
327#define NAME_BUFFER_SIZE 256
328 ANSI_STRING asObjectName;
329 UNICODE_STRING usObjectName;
330 WCHAR ObjectNameW[NAME_BUFFER_SIZE] = { 0 };
331
332
333 ASSERT(ObjectName);
334
335
336 if (!ActiveUserAgent)
337 {
338 LOG(LOG_SS_MISC, LOG_PRIORITY_DEBUG, ("IssueUserlandAskUserRequest: no Agent Service\n"));
339 return Action;
340 }
341
342 if (KeGetCurrentIrql() != PASSIVE_LEVEL)
343 {
344 LOG(LOG_SS_MISC, LOG_PRIORITY_DEBUG, ("IssueUserlandAskUserRequest: Running at high IRQL\n"));
345 return FALSE;
346 }
347
348
349 if (CURRENT_PROCESS_PID == SystemProcessId)
350 {
351 LOG(LOG_SS_MISC, LOG_PRIORITY_DEBUG, ("IssueUserlandAskUserRequest: Cannot issue requests on behalf of SYSTEM process\n"));
352 return FALSE;
353 }
354
355
356 Process = FindImagePidEntry(CURRENT_PROCESS_PID, 0);
357 if (Process == NULL)
358 {
359 LOG(LOG_SS_MISC, LOG_PRIORITY_DEBUG, ("IssueUserlandAskUserRequest: Process %d not found\n", CURRENT_PROCESS_PID));
360 return Action;
361 }
362
363
364 /* \KnownDlls section rules need to be converted to DLLs */
365 if (RuleType == RULE_SECTION)
366 {
367 if (_strnicmp(ObjectName, "\\KnownDlls\\", 11) == 0)
368 {
369 ObjectName += 11;
370 RuleType = RULE_DLL;
371 OperationType = OP_LOAD;
372 }
373 }
374
375
376 ObjectName = FilterObjectName(ObjectName);
377
378 usObjectName.Length = 0;
379 usObjectName.MaximumLength = sizeof(ObjectNameW);
380 usObjectName.Buffer = ObjectNameW;
381
382 RtlInitAnsiString(&asObjectName, ObjectName);
383
384 RtlAnsiStringToUnicodeString(&usObjectName, &asObjectName, FALSE);
385 ObjectNameW[ asObjectName.Length ] = 0;
386
387
388 /* extra +1 for ProcessName zero termination */
389 Size = sizeof(ASK_USER_REQUEST) + (wcslen(ObjectNameW) + wcslen(Process->ImageName) + 1) * sizeof(WCHAR);
390
391 pAskUserRequest = ExAllocatePoolWithTag(NonPagedPool, Size, _POOL_TAG);
392
393 if (pAskUserRequest == NULL)
394 {
395 LOG(LOG_SS_MISC, LOG_PRIORITY_DEBUG, ("IssueUserlandAskUserRequest: out of memory\n"));
396 return Action;
397 }
398
399
400 pAskUserRequest->RequestHeader.RequestType = USERLAND_ASK_USER_REQUEST;
401 pAskUserRequest->RequestHeader.RequestSize = Size;
402 pAskUserRequest->RequestHeader.ProcessId = Process->ProcessId;
403
404 if (++SeqId == 0) SeqId = 1;
405 pAskUserRequest->RequestHeader.SeqId = SeqId;
406
407 pAskUserRequest->RuleType = RuleType;
408 pAskUserRequest->OperationType = OperationType;
409 pAskUserRequest->ObjectNameLength = (USHORT) wcslen(ObjectNameW);
410 pAskUserRequest->ProcessNameLength = (USHORT) wcslen(Process->ImageName);
411
412 wcscpy(pAskUserRequest->ObjectName, ObjectNameW);
413
414 /* process name follows the object name */
415 wcscpy(pAskUserRequest->ObjectName + pAskUserRequest->ObjectNameLength + 1, Process->ImageName);
416
417
418 KeAcquireSpinLock(&gUserlandRequestListSpinLock, &irql);
419 {
420 pAskUserRequest->RequestHeader.Next = UserlandRequestList;
421 UserlandRequestList = (PUSERLAND_REQUEST_HEADER) pAskUserRequest;
422 }
423 KeReleaseSpinLock(&gUserlandRequestListSpinLock, irql);
424
425
426 Process->WaitingForUserRequestId = SeqId;
427 Process->UserlandReply = NULL;
428
429
430 KeClearEvent(&Process->UserlandRequestDoneEvent);
431
432
433 /* signal the userland agent service */
434 if (UserlandRequestUserEvent)
435 {
436 /* pulse twice since userland sometimes misses single pulses */
437 KeSetEvent(UserlandRequestUserEvent, 0, FALSE);
438 KeClearEvent(UserlandRequestUserEvent);
439
440 KeSetEvent(UserlandRequestUserEvent, 0, FALSE);
441 KeClearEvent(UserlandRequestUserEvent);
442 }
443 else
444 {
445 LOG(LOG_SS_MISC, LOG_PRIORITY_DEBUG, ("IssueUserlandAskUserRequest: UserlandRequestUserEvent is NULL\n"));
446 }
447
448
449 LOG(LOG_SS_MISC, LOG_PRIORITY_DEBUG, ("%d IssueUserlandAskUserRequest: Waiting for agent service\n", CURRENT_PROCESS_PID));
450
451
452 /* wait for the user/userland service to reply (wait for maximum of USERLAND_REQUEST_TIMEOUT seconds) */
453 liDelay.QuadPart = SECONDS(USERLAND_REQUEST_TIMEOUT);
454
455 status = KeWaitForSingleObject(&Process->UserlandRequestDoneEvent, UserRequest, KernelMode, FALSE, &liDelay);
456
457
458 Process->WaitingForUserRequestId = 0;
459
460 if (status != STATUS_TIMEOUT)
461 {
462 PASK_USER_REPLY pAskUserReply = (PASK_USER_REPLY) Process->UserlandReply;
463
464 if (pAskUserReply)
465 {
466 Action = pAskUserReply->Action;
467
468 LOG(LOG_SS_MISC, LOG_PRIORITY_DEBUG, ("IssueUserlandAskUserRequest: received back action %d\n", Action));
469
470 ExFreePoolWithTag(Process->UserlandReply, _POOL_TAG);
471 Process->UserlandReply = NULL;
472 }
473
474 LOG(LOG_SS_MISC, LOG_PRIORITY_DEBUG, ("IssueUserlandAskUserRequest: IssueUserlandAskUserRequest returned\n"));
475 }
476 else
477 {
478 LOG(LOG_SS_MISC, LOG_PRIORITY_DEBUG, ("IssueUserlandAskUserRequest: KeWaitForSingleObject timed out\n"));
479
480 //XXX need to remove pAskUserRequest from the list
481 }
482
483
484 /* at this point pAskUserRequest has already been deallocated in driver.c!DriverDeviceControl */
485
486
487 return Action;
488}
489
490
491
492/*
493 * InitUserland()
494 *
495 * Description:
496 * Initializes all the userland related data.
497 *
498 * NOTE: Called once during driver initialization (DriverEntry()).
499 *
500 * Parameters:
501 * None.
502 *
503 * Returns:
504 * TRUE to indicate success, FALSE if failed.
505 */
506
507BOOLEAN
508InitUserland()
509{
510 if (BootingUp == FALSE)
511 {
512 if (UserlandPostBootup() == FALSE)
513
514 return FALSE;
515 }
516
517
518 return TRUE;
519}
520
521
522
523/*
524 * ShutdownUserland()
525 *
526 * Description:
527 * XXX.
528 *
529 * NOTE: Called once during driver unload (DriverUnload()).
530 *
531 * Parameters:
532 * None.
533 *
534 * Returns:
535 * Nothing.
536 */
537
538VOID
539ShutdownUserland()
540{
541 PUSERLAND_REQUEST_HEADER tmp;
542 KIRQL irql;
543
544
545 if (UserlandRequestUserEventHandle)
546 ZwClose(UserlandRequestUserEventHandle);
547
548
549 KeAcquireSpinLock(&gUserlandRequestListSpinLock, &irql);
550 {
551 while (UserlandRequestList)
552 {
553 tmp = UserlandRequestList;
554 UserlandRequestList = UserlandRequestList->Next;
555
556 ExFreePoolWithTag(tmp, _POOL_TAG);
557 }
558 }
559 KeReleaseSpinLock(&gUserlandRequestListSpinLock, irql);
560
561
562 if (CachedSid)
563 {
564 ExFreePoolWithTag(CachedSid, _POOL_TAG);
565 CachedSid = NULL;
566 }
567
568 if (CachedSidReply)
569 {
570 ExFreePoolWithTag(CachedSidReply, _POOL_TAG);
571 CachedSidReply = NULL;
572 }
573}
diff --git a/userland.h b/userland.h
new file mode 100644
index 0000000..03764fb
--- /dev/null
+++ b/userland.h
@@ -0,0 +1,133 @@
1/*
2 * Copyright (c) 2004 Security Architects Corporation. All rights reserved.
3 *
4 * Module Name:
5 *
6 * userland.h
7 *
8 * Abstract:
9 *
10 * This module defines various types used by userland interacting routines.
11 *
12 * Author:
13 *
14 * Eugene Tsyrklevich 18-Apr-2004
15 *
16 * Revision History:
17 *
18 * None.
19 */
20
21#ifndef __USERLAND_H__
22#define __USERLAND_H__
23
24
25#include <NTDDK.h>
26#include "policy.h"
27#include "misc.h"
28
29
30/* number of seconds to wait for userland agent to reply */
31#define USERLAND_REQUEST_TIMEOUT 5
32
33
34#define USERLAND_SID_RESOLVE_REQUEST 1
35#define USERLAND_ASK_USER_REQUEST 2
36
37
38/*
39 * all userland requests start with the following header
40 */
41
42typedef struct _USERLAND_REQUEST_HEADER
43{
44 struct _USERLAND_REQUEST_HEADER *Next;
45
46 USHORT RequestType;
47 USHORT RequestSize;
48 ULONG ProcessId;
49 UCHAR SeqId; /* Sequence id, will roll over but that's fine */
50
51} USERLAND_REQUEST_HEADER, *PUSERLAND_REQUEST_HEADER;
52
53
54/* binary SID -> ASCII name resolve request */
55
56typedef struct _SID_RESOLVE_REQUEST
57{
58 USERLAND_REQUEST_HEADER RequestHeader;
59 PSID_AND_ATTRIBUTES PUserSidAndAttributes;
60
61} SID_RESOLVE_REQUEST, *PSID_RESOLVE_REQUEST;
62
63
64/* Ask user request */
65
66typedef struct _ASK_USER_REQUEST
67{
68 USERLAND_REQUEST_HEADER RequestHeader;
69 RULE_TYPE RuleType;
70 UCHAR OperationType;
71 USHORT ObjectNameLength;
72 USHORT ProcessNameLength;
73
74 WCHAR ObjectName[ANYSIZE_ARRAY];
75
76 /* ProcessName follows the zero-terminated ObjectName */
77// WCHAR ProcessName[ANYSIZE_ARRAY];
78
79} ASK_USER_REQUEST, *PASK_USER_REQUEST;
80
81
82
83/*
84 * all userland replies start with the following header
85 */
86
87typedef struct _USERLAND_REPLY_HEADER
88{
89 ULONG ProcessId;
90 USHORT ReplySize;
91 UCHAR SeqId; /* Sequence id, will roll over but that's fine */
92
93} USERLAND_REPLY_HEADER, *PUSERLAND_REPLY_HEADER;
94
95
96/* binary SID -> ASCII name resolve reply */
97
98typedef struct _SID_RESOLVE_REPLY
99{
100 USERLAND_REPLY_HEADER ReplyHeader;
101 USHORT UserNameLength;
102 WCHAR UserName[ANYSIZE_ARRAY];
103
104} SID_RESOLVE_REPLY, *PSID_RESOLVE_REPLY;
105
106
107/* Ask user reply */
108
109typedef struct _ASK_USER_REPLY
110{
111 USERLAND_REPLY_HEADER ReplyHeader;
112 ACTION_TYPE Action;
113
114} ASK_USER_REPLY, *PASK_USER_REPLY;
115
116
117extern BOOLEAN ActiveUserAgent;
118extern PUSERLAND_REQUEST_HEADER UserlandRequestList;
119extern KSPIN_LOCK gUserlandRequestListSpinLock;
120extern PKEVENT UserlandRequestUserEvent;
121
122
123BOOLEAN InitUserland();
124BOOLEAN UserlandPostBootup();
125VOID ShutdownUserland();
126
127typedef struct _IMAGE_PID_ENTRY *PIMAGE_PID_ENTRY;
128
129BOOLEAN IssueUserlandSidResolveRequest(PIMAGE_PID_ENTRY Process);
130ACTION_TYPE IssueUserlandAskUserRequest(RULE_TYPE RuleType, UCHAR OperationType, PCHAR ObjectName);
131
132
133#endif /* __USERLAND_H__ */ \ No newline at end of file
diff --git a/vdm.c b/vdm.c
new file mode 100644
index 0000000..e445d2f
--- /dev/null
+++ b/vdm.c
@@ -0,0 +1,227 @@
1/*
2 * Copyright (c) 2004 Security Architects Corporation. All rights reserved.
3 *
4 * Module Name:
5 *
6 * vdm.c
7 *
8 * Abstract:
9 *
10 * This module implements various VDM (Virtual Dos Machine) hooking routines.
11 *
12 * Author:
13 *
14 * Eugene Tsyrklevich 06-Apr-2004
15 *
16 * Revision History:
17 *
18 * None.
19 */
20
21
22#include <NTDDK.h>
23#include "vdm.h"
24#include "policy.h"
25#include "hookproc.h"
26#include "procname.h"
27#include "policy.h"
28#include "learn.h"
29#include "log.h"
30
31
32#ifdef ALLOC_PRAGMA
33#pragma alloc_text (INIT, InitVdmHooks)
34#endif
35
36
37fpZwSetLdtEntries OriginalNtSetLdtEntries = NULL;
38fpZwVdmControl OriginalNtVdmControl = NULL;
39
40
41
42/*
43 * IsVdmAllowed()
44 *
45 * Description:
46 * Check whether the current process is allowed to use dos16/VDM functionality.
47 *
48 * Parameters:
49 * None.
50 *
51 * Returns:
52 * FALSE if VDM is disabled. TRUE otherwise.
53 */
54
55BOOLEAN
56IsVdmAllowed()
57{
58 PIMAGE_PID_ENTRY CurrentProcess;
59 BOOLEAN VdmAllowed = FALSE;
60
61
62 /* check the global policy first */
63 if (! IS_VDM_PROTECTION_ON(gSecPolicy))
64 return TRUE;
65
66
67 /* now check the process specific policy */
68 CurrentProcess = FindImagePidEntry(CURRENT_PROCESS_PID, 0);
69
70 if (CurrentProcess != NULL)
71 {
72 VdmAllowed = ! IS_VDM_PROTECTION_ON(CurrentProcess->SecPolicy);
73 }
74 else
75 {
76 LOG(LOG_SS_VDM, LOG_PRIORITY_DEBUG, ("%d IsVdmAllowed: CurrentProcess = NULL!\n", CURRENT_PROCESS_PID));
77 }
78
79
80 return VdmAllowed;
81}
82
83
84
85/*
86 * HookedNtSetLdtEntries()
87 *
88 * Description:
89 * This function mediates the NtSetLdtEntries() system service and disallows access to it.
90 *
91 * NOTE: ZwSetLdtEntries sets Local Descriptor Table (LDT) entries for a Virtual DOS Machine (VDM). [NAR]
92 *
93 * Parameters:
94 * Those of NtSetLdtEntries().
95 *
96 * Returns:
97 * STATUS_ACCESS_DENIED if 16-bit applications are disabled.
98 * Otherwise, NTSTATUS returned by NtSetLdtEntries().
99 */
100
101NTSTATUS
102NTAPI
103HookedNtSetLdtEntries
104(
105 IN ULONG Selector0,
106 IN ULONG Entry0Low,
107 IN ULONG Entry0Hi,
108 IN ULONG Selector1,
109 IN ULONG Entry1Low,
110 IN ULONG Entry1Hi
111)
112{
113 HOOK_ROUTINE_ENTER();
114
115
116 LOG(LOG_SS_VDM, LOG_PRIORITY_VERBOSE, ("%d (%S) HookedNtSetLdtEntries(%x %x %x)\n", (ULONG) PsGetCurrentProcessId(), GetCurrentProcessName(), Selector0, Entry0Low, Entry0Hi));
117
118 if (LearningMode == FALSE && IsVdmAllowed() == FALSE)
119 {
120 LOG(LOG_SS_VDM, LOG_PRIORITY_DEBUG, ("%d (%S) HookedNtSetLdtEntries: disallowing VDM access\n", (ULONG) PsGetCurrentProcessId(), GetCurrentProcessName()));
121
122 LogAlert(ALERT_SS_VDM, OP_VDM_USE, ALERT_RULE_NONE, ACTION_DENY, ALERT_PRIORITY_MEDIUM, NULL, 0, NULL);
123
124 HOOK_ROUTINE_EXIT( STATUS_ACCESS_DENIED );
125 }
126
127
128 ASSERT(OriginalNtSetLdtEntries);
129
130 rc = OriginalNtSetLdtEntries(Selector0, Entry0Low, Entry0Hi, Selector1, Entry1Low, Entry1Hi);
131
132
133 if (LearningMode == TRUE)
134 TURN_VDM_PROTECTION_OFF(NewPolicy);
135
136
137 HOOK_ROUTINE_EXIT(rc);
138}
139
140
141
142/*
143 * HookedNtVdmControl()
144 *
145 * Description:
146 * This function mediates the NtVdmControl() system service and disallows access to it.
147 *
148 * NOTE: ZwVdmControl performs a control operation on a VDM. [NAR]
149 *
150 * Parameters:
151 * Those of NtVdmControl().
152 *
153 * Returns:
154 * STATUS_ACCESS_DENIED if 16-bit applications are disabled.
155 * Otherwise, NTSTATUS returned by NtVdmControl().
156 */
157
158NTSTATUS
159NTAPI
160HookedNtVdmControl
161(
162 IN ULONG ControlCode,
163 IN PVOID ControlData
164)
165{
166 HOOK_ROUTINE_ENTER();
167
168
169 LOG(LOG_SS_VDM, LOG_PRIORITY_VERBOSE, ("%d (%S) HookedNtVdmControl(%x %x)\n", (ULONG) PsGetCurrentProcessId(), GetCurrentProcessName(), ControlCode, ControlData));
170
171 if (LearningMode == FALSE && IsVdmAllowed() == FALSE)
172 {
173 LOG(LOG_SS_VDM, LOG_PRIORITY_DEBUG, ("%d (%S) HookedNtVdmControl: disallowing VDM access\n", (ULONG) PsGetCurrentProcessId(), GetCurrentProcessName()));
174
175 LogAlert(ALERT_SS_VDM, OP_VDM_USE, ALERT_RULE_NONE, ACTION_DENY, ALERT_PRIORITY_MEDIUM, NULL, 0, NULL);
176
177 HOOK_ROUTINE_EXIT( STATUS_ACCESS_DENIED );
178 }
179
180
181 ASSERT(OriginalNtVdmControl);
182
183 rc = OriginalNtVdmControl(ControlCode, ControlData);
184
185
186 if (LearningMode == TRUE)
187 TURN_VDM_PROTECTION_OFF(NewPolicy);
188
189
190 HOOK_ROUTINE_EXIT(rc);
191}
192
193
194
195/*
196 * InitVdmHooks()
197 *
198 * Description:
199 * Initializes all the mediated vdm operation pointers. The "OriginalFunction" pointers
200 * are initialized by InstallSyscallsHooks() that must be called prior to this function.
201 *
202 * NOTE: Called once during driver initialization (DriverEntry()).
203 *
204 * Parameters:
205 * None.
206 *
207 * Returns:
208 * TRUE to indicate success, FALSE if failed.
209 */
210
211BOOLEAN
212InitVdmHooks()
213{
214 if ( (OriginalNtSetLdtEntries = (fpZwSetLdtEntries) ZwCalls[ZW_SET_LDT_ENTRIES_INDEX].OriginalFunction) == NULL)
215 {
216 LOG(LOG_SS_VDM, LOG_PRIORITY_DEBUG, ("InitVdmHooks: OriginalNtSetLdtEntries is NULL\n"));
217 return FALSE;
218 }
219
220 if ( (OriginalNtVdmControl = (fpZwVdmControl) ZwCalls[ZW_VDM_CONTROL_INDEX].OriginalFunction) == NULL)
221 {
222 LOG(LOG_SS_VDM, LOG_PRIORITY_DEBUG, ("InitVdmHooks: OriginalNtVdmControl is NULL\n"));
223 return FALSE;
224 }
225
226 return TRUE;
227}
diff --git a/vdm.h b/vdm.h
new file mode 100644
index 0000000..260a05e
--- /dev/null
+++ b/vdm.h
@@ -0,0 +1,72 @@
1/*
2 * Copyright (c) 2004 Security Architects Corporation. All rights reserved.
3 *
4 * Module Name:
5 *
6 * vdm.h
7 *
8 * Abstract:
9 *
10 * This module implements various VDM (Virtual Dos Machine) hooking routines.
11 *
12 * Author:
13 *
14 * Eugene Tsyrklevich 06-Apr-2004
15 *
16 * Revision History:
17 *
18 * None.
19 */
20
21
22#ifndef __VDM_H__
23#define __VDM_H__
24
25
26
27/*
28 * ZwSetLdtEntries sets Local Descriptor Table (LDT) entries for a Virtual DOS Machine (VDM). [NAR]
29 */
30
31typedef NTSTATUS (*fpZwSetLdtEntries) (
32 IN ULONG Selector0,
33 IN ULONG Entry0Low,
34 IN ULONG Entry0Hi,
35 IN ULONG Selector1,
36 IN ULONG Entry1Low,
37 IN ULONG Entry1Hi
38 );
39
40NTSTATUS
41NTAPI
42HookedNtSetLdtEntries(
43 IN ULONG Selector0,
44 IN ULONG Entry0Low,
45 IN ULONG Entry0Hi,
46 IN ULONG Selector1,
47 IN ULONG Entry1Low,
48 IN ULONG Entry1Hi
49 );
50
51
52/*
53 * ZwVdmControl performs a control operation on a VDM. [NAR]
54 */
55
56typedef NTSTATUS (*fpZwVdmControl) (
57 IN ULONG ControlCode,
58 IN PVOID ControlData
59 );
60
61NTSTATUS
62NTAPI
63HookedNtVdmControl(
64 IN ULONG ControlCode,
65 IN PVOID ControlData
66 );
67
68
69BOOLEAN InitVdmHooks();
70
71
72#endif /* __VDM_H__ */
diff --git a/wireless.c b/wireless.c
new file mode 100644
index 0000000..0132824
--- /dev/null
+++ b/wireless.c
@@ -0,0 +1,338 @@
1/*
2 * Copyright (c) 2004 Security Architects Corporation. All rights reserved.
3 *
4 * Module Name:
5 *
6 * wireless.c
7 *
8 * Abstract:
9 *
10 * This module deals with wireless cards.
11 *
12 * Author:
13 *
14 * Eugene Tsyrklevich 12-Oct-2004
15 */
16
17
18#include <NTDDK.h>
19
20#undef DEFINE_GUID
21#define DEFINE_GUID(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) const GUID name \
22 = { l, w1, w2, { b1, b2, b3, b4, b5, b6, b7, b8 } }
23
24#include <ntddstor.h>
25#include <wdmguid.h>
26#include "wireless.h"
27#include "pathproc.h"
28#include "policy.h"
29
30
31#ifdef ALLOC_PRAGMA
32#pragma alloc_text (INIT, InitWirelessHooks)
33#pragma alloc_text (PAGE, RemoveWirelessHooks)
34#endif
35
36
37PVOID WirelessNotificationEntry = NULL;
38
39/* removable wireless flags defined in drive.h (READONLY, etc) */
40UCHAR WirelessRemovableFlags = 0;
41
42
43typedef struct _WORK_CONTEXT
44{
45 PIO_WORKITEM Item;
46 UNICODE_STRING SymbolicLinkName;
47
48} WORK_CONTEXT, *PWORK_CONTEXT;
49
50
51
52/*
53 * AddDrive()
54 *
55 * Description:
56 * .
57 *
58 * Parameters:
59 * pusDriveName - .
60 * DriveLetter - .
61 *
62 * Returns:
63 * Nothing.
64 */
65
66VOID
67AddDrive(PUNICODE_STRING pusDriveName, CHAR DriveLetter)
68{
69 PDEVICE_OBJECT pDeviceObject;
70 STORAGE_HOTPLUG_INFO HotplugInfo;
71
72
73 pDeviceObject = GetDriveHotplugInformation(pusDriveName, &HotplugInfo);
74 if (pDeviceObject == NULL)
75 return;
76
77
78 LOG(LOG_SS_DRIVE, LOG_PRIORITY_DEBUG, ("AddDrive: %c:\\ drive: %d %d %d %d %d\n", DriveLetter, HotplugInfo.Size, HotplugInfo.WirelessRemovable, HotplugInfo.WirelessHotplug, HotplugInfo.DeviceHotplug, HotplugInfo.WriteCacheEnableOverride));
79
80
81 //XXX remove
82 if (HotplugInfo.WirelessRemovable == FALSE && HotplugInfo.WirelessHotplug == TRUE)
83 {
84 LOG(LOG_SS_DRIVE, LOG_PRIORITY_DEBUG, ("AddDrive: hotpluggable but not removable drive! %c: %S\n", DriveLetter, pusDriveName->Buffer));
85 }
86
87 if (HotplugInfo.WirelessRemovable)
88 {
89 CHAR rule[MAX_PATH];
90
91
92 LOG(LOG_SS_DRIVE, LOG_PRIORITY_DEBUG, ("AddDrive: removable drive! %c: %S\n", DriveLetter, pusDriveName->Buffer));
93
94
95 /* Create a new global policy rule */
96
97 if (IS_REMOVABLE_WIRELESS_DISABLED())
98 {
99 sprintf(rule, "name match \"%c:\\*\" then %s", DriveLetter, "deny");
100
101 PolicyParseObjectRule(&gSecPolicy, RULE_FILE, "all", rule);
102
103 /* no need to process other rules, this one denies everything already */
104 return;
105 }
106
107 if (IS_REMOVABLE_WIRELESS_READONLY())
108 {
109 sprintf(rule, "name match \"%c:\\*\" then %s", DriveLetter, "deny");
110
111 PolicyParseObjectRule(&gSecPolicy, RULE_FILE, "write", rule);
112 }
113
114 if (IS_REMOVABLE_WIRELESS_NOEXECUTE())
115 {
116 sprintf(rule, "name match \"%c:\\*\" then %s", DriveLetter, "deny");
117
118 PolicyParseObjectRule(&gSecPolicy, RULE_FILE, "execute", rule);
119 }
120 }
121
122
123 return;
124}
125
126
127
128/*
129 * RemoveDrive()
130 *
131 * Description:
132 * .
133 *
134 * Parameters:
135 * pusDriveName - .
136 *
137 * Returns:
138 * Nothing.
139 */
140
141VOID
142RemoveDrive(PUNICODE_STRING pusDriveName)
143{
144 PDEVICE_OBJECT pDeviceObject;
145 STORAGE_HOTPLUG_INFO HotplugInfo;
146 NTSTATUS rc;
147
148
149 pDeviceObject = GetDriveHotplugInformation(pusDriveName, &HotplugInfo);
150 if (pDeviceObject == NULL)
151 return;
152
153// KdPrint(("success %d %d %d %d %d\n", info.Size, info.WirelessRemovable, info.WirelessHotplug, info.DeviceHotplug, info.WriteCacheEnableOverride));
154
155 if (HotplugInfo.WirelessRemovable)
156 LOG(LOG_SS_DRIVE, LOG_PRIORITY_DEBUG, ("RemoveDrive: removable drive! %S\n", pusDriveName->Buffer));
157
158
159 rc = RtlVolumeDeviceToDosName(pDeviceObject, pusDriveName);
160 if (NT_SUCCESS(rc))
161 LOG(LOG_SS_DRIVE, LOG_PRIORITY_DEBUG, ("RemoveDrive: IoVolumeDeviceToDosName returned %S\n", pusDriveName->Buffer));
162
163 return;
164}
165
166
167
168/*
169 * PnpWorker()
170 *
171 * Description:
172 * A work item routine that runs at PASSIVE_LEVEL irql. The routine is scheduled by PnpCallback
173 * which is not allowed to block.
174 *
175 * PnpWorker calls RemoveDrive() with a drive name setup by PnpCallback.
176 *
177 * Parameters:
178 * pDeviceObject - .
179 * Context - .
180 *
181 * Returns:
182 * Nothing.
183 */
184
185VOID
186PnpWorker(IN PDEVICE_OBJECT pDeviceObject, IN PVOID Context)
187{
188 PWORK_CONTEXT WorkContext = (PWORK_CONTEXT) Context;
189
190
191 if (WorkContext == NULL)
192 {
193 LOG(LOG_SS_DRIVE, LOG_PRIORITY_DEBUG, ("PnpWorker: WorkContext = NULL\n"));
194 return;
195 }
196
197 LOG(LOG_SS_DRIVE, LOG_PRIORITY_DEBUG, ("PnpWorker: %S\n", WorkContext->SymbolicLinkName.Buffer));
198
199
200 RemoveDrive(&WorkContext->SymbolicLinkName);
201
202
203 IoFreeWorkItem(WorkContext->Item);
204
205 ExFreePoolWithTag(WorkContext, _POOL_TAG);
206}
207
208
209
210/*
211 * PnpCallback()
212 *
213 * Description:
214 * Plug-and-Play callback. Gets called when a p-n-p drive/cdrom interface is modified
215 * (i.e. when a removable drive is added or removed from the system).
216 *
217 * Parameters:
218 * NotificationStructure - DEVICE_INTERFACE_CHANGE_NOTIFICATION indicating which interface changed.
219 * Context - the driver's device context.
220 *
221 * Returns:
222 * STATUS_SUCCESS.
223 */
224
225NTSTATUS
226PnpCallback(IN PVOID NotificationStructure, IN PVOID Context)
227{
228 PDEVICE_INTERFACE_CHANGE_NOTIFICATION Notify = (PDEVICE_INTERFACE_CHANGE_NOTIFICATION) NotificationStructure;
229 PDEVICE_OBJECT pDeviceObject = (PDEVICE_OBJECT) Context;
230 PIO_WORKITEM WorkItem;
231 PWORK_CONTEXT WorkContext;
232
233
234 if (IsEqualGUID((LPGUID) &Notify->Event, (LPGUID) &GUID_DEVICE_INTERFACE_REMOVAL))
235 {
236 LOG(LOG_SS_DRIVE, LOG_PRIORITY_DEBUG, ("GUID_DEVICE_INTERFACE_REMOVAL %S\n", Notify->SymbolicLinkName->Buffer));
237/*
238 }
239
240
241 if (IsEqualGUID((LPGUID) &Notify->Event, (LPGUID) &GUID_DEVICE_INTERFACE_ARRIVAL) ||
242 IsEqualGUID((LPGUID) &Notify->Event, (LPGUID) &GUID_DEVICE_INTERFACE_REMOVAL))
243 {
244 LOG(LOG_SS_DRIVE, LOG_PRIORITY_DEBUG, ("GUID_DEVICE_INTERFACE_ARRIVAL %x %S\n", Notify->SymbolicLinkName, Notify->SymbolicLinkName->Buffer));
245*/
246
247 /*
248 * Schedule a work item to process this request. Cannot block in this callback function.
249 */
250
251 WorkItem = IoAllocateWorkItem(pDeviceObject);
252
253 WorkContext = (PWORK_CONTEXT) ExAllocatePoolWithTag(PagedPool,
254 sizeof(WORK_CONTEXT) + Notify->SymbolicLinkName->Length,
255 _POOL_TAG);
256 if (!WorkContext)
257 {
258 IoFreeWorkItem(WorkItem);
259 return(STATUS_SUCCESS);
260 }
261
262 WorkContext->SymbolicLinkName.Buffer = (PWSTR) ((PCHAR) &WorkContext->SymbolicLinkName + sizeof(UNICODE_STRING));
263 WorkContext->SymbolicLinkName.MaximumLength = Notify->SymbolicLinkName->Length;
264 WorkContext->SymbolicLinkName.Length = 0;
265
266 WorkContext->Item = WorkItem;
267 RtlCopyUnicodeString(&WorkContext->SymbolicLinkName, Notify->SymbolicLinkName);
268
269 IoQueueWorkItem(WorkItem, PnpWorker, DelayedWorkQueue, WorkContext);
270 }
271
272
273 return STATUS_SUCCESS;
274}
275
276
277
278/*
279 * InitWirelessHooks()
280 *
281 * Description:
282 * Process any existing wireless cards and register Plug-and-Play notifications for future drive additions/removals.
283 *
284 * NOTE: Called once during driver initialization (DriverEntry()).
285 *
286 * Parameters:
287 * None.
288 *
289 * Returns:
290 * TRUE to indicate success, FALSE if failed.
291 */
292
293BOOLEAN
294InitWirelessHooks(IN PDRIVER_OBJECT pDriverObject, IN PDEVICE_OBJECT pDeviceObject)
295{
296 NTSTATUS rc;
297
298
299 rc = IoRegisterPlugPlayNotification(EventCategoryDeviceInterfaceChange,
300 /*0,*/PNPNOTIFY_DEVICE_INTERFACE_INCLUDE_EXISTING_INTERFACES,
301 (LPGUID) &GUID_DEVINTERFACE_DISK,
302 pDriverObject,
303 PnpCallback,
304 pDeviceObject,
305 &WirelessNotificationEntry);
306
307 if (! NT_SUCCESS(rc))
308 {
309 LOG(LOG_SS_DRIVE, LOG_PRIORITY_DEBUG, ("InitWirelessHooks: IoRegisterPlugPlayNotification failed with status %x\n", rc));
310 return FALSE;
311 }
312
313
314 return TRUE;
315}
316
317
318
319/*
320 * RemoveWirelessHooks()
321 *
322 * Description:
323 * Unregister Plug-and-Play notifications.
324 *
325 * Parameters:
326 * None.
327 *
328 * Returns:
329 * Nothing.
330 */
331
332VOID
333RemoveWirelessHooks()
334{
335 if (WirelessNotificationEntry)
336 if (! NT_SUCCESS(IoUnregisterPlugPlayNotification(WirelessNotificationEntry)))
337 LOG(LOG_SS_DRIVE, LOG_PRIORITY_DEBUG, ("RemoveWirelessHooks: IoUnregisterPlugPlayNotification failed\n"));
338}
diff --git a/wireless.h b/wireless.h
new file mode 100644
index 0000000..ac55368
--- /dev/null
+++ b/wireless.h
@@ -0,0 +1,40 @@
1/*
2 * Copyright (c) 2004 Security Architects Corporation. All rights reserved.
3 *
4 * Module Name:
5 *
6 * wireless.c
7 *
8 * Abstract:
9 *
10 * This module deals with wireless cards.
11 *
12 * Author:
13 *
14 * Eugene Tsyrklevich 02-Jun-2004
15 */
16
17
18#ifndef __WIRELESS_H__
19#define __WIRELESS_H__
20
21
22#define WIRELESS_REMOVABLE_PERMIT 0
23#define WIRELESS_REMOVABLE_DISABLE 1
24#define WIRELESS_REMOVABLE_READONLY 2
25#define WIRELESS_REMOVABLE_NOEXECUTE 4
26
27#define IS_REMOVABLE_WIRELESS_READONLY() ((WirelessRemovableFlags & WIRELESS_REMOVABLE_READONLY) == WIRELESS_REMOVABLE_READONLY)
28#define IS_REMOVABLE_WIRELESS_DISABLED() ((WirelessRemovableFlags & WIRELESS_REMOVABLE_DISABLE) == WIRELESS_REMOVABLE_DISABLE)
29#define IS_REMOVABLE_WIRELESS_NOEXECUTE() ((WirelessRemovableFlags & WIRELESS_REMOVABLE_NOEXECUTE) == WIRELESS_REMOVABLE_NOEXECUTE)
30
31
32extern UCHAR WirelessRemovableFlags;
33
34
35BOOLEAN InitWirelessHooks(IN PDRIVER_OBJECT pDriverObject, IN PDEVICE_OBJECT pDeviceObject);
36VOID RemoveRemovableWirelessHooks();
37VOID MonitorDriveLinks(const PCHAR Link);
38
39
40#endif /* __WIRELESS_H__ */