summaryrefslogtreecommitdiff
path: root/learn.c
diff options
context:
space:
mode:
authortumagonx2017-08-08 10:54:53 +0700
committertumagonx2017-08-08 10:54:53 +0700
commit2acec63b2ed75bf4b71ad257db573c4b8f9639e7 (patch)
treea8bea139ddd26116d44ea182b0b8436f2162e6e3 /learn.c
initial commit
Diffstat (limited to 'learn.c')
-rw-r--r--learn.c1414
1 files changed, 1414 insertions, 0 deletions
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}