diff options
| -rw-r--r-- | MAKEFILE | 8 | ||||
| -rw-r--r-- | Sources | 9 | ||||
| -rw-r--r-- | TODO | 122 | ||||
| -rw-r--r-- | accessmask.c | 693 | ||||
| -rw-r--r-- | accessmask.h | 55 | ||||
| -rw-r--r-- | atom.c | 187 | ||||
| -rw-r--r-- | atom.h | 78 | ||||
| -rw-r--r-- | boprot.c | 173 | ||||
| -rw-r--r-- | boprot.h | 33 | ||||
| -rw-r--r-- | debug.c | 162 | ||||
| -rw-r--r-- | debug.h | 47 | ||||
| -rw-r--r-- | dirobj.c | 153 | ||||
| -rw-r--r-- | dirobj.h | 78 | ||||
| -rw-r--r-- | driver.c | 1237 | ||||
| -rw-r--r-- | driver.h | 90 | ||||
| -rw-r--r-- | driver.sln | 21 | ||||
| -rw-r--r-- | driver.vcproj | 341 | ||||
| -rw-r--r-- | driverobj.c | 205 | ||||
| -rw-r--r-- | driverobj.h | 68 | ||||
| -rw-r--r-- | event.c | 259 | ||||
| -rw-r--r-- | event.h | 105 | ||||
| -rw-r--r-- | file.c | 665 | ||||
| -rw-r--r-- | file.h | 273 | ||||
| -rw-r--r-- | hookproc.c | 1799 | ||||
| -rw-r--r-- | hookproc.h | 460 | ||||
| -rw-r--r-- | i386.c | 178 | ||||
| -rw-r--r-- | i386.h | 184 | ||||
| -rw-r--r-- | job.c | 157 | ||||
| -rw-r--r-- | job.h | 68 | ||||
| -rw-r--r-- | learn.c | 1414 | ||||
| -rw-r--r-- | learn.h | 43 | ||||
| -rw-r--r-- | log.c | 459 | ||||
| -rw-r--r-- | log.h | 236 | ||||
| -rw-r--r-- | media.c | 444 | ||||
| -rw-r--r-- | media.h | 40 | ||||
| -rw-r--r-- | misc.c | 943 | ||||
| -rw-r--r-- | misc.h | 101 | ||||
| -rw-r--r-- | mutant.c | 151 | ||||
| -rw-r--r-- | mutant.h | 78 | ||||
| -rw-r--r-- | network.c | 715 | ||||
| -rw-r--r-- | network.h | 57 | ||||
| -rw-r--r-- | ntproto.h | 289 | ||||
| -rw-r--r-- | pathproc.c | 1093 | ||||
| -rw-r--r-- | pathproc.h | 67 | ||||
| -rw-r--r-- | policy.c | 3243 | ||||
| -rw-r--r-- | policy.h | 344 | ||||
| -rw-r--r-- | port.c | 318 | ||||
| -rw-r--r-- | port.h | 162 | ||||
| -rw-r--r-- | process.c | 1270 | ||||
| -rw-r--r-- | process.h | 215 | ||||
| -rw-r--r-- | procname.c | 677 | ||||
| -rw-r--r-- | procname.h | 68 | ||||
| -rw-r--r-- | registry.c | 402 | ||||
| -rw-r--r-- | registry.h | 140 | ||||
| -rw-r--r-- | resource.h | 15 | ||||
| -rw-r--r-- | section.c | 285 | ||||
| -rw-r--r-- | section.h | 112 | ||||
| -rw-r--r-- | semaphore.c | 161 | ||||
| -rw-r--r-- | semaphore.h | 69 | ||||
| -rw-r--r-- | symlink.c | 185 | ||||
| -rw-r--r-- | symlink.h | 78 | ||||
| -rw-r--r-- | sysinfo.c | 197 | ||||
| -rw-r--r-- | sysinfo.h | 190 | ||||
| -rw-r--r-- | time.c | 190 | ||||
| -rw-r--r-- | time.h | 68 | ||||
| -rw-r--r-- | timer.c | 151 | ||||
| -rw-r--r-- | timer.h | 78 | ||||
| -rw-r--r-- | token.c | 250 | ||||
| -rw-r--r-- | token.h | 145 | ||||
| -rw-r--r-- | userland.c | 573 | ||||
| -rw-r--r-- | userland.h | 133 | ||||
| -rw-r--r-- | vdm.c | 227 | ||||
| -rw-r--r-- | vdm.h | 72 | ||||
| -rw-r--r-- | wireless.c | 338 | ||||
| -rw-r--r-- | wireless.h | 40 |
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 | |||
| @@ -0,0 +1,9 @@ | |||
| 1 | TARGETNAME=ozone | ||
| 2 | TARGETTYPE=DRIVER | ||
| 3 | |||
| 4 | TARGETPATH=. | ||
| 5 | INCLUDES= $(BASEDIR)\inc;. | ||
| 6 | |||
| 7 | TARGETLIBS=$(DDK_LIB_PATH)\tdi.lib | ||
| 8 | |||
| 9 | SOURCES=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 | ||
| @@ -0,0 +1,122 @@ | |||
| 1 | TODO: | ||
| 2 | |||
| 3 | append only files can be achieved by making sure that offsets passed to writefile are not less than the total size of the file | ||
| 4 | |||
| 5 | disable 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 | |||
| 8 | svchost.exe needs to be jailed by DLLs... each DLL will have its own policy | ||
| 9 | |||
| 10 | policy_include: additional.policy | ||
| 11 | |||
| 12 | add ability to deny logons to certain users | ||
| 13 | |||
| 14 | add a "signature" rule.. LocalSystem execution of different processes (especially cmd.exe) should be logged and possibly denied? | ||
| 15 | |||
| 16 | allow occasional rules to go through w/o logging? especially file & registry? | ||
| 17 | |||
| 18 | investigate SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\App Paths\\IEXPLORE.EXE | ||
| 19 | |||
| 20 | |||
| 21 | disable execution of certain applications based on their version (i.e. vulnerable IE) (from okena) | ||
| 22 | add sniffer & non-ip protocol detection (from okena) | ||
| 23 | COM/ActiveX interception | ||
| 24 | support for application clauses (chapter 6) | ||
| 25 | |||
| 26 | when creating an "exception" rule, MC can/should ask for whether the exception rule should be created on | ||
| 27 | the selected agent only, all agents of a certain type or all agents of all types | ||
| 28 | |||
| 29 | |||
| 30 | block debuggers | ||
| 31 | |||
| 32 | non-GUI/system apps cannot use GUI calls? | ||
| 33 | |||
| 34 | |||
| 35 | in server paranoid mode, allow only c:\program files\*.exe and c:\windows\*.exe to execute? | ||
| 36 | trusted 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 | |||
| 39 | explorer option.. "Run process in a sandbox.." brings up a gui that asks whether to allow file, reg, network access? | ||
| 40 | |||
| 41 | port to Itanium/AMD64 | ||
| 42 | |||
| 43 | see if we can take over the job of a buffer overflow security exception handler | ||
| 44 | on win2k3 install custom BO exception handler that terminates a process | ||
| 45 | |||
| 46 | need 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? | ||
| 47 | disable modem access, etc | ||
| 48 | |||
| 49 | raw devices of all (mounted?) filesystems should be read-only | ||
| 50 | |||
| 51 | copy in all unicode strings, check them and then pass the kernel copies to the kernel to avoid race conditions? | ||
| 52 | |||
| 53 | disable our driver if loading using LastKnownGood configuration (notify MC?) | ||
| 54 | |||
| 55 | restrict reboot capability and certain programs only to interactive sessions?! | ||
| 56 | |||
| 57 | add ability to load what programs are allowed to run? (sha1 hashes, signed binaries) | ||
| 58 | |||
| 59 | investigate kernel32!CreateHardLink | ||
| 60 | |||
| 61 | dll_all: log will also log all section rules since RULE_DLL will be converted to RULE_SECTION | ||
| 62 | |||
| 63 | protect crypto keys | ||
| 64 | |||
| 65 | use 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 | |||
| 68 | device naming on terminal servers | ||
| 69 | |||
| 70 | have a webpage which lists new vulnerabilities and whether our system would automatically protect against it | ||
| 71 | |||
| 72 | deallocate allocated virtual memory that was used by AS randomization once the process is loaded and initialized (what about dynamically loaded DLLs)? | ||
| 73 | |||
| 74 | create 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 | |||
| 76 | interactive learning mode | ||
| 77 | |||
| 78 | policy_ask user app should not run as an interative service but rather as a separate app running as a particular user | ||
| 79 | |||
| 80 | IIS install should scan the registry for any known virtual roots and automatically add them to the policy.. same for other apps | ||
| 81 | |||
| 82 | make sure that file-system protection cannot be subverted by accessing files by other means (\\127.0.0.1\share\file) | ||
| 83 | |||
| 84 | per-group policy, per-user global policy | ||
| 85 | |||
| 86 | |||
| 87 | network connect should be able to specify ports and not just ip addresses | ||
| 88 | address eq "127.0.0.1:443" then permit | ||
| 89 | address eq "0:443" then deny | ||
| 90 | address eq "\\UNCpath\blah" then log | ||
| 91 | address eq "www.porn.com:80" then deny | ||
| 92 | |||
| 93 | |||
| 94 | new 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) | ||
| 96 | posix 1003e | ||
| 97 | |||
| 98 | |||
| 99 | layers: | ||
| 100 | |||
| 101 | desktop | ||
| 102 | web server (iis, apache, netscape) | ||
| 103 | database server (oracle, MS SQL / access, Sybase, DB2, Informix, Interbase, MySQL) | ||
| 104 | terminal server | ||
| 105 | mail server | ||
| 106 | VPN server / remote access server | ||
| 107 | |||
| 108 | dns server | ||
| 109 | dhcp server | ||
| 110 | wins server | ||
| 111 | streaming media server | ||
| 112 | domain controller | ||
| 113 | file and print server | ||
| 114 | (application server – websphere, BEA websphere) | ||
| 115 | (collaboration server – IBM Lotus Domino) | ||
| 116 | |||
| 117 | |||
| 118 | client 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 | |||
| 40 | UCHAR | ||
| 41 | Get_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 | |||
| 113 | void | ||
| 114 | DecodeFileOperationType(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 | |||
| 200 | UCHAR | ||
| 201 | Get_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 | |||
| 222 | UCHAR | ||
| 223 | Get_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 | |||
| 244 | UCHAR | ||
| 245 | Get_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 | |||
| 310 | UCHAR | ||
| 311 | Get_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 | |||
| 358 | UCHAR | ||
| 359 | Get_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 | |||
| 405 | UCHAR | ||
| 406 | Get_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 | |||
| 461 | UCHAR | ||
| 462 | Get_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 | |||
| 506 | UCHAR | ||
| 507 | Get_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 | |||
| 555 | UCHAR | ||
| 556 | Get_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 | |||
| 600 | UCHAR | ||
| 601 | Get_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 | |||
| 642 | UCHAR | ||
| 643 | Get_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 | |||
| 664 | UCHAR | ||
| 665 | Get_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 | |||
| 37 | UCHAR Get_FILE_OperationType(ACCESS_MASK DesiredAccess); | ||
| 38 | UCHAR Get_NAMEDPIPE_OperationType(ACCESS_MASK DesiredAccess); | ||
| 39 | UCHAR Get_MAILSLOT_OperationType(ACCESS_MASK DesiredAccess); | ||
| 40 | UCHAR Get_REGISTRY_OperationType(ACCESS_MASK DesiredAccess); | ||
| 41 | UCHAR Get_EVENT_OperationType(ACCESS_MASK DesiredAccess); | ||
| 42 | UCHAR Get_SEMAPHORE_OperationType(ACCESS_MASK DesiredAccess); | ||
| 43 | UCHAR Get_SECTION_OperationType(ACCESS_MASK DesiredAccess); | ||
| 44 | UCHAR Get_JOB_OperationType(ACCESS_MASK DesiredAccess); | ||
| 45 | UCHAR Get_MUTANT_OperationType(ACCESS_MASK DesiredAccess); | ||
| 46 | UCHAR Get_SYMLINK_OperationType(ACCESS_MASK DesiredAccess); | ||
| 47 | UCHAR Get_TIMER_OperationType(ACCESS_MASK DesiredAccess); | ||
| 48 | UCHAR Get_PORT_OperationType(ACCESS_MASK DesiredAccess); | ||
| 49 | UCHAR Get_DIROBJ_OperationType(ACCESS_MASK DesiredAccess); | ||
| 50 | |||
| 51 | void DecodeFileOperationType(ACCESS_MASK DesiredAccess); | ||
| 52 | |||
| 53 | |||
| 54 | |||
| 55 | #endif /* __ACCESSMASK_H__ */ \ No newline at end of file | ||
| @@ -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 | |||
| 30 | fpZwAddAtom OriginalNtAddAtom = NULL; | ||
| 31 | fpZwFindAtom 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 | |||
| 52 | NTSTATUS | ||
| 53 | NTAPI | ||
| 54 | HookedNtAddAtom | ||
| 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 | |||
| 112 | NTSTATUS | ||
| 113 | NTAPI | ||
| 114 | HookedNtFindAtom | ||
| 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 | |||
| 171 | BOOLEAN | ||
| 172 | InitAtomHooks() | ||
| 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 | } | ||
| @@ -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 | |||
| 39 | typedef NTSTATUS (*fpZwAddAtom) ( | ||
| 40 | IN PWSTR String, | ||
| 41 | IN ULONG StringLength, | ||
| 42 | OUT PUSHORT Atom | ||
| 43 | ); | ||
| 44 | |||
| 45 | NTSTATUS | ||
| 46 | NTAPI | ||
| 47 | HookedNtAddAtom( | ||
| 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 | |||
| 60 | typedef NTSTATUS (*fpZwFindAtom) ( | ||
| 61 | IN PWSTR String, | ||
| 62 | IN ULONG StringLength, | ||
| 63 | OUT PUSHORT Atom | ||
| 64 | ); | ||
| 65 | |||
| 66 | NTSTATUS | ||
| 67 | NTAPI | ||
| 68 | HookedNtFindAtom( | ||
| 69 | IN PWSTR String, | ||
| 70 | IN ULONG StringLength, | ||
| 71 | OUT PUSHORT Atom | ||
| 72 | ); | ||
| 73 | |||
| 74 | |||
| 75 | BOOLEAN 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 | |||
| 34 | ULONG 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 | |||
| 52 | BOOLEAN | ||
| 53 | InitBufferOverflowProtection() | ||
| 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 | |||
| 147 | VOID | ||
| 148 | ShutdownBufferOverflowProtection() | ||
| 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 | |||
| 29 | BOOLEAN InitBufferOverflowProtection(); | ||
| 30 | VOID ShutdownBufferOverflowProtection(); | ||
| 31 | |||
| 32 | |||
| 33 | #endif /* __BOPROT_H__ */ | ||
| @@ -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 | |||
| 35 | fpZwDebugActiveProcess 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 | |||
| 54 | BOOLEAN | ||
| 55 | IsDebuggingAllowed() | ||
| 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 | |||
| 99 | NTSTATUS | ||
| 100 | NTAPI | ||
| 101 | HookedNtDebugActiveProcess | ||
| 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 | |||
| 152 | BOOLEAN | ||
| 153 | InitDebugHooks() | ||
| 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 | } | ||
| @@ -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 | |||
| 31 | typedef NTSTATUS (*fpZwDebugActiveProcess) ( | ||
| 32 | UINT32 Unknown1, | ||
| 33 | UINT32 Unknown2 | ||
| 34 | ); | ||
| 35 | |||
| 36 | NTSTATUS | ||
| 37 | NTAPI | ||
| 38 | HookedNtDebugActiveProcess( | ||
| 39 | UINT32 Unknown1, | ||
| 40 | UINT32 Unknown2 | ||
| 41 | ); | ||
| 42 | |||
| 43 | |||
| 44 | BOOLEAN 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 | |||
| 32 | fpZwOpenDirectoryObject OriginalNtOpenDirectoryObject = NULL; | ||
| 33 | fpZwCreateDirectoryObject 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 | |||
| 54 | NTSTATUS | ||
| 55 | NTAPI | ||
| 56 | HookedNtCreateDirectoryObject | ||
| 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 | |||
| 96 | NTSTATUS | ||
| 97 | NTAPI | ||
| 98 | HookedNtOpenDirectoryObject | ||
| 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 | |||
| 137 | BOOLEAN | ||
| 138 | InitDirobjHooks() | ||
| 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 | |||
| 41 | typedef NTSTATUS (*fpZwCreateDirectoryObject) ( | ||
| 42 | OUT PHANDLE DirectoryHandle, | ||
| 43 | IN ACCESS_MASK DesiredAccess, | ||
| 44 | IN POBJECT_ATTRIBUTES ObjectAttributes | ||
| 45 | ); | ||
| 46 | |||
| 47 | NTSTATUS | ||
| 48 | NTAPI | ||
| 49 | HookedNtCreateDirectoryObject( | ||
| 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 | |||
| 60 | typedef NTSTATUS (*fpZwOpenDirectoryObject) ( | ||
| 61 | OUT PHANDLE DirectoryHandle, | ||
| 62 | IN ACCESS_MASK DesiredAccess, | ||
| 63 | IN POBJECT_ATTRIBUTES ObjectAttributes | ||
| 64 | ); | ||
| 65 | |||
| 66 | NTSTATUS | ||
| 67 | NTAPI | ||
| 68 | HookedNtOpenDirectoryObject( | ||
| 69 | OUT PHANDLE DirectoryHandle, | ||
| 70 | IN ACCESS_MASK DesiredAccess, | ||
| 71 | IN POBJECT_ATTRIBUTES ObjectAttributes | ||
| 72 | ); | ||
| 73 | |||
| 74 | |||
| 75 | BOOLEAN 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 | |||
| 58 | LONG SysenterEip = 0; | ||
| 59 | |||
| 60 | |||
| 61 | __declspec(naked) | ||
| 62 | VOID | ||
| 63 | SysenterHandler() | ||
| 64 | { | ||
| 65 | _asm and ecx, 0x000000FF | ||
| 66 | _asm sub esp, ecx | ||
| 67 | _asm jmp [SysenterEip] | ||
| 68 | } | ||
| 69 | |||
| 70 | |||
| 71 | VOID | ||
| 72 | blah() | ||
| 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 | /* | ||
| 133 | PVOID Find_Kernel32_Base(); | ||
| 134 | NTSTATUS | ||
| 135 | NTAPI | ||
| 136 | ZwCreateSymbolicLinkObject( | ||
| 137 | OUT PHANDLE SymbolicLinkHandle, | ||
| 138 | IN ACCESS_MASK DesiredAccess, | ||
| 139 | IN POBJECT_ATTRIBUTES ObjectAttributes, | ||
| 140 | IN PUNICODE_STRING TargetName | ||
| 141 | ); | ||
| 142 | HANDLE h; | ||
| 143 | */ | ||
| 144 | NTSTATUS | ||
| 145 | DriverEntry(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 | |||
| 527 | VOID | ||
| 528 | DriverUnload(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 | |||
| 644 | NTSTATUS | ||
| 645 | DriverDeviceControl(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 | |||
| 1072 | NTSTATUS | ||
| 1073 | DriverCreate(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 | |||
| 1117 | NTSTATUS | ||
| 1118 | DriverClose(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 | |||
| 1152 | NTSTATUS | ||
| 1153 | DriverCleanup(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 | ||
| 1179 | NTSTATUS | ||
| 1180 | DriverRead(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 | |||
| 1210 | NTSTATUS | ||
| 1211 | DriverWrite(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 | |||
| 27 | typedef 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 | |||
| 52 | extern BOOLEAN ActiveUserAgent; | ||
| 53 | |||
| 54 | |||
| 55 | VOID DriverUnload(IN PDRIVER_OBJECT pDriverObject); | ||
| 56 | NTSTATUS DriverCreate(IN PDEVICE_OBJECT pDeviceObject, IN PIRP pIrp); | ||
| 57 | NTSTATUS DriverCleanup(IN PDEVICE_OBJECT pDeviceObject, IN PIRP pIrp); | ||
| 58 | NTSTATUS DriverClose (IN PDEVICE_OBJECT pDeviceObject, IN PIRP pIrp); | ||
| 59 | NTSTATUS DriverRead (IN PDEVICE_OBJECT pDeviceObject, IN PIRP pIrp); | ||
| 60 | NTSTATUS DriverWrite (IN PDEVICE_OBJECT pDeviceObject, IN PIRP pIrp); | ||
| 61 | NTSTATUS 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 @@ | |||
| 1 | Microsoft Visual Studio Solution File, Format Version 8.00 | ||
| 2 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "driver", "driver.vcproj", "{D5256063-DBCD-44E3-890B-682CBCF94848}" | ||
| 3 | ProjectSection(ProjectDependencies) = postProject | ||
| 4 | EndProjectSection | ||
| 5 | EndProject | ||
| 6 | Global | ||
| 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 | ||
| 21 | EndGlobal | ||
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 | |||
| 30 | fpZwLoadDriver OriginalNtLoadDriver = NULL; | ||
| 31 | fpZwUnloadDriver 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 | |||
| 51 | NTSTATUS | ||
| 52 | NTAPI | ||
| 53 | HookedNtLoadDriver | ||
| 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 | ||
| 119 | NTSTATUS | ||
| 120 | NTAPI | ||
| 121 | HookedNtUnloadDriver | ||
| 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 | |||
| 189 | BOOLEAN | ||
| 190 | InitDriverObjectHooks() | ||
| 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 | |||
| 39 | typedef NTSTATUS (*fpZwLoadDriver) ( | ||
| 40 | IN PUNICODE_STRING DriverServiceName | ||
| 41 | ); | ||
| 42 | |||
| 43 | NTSTATUS | ||
| 44 | NTAPI | ||
| 45 | HookedNtLoadDriver( | ||
| 46 | IN PUNICODE_STRING DriverServiceName | ||
| 47 | ); | ||
| 48 | |||
| 49 | |||
| 50 | /* | ||
| 51 | * ZwUnloadDriver unloads a device driver. [NAR] | ||
| 52 | */ | ||
| 53 | |||
| 54 | typedef NTSTATUS (*fpZwUnloadDriver) ( | ||
| 55 | IN PUNICODE_STRING DriverServiceName | ||
| 56 | ); | ||
| 57 | |||
| 58 | NTSTATUS | ||
| 59 | NTAPI | ||
| 60 | HookedNtUnloadDriver( | ||
| 61 | IN PUNICODE_STRING DriverServiceName | ||
| 62 | ); | ||
| 63 | |||
| 64 | |||
| 65 | BOOLEAN InitDriverObjectHooks(); | ||
| 66 | |||
| 67 | |||
| 68 | #endif /* __DRIVEROBJ_H__ */ | ||
| @@ -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 | |||
| 37 | fpZwCreateEventPair OriginalNtCreateEventPair = NULL; | ||
| 38 | fpZwOpenEventPair OriginalNtOpenEventPair = NULL; | ||
| 39 | |||
| 40 | fpZwCreateEvent OriginalNtCreateEvent = NULL; | ||
| 41 | fpZwOpenEvent 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 | |||
| 61 | NTSTATUS | ||
| 62 | NTAPI | ||
| 63 | HookedNtCreateEvent | ||
| 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 | |||
| 105 | NTSTATUS | ||
| 106 | NTAPI | ||
| 107 | HookedNtOpenEvent | ||
| 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 | |||
| 147 | NTSTATUS | ||
| 148 | NTAPI | ||
| 149 | HookedNtCreateEventPair | ||
| 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 | |||
| 190 | NTSTATUS | ||
| 191 | NTAPI | ||
| 192 | HookedNtOpenEventPair | ||
| 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 | |||
| 231 | BOOLEAN | ||
| 232 | InitEventHooks() | ||
| 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 | } | ||
| @@ -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 | |||
| 31 | typedef 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 | |||
| 39 | NTSTATUS 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 | |||
| 52 | typedef NTSTATUS (*fpZwOpenEvent) ( | ||
| 53 | OUT PHANDLE EventHandle, | ||
| 54 | IN ACCESS_MASK DesiredAccess, | ||
| 55 | IN POBJECT_ATTRIBUTES ObjectAttributes | ||
| 56 | ); | ||
| 57 | |||
| 58 | NTSTATUS 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 | |||
| 69 | typedef NTSTATUS (*fpZwCreateEventPair) ( | ||
| 70 | OUT PHANDLE EventPairHandle, | ||
| 71 | IN ACCESS_MASK DesiredAccess, | ||
| 72 | IN POBJECT_ATTRIBUTES ObjectAttributes | ||
| 73 | ); | ||
| 74 | |||
| 75 | NTSTATUS 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 | |||
| 86 | typedef NTSTATUS (*fpZwOpenEventPair) ( | ||
| 87 | OUT PHANDLE EventPairHandle, | ||
| 88 | IN ACCESS_MASK DesiredAccess, | ||
| 89 | IN POBJECT_ATTRIBUTES ObjectAttributes | ||
| 90 | ); | ||
| 91 | |||
| 92 | NTSTATUS | ||
| 93 | NTAPI | ||
| 94 | HookedNtOpenEventPair( | ||
| 95 | OUT PHANDLE EventPairHandle, | ||
| 96 | IN ACCESS_MASK DesiredAccess, | ||
| 97 | IN POBJECT_ATTRIBUTES ObjectAttributes | ||
| 98 | ); | ||
| 99 | |||
| 100 | |||
| 101 | |||
| 102 | BOOLEAN InitEventHooks(); | ||
| 103 | |||
| 104 | |||
| 105 | #endif /* __EVENT_H__ */ | ||
| @@ -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 | |||
| 36 | fpZwCreateFile OriginalNtCreateFile = NULL; | ||
| 37 | fpZwOpenFile OriginalNtOpenFile = NULL; | ||
| 38 | fpZwDeleteFile OriginalNtDeleteFile = NULL; | ||
| 39 | fpZwQueryAttributesFile OriginalNtQueryAttributesFile = NULL; | ||
| 40 | fpZwQueryFullAttributesFile OriginalNtQueryFullAttributesFile = NULL; | ||
| 41 | fpZwQueryDirectoryFile OriginalNtQueryDirectoryFile = NULL; | ||
| 42 | fpZwSetInformationFile OriginalNtSetInformationFile = NULL; | ||
| 43 | |||
| 44 | fpZwCreateMailslotFile OriginalNtCreateMailslotFile = NULL; | ||
| 45 | fpZwCreateNamedPipeFile 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 | |||
| 71 | NTSTATUS | ||
| 72 | NTAPI | ||
| 73 | HookedNtCreateFile | ||
| 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 | /* | ||
| 124 | XXX | ||
| 125 | investigate | ||
| 126 | |||
| 127 | The FileId can be used to open the file, when the FILE_OPEN_BY_FILE_ID | ||
| 128 | CreateOption is specified in a call to ZwCreateFile. | ||
| 129 | |||
| 130 | whether 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 | |||
| 176 | NTSTATUS | ||
| 177 | NTAPI | ||
| 178 | HookedNtOpenFile | ||
| 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 | |||
| 237 | NTSTATUS | ||
| 238 | NTAPI | ||
| 239 | HookedNtDeleteFile | ||
| 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 | |||
| 277 | NTSTATUS | ||
| 278 | NTAPI | ||
| 279 | HookedNtQueryAttributesFile | ||
| 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 | |||
| 318 | NTSTATUS | ||
| 319 | NTAPI | ||
| 320 | HookedNtQueryFullAttributesFile | ||
| 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 | |||
| 359 | NTSTATUS | ||
| 360 | NTAPI | ||
| 361 | HookedNtQueryDirectoryFile | ||
| 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 | |||
| 438 | NTSTATUS | ||
| 439 | NTAPI | ||
| 440 | HookedNtSetInformationFile | ||
| 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 | |||
| 504 | NTSTATUS | ||
| 505 | NTAPI | ||
| 506 | HookedNtCreateNamedPipeFile | ||
| 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 | |||
| 560 | NTSTATUS | ||
| 561 | NTAPI | ||
| 562 | HookedNtCreateMailslotFile | ||
| 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 | |||
| 607 | BOOLEAN | ||
| 608 | InitFileHooks() | ||
| 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 | } | ||
| @@ -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 | |||
| 30 | typedef 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 | |||
| 44 | NTSTATUS | ||
| 45 | NTAPI | ||
| 46 | HookedNtCreateFile( | ||
| 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 | |||
| 65 | typedef 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 | |||
| 74 | NTSTATUS | ||
| 75 | NTAPI | ||
| 76 | HookedNtOpenFile( | ||
| 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 | |||
| 90 | typedef NTSTATUS (*fpZwDeleteFile) ( | ||
| 91 | IN POBJECT_ATTRIBUTES ObjectAttributes | ||
| 92 | ); | ||
| 93 | |||
| 94 | NTSTATUS | ||
| 95 | NTAPI | ||
| 96 | HookedNtDeleteFile( | ||
| 97 | IN POBJECT_ATTRIBUTES ObjectAttributes | ||
| 98 | ); | ||
| 99 | |||
| 100 | |||
| 101 | /* | ||
| 102 | * ZwQueryDirectoryFile retrieves information about the contents of a directory. [NAR] | ||
| 103 | */ | ||
| 104 | |||
| 105 | typedef 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 | |||
| 119 | NTSTATUS | ||
| 120 | NTAPI | ||
| 121 | HookedNtQueryDirectoryFile( | ||
| 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 | |||
| 140 | typedef NTSTATUS (*fpZwQueryAttributesFile) ( | ||
| 141 | IN POBJECT_ATTRIBUTES ObjectAttributes, | ||
| 142 | OUT PFILE_BASIC_INFORMATION FileInformation | ||
| 143 | ); | ||
| 144 | |||
| 145 | NTSTATUS | ||
| 146 | NTAPI | ||
| 147 | HookedNtQueryAttributesFile( | ||
| 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 | |||
| 157 | typedef NTSTATUS (*fpZwQueryFullAttributesFile) ( | ||
| 158 | IN POBJECT_ATTRIBUTES ObjectAttributes, | ||
| 159 | OUT PFILE_NETWORK_OPEN_INFORMATION FileInformation | ||
| 160 | ); | ||
| 161 | |||
| 162 | NTSTATUS | ||
| 163 | NTAPI | ||
| 164 | HookedNtQueryFullAttributesFile( | ||
| 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 | |||
| 174 | typedef 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 | |||
| 182 | NTSTATUS | ||
| 183 | NTAPI | ||
| 184 | HookedNtSetInformationFile( | ||
| 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 | |||
| 198 | typedef 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 | |||
| 220 | NTSTATUS | ||
| 221 | NTAPI | ||
| 222 | HookedNtCreateNamedPipeFile( | ||
| 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 | |||
| 245 | typedef 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 | |||
| 256 | NTSTATUS | ||
| 257 | NTAPI | ||
| 258 | HookedNtCreateMailslotFile( | ||
| 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 | |||
| 270 | BOOLEAN 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 | ||
| 65 | int HookedRoutineRunning = 0; | ||
| 66 | #endif | ||
| 67 | |||
| 68 | PCHAR NTDLL_Base; | ||
| 69 | |||
| 70 | int 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 | |||
| 102 | int | ||
| 103 | FindFunctionOffset(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 | |||
| 192 | PVOID | ||
| 193 | HookSystemService(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 | |||
| 259 | PVOID | ||
| 260 | HookSystemServiceByIndex(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 | |||
| 316 | PULONG | ||
| 317 | FindSystemServiceByIndex(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 | |||
| 366 | BOOLEAN | ||
| 367 | HookSystemServiceByName(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 | |||
| 412 | ULONG | ||
| 413 | FindSystemServiceIndex(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 | |||
| 447 | ULONG | ||
| 448 | FindSystemServiceNumber(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 | |||
| 484 | PVOID | ||
| 485 | Find_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 | ||
| 557 | PVOID | ||
| 558 | Find_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 | |||
| 601 | PVOID | ||
| 602 | Find_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 | |||
| 670 | PVOID | ||
| 671 | FindFunctionBase(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 | |||
| 762 | int | ||
| 763 | FindZwFunctionIndex(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 | |||
| 797 | struct _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 | |||
| 1539 | ACTION_TYPE | ||
| 1540 | VerifySystemServiceCall(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 | |||
| 1626 | SYSCALL_HANDLER(0) SYSCALL_HANDLER(1) SYSCALL_HANDLER(2) SYSCALL_HANDLER(3) SYSCALL_HANDLER(4) | ||
| 1627 | SYSCALL_HANDLER(5) SYSCALL_HANDLER(6) SYSCALL_HANDLER(7) SYSCALL_HANDLER(8) SYSCALL_HANDLER(9) | ||
| 1628 | SYSCALL_HANDLER(10) SYSCALL_HANDLER(11) SYSCALL_HANDLER(12) SYSCALL_HANDLER(13) SYSCALL_HANDLER(14) | ||
| 1629 | SYSCALL_HANDLER(15) SYSCALL_HANDLER(16) SYSCALL_HANDLER(17) SYSCALL_HANDLER(18) SYSCALL_HANDLER(19) | ||
| 1630 | SYSCALL_HANDLER(20) SYSCALL_HANDLER(21) SYSCALL_HANDLER(22) SYSCALL_HANDLER(23) SYSCALL_HANDLER(24) | ||
| 1631 | SYSCALL_HANDLER(25) SYSCALL_HANDLER(26) SYSCALL_HANDLER(27) SYSCALL_HANDLER(28) SYSCALL_HANDLER(29) | ||
| 1632 | SYSCALL_HANDLER(30) SYSCALL_HANDLER(31) SYSCALL_HANDLER(32) SYSCALL_HANDLER(33) SYSCALL_HANDLER(34) | ||
| 1633 | SYSCALL_HANDLER(35) SYSCALL_HANDLER(36) SYSCALL_HANDLER(37) SYSCALL_HANDLER(38) SYSCALL_HANDLER(39) | ||
| 1634 | SYSCALL_HANDLER(40) SYSCALL_HANDLER(41) SYSCALL_HANDLER(42) SYSCALL_HANDLER(43) SYSCALL_HANDLER(44) | ||
| 1635 | SYSCALL_HANDLER(45) SYSCALL_HANDLER(46) SYSCALL_HANDLER(47) SYSCALL_HANDLER(48) SYSCALL_HANDLER(49) | ||
| 1636 | SYSCALL_HANDLER(50) SYSCALL_HANDLER(51) SYSCALL_HANDLER(52) SYSCALL_HANDLER(53) SYSCALL_HANDLER(54) | ||
| 1637 | SYSCALL_HANDLER(55) SYSCALL_HANDLER(56) SYSCALL_HANDLER(57) SYSCALL_HANDLER(58) SYSCALL_HANDLER(59) | ||
| 1638 | SYSCALL_HANDLER(60) SYSCALL_HANDLER(61) SYSCALL_HANDLER(62) SYSCALL_HANDLER(63) SYSCALL_HANDLER(64) | ||
| 1639 | SYSCALL_HANDLER(65) SYSCALL_HANDLER(66) SYSCALL_HANDLER(67) SYSCALL_HANDLER(68) SYSCALL_HANDLER(69) | ||
| 1640 | SYSCALL_HANDLER(70) SYSCALL_HANDLER(71) SYSCALL_HANDLER(72) SYSCALL_HANDLER(73) SYSCALL_HANDLER(74) | ||
| 1641 | SYSCALL_HANDLER(75) SYSCALL_HANDLER(76) SYSCALL_HANDLER(77) SYSCALL_HANDLER(78) SYSCALL_HANDLER(79) | ||
| 1642 | SYSCALL_HANDLER(80) SYSCALL_HANDLER(81) SYSCALL_HANDLER(82) SYSCALL_HANDLER(83) SYSCALL_HANDLER(84) | ||
| 1643 | SYSCALL_HANDLER(85) SYSCALL_HANDLER(86) SYSCALL_HANDLER(87) SYSCALL_HANDLER(88) SYSCALL_HANDLER(89) | ||
| 1644 | SYSCALL_HANDLER(90) SYSCALL_HANDLER(91) SYSCALL_HANDLER(92) SYSCALL_HANDLER(93) SYSCALL_HANDLER(94) | ||
| 1645 | SYSCALL_HANDLER(95) SYSCALL_HANDLER(96) SYSCALL_HANDLER(97) SYSCALL_HANDLER(98) SYSCALL_HANDLER(99) | ||
| 1646 | SYSCALL_HANDLER(100) SYSCALL_HANDLER(101) SYSCALL_HANDLER(102) SYSCALL_HANDLER(103) SYSCALL_HANDLER(104) | ||
| 1647 | SYSCALL_HANDLER(105) SYSCALL_HANDLER(106) SYSCALL_HANDLER(107) SYSCALL_HANDLER(108) SYSCALL_HANDLER(109) | ||
| 1648 | SYSCALL_HANDLER(110) SYSCALL_HANDLER(111) SYSCALL_HANDLER(112) SYSCALL_HANDLER(113) SYSCALL_HANDLER(114) | ||
| 1649 | SYSCALL_HANDLER(115) SYSCALL_HANDLER(116) SYSCALL_HANDLER(117) SYSCALL_HANDLER(118) SYSCALL_HANDLER(119) | ||
| 1650 | SYSCALL_HANDLER(120) SYSCALL_HANDLER(121) SYSCALL_HANDLER(122) SYSCALL_HANDLER(123) SYSCALL_HANDLER(124) | ||
| 1651 | SYSCALL_HANDLER(125) SYSCALL_HANDLER(126) SYSCALL_HANDLER(127) SYSCALL_HANDLER(128) SYSCALL_HANDLER(129) | ||
| 1652 | SYSCALL_HANDLER(130) SYSCALL_HANDLER(131) SYSCALL_HANDLER(132) SYSCALL_HANDLER(133) SYSCALL_HANDLER(134) | ||
| 1653 | SYSCALL_HANDLER(135) SYSCALL_HANDLER(136) SYSCALL_HANDLER(137) SYSCALL_HANDLER(138) SYSCALL_HANDLER(139) | ||
| 1654 | SYSCALL_HANDLER(140) SYSCALL_HANDLER(141) SYSCALL_HANDLER(142) SYSCALL_HANDLER(143) SYSCALL_HANDLER(144) | ||
| 1655 | SYSCALL_HANDLER(145) SYSCALL_HANDLER(146) SYSCALL_HANDLER(147) SYSCALL_HANDLER(148) SYSCALL_HANDLER(149) | ||
| 1656 | SYSCALL_HANDLER(150) SYSCALL_HANDLER(151) SYSCALL_HANDLER(152) SYSCALL_HANDLER(153) SYSCALL_HANDLER(154) | ||
| 1657 | SYSCALL_HANDLER(155) SYSCALL_HANDLER(156) SYSCALL_HANDLER(157) SYSCALL_HANDLER(158) SYSCALL_HANDLER(159) | ||
| 1658 | SYSCALL_HANDLER(160) SYSCALL_HANDLER(161) SYSCALL_HANDLER(162) SYSCALL_HANDLER(163) SYSCALL_HANDLER(164) | ||
| 1659 | SYSCALL_HANDLER(165) SYSCALL_HANDLER(166) SYSCALL_HANDLER(167) SYSCALL_HANDLER(168) SYSCALL_HANDLER(169) | ||
| 1660 | SYSCALL_HANDLER(170) SYSCALL_HANDLER(171) SYSCALL_HANDLER(172) SYSCALL_HANDLER(173) SYSCALL_HANDLER(174) | ||
| 1661 | SYSCALL_HANDLER(175) SYSCALL_HANDLER(176) SYSCALL_HANDLER(177) SYSCALL_HANDLER(178) SYSCALL_HANDLER(179) | ||
| 1662 | SYSCALL_HANDLER(180) SYSCALL_HANDLER(181) SYSCALL_HANDLER(182) SYSCALL_HANDLER(183) SYSCALL_HANDLER(184) | ||
| 1663 | SYSCALL_HANDLER(185) SYSCALL_HANDLER(186) SYSCALL_HANDLER(187) SYSCALL_HANDLER(188) SYSCALL_HANDLER(189) | ||
| 1664 | SYSCALL_HANDLER(190) SYSCALL_HANDLER(191) SYSCALL_HANDLER(192) SYSCALL_HANDLER(193) SYSCALL_HANDLER(194) | ||
| 1665 | SYSCALL_HANDLER(195) SYSCALL_HANDLER(196) SYSCALL_HANDLER(197) SYSCALL_HANDLER(198) SYSCALL_HANDLER(199) | ||
| 1666 | SYSCALL_HANDLER(200) SYSCALL_HANDLER(201) SYSCALL_HANDLER(202) SYSCALL_HANDLER(203) SYSCALL_HANDLER(204) | ||
| 1667 | SYSCALL_HANDLER(205) SYSCALL_HANDLER(206) SYSCALL_HANDLER(207) SYSCALL_HANDLER(208) SYSCALL_HANDLER(209) | ||
| 1668 | SYSCALL_HANDLER(210) SYSCALL_HANDLER(211) SYSCALL_HANDLER(212) SYSCALL_HANDLER(213) SYSCALL_HANDLER(214) | ||
| 1669 | SYSCALL_HANDLER(215) SYSCALL_HANDLER(216) SYSCALL_HANDLER(217) SYSCALL_HANDLER(218) SYSCALL_HANDLER(219) | ||
| 1670 | SYSCALL_HANDLER(220) SYSCALL_HANDLER(221) SYSCALL_HANDLER(222) SYSCALL_HANDLER(223) SYSCALL_HANDLER(224) | ||
| 1671 | SYSCALL_HANDLER(225) SYSCALL_HANDLER(226) SYSCALL_HANDLER(227) SYSCALL_HANDLER(228) SYSCALL_HANDLER(229) | ||
| 1672 | SYSCALL_HANDLER(230) SYSCALL_HANDLER(231) SYSCALL_HANDLER(232) SYSCALL_HANDLER(233) SYSCALL_HANDLER(234) | ||
| 1673 | SYSCALL_HANDLER(235) SYSCALL_HANDLER(236) SYSCALL_HANDLER(237) SYSCALL_HANDLER(238) SYSCALL_HANDLER(239) | ||
| 1674 | SYSCALL_HANDLER(240) SYSCALL_HANDLER(241) SYSCALL_HANDLER(242) SYSCALL_HANDLER(243) SYSCALL_HANDLER(244) | ||
| 1675 | SYSCALL_HANDLER(245) SYSCALL_HANDLER(246) SYSCALL_HANDLER(247) SYSCALL_HANDLER(248) SYSCALL_HANDLER(249) | ||
| 1676 | SYSCALL_HANDLER(250) SYSCALL_HANDLER(251) SYSCALL_HANDLER(252) SYSCALL_HANDLER(253) SYSCALL_HANDLER(254) | ||
| 1677 | SYSCALL_HANDLER(255) SYSCALL_HANDLER(256) SYSCALL_HANDLER(257) SYSCALL_HANDLER(258) SYSCALL_HANDLER(259) | ||
| 1678 | SYSCALL_HANDLER(260) SYSCALL_HANDLER(261) SYSCALL_HANDLER(262) SYSCALL_HANDLER(263) SYSCALL_HANDLER(264) | ||
| 1679 | SYSCALL_HANDLER(265) SYSCALL_HANDLER(266) SYSCALL_HANDLER(267) SYSCALL_HANDLER(268) SYSCALL_HANDLER(269) | ||
| 1680 | SYSCALL_HANDLER(270) SYSCALL_HANDLER(271) SYSCALL_HANDLER(272) SYSCALL_HANDLER(273) SYSCALL_HANDLER(274) | ||
| 1681 | SYSCALL_HANDLER(275) SYSCALL_HANDLER(276) SYSCALL_HANDLER(277) SYSCALL_HANDLER(278) SYSCALL_HANDLER(279) | ||
| 1682 | SYSCALL_HANDLER(280) SYSCALL_HANDLER(281) SYSCALL_HANDLER(282) SYSCALL_HANDLER(283) SYSCALL_HANDLER(284) | ||
| 1683 | SYSCALL_HANDLER(285) SYSCALL_HANDLER(286) SYSCALL_HANDLER(287) SYSCALL_HANDLER(288) SYSCALL_HANDLER(289) | ||
| 1684 | SYSCALL_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 | |||
| 1705 | BOOLEAN | ||
| 1706 | InitSyscallsHooks() | ||
| 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 | |||
| 1740 | BOOLEAN | ||
| 1741 | InstallSyscallsHooks() | ||
| 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 | |||
| 1783 | void | ||
| 1784 | RemoveSyscallsHooks() | ||
| 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) | ||
| 57 | typedef 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 | |||
| 106 | void SystemCallHandler0(); void SystemCallHandler1(); void SystemCallHandler2(); void SystemCallHandler3(); | ||
| 107 | void SystemCallHandler4(); void SystemCallHandler5(); void SystemCallHandler6(); void SystemCallHandler7(); | ||
| 108 | void SystemCallHandler8(); void SystemCallHandler9(); void SystemCallHandler10(); void SystemCallHandler11(); | ||
| 109 | void SystemCallHandler12(); void SystemCallHandler13(); void SystemCallHandler14(); void SystemCallHandler15(); | ||
| 110 | void SystemCallHandler16(); void SystemCallHandler17(); void SystemCallHandler18(); void SystemCallHandler19(); | ||
| 111 | void SystemCallHandler20(); void SystemCallHandler21(); void SystemCallHandler22(); void SystemCallHandler23(); | ||
| 112 | void SystemCallHandler24(); void SystemCallHandler25(); void SystemCallHandler26(); void SystemCallHandler27(); | ||
| 113 | void SystemCallHandler28(); void SystemCallHandler29(); void SystemCallHandler30(); void SystemCallHandler31(); | ||
| 114 | void SystemCallHandler32(); void SystemCallHandler33(); void SystemCallHandler34(); void SystemCallHandler35(); | ||
| 115 | void SystemCallHandler36(); void SystemCallHandler37(); void SystemCallHandler38(); void SystemCallHandler39(); | ||
| 116 | void SystemCallHandler40(); void SystemCallHandler41(); void SystemCallHandler42(); void SystemCallHandler43(); | ||
| 117 | void SystemCallHandler44(); void SystemCallHandler45(); void SystemCallHandler46(); void SystemCallHandler47(); | ||
| 118 | void SystemCallHandler48(); void SystemCallHandler49(); void SystemCallHandler50(); void SystemCallHandler51(); | ||
| 119 | void SystemCallHandler52(); void SystemCallHandler53(); void SystemCallHandler54(); void SystemCallHandler55(); | ||
| 120 | void SystemCallHandler56(); void SystemCallHandler57(); void SystemCallHandler58(); void SystemCallHandler59(); | ||
| 121 | void SystemCallHandler60(); void SystemCallHandler61(); void SystemCallHandler62(); void SystemCallHandler63(); | ||
| 122 | void SystemCallHandler64(); void SystemCallHandler65(); void SystemCallHandler66(); void SystemCallHandler67(); | ||
| 123 | void SystemCallHandler68(); void SystemCallHandler69(); void SystemCallHandler70(); void SystemCallHandler71(); | ||
| 124 | void SystemCallHandler72(); void SystemCallHandler73(); void SystemCallHandler74(); void SystemCallHandler75(); | ||
| 125 | void SystemCallHandler76(); void SystemCallHandler77(); void SystemCallHandler78(); void SystemCallHandler79(); | ||
| 126 | void SystemCallHandler80(); void SystemCallHandler81(); void SystemCallHandler82(); void SystemCallHandler83(); | ||
| 127 | void SystemCallHandler84(); void SystemCallHandler85(); void SystemCallHandler86(); void SystemCallHandler87(); | ||
| 128 | void SystemCallHandler88(); void SystemCallHandler89(); void SystemCallHandler90(); void SystemCallHandler91(); | ||
| 129 | void SystemCallHandler92(); void SystemCallHandler93(); void SystemCallHandler94(); void SystemCallHandler95(); | ||
| 130 | void SystemCallHandler96(); void SystemCallHandler97(); void SystemCallHandler98(); void SystemCallHandler99(); | ||
| 131 | void SystemCallHandler100(); void SystemCallHandler101(); void SystemCallHandler102(); void SystemCallHandler103(); | ||
| 132 | void SystemCallHandler104(); void SystemCallHandler105(); void SystemCallHandler106(); void SystemCallHandler107(); | ||
| 133 | void SystemCallHandler108(); void SystemCallHandler109(); void SystemCallHandler110(); void SystemCallHandler111(); | ||
| 134 | void SystemCallHandler112(); void SystemCallHandler113(); void SystemCallHandler114(); void SystemCallHandler115(); | ||
| 135 | void SystemCallHandler116(); void SystemCallHandler117(); void SystemCallHandler118(); void SystemCallHandler119(); | ||
| 136 | void SystemCallHandler120(); void SystemCallHandler121(); void SystemCallHandler122(); void SystemCallHandler123(); | ||
| 137 | void SystemCallHandler124(); void SystemCallHandler125(); void SystemCallHandler126(); void SystemCallHandler127(); | ||
| 138 | void SystemCallHandler128(); void SystemCallHandler129(); void SystemCallHandler130(); void SystemCallHandler131(); | ||
| 139 | void SystemCallHandler132(); void SystemCallHandler133(); void SystemCallHandler134(); void SystemCallHandler135(); | ||
| 140 | void SystemCallHandler136(); void SystemCallHandler137(); void SystemCallHandler138(); void SystemCallHandler139(); | ||
| 141 | void SystemCallHandler140(); void SystemCallHandler141(); void SystemCallHandler142(); void SystemCallHandler143(); | ||
| 142 | void SystemCallHandler144(); void SystemCallHandler145(); void SystemCallHandler146(); void SystemCallHandler147(); | ||
| 143 | void SystemCallHandler148(); void SystemCallHandler149(); void SystemCallHandler150(); void SystemCallHandler151(); | ||
| 144 | void SystemCallHandler152(); void SystemCallHandler153(); void SystemCallHandler154(); void SystemCallHandler155(); | ||
| 145 | void SystemCallHandler156(); void SystemCallHandler157(); void SystemCallHandler158(); void SystemCallHandler159(); | ||
| 146 | void SystemCallHandler160(); void SystemCallHandler161(); void SystemCallHandler162(); void SystemCallHandler163(); | ||
| 147 | void SystemCallHandler164(); void SystemCallHandler165(); void SystemCallHandler166(); void SystemCallHandler167(); | ||
| 148 | void SystemCallHandler168(); void SystemCallHandler169(); void SystemCallHandler170(); void SystemCallHandler171(); | ||
| 149 | void SystemCallHandler172(); void SystemCallHandler173(); void SystemCallHandler174(); void SystemCallHandler175(); | ||
| 150 | void SystemCallHandler176(); void SystemCallHandler177(); void SystemCallHandler178(); void SystemCallHandler179(); | ||
| 151 | void SystemCallHandler180(); void SystemCallHandler181(); void SystemCallHandler182(); void SystemCallHandler183(); | ||
| 152 | void SystemCallHandler184(); void SystemCallHandler185(); void SystemCallHandler186(); void SystemCallHandler187(); | ||
| 153 | void SystemCallHandler188(); void SystemCallHandler189(); void SystemCallHandler190(); void SystemCallHandler191(); | ||
| 154 | void SystemCallHandler192(); void SystemCallHandler193(); void SystemCallHandler194(); void SystemCallHandler195(); | ||
| 155 | void SystemCallHandler196(); void SystemCallHandler197(); void SystemCallHandler198(); void SystemCallHandler199(); | ||
| 156 | void SystemCallHandler200(); void SystemCallHandler201(); void SystemCallHandler202(); void SystemCallHandler203(); | ||
| 157 | void SystemCallHandler204(); void SystemCallHandler205(); void SystemCallHandler206(); void SystemCallHandler207(); | ||
| 158 | void SystemCallHandler208(); void SystemCallHandler209(); void SystemCallHandler210(); void SystemCallHandler211(); | ||
| 159 | void SystemCallHandler212(); void SystemCallHandler213(); void SystemCallHandler214(); void SystemCallHandler215(); | ||
| 160 | void SystemCallHandler216(); void SystemCallHandler217(); void SystemCallHandler218(); void SystemCallHandler219(); | ||
| 161 | void SystemCallHandler220(); void SystemCallHandler221(); void SystemCallHandler222(); void SystemCallHandler223(); | ||
| 162 | void SystemCallHandler224(); void SystemCallHandler225(); void SystemCallHandler226(); void SystemCallHandler227(); | ||
| 163 | void SystemCallHandler228(); void SystemCallHandler229(); void SystemCallHandler230(); void SystemCallHandler231(); | ||
| 164 | void SystemCallHandler232(); void SystemCallHandler233(); void SystemCallHandler234(); void SystemCallHandler235(); | ||
| 165 | void SystemCallHandler236(); void SystemCallHandler237(); void SystemCallHandler238(); void SystemCallHandler239(); | ||
| 166 | void SystemCallHandler240(); void SystemCallHandler241(); void SystemCallHandler242(); void SystemCallHandler243(); | ||
| 167 | void SystemCallHandler244(); void SystemCallHandler245(); void SystemCallHandler246(); void SystemCallHandler247(); | ||
| 168 | void SystemCallHandler248(); void SystemCallHandler249(); void SystemCallHandler250(); void SystemCallHandler251(); | ||
| 169 | void SystemCallHandler252(); void SystemCallHandler253(); void SystemCallHandler254(); void SystemCallHandler255(); | ||
| 170 | void SystemCallHandler256(); void SystemCallHandler257(); void SystemCallHandler258(); void SystemCallHandler259(); | ||
| 171 | void SystemCallHandler260(); void SystemCallHandler261(); void SystemCallHandler262(); void SystemCallHandler263(); | ||
| 172 | void SystemCallHandler264(); void SystemCallHandler265(); void SystemCallHandler266(); void SystemCallHandler267(); | ||
| 173 | void SystemCallHandler268(); void SystemCallHandler269(); void SystemCallHandler270(); void SystemCallHandler271(); | ||
| 174 | void SystemCallHandler272(); void SystemCallHandler273(); void SystemCallHandler274(); void SystemCallHandler275(); | ||
| 175 | void SystemCallHandler276(); void SystemCallHandler277(); void SystemCallHandler278(); void SystemCallHandler279(); | ||
| 176 | void SystemCallHandler280(); void SystemCallHandler281(); void SystemCallHandler282(); void SystemCallHandler283(); | ||
| 177 | void SystemCallHandler284(); void SystemCallHandler285(); void SystemCallHandler286(); void SystemCallHandler287(); | ||
| 178 | void SystemCallHandler288(); void SystemCallHandler289(); void SystemCallHandler290(); void SystemCallHandler291(); | ||
| 179 | void 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 | |||
| 186 | extern 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 | |||
| 197 | extern 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 | |||
| 296 | extern 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 | |||
| 300 | extern 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 | |||
| 443 | extern PCHAR NTDLL_Base; | ||
| 444 | extern int ZwCallsNumber; | ||
| 445 | |||
| 446 | |||
| 447 | PVOID HookSystemService(PVOID OldService, PVOID NewService); | ||
| 448 | PVOID HookSystemServiceByIndex(ULONG ServiceIDNumber, PVOID NewService); | ||
| 449 | BOOLEAN HookSystemServiceByName(PCHAR ServiceName, PULONG_PTR HookFunction); | ||
| 450 | |||
| 451 | BOOLEAN InitSyscallsHooks(); | ||
| 452 | BOOLEAN InstallSyscallsHooks(); | ||
| 453 | void RemoveSyscallsHooks(); | ||
| 454 | |||
| 455 | int FindZwFunctionIndex(PCSTR Name); | ||
| 456 | PVOID FindFunctionBase(PCHAR ImageBase, PCSTR Name); | ||
| 457 | ULONG FindSystemServiceNumber(PCHAR ServiceName); | ||
| 458 | |||
| 459 | |||
| 460 | #endif /* __HOOKPROC_H__ */ \ No newline at end of file | ||
| @@ -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 | |||
| 33 | ULONG SystemAddressStart; | ||
| 34 | static ULONG SharedUserDataAddress, TssAddress; | ||
| 35 | ULONG 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 | |||
| 55 | BOOLEAN | ||
| 56 | InitI386() | ||
| 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 | |||
| 139 | VOID | ||
| 140 | VerifyUserReturnAddress() | ||
| 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 | } | ||
| @@ -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 | |||
| 27 | typedef 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 | |||
| 74 | typedef 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 | |||
| 177 | extern ULONG SystemAddressStart; | ||
| 178 | |||
| 179 | |||
| 180 | BOOLEAN InitI386(); | ||
| 181 | VOID VerifyUserReturnAddress(); | ||
| 182 | |||
| 183 | |||
| 184 | #endif /* __I386_H__ */ \ No newline at end of file | ||
| @@ -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 | |||
| 37 | fpZwCreateJobObject OriginalNtCreateJobObject = NULL; | ||
| 38 | fpZwOpenJobObject 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 | |||
| 58 | NTSTATUS | ||
| 59 | NTAPI | ||
| 60 | HookedNtCreateJobObject | ||
| 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 | |||
| 100 | NTSTATUS | ||
| 101 | NTAPI | ||
| 102 | HookedNtOpenJobObject | ||
| 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 | |||
| 141 | BOOLEAN | ||
| 142 | InitJobHooks() | ||
| 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 | } | ||
| @@ -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 | |||
| 31 | typedef NTSTATUS (*fpZwCreateJobObject) ( | ||
| 32 | OUT PHANDLE JobHandle, | ||
| 33 | IN ACCESS_MASK DesiredAccess, | ||
| 34 | IN POBJECT_ATTRIBUTES ObjectAttributes | ||
| 35 | ); | ||
| 36 | |||
| 37 | NTSTATUS | ||
| 38 | NTAPI | ||
| 39 | HookedNtCreateJobObject( | ||
| 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 | |||
| 50 | typedef NTSTATUS (*fpZwOpenJobObject) ( | ||
| 51 | OUT PHANDLE JobHandle, | ||
| 52 | IN ACCESS_MASK DesiredAccess, | ||
| 53 | IN POBJECT_ATTRIBUTES ObjectAttributes | ||
| 54 | ); | ||
| 55 | |||
| 56 | NTSTATUS | ||
| 57 | NTAPI | ||
| 58 | HookedNtOpenJobObject( | ||
| 59 | OUT PHANDLE JobHandle, | ||
| 60 | IN ACCESS_MASK DesiredAccess, | ||
| 61 | IN POBJECT_ATTRIBUTES ObjectAttributes | ||
| 62 | ); | ||
| 63 | |||
| 64 | |||
| 65 | BOOLEAN InitJobHooks(); | ||
| 66 | |||
| 67 | |||
| 68 | #endif /* __JOB_H__ */ | ||
| @@ -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 | |||
| 40 | WCHAR ProcessToMonitor[MAX_PROCESS_NAME] = L""; | ||
| 41 | |||
| 42 | BOOLEAN LearningMode = FALSE; | ||
| 43 | HANDLE hFile; | ||
| 44 | INT64 offset; | ||
| 45 | |||
| 46 | BOOLEAN IsGuiThread = FALSE; /* does the process we are profiling contain any GUI threads? */ | ||
| 47 | |||
| 48 | SECURITY_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 | |||
| 68 | BOOLEAN | ||
| 69 | InitLearningMode() | ||
| 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 | |||
| 126 | PCHAR | ||
| 127 | FilterFilePath(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 | |||
| 218 | PCHAR | ||
| 219 | FilterMailslotPath(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 | |||
| 248 | PCHAR | ||
| 249 | FilterNamedpipePath(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 | |||
| 279 | PCHAR | ||
| 280 | FilterRegistryPath(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 | |||
| 326 | PCHAR | ||
| 327 | FilterBaseNamedObjectsPath(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 | |||
| 353 | PCHAR | ||
| 354 | FilterDll(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 | |||
| 379 | PCHAR | ||
| 380 | FilterPath(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 | |||
| 410 | PCHAR | ||
| 411 | FilterOperation(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 | |||
| 457 | PCHAR | ||
| 458 | FilterSimpleOperation(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 | |||
| 490 | PCHAR | ||
| 491 | FilterCreateOpenOperation(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 | |||
| 526 | PCHAR | ||
| 527 | FilterDirectoryOperation(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 | |||
| 550 | PCHAR | ||
| 551 | FilterProcessOperation(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 | |||
| 584 | PCHAR | ||
| 585 | FilterNetworkOperation(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 | |||
| 621 | PCHAR | ||
| 622 | FilterPortOperation(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 | |||
| 658 | PCHAR | ||
| 659 | FilterAtomOperation(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 | |||
| 694 | PCHAR | ||
| 695 | FilterDriverOperation(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 | |||
| 723 | PCHAR | ||
| 724 | FilterDllOperation(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 | |||
| 744 | PCHAR | ||
| 745 | FilterServiceOperation(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 | |||
| 781 | PCHAR | ||
| 782 | FilterTimeOperation(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 | |||
| 809 | PCHAR | ||
| 810 | FilterTokenOperation(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 | |||
| 837 | PCHAR | ||
| 838 | FilterSyscallOperation(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 | |||
| 847 | typedef PCHAR (*fpFilterObject) (PCHAR path); | ||
| 848 | typedef PCHAR (*fpFilterOperation) (UCHAR OperationType); | ||
| 849 | |||
| 850 | |||
| 851 | /* in C++ these would be member methods */ | ||
| 852 | |||
| 853 | struct | ||
| 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 | |||
| 902 | PCHAR | ||
| 903 | DecodeAction(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 | |||
| 956 | BOOLEAN | ||
| 957 | CreateRule(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 | |||
| 1046 | BOOLEAN | ||
| 1047 | CreateServiceRule(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 | |||
| 1058 | BOOLEAN WriteRule(PCHAR rule); | ||
| 1059 | BOOLEAN WritePolicyFile(PCHAR buffer); | ||
| 1060 | |||
| 1061 | |||
| 1062 | /* | ||
| 1063 | * FlushPolicy() | ||
| 1064 | * | ||
| 1065 | * Description: | ||
| 1066 | * . | ||
| 1067 | * | ||
| 1068 | * Parameters: | ||
| 1069 | * . | ||
| 1070 | * | ||
| 1071 | * Returns: | ||
| 1072 | * Nothing. | ||
| 1073 | */ | ||
| 1074 | |||
| 1075 | void | ||
| 1076 | FlushPolicy() | ||
| 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 | |||
| 1157 | BOOLEAN | ||
| 1158 | ShutdownLearningMode() | ||
| 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 | |||
| 1217 | BOOLEAN | ||
| 1218 | WritePolicyFile(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 | |||
| 1256 | BOOLEAN | ||
| 1257 | WriteRule(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 | |||
| 1284 | BOOLEAN | ||
| 1285 | RememberRule(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 | |||
| 1369 | void | ||
| 1370 | DetermineThreadType() | ||
| 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 | |||
| 1396 | BOOLEAN | ||
| 1397 | AddRule(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 | } | ||
| @@ -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 | |||
| 28 | extern BOOLEAN LearningMode; | ||
| 29 | |||
| 30 | extern SECURITY_POLICY NewPolicy; | ||
| 31 | |||
| 32 | /* In characters */ | ||
| 33 | #define MAX_PROCESS_NAME 32 | ||
| 34 | |||
| 35 | extern WCHAR ProcessToMonitor[]; | ||
| 36 | |||
| 37 | |||
| 38 | BOOLEAN InitLearningMode(); | ||
| 39 | BOOLEAN ShutdownLearningMode(); | ||
| 40 | BOOLEAN AddRule(RULE_TYPE RuleType, PCHAR str, UCHAR OperationType); | ||
| 41 | |||
| 42 | |||
| 43 | #endif /* __LEARN_H__ */ \ No newline at end of file | ||
| @@ -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 | |||
| 34 | KSPIN_LOCK gLogSpinLock; | ||
| 35 | |||
| 36 | PKEVENT LogUserEvent = NULL; | ||
| 37 | HANDLE LogUserEventHandle = NULL; | ||
| 38 | |||
| 39 | PSECURITY_ALERT LogList = NULL; /* alert queue */ | ||
| 40 | PSECURITY_ALERT LastAlert = NULL; /* pointer to the last queued alert, used for quick inserts */ | ||
| 41 | |||
| 42 | USHORT 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 | |||
| 61 | ALERT_PRIORITY | ||
| 62 | GetObjectAccessAlertPriority(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 | ||
| 137 | PCHAR | ||
| 138 | FilterObjectName(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 | |||
| 180 | VOID | ||
| 181 | LogAlert(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 | |||
| 363 | BOOLEAN | ||
| 364 | LogPostBootup() | ||
| 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 | |||
| 405 | BOOLEAN | ||
| 406 | InitLog() | ||
| 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 | |||
| 436 | VOID | ||
| 437 | ShutdownLog() | ||
| 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 | } | ||
| @@ -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 */ | ||
| 182 | typedef unsigned char ACTION_TYPE; | ||
| 183 | typedef struct _POLICY_RULE POLICY_RULE, *PPOLICY_RULE; | ||
| 184 | typedef enum _AlertPriority ALERT_PRIORITY; | ||
| 185 | |||
| 186 | |||
| 187 | #pragma pack(push, 1) | ||
| 188 | typedef 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 | |||
| 221 | extern KSPIN_LOCK gLogSpinLock; | ||
| 222 | extern PSECURITY_ALERT LogList; | ||
| 223 | extern PSECURITY_ALERT LastAlert; | ||
| 224 | extern USHORT NumberOfAlerts; | ||
| 225 | |||
| 226 | |||
| 227 | BOOLEAN InitLog(); | ||
| 228 | VOID ShutdownLog(); | ||
| 229 | VOID LogAlert(UCHAR AlertSubSystem, UCHAR OperationType, UCHAR AlertRuleNumber, ACTION_TYPE ActionTaken, ALERT_PRIORITY AlertPriority, PWSTR PolicyFilename, USHORT PolicyLineNumber, PCHAR ObjectName); | ||
| 230 | ALERT_PRIORITY GetObjectAccessAlertPriority(UCHAR AlertSubSystem, UCHAR Operation, ACTION_TYPE ActionTaken); | ||
| 231 | BOOLEAN LogPostBootup(); | ||
| 232 | |||
| 233 | PCHAR FilterObjectName(PCHAR ObjectName); | ||
| 234 | |||
| 235 | |||
| 236 | #endif /* __LOG_H__ */ | ||
| @@ -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 | |||
| 47 | PVOID DiskNotificationEntry = NULL, CdromNotificationEntry = NULL; | ||
| 48 | |||
| 49 | /* removable media flags defined in drive.h (READONLY, etc) */ | ||
| 50 | UCHAR MediaRemovableFlags = 0; | ||
| 51 | |||
| 52 | |||
| 53 | typedef 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 | |||
| 76 | VOID | ||
| 77 | AddDrive(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 | |||
| 149 | VOID | ||
| 150 | RemoveDrive(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 | |||
| 196 | VOID | ||
| 197 | MonitorDriveLinks(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 | |||
| 257 | VOID | ||
| 258 | PnpWorker(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 | |||
| 297 | NTSTATUS | ||
| 298 | PnpCallback(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 | |||
| 365 | BOOLEAN | ||
| 366 | InitRemovableMediaHooks(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 | |||
| 434 | VOID | ||
| 435 | RemoveRemovableMediaHooks() | ||
| 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 | } | ||
| @@ -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 | |||
| 32 | extern UCHAR MediaRemovableFlags; | ||
| 33 | |||
| 34 | |||
| 35 | BOOLEAN InitRemovableMediaHooks(IN PDRIVER_OBJECT pDriverObject, IN PDEVICE_OBJECT pDeviceObject); | ||
| 36 | VOID RemoveRemovableMediaHooks(); | ||
| 37 | VOID MonitorDriveLinks(const PCHAR Link); | ||
| 38 | |||
| 39 | |||
| 40 | #endif /* __MEDIA_H__ */ | ||
| @@ -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 | |||
| 29 | BOOLEAN 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 | |||
| 45 | INT32 | ||
| 46 | atoi(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 | |||
| 79 | PCHAR | ||
| 80 | itoa(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 | |||
| 126 | ULONG | ||
| 127 | ntohl(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 | |||
| 155 | USHORT | ||
| 156 | ntohs(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 | |||
| 180 | ULONG | ||
| 181 | htonl(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 | |||
| 231 | ULONG | ||
| 232 | inet_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 | ||
| 342 | PCHAR | ||
| 343 | inet_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 */ | ||
| 358 | VOID | ||
| 359 | inet_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 | |||
| 392 | BOOLEAN | ||
| 393 | VerifyUnicodeString(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 | |||
| 465 | BOOLEAN | ||
| 466 | VerifyPwstr(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 | |||
| 524 | PKEY_VALUE_PARTIAL_INFORMATION | ||
| 525 | ReadStringRegistryValue(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 | |||
| 601 | BOOLEAN | ||
| 602 | ReadStringRegistryValueA(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 | |||
| 645 | BOOLEAN | ||
| 646 | ReadStringRegistryValueW(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 | |||
| 698 | BOOLEAN | ||
| 699 | ReadSymlinkValue(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 | |||
| 757 | VOID | ||
| 758 | InitPostBootup() | ||
| 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 | |||
| 784 | typedef struct _TOKEN_GROUPS { | ||
| 785 | DWORD GroupCount; | ||
| 786 | SID_AND_ATTRIBUTES Groups[ANYSIZE_ARRAY]; | ||
| 787 | } TOKEN_GROUPS, *PTOKEN_GROUPS; | ||
| 788 | |||
| 789 | PCHAR | ||
| 790 | GetCurrentUserSid(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 | |||
| 888 | PVOID | ||
| 889 | ExchangeReadOnlyMemoryPointer(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 | } | ||
| @@ -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 | |||
| 52 | KPROCESSOR_MODE | ||
| 53 | KeGetPreviousMode( | ||
| 54 | VOID | ||
| 55 | ); | ||
| 56 | |||
| 57 | |||
| 58 | int sprintf(char *buffer, const char *format, ...); | ||
| 59 | int _snprintf(char *buffer, size_t count, const char *format, ...); | ||
| 60 | int _snwprintf(wchar_t *buffer, size_t count, const wchar_t *format, ...); | ||
| 61 | |||
| 62 | BOOLEAN 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 | |||
| 74 | extern BOOLEAN BootingUp; | ||
| 75 | |||
| 76 | |||
| 77 | INT32 atoi(IN PCHAR buf); | ||
| 78 | PCHAR itoa(int value, char *string, unsigned int radix); | ||
| 79 | |||
| 80 | /* XXX move to netmisc.c */ | ||
| 81 | ULONG ntohl(IN ULONG netlong); | ||
| 82 | USHORT ntohs(IN USHORT netshort); | ||
| 83 | |||
| 84 | ULONG inet_addr(IN PCCHAR cp); | ||
| 85 | VOID inet_ntoa(ULONG ina, PCHAR buf); | ||
| 86 | PCHAR inet_ntoa2(IN ULONG ina); | ||
| 87 | |||
| 88 | BOOLEAN VerifyUnicodeString(IN PUNICODE_STRING InputUnicodeString, OUT PUNICODE_STRING OutputUnicodeString); | ||
| 89 | BOOLEAN VerifyPwstr(IN PWSTR InputString, IN ULONG InputStringLength); | ||
| 90 | |||
| 91 | BOOLEAN ReadStringRegistryValueA(IN PWSTR RegistryPath, IN PWSTR KeyName, OUT PCHAR Buffer, IN USHORT BufferSize); | ||
| 92 | BOOLEAN ReadStringRegistryValueW(IN PWSTR RegistryPath, IN PWSTR KeyName, OUT PWSTR Buffer, IN USHORT BufferSize); | ||
| 93 | BOOLEAN ReadSymlinkValue(IN PWSTR SymlinkPath, OUT PCHAR Buffer, IN USHORT BufferSize); | ||
| 94 | |||
| 95 | VOID InitPostBootup(); | ||
| 96 | PCHAR GetCurrentUserSid(PUSHORT Size); | ||
| 97 | |||
| 98 | PVOID 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 | |||
| 30 | fpZwCreateMutant OriginalNtCreateMutant = NULL; | ||
| 31 | fpZwOpenMutant 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 | |||
| 51 | NTSTATUS | ||
| 52 | NTAPI | ||
| 53 | HookedNtCreateMutant | ||
| 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 | |||
| 94 | NTSTATUS | ||
| 95 | NTAPI | ||
| 96 | HookedNtOpenMutant | ||
| 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 | |||
| 135 | BOOLEAN | ||
| 136 | InitMutantHooks() | ||
| 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 | |||
| 39 | typedef NTSTATUS (*fpZwCreateMutant) ( | ||
| 40 | OUT PHANDLE MutantHandle, | ||
| 41 | IN ACCESS_MASK DesiredAccess, | ||
| 42 | IN POBJECT_ATTRIBUTES ObjectAttributes, | ||
| 43 | IN BOOLEAN InitialOwner | ||
| 44 | ); | ||
| 45 | |||
| 46 | NTSTATUS | ||
| 47 | NTAPI | ||
| 48 | HookedNtCreateMutant( | ||
| 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 | |||
| 60 | typedef NTSTATUS (*fpZwOpenMutant) ( | ||
| 61 | OUT PHANDLE MutantHandle, | ||
| 62 | IN ACCESS_MASK DesiredAccess, | ||
| 63 | IN POBJECT_ATTRIBUTES ObjectAttributes | ||
| 64 | ); | ||
| 65 | |||
| 66 | NTSTATUS | ||
| 67 | NTAPI | ||
| 68 | HookedNtOpenMutant( | ||
| 69 | OUT PHANDLE MutantHandle, | ||
| 70 | IN ACCESS_MASK DesiredAccess, | ||
| 71 | IN POBJECT_ATTRIBUTES ObjectAttributes | ||
| 72 | ); | ||
| 73 | |||
| 74 | |||
| 75 | BOOLEAN 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 | |||
| 42 | PDEVICE_OBJECT pTcpDevice = NULL, pTcpDeviceOriginal = NULL; | ||
| 43 | PDEVICE_OBJECT pUdpDevice = NULL, pUdpDeviceOriginal = NULL; | ||
| 44 | PDEVICE_OBJECT pIpDevice = NULL, pIpDeviceOriginal = NULL; | ||
| 45 | |||
| 46 | #if DBG | ||
| 47 | int 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 | |||
| 66 | NTSTATUS | ||
| 67 | TdiStub(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 | |||
| 75 | NTSTATUS | ||
| 76 | TdiSetEventHandler(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 | |||
| 103 | NTSTATUS | ||
| 104 | TdiConnect(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 | |||
| 169 | NTSTATUS | ||
| 170 | TdiListen(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 | |||
| 216 | NTSTATUS | ||
| 217 | TdiAccept(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 | /* | ||
| 239 | NTSTATUS | ||
| 240 | GenericCompletion(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 | |||
| 250 | TDI_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) | ||
| 273 | BOOLEAN | ||
| 274 | TDIDispatch(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 | |||
| 427 | NTSTATUS | ||
| 428 | TDICreateAddressCompletion(IN PDEVICE_OBJECT DeviceObject, IN PIRP pIrp, IN PVOID Context) | ||
| 429 | { | ||
| 430 | return STATUS_SUCCESS; | ||
| 431 | } | ||
| 432 | |||
| 433 | |||
| 434 | |||
| 435 | NTSTATUS | ||
| 436 | TDICreate(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 | |||
| 588 | NTSTATUS | ||
| 589 | InstallNetworkHooks(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 | |||
| 686 | void | ||
| 687 | RemoveNetworkHooks(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 | |||
| 32 | typedef struct _TDI_CALLBACK | ||
| 33 | { | ||
| 34 | PIO_COMPLETION_ROUTINE Routine; | ||
| 35 | PVOID Context; | ||
| 36 | |||
| 37 | } TDI_CALLBACK, *PTDI_CALLBACK; | ||
| 38 | |||
| 39 | |||
| 40 | typedef int (*TDI_IOCTL_PFUNC) (IN PIRP pIrp, IN PIO_STACK_LOCATION pIrpStack, OUT PTDI_CALLBACK pCompletion, IN ULONG DeviceType); | ||
| 41 | |||
| 42 | typedef struct _TDI_IOCTL | ||
| 43 | { | ||
| 44 | UCHAR MinorFunction; | ||
| 45 | PCHAR Description; | ||
| 46 | TDI_IOCTL_PFUNC pfRoutine; | ||
| 47 | |||
| 48 | } TDI_IOCTL, PTDI_IOCTL; | ||
| 49 | |||
| 50 | |||
| 51 | BOOLEAN TDIDispatch(PDEVICE_OBJECT pDeviceObject, PIRP pIrp, NTSTATUS *status); | ||
| 52 | NTSTATUS TDICreate(IN PDEVICE_OBJECT pDeviceObject, IN PIRP pIrp, IN PIO_STACK_LOCATION pIrpStack, OUT PTDI_CALLBACK pCompletion); | ||
| 53 | NTSTATUS InstallNetworkHooks(PDRIVER_OBJECT pDriverObject); | ||
| 54 | void 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 | |||
| 22 | typedef 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 | |||
| 42 | typedef unsigned short WORD; | ||
| 43 | typedef unsigned long DWORD; | ||
| 44 | typedef unsigned char BYTE; | ||
| 45 | |||
| 46 | #define IMAGE_DOS_SIGNATURE 0x5A4D | ||
| 47 | |||
| 48 | typedef 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 | |||
| 71 | typedef 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 | |||
| 83 | typedef 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 | |||
| 92 | typedef 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 | |||
| 140 | typedef 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 | ||
| 151 | typedef IMAGE_NT_HEADERS32 IMAGE_NT_HEADERS; | ||
| 152 | typedef PIMAGE_NT_HEADERS32 PIMAGE_NT_HEADERS; | ||
| 153 | #endif | ||
| 154 | |||
| 155 | typedef 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 | |||
| 189 | typedef struct _SID_AND_ATTRIBUTES | ||
| 190 | { | ||
| 191 | PSID Sid; | ||
| 192 | DWORD Attributes; | ||
| 193 | |||
| 194 | } SID_AND_ATTRIBUTES, *PSID_AND_ATTRIBUTES; | ||
| 195 | |||
| 196 | // Query Set | ||
| 197 | typedef 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 | |||
| 217 | typedef 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 | |||
| 44 | BOOLEAN | ||
| 45 | ResolveFilename(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 | |||
| 58 | restart: | ||
| 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 | |||
| 160 | BOOLEAN | ||
| 161 | ResolveFilenameW(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 | |||
| 183 | restart: | ||
| 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 | |||
| 295 | BOOLEAN | ||
| 296 | GetPathFromOA(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 | |||
| 473 | BOOLEAN | ||
| 474 | GetPathFromOAW(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 | |||
| 674 | BOOLEAN | ||
| 675 | ConvertLongFileNameToShort(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 | |||
| 808 | PWSTR | ||
| 809 | GetNameFromHandle(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 | |||
| 863 | PCHAR | ||
| 864 | StripFileMacros(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 | |||
| 907 | BOOLEAN | ||
| 908 | FixupFilename(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 | |||
| 956 | BOOLEAN | ||
| 957 | AreMalformedExtensionsAllowed() | ||
| 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 | |||
| 1008 | BOOLEAN | ||
| 1009 | VerifyExecutableName(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 | |||
| 47 | BOOLEAN GetPathFromOA(IN POBJECT_ATTRIBUTES ObjectAttributes, OUT PCHAR OutBuffer, IN USHORT OutBufferSize, IN BOOLEAN ResolveLinks); | ||
| 48 | BOOLEAN GetPathFromOAW(IN POBJECT_ATTRIBUTES ObjectAttributes, OUT PCHAR OutBuffer, IN USHORT OutBufferSize, IN BOOLEAN ResolveLinks); | ||
| 49 | BOOLEAN ResolveFilename(IN PCHAR szFileName, OUT PCHAR szResult, IN USHORT szResultSize); | ||
| 50 | BOOLEAN ResolveFilenameW(IN PUNICODE_STRING szFileName, OUT PCHAR szResult, IN USHORT szResultSize); | ||
| 51 | PWSTR GetNameFromHandle(IN HANDLE ObjectHandle, OUT PWSTR OutBuffer, IN USHORT OutBufferSize); | ||
| 52 | BOOLEAN FixupFilename(IN PCHAR szFileName, OUT PCHAR szResult, IN USHORT szResultSize); | ||
| 53 | BOOLEAN VerifyExecutableName(IN PCHAR szFileName); | ||
| 54 | PCHAR StripFileMacros(IN PCHAR Path, OUT PCHAR Buffer, IN USHORT BufferSize); | ||
| 55 | BOOLEAN ConvertLongFileNameToShort(IN PCHAR LongFileName, OUT PCHAR ShortFileName, IN USHORT ShortFileNameSize); | ||
| 56 | |||
| 57 | |||
| 58 | NTSTATUS | ||
| 59 | ObQueryNameString( | ||
| 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 | |||
| 38 | BOOLEAN PolicyParseRule(OUT PSECURITY_POLICY pSecPolicy, IN PCHAR rule, OUT BOOLEAN *Critical); | ||
| 39 | BOOLEAN PolicyParsePolicyRule(OUT PSECURITY_POLICY pSecPolicy, IN PCHAR Operation, IN PCHAR rule, OUT BOOLEAN *Critical); | ||
| 40 | BOOLEAN PolicyParseObjectRule(PSECURITY_POLICY pSecPolicy, RULE_TYPE RuleType, PCHAR Operation, PCHAR rule); | ||
| 41 | BOOLEAN PolicyParseSyscallRule(PSECURITY_POLICY pSecPolicy, PCHAR SyscallName, PCHAR rule); | ||
| 42 | BOOLEAN PolicyParseProtectionRule(PSECURITY_POLICY pSecPolicy, PCHAR Operation, PCHAR rule); | ||
| 43 | BOOLEAN 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 | |||
| 62 | CHAR SystemDrive, SystemRoot[MAX_PATH], SystemRootUnresolved[MAX_PATH], *SystemRootDirectory, CDrive[MAX_PATH]; | ||
| 63 | USHORT SystemRootLength = 0, SystemRootUnresolvedLength = 0, SystemRootDirectoryLength = 0, CDriveLength = 0; | ||
| 64 | |||
| 65 | USHORT gPolicyLineNumber; | ||
| 66 | PWSTR gPolicyFilename, gFilePath; | ||
| 67 | |||
| 68 | // to be portable on 32 & 64 bit platforms | ||
| 69 | ULONG NumberOfBitsInUlong, UlongBitShift; | ||
| 70 | |||
| 71 | /* LoadPolicy() can be used by only one thread at a time due to use of global variables */ | ||
| 72 | KMUTEX LoadPolicyMutex; | ||
| 73 | |||
| 74 | /* Global Security Policy */ | ||
| 75 | SECURITY_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 | |||
| 94 | BOOLEAN | ||
| 95 | InitPolicy() | ||
| 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 | |||
| 201 | BOOLEAN | ||
| 202 | PolicyPostBootup() | ||
| 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 | |||
| 236 | void | ||
| 237 | PolicyRemove() | ||
| 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 | |||
| 257 | void | ||
| 258 | PolicyDelete(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 | |||
| 325 | BOOLEAN | ||
| 326 | LoadSecurityPolicy(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 | |||
| 513 | BOOLEAN | ||
| 514 | FindAndLoadSecurityPolicy(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 */ | ||
| 545 | ReloadPolicy: | ||
| 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 | |||
| 623 | static BOOLEAN | ||
| 624 | PolicyParseRule(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 | |||
| 847 | UCHAR | ||
| 848 | ParseDllOperation(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 | |||
| 874 | UCHAR | ||
| 875 | ParseTimeOperation(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 | |||
| 901 | UCHAR | ||
| 902 | ParseTokenOperation(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 | |||
| 928 | UCHAR | ||
| 929 | ParsePortOperation(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 | |||
| 959 | UCHAR | ||
| 960 | ParseCreateOpenOperation(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 | |||
| 990 | UCHAR | ||
| 991 | ParseAtomOperation(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 | |||
| 1021 | UCHAR | ||
| 1022 | ParseDriverOperation(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 | |||
| 1051 | UCHAR | ||
| 1052 | ParseDirectoryOperation(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 | |||
| 1078 | UCHAR | ||
| 1079 | ParseObjectOperation(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 | |||
| 1122 | UCHAR | ||
| 1123 | ParseProcessOperation(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 | |||
| 1153 | UCHAR | ||
| 1154 | ParseServiceOperation(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 | |||
| 1194 | UCHAR | ||
| 1195 | ParseNetworkOperation(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 | |||
| 1239 | size_t | ||
| 1240 | ParseNetworkObject(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 | |||
| 1284 | size_t | ||
| 1285 | ParseStub(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 | |||
| 1309 | size_t | ||
| 1310 | ParseRegistryObject(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 | |||
| 1363 | size_t | ||
| 1364 | ParseFileObject(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 | |||
| 1479 | size_t | ||
| 1480 | ParseProcessObject(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 | |||
| 1511 | size_t | ||
| 1512 | ParseBaseNamedObjectsObject(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 | |||
| 1558 | size_t | ||
| 1559 | ParseMailslotObject(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 | |||
| 1605 | size_t | ||
| 1606 | ParseNamedpipeObject(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 | |||
| 1654 | size_t | ||
| 1655 | ParseDllObject(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 | |||
| 1701 | size_t | ||
| 1702 | ParseTimeObject(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 | |||
| 1727 | size_t | ||
| 1728 | ParseServiceObject(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 | |||
| 1751 | typedef size_t (*OBJECT_PARSER)(IN PCHAR name, OUT PCHAR *Object, OUT BOOLEAN *wildcard); | ||
| 1752 | typedef UCHAR (*OPERATION_TYPE_PARSER)(IN PCHAR name); | ||
| 1753 | |||
| 1754 | |||
| 1755 | /* in C++ these would be member methods */ | ||
| 1756 | |||
| 1757 | struct _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 | |||
| 1804 | BOOLEAN | ||
| 1805 | PolicyParseActionClause(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 | |||
| 1938 | BOOLEAN | ||
| 1939 | PolicyParseOnOffClause(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 | |||
| 1988 | UCHAR | ||
| 1989 | VerifyToken2(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 | |||
| 2058 | BOOLEAN | ||
| 2059 | PolicyParsePolicyRule(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 | |||
| 2146 | BOOLEAN | ||
| 2147 | PolicyParseProtectionRule(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 | |||
| 2313 | BOOLEAN | ||
| 2314 | PolicyParseMediaRule(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 | |||
| 2372 | VOID | ||
| 2373 | InsertPolicyRule(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 | |||
| 2432 | BOOLEAN | ||
| 2433 | PolicyParseObjectRule(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 | |||
| 2566 | ParseLastToken: | ||
| 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 | |||
| 2665 | BOOLEAN | ||
| 2666 | PolicyParseSyscallRule(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 | |||
| 2814 | int | ||
| 2815 | WildcardMatch(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 | |||
| 2988 | ACTION_TYPE | ||
| 2989 | PolicyCheckPolicy(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 | |||
| 3124 | ACTION_TYPE | ||
| 3125 | PolicyCheck(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 | |||
| 3232 | done: | ||
| 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 | ||
| 36 | typedef 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 | |||
| 62 | typedef 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 | |||
| 101 | typedef 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 | |||
| 132 | typedef enum _MatchType | ||
| 133 | { | ||
| 134 | MATCH_SINGLE = 0, | ||
| 135 | MATCH_WILDCARD, | ||
| 136 | MATCH_ALL, | ||
| 137 | MATCH_NONE | ||
| 138 | |||
| 139 | } MATCH_TYPE; | ||
| 140 | |||
| 141 | |||
| 142 | typedef 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 | ||
| 238 | typedef struct _SECURITY_POLICY SECURITY_POLICY, *PSECURITY_POLICY; | ||
| 239 | |||
| 240 | |||
| 241 | /* Rule should really be a class */ | ||
| 242 | |||
| 243 | typedef 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 | |||
| 278 | typedef 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 | |||
| 322 | extern SECURITY_POLICY gSecPolicy; | ||
| 323 | extern CHAR SystemDrive, SystemRoot[], SystemRootUnresolved[], *SystemRootDirectory, CDrive[]; | ||
| 324 | extern USHORT SystemRootLength, SystemRootUnresolvedLength, SystemRootDirectoryLength, CDriveLength; | ||
| 325 | extern ULONG NumberOfBitsInUlong, UlongBitShift; | ||
| 326 | |||
| 327 | |||
| 328 | #define WILDCARD_MATCH 1 | ||
| 329 | #define WILDCARD_NO_MATCH 0 | ||
| 330 | |||
| 331 | |||
| 332 | BOOLEAN InitPolicy(); | ||
| 333 | void PolicyRemove(); | ||
| 334 | void PolicyDelete(IN PSECURITY_POLICY pSecPolicy); | ||
| 335 | BOOLEAN LoadSecurityPolicy(OUT PSECURITY_POLICY pSecPolicy, IN PWSTR PolicyFile, IN PWSTR FilePath); | ||
| 336 | BOOLEAN FindAndLoadSecurityPolicy(OUT PSECURITY_POLICY pSecPolicy, IN PWSTR filename, IN PWSTR UserName); | ||
| 337 | ACTION_TYPE PolicyCheck(RULE_TYPE RuleType, PCHAR Object, UCHAR OperationType, UCHAR *RuleNumber, PWSTR *PolicyFilename, USHORT *PolicyLineNumber); | ||
| 338 | BOOLEAN PolicyParseObjectRule(PSECURITY_POLICY pSecPolicy, RULE_TYPE RuleType, PCHAR Operation, PCHAR rule); | ||
| 339 | VOID InsertPolicyRule(PSECURITY_POLICY pSecPolicy, PPOLICY_RULE PolicyRule, RULE_TYPE RuleType); | ||
| 340 | BOOLEAN PolicyPostBootup(); | ||
| 341 | int WildcardMatch(PCHAR path, PCHAR regex); | ||
| 342 | |||
| 343 | |||
| 344 | #endif /* __POLICY_H__ */ | ||
| @@ -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 | |||
| 30 | fpZwCreatePort OriginalNtCreatePort = NULL; | ||
| 31 | fpZwCreateWaitablePort OriginalNtCreateWaitablePort = NULL; | ||
| 32 | |||
| 33 | fpZwConnectPort OriginalNtConnectPort = NULL; | ||
| 34 | fpZwSecureConnectPort 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 | |||
| 54 | NTSTATUS | ||
| 55 | NTAPI | ||
| 56 | HookedNtCreatePort | ||
| 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 | |||
| 98 | NTSTATUS | ||
| 99 | NTAPI | ||
| 100 | HookedNtCreateWaitablePort | ||
| 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 | |||
| 142 | NTSTATUS | ||
| 143 | NTAPI | ||
| 144 | HookedNtConnectPort | ||
| 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 | |||
| 213 | NTSTATUS | ||
| 214 | NTAPI | ||
| 215 | HookedNtSecureConnectPort | ||
| 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 | |||
| 290 | BOOLEAN | ||
| 291 | InitPortHooks() | ||
| 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 | } | ||
| @@ -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 | |||
| 39 | typedef 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 | |||
| 47 | NTSTATUS | ||
| 48 | NTAPI | ||
| 49 | HookedNtCreatePort( | ||
| 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 | |||
| 62 | typedef 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 | |||
| 70 | NTSTATUS | ||
| 71 | NTAPI | ||
| 72 | HookedNtCreateWaitablePort( | ||
| 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 | |||
| 82 | typedef struct _PORT_SECTION_READ { | ||
| 83 | ULONG Length; | ||
| 84 | ULONG ViewSize; | ||
| 85 | ULONG ViewBase; | ||
| 86 | } PORT_SECTION_READ, *PPORT_SECTION_READ; | ||
| 87 | |||
| 88 | typedef 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 | |||
| 102 | typedef 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 | |||
| 113 | NTSTATUS | ||
| 114 | NTAPI | ||
| 115 | HookedNtConnectPort( | ||
| 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 | |||
| 131 | typedef 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 | |||
| 143 | NTSTATUS | ||
| 144 | NTAPI | ||
| 145 | HookedNtSecureConnectPort( | ||
| 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 | |||
| 159 | BOOLEAN 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 | |||
| 42 | fpZwCreateProcess OriginalNtCreateProcess = NULL; | ||
| 43 | fpZwCreateProcessEx OriginalNtCreateProcessEx = NULL; | ||
| 44 | fpZwOpenProcess OriginalNtOpenProcess = NULL; | ||
| 45 | |||
| 46 | fpZwCreateThread OriginalNtCreateThread = NULL; | ||
| 47 | fpZwOpenThread OriginalNtOpenThread = NULL; | ||
| 48 | |||
| 49 | |||
| 50 | BOOLEAN AllowProcessesWithPoliciesOnly = FALSE; | ||
| 51 | |||
| 52 | WCHAR OzoneInstallPath[MAX_PATH]; | ||
| 53 | USHORT OzoneInstallPathSize = 0; | ||
| 54 | |||
| 55 | |||
| 56 | /* XXX this will not work on 64-bit architectures, due to assumption of size of ulong, pointers, etc */ | ||
| 57 | typedef struct _CONTROL_AREA { // must be quadword sized. | ||
| 58 | ULONG data[9]; | ||
| 59 | PFILE_OBJECT FilePointer; | ||
| 60 | } CONTROL_AREA, *PCONTROL_AREA; | ||
| 61 | |||
| 62 | typedef struct _SEGMENT { | ||
| 63 | struct _CONTROL_AREA *ControlArea; | ||
| 64 | } SEGMENT, *PSEGMENT; | ||
| 65 | |||
| 66 | typedef 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 | |||
| 86 | ULONG | ||
| 87 | rand(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 | |||
| 134 | ULONG | ||
| 135 | PostProcessNtCreateProcess(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 | |||
| 504 | NTSTATUS | ||
| 505 | NTAPI | ||
| 506 | HookedNtCreateProcess | ||
| 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 | |||
| 560 | NTSTATUS | ||
| 561 | NTAPI | ||
| 562 | HookedNtCreateProcessEx | ||
| 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 | |||
| 617 | NTSTATUS | ||
| 618 | NTAPI | ||
| 619 | HookedNtOpenProcess | ||
| 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 | /* | ||
| 635 | PROCESS_TERMINATE Terminate process | ||
| 636 | PROCESS_CREATE_THREAD Create threads in process | ||
| 637 | PROCESS_SET_SESSIONID Set process session id | ||
| 638 | PROCESS_VM_OPERATION Protect and lock memory of process | ||
| 639 | PROCESS_VM_READ Read memory of process | ||
| 640 | PROCESS_VM_WRITE Write memory of process | ||
| 641 | PROCESS_DUP_HANDLE Duplicate handles of process | ||
| 642 | PROCESS_CREATE_PROCESS Bequeath address space and handles to new process | ||
| 643 | PROCESS_SET_QUOTA Set process quotas | ||
| 644 | PROCESS_SET_INFORMATION Set information about process | ||
| 645 | PROCESS_QUERY_INFORMATION Query information about process | ||
| 646 | PROCESS_SET_PORT Set process exception or debug port | ||
| 647 | PROCESS_ALL_ACCESS All of the preceding | ||
| 648 | |||
| 649 | find 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 | |||
| 758 | done: | ||
| 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 | |||
| 786 | NTSTATUS | ||
| 787 | NTAPI | ||
| 788 | HookedNtCreateThread | ||
| 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 | |||
| 1075 | done: | ||
| 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 | |||
| 1114 | NTSTATUS | ||
| 1115 | NTAPI | ||
| 1116 | HookedNtOpenThread | ||
| 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 | |||
| 1173 | VOID | ||
| 1174 | ProcessPostBootup() | ||
| 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 | /* | ||
| 1205 | VOID | ||
| 1206 | LoadImageNotifyProc | ||
| 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 | |||
| 1224 | BOOLEAN | ||
| 1225 | InitProcessEntries() | ||
| 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 | |||
| 25 | extern ULONG SystemProcessId; | ||
| 26 | |||
| 27 | extern WCHAR OzoneInstallPath[]; | ||
| 28 | extern USHORT OzoneInstallPathSize; | ||
| 29 | |||
| 30 | |||
| 31 | /* | ||
| 32 | * ZwCreateProcess creates a process object. [NAR] | ||
| 33 | */ | ||
| 34 | |||
| 35 | typedef 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 | |||
| 46 | NTSTATUS | ||
| 47 | NTAPI | ||
| 48 | HookedNtCreateProcess( | ||
| 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 | |||
| 60 | typedef 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 | |||
| 72 | NTSTATUS | ||
| 73 | NTAPI | ||
| 74 | HookedNtCreateProcessEx( | ||
| 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 | |||
| 91 | typedef NTSTATUS (*fpZwOpenProcess) ( | ||
| 92 | OUT PHANDLE ProcessHandle, | ||
| 93 | IN ACCESS_MASK DesiredAccess, | ||
| 94 | IN POBJECT_ATTRIBUTES ObjectAttributes, | ||
| 95 | IN PCLIENT_ID ClientId OPTIONAL | ||
| 96 | ); | ||
| 97 | |||
| 98 | NTSTATUS | ||
| 99 | NTAPI | ||
| 100 | HookedNtOpenProcess( | ||
| 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 | |||
| 112 | typedef struct _USER_STACK { | ||
| 113 | PVOID FixedStackBase; | ||
| 114 | PVOID FixedStackLimit; | ||
| 115 | PVOID ExpandableStackBase; | ||
| 116 | PVOID ExpandableStackLimit; | ||
| 117 | PVOID ExpandableStackBottom; | ||
| 118 | } USER_STACK, *PUSER_STACK; | ||
| 119 | |||
| 120 | typedef 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 | |||
| 131 | NTSTATUS | ||
| 132 | NTAPI | ||
| 133 | HookedNtCreateThread( | ||
| 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 | |||
| 149 | typedef NTSTATUS (*fpZwOpenThread) ( | ||
| 150 | OUT PHANDLE ThreadHandle, | ||
| 151 | IN ACCESS_MASK DesiredAccess, | ||
| 152 | IN POBJECT_ATTRIBUTES ObjectAttributes, | ||
| 153 | IN PCLIENT_ID ClientId | ||
| 154 | ); | ||
| 155 | |||
| 156 | NTSTATUS | ||
| 157 | NTAPI | ||
| 158 | HookedNtOpenThread( | ||
| 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 | |||
| 170 | NTSYSAPI | ||
| 171 | NTSTATUS | ||
| 172 | NTAPI | ||
| 173 | ZwAllocateVirtualMemory( | ||
| 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 | |||
| 187 | NTSYSAPI | ||
| 188 | NTSTATUS | ||
| 189 | NTAPI | ||
| 190 | ZwQueryInformationProcess( | ||
| 191 | IN HANDLE ProcessHandle, | ||
| 192 | IN PROCESSINFOCLASS ProcessInformationClass, | ||
| 193 | OUT PVOID ProcessInformation, | ||
| 194 | IN ULONG ProcessInformationLength, | ||
| 195 | OUT PULONG ReturnLength OPTIONAL | ||
| 196 | ); | ||
| 197 | |||
| 198 | |||
| 199 | VOID | ||
| 200 | KeAttachProcess( | ||
| 201 | IN /*PRKPROCESS*/ PVOID Process | ||
| 202 | ); | ||
| 203 | |||
| 204 | VOID | ||
| 205 | KeDetachProcess ( | ||
| 206 | VOID | ||
| 207 | ); | ||
| 208 | |||
| 209 | |||
| 210 | BOOLEAN InitProcessEntries(); | ||
| 211 | VOID RemoveProcessEntries(); | ||
| 212 | VOID 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 | |||
| 41 | void 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 | |||
| 52 | ULONG SystemProcessId; | ||
| 53 | |||
| 54 | /* 67 * 144 = 10 kilobytes */ | ||
| 55 | IMAGE_PID_ENTRY gImagePidHtbl[IMAGE_PID_HASHTABLE_SIZE]; | ||
| 56 | |||
| 57 | //XXX investigate KeAcquireInStackQueuedSpinLock | ||
| 58 | KSPIN_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 | |||
| 74 | PIMAGE_PID_ENTRY | ||
| 75 | FindImagePidEntry(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 | |||
| 132 | BOOLEAN | ||
| 133 | ProcessInsertImagePidEntry(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 | |||
| 190 | PIMAGE_PID_ENTRY | ||
| 191 | CreateNewProcessEntry(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 | |||
| 239 | PIMAGE_PID_ENTRY | ||
| 240 | CreateAndLoadNewProcessEntry(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 | |||
| 292 | VOID | ||
| 293 | CreateProcessNotifyProc | ||
| 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 | |||
| 388 | USHORT 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 | |||
| 410 | void | ||
| 411 | FindProcessNameOffset() | ||
| 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 | |||
| 457 | PWCHAR | ||
| 458 | GetCurrentProcessName() | ||
| 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 | |||
| 496 | VOID | ||
| 497 | EnumerateExistingProcesses() | ||
| 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 | |||
| 596 | BOOLEAN | ||
| 597 | InitProcessNameEntries() | ||
| 598 | { | ||
| 599 | memset(gImagePidHtbl, 0, sizeof(gImagePidHtbl)); | ||
| 600 | |||
| 601 | KeInitializeSpinLock(&gImagePidHtblSpinLock); | ||
| 602 | |||
| 603 | SystemProcessId = (ULONG) PsGetCurrentProcessId(); | ||
| 604 | |||
| 605 | FindProcessNameOffset(); | ||
| 606 | |||
| 607 | |||
| 608 | /* XXX investigate | ||
| 609 | A 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 | |||
| 637 | VOID | ||
| 638 | RemoveProcessNameEntries() | ||
| 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 | |||
| 28 | typedef 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 | |||
| 52 | extern IMAGE_PID_ENTRY gImagePidHtbl[IMAGE_PID_HASHTABLE_SIZE]; | ||
| 53 | |||
| 54 | extern USHORT ProcessNameOffset, ThreadServiceTableOffset; | ||
| 55 | extern BOOLEAN BootingUp; | ||
| 56 | |||
| 57 | |||
| 58 | BOOLEAN InitProcessNameEntries(); | ||
| 59 | VOID RemoveProcessNameEntries(); | ||
| 60 | PIMAGE_PID_ENTRY FindImagePidEntry(ULONG ProcessId, ULONG ParentId); | ||
| 61 | BOOLEAN ProcessInsertImagePidEntry(ULONG ProcessId, PIMAGE_PID_ENTRY NewProcess); | ||
| 62 | PIMAGE_PID_ENTRY CreateNewProcessEntry(ULONG ProcessId, ULONG ParentId, PUNICODE_STRING ProcessName, BOOLEAN NewProcess); | ||
| 63 | //PIMAGE_PID_ENTRY CreateAndLoadNewProcessEntry(ULONG ProcessId, PUNICODE_STRING ProcessName, BOOLEAN NewProcess); | ||
| 64 | VOID EnumerateExistingProcesses(); | ||
| 65 | PWCHAR 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 | |||
| 38 | fpZwCreateKey OriginalNtCreateKey = NULL; | ||
| 39 | fpZwOpenKey OriginalNtOpenKey = NULL; | ||
| 40 | |||
| 41 | fpZwDeleteKey OriginalNtDeleteKey = NULL; | ||
| 42 | |||
| 43 | fpZwSetValueKey OriginalNtSetValueKey = NULL; | ||
| 44 | fpZwQueryValueKey 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 | |||
| 65 | NTSTATUS | ||
| 66 | NTAPI | ||
| 67 | HookedNtCreateKey | ||
| 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 | |||
| 112 | NTSTATUS | ||
| 113 | NTAPI | ||
| 114 | HookedNtOpenKey | ||
| 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 | |||
| 154 | NTSTATUS | ||
| 155 | NTAPI | ||
| 156 | HookedNtDeleteKey | ||
| 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 | |||
| 218 | NTSTATUS | ||
| 219 | NTAPI | ||
| 220 | HookedNtSetValueKey | ||
| 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 | |||
| 292 | NTSTATUS | ||
| 293 | NTAPI | ||
| 294 | HookedNtQueryValueKey | ||
| 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 | |||
| 366 | BOOLEAN | ||
| 367 | InitRegistryHooks() | ||
| 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 | |||
| 30 | typedef 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 | |||
| 40 | NTSTATUS | ||
| 41 | NTAPI | ||
| 42 | HookedNtCreateKey( | ||
| 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 | |||
| 57 | typedef NTSTATUS (*fpZwOpenKey) ( | ||
| 58 | OUT PHANDLE KeyHandle, | ||
| 59 | IN ACCESS_MASK DesiredAccess, | ||
| 60 | IN POBJECT_ATTRIBUTES ObjectAttributes | ||
| 61 | ); | ||
| 62 | |||
| 63 | NTSTATUS | ||
| 64 | NTAPI | ||
| 65 | HookedNtOpenKey( | ||
| 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 | |||
| 76 | typedef 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 | |||
| 85 | NTSTATUS | ||
| 86 | NTAPI | ||
| 87 | HookedNtSetValueKey( | ||
| 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 | |||
| 101 | typedef 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 | |||
| 110 | NTSTATUS | ||
| 111 | NTAPI | ||
| 112 | HookedNtQueryValueKey( | ||
| 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 | |||
| 126 | typedef NTSTATUS (*fpZwDeleteKey) ( | ||
| 127 | IN HANDLE KeyHandle | ||
| 128 | ); | ||
| 129 | |||
| 130 | NTSTATUS | ||
| 131 | NTAPI | ||
| 132 | HookedNtDeleteKey( | ||
| 133 | IN HANDLE KeyHandle | ||
| 134 | ); | ||
| 135 | |||
| 136 | |||
| 137 | BOOLEAN 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 | |||
| 42 | fpZwCreateSection OriginalNtCreateSection = NULL; | ||
| 43 | fpZwOpenSection OriginalNtOpenSection = NULL; | ||
| 44 | fpZwMapViewOfSection 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 | |||
| 68 | NTSTATUS | ||
| 69 | NTAPI | ||
| 70 | HookedNtCreateSection | ||
| 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 | |||
| 139 | NTSTATUS | ||
| 140 | NTAPI | ||
| 141 | HookedNtOpenSection | ||
| 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 | |||
| 205 | NTSTATUS | ||
| 206 | NTAPI | ||
| 207 | HookedNtMapViewOfSection | ||
| 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 | |||
| 263 | BOOLEAN | ||
| 264 | InitSectionHooks() | ||
| 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 | |||
| 33 | typedef NTSTATUS (*fpZwOpenSection) ( | ||
| 34 | OUT PHANDLE SectionHandle, | ||
| 35 | IN ACCESS_MASK DesiredAccess, | ||
| 36 | IN POBJECT_ATTRIBUTES ObjectAttributes | ||
| 37 | ); | ||
| 38 | |||
| 39 | |||
| 40 | NTSTATUS | ||
| 41 | NTAPI | ||
| 42 | HookedNtOpenSection( | ||
| 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 | |||
| 53 | typedef 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 | |||
| 63 | NTSTATUS | ||
| 64 | NTAPI | ||
| 65 | HookedNtCreateSection( | ||
| 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 | |||
| 80 | typedef 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 | |||
| 93 | NTSTATUS | ||
| 94 | NTAPI | ||
| 95 | HookedNtMapViewOfSection( | ||
| 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 | |||
| 109 | BOOLEAN 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 | |||
| 37 | fpZwCreateSemaphore OriginalNtCreateSemaphore = NULL; | ||
| 38 | fpZwOpenSemaphore 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 | |||
| 59 | NTSTATUS | ||
| 60 | NTAPI | ||
| 61 | HookedNtCreateSemaphore | ||
| 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 | |||
| 104 | NTSTATUS | ||
| 105 | NTAPI | ||
| 106 | HookedNtOpenSemaphore | ||
| 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 | |||
| 145 | BOOLEAN | ||
| 146 | InitSemaphoreHooks() | ||
| 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 | |||
| 31 | typedef 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 | |||
| 39 | NTSTATUS 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 | |||
| 52 | typedef NTSTATUS (*fpZwOpenSemaphore) ( | ||
| 53 | OUT PHANDLE SemaphoreHandle, | ||
| 54 | IN ACCESS_MASK DesiredAccess, | ||
| 55 | IN POBJECT_ATTRIBUTES ObjectAttributes | ||
| 56 | ); | ||
| 57 | |||
| 58 | NTSTATUS HookedNtOpenSemaphore( | ||
| 59 | OUT PHANDLE SemaphoreHandle, | ||
| 60 | IN ACCESS_MASK DesiredAccess, | ||
| 61 | IN POBJECT_ATTRIBUTES ObjectAttributes | ||
| 62 | ); | ||
| 63 | |||
| 64 | |||
| 65 | |||
| 66 | BOOLEAN 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 | |||
| 31 | fpZwCreateSymbolicLinkObject OriginalNtCreateSymbolicLinkObject = NULL; | ||
| 32 | fpZwOpenSymbolicLinkObject 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 | |||
| 52 | NTSTATUS | ||
| 53 | NTAPI | ||
| 54 | HookedNtCreateSymbolicLinkObject | ||
| 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 | |||
| 118 | NTSTATUS | ||
| 119 | NTAPI | ||
| 120 | HookedNtOpenSymbolicLinkObject | ||
| 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 | |||
| 167 | BOOLEAN | ||
| 168 | InitSymlinkHooks() | ||
| 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 | |||
| 39 | typedef NTSTATUS (*fpZwCreateSymbolicLinkObject) ( | ||
| 40 | OUT PHANDLE SymbolicLinkHandle, | ||
| 41 | IN ACCESS_MASK DesiredAccess, | ||
| 42 | IN POBJECT_ATTRIBUTES ObjectAttributes, | ||
| 43 | IN PUNICODE_STRING TargetName | ||
| 44 | ); | ||
| 45 | |||
| 46 | NTSTATUS | ||
| 47 | NTAPI | ||
| 48 | HookedNtCreateSymbolicLinkObject( | ||
| 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 | |||
| 60 | typedef NTSTATUS (*fpZwOpenSymbolicLinkObject) ( | ||
| 61 | OUT PHANDLE SymbolicLinkHandle, | ||
| 62 | IN ACCESS_MASK DesiredAccess, | ||
| 63 | IN POBJECT_ATTRIBUTES ObjectAttributes | ||
| 64 | ); | ||
| 65 | |||
| 66 | NTSTATUS | ||
| 67 | NTAPI | ||
| 68 | HookedNtOpenSymbolicLinkObject( | ||
| 69 | OUT PHANDLE SymbolicLinkHandle, | ||
| 70 | IN ACCESS_MASK DesiredAccess, | ||
| 71 | IN POBJECT_ATTRIBUTES ObjectAttributes | ||
| 72 | ); | ||
| 73 | |||
| 74 | |||
| 75 | BOOLEAN 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 | |||
| 38 | fpZwSetSystemInformation 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 | |||
| 59 | NTSTATUS | ||
| 60 | NTAPI | ||
| 61 | HookedNtSetSystemInformation | ||
| 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 | |||
| 187 | BOOLEAN | ||
| 188 | InitSysInfoHooks() | ||
| 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 | ||
| 33 | typedef 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 | |||
| 95 | typedef enum { | ||
| 96 | StateInitialized, | ||
| 97 | StateReady, | ||
| 98 | StateRunning, | ||
| 99 | StateStandby, | ||
| 100 | StateTerminated, | ||
| 101 | StateWait, | ||
| 102 | StateTransition, | ||
| 103 | StateUnknown | ||
| 104 | } THREAD_STATE; | ||
| 105 | |||
| 106 | typedef 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 | |||
| 120 | typedef 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 | |||
| 139 | NTSTATUS | ||
| 140 | NTAPI | ||
| 141 | HookedNtSetSystemInformation( | ||
| 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 | |||
| 152 | NTSYSAPI | ||
| 153 | NTSTATUS | ||
| 154 | NTAPI | ||
| 155 | ZwQuerySystemInformation( | ||
| 156 | IN SYSTEM_INFORMATION_CLASS SystemInformationClass, | ||
| 157 | IN OUT PVOID SystemInformation, | ||
| 158 | IN ULONG SystemInformationLength, | ||
| 159 | OUT PULONG ReturnLength OPTIONAL | ||
| 160 | ); | ||
| 161 | |||
| 162 | |||
| 163 | typedef 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 | |||
| 179 | typedef 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 | |||
| 187 | BOOLEAN InitSysInfoHooks(); | ||
| 188 | |||
| 189 | |||
| 190 | #endif /* __SYSINFO_H__ */ | ||
| @@ -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 | |||
| 36 | fpZwSetSystemTime OriginalNtSetSystemTime = NULL; | ||
| 37 | fpZwSetTimerResolution 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 | |||
| 58 | NTSTATUS | ||
| 59 | NTAPI | ||
| 60 | HookedNtSetSystemTime | ||
| 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 | |||
| 116 | NTSTATUS | ||
| 117 | NTAPI | ||
| 118 | HookedNtSetTimerResolution | ||
| 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 | |||
| 172 | BOOLEAN | ||
| 173 | InitTimeHooks() | ||
| 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 | } | ||
| @@ -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 | |||
| 33 | typedef NTSTATUS (*fpZwSetSystemTime)( | ||
| 34 | IN PLARGE_INTEGER NewTime, | ||
| 35 | OUT PLARGE_INTEGER OldTime OPTIONAL | ||
| 36 | ); | ||
| 37 | |||
| 38 | NTSTATUS | ||
| 39 | NTAPI | ||
| 40 | HookedNtSetSystemTime( | ||
| 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 | |||
| 50 | typedef NTSTATUS (*fpZwSetTimerResolution)( | ||
| 51 | IN ULONG RequestedResolution, | ||
| 52 | IN BOOLEAN Set, | ||
| 53 | OUT PULONG ActualResolution | ||
| 54 | ); | ||
| 55 | |||
| 56 | NTSTATUS | ||
| 57 | NTAPI | ||
| 58 | HookedNtSetTimerResolution( | ||
| 59 | IN ULONG RequestedResolution, | ||
| 60 | IN BOOLEAN Set, | ||
| 61 | OUT PULONG ActualResolution | ||
| 62 | ); | ||
| 63 | |||
| 64 | |||
| 65 | BOOLEAN InitTimeHooks(); | ||
| 66 | |||
| 67 | |||
| 68 | #endif /* __TIME_H__ */ | ||
| @@ -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 | |||
| 30 | fpZwCreateTimer OriginalNtCreateTimer = NULL; | ||
| 31 | fpZwOpenTimer 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 | |||
| 51 | NTSTATUS | ||
| 52 | NTAPI | ||
| 53 | HookedNtCreateTimer | ||
| 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 | |||
| 94 | NTSTATUS | ||
| 95 | NTAPI | ||
| 96 | HookedNtOpenTimer | ||
| 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 | |||
| 135 | BOOLEAN | ||
| 136 | InitTimerHooks() | ||
| 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 | } | ||
| @@ -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 | |||
| 39 | typedef NTSTATUS (*fpZwCreateTimer) ( | ||
| 40 | OUT PHANDLE TimerHandle, | ||
| 41 | IN ACCESS_MASK DesiredAccess, | ||
| 42 | IN POBJECT_ATTRIBUTES ObjectAttributes, | ||
| 43 | IN TIMER_TYPE TimerType | ||
| 44 | ); | ||
| 45 | |||
| 46 | NTSTATUS | ||
| 47 | NTAPI | ||
| 48 | HookedNtCreateTimer( | ||
| 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 | |||
| 60 | typedef NTSTATUS (*fpZwOpenTimer) ( | ||
| 61 | OUT PHANDLE TimerHandle, | ||
| 62 | IN ACCESS_MASK DesiredAccess, | ||
| 63 | IN POBJECT_ATTRIBUTES ObjectAttributes | ||
| 64 | ); | ||
| 65 | |||
| 66 | NTSTATUS | ||
| 67 | NTAPI | ||
| 68 | HookedNtOpenTimer( | ||
| 69 | OUT PHANDLE TimerHandle, | ||
| 70 | IN ACCESS_MASK DesiredAccess, | ||
| 71 | IN POBJECT_ATTRIBUTES ObjectAttributes | ||
| 72 | ); | ||
| 73 | |||
| 74 | |||
| 75 | BOOLEAN InitTimerHooks(); | ||
| 76 | |||
| 77 | |||
| 78 | #endif /* __TIMER_H__ */ | ||
| @@ -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 | |||
| 32 | fpZwAdjustPrivilegesToken OriginalNtAdjustPrivilegesToken = NULL; | ||
| 33 | fpZwSetInformationToken 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 | |||
| 53 | NTSTATUS | ||
| 54 | NTAPI | ||
| 55 | HookedNtAdjustPrivilegesToken | ||
| 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 | |||
| 168 | NTSTATUS | ||
| 169 | NTAPI | ||
| 170 | HookedNtSetInformationToken | ||
| 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 | |||
| 234 | BOOLEAN | ||
| 235 | InitTokenHooks() | ||
| 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 | } | ||
| @@ -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 | /* | ||
| 36 | ZwAdjustGroupsToken | ||
| 37 | ZwCreateToken | ||
| 38 | ZwOpenProcessToken | ||
| 39 | ZwOpenProcessTokenEx | ||
| 40 | ZwOpenThreadToken | ||
| 41 | ZwOpenThreadTokenEx | ||
| 42 | */ | ||
| 43 | |||
| 44 | |||
| 45 | typedef 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 | |||
| 55 | typedef 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 | |||
| 64 | NTSTATUS | ||
| 65 | NTAPI | ||
| 66 | HookedNtAdjustPrivilegesToken( | ||
| 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 | |||
| 80 | typedef NTSTATUS (*fpZwSetInformationToken) ( | ||
| 81 | IN HANDLE TokenHandle, | ||
| 82 | IN TOKEN_INFORMATION_CLASS TokenInformationClass, | ||
| 83 | IN PVOID TokenInformation, | ||
| 84 | IN ULONG TokenInformationLength | ||
| 85 | ); | ||
| 86 | |||
| 87 | NTSTATUS | ||
| 88 | NTAPI | ||
| 89 | HookedNtSetInformationToken( | ||
| 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 | |||
| 101 | NTSYSAPI | ||
| 102 | NTSTATUS | ||
| 103 | NTAPI | ||
| 104 | ZwOpenProcessToken( | ||
| 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 | |||
| 115 | NTSYSAPI | ||
| 116 | NTSTATUS | ||
| 117 | NTAPI | ||
| 118 | ZwOpenThreadToken( | ||
| 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 | |||
| 130 | NTSYSAPI | ||
| 131 | NTSTATUS | ||
| 132 | NTAPI | ||
| 133 | ZwQueryInformationToken( | ||
| 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 | |||
| 142 | BOOLEAN 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 | |||
| 34 | BOOLEAN ActiveUserAgent = FALSE; | ||
| 35 | |||
| 36 | PKEVENT UserlandRequestUserEvent = NULL; | ||
| 37 | HANDLE UserlandRequestUserEventHandle = NULL; | ||
| 38 | |||
| 39 | PUSERLAND_REQUEST_HEADER UserlandRequestList = NULL; | ||
| 40 | KSPIN_LOCK gUserlandRequestListSpinLock; | ||
| 41 | |||
| 42 | BOOLEAN CacheSid = TRUE; | ||
| 43 | ULONG CachedSidSize = 0, CachedSidReplySize = 0; | ||
| 44 | PVOID CachedSid = NULL; | ||
| 45 | PSID_RESOLVE_REPLY CachedSidReply = NULL; | ||
| 46 | |||
| 47 | UCHAR 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 | |||
| 68 | BOOLEAN | ||
| 69 | UserlandPostBootup() | ||
| 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 | |||
| 113 | BOOLEAN | ||
| 114 | IssueUserlandSidResolveRequest(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 | |||
| 316 | ACTION_TYPE | ||
| 317 | IssueUserlandAskUserRequest(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 | |||
| 507 | BOOLEAN | ||
| 508 | InitUserland() | ||
| 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 | |||
| 538 | VOID | ||
| 539 | ShutdownUserland() | ||
| 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 | |||
| 42 | typedef 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 | |||
| 56 | typedef 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 | |||
| 66 | typedef 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 | |||
| 87 | typedef 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 | |||
| 98 | typedef 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 | |||
| 109 | typedef struct _ASK_USER_REPLY | ||
| 110 | { | ||
| 111 | USERLAND_REPLY_HEADER ReplyHeader; | ||
| 112 | ACTION_TYPE Action; | ||
| 113 | |||
| 114 | } ASK_USER_REPLY, *PASK_USER_REPLY; | ||
| 115 | |||
| 116 | |||
| 117 | extern BOOLEAN ActiveUserAgent; | ||
| 118 | extern PUSERLAND_REQUEST_HEADER UserlandRequestList; | ||
| 119 | extern KSPIN_LOCK gUserlandRequestListSpinLock; | ||
| 120 | extern PKEVENT UserlandRequestUserEvent; | ||
| 121 | |||
| 122 | |||
| 123 | BOOLEAN InitUserland(); | ||
| 124 | BOOLEAN UserlandPostBootup(); | ||
| 125 | VOID ShutdownUserland(); | ||
| 126 | |||
| 127 | typedef struct _IMAGE_PID_ENTRY *PIMAGE_PID_ENTRY; | ||
| 128 | |||
| 129 | BOOLEAN IssueUserlandSidResolveRequest(PIMAGE_PID_ENTRY Process); | ||
| 130 | ACTION_TYPE IssueUserlandAskUserRequest(RULE_TYPE RuleType, UCHAR OperationType, PCHAR ObjectName); | ||
| 131 | |||
| 132 | |||
| 133 | #endif /* __USERLAND_H__ */ \ No newline at end of file | ||
| @@ -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 | |||
| 37 | fpZwSetLdtEntries OriginalNtSetLdtEntries = NULL; | ||
| 38 | fpZwVdmControl 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 | |||
| 55 | BOOLEAN | ||
| 56 | IsVdmAllowed() | ||
| 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 | |||
| 101 | NTSTATUS | ||
| 102 | NTAPI | ||
| 103 | HookedNtSetLdtEntries | ||
| 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 | |||
| 158 | NTSTATUS | ||
| 159 | NTAPI | ||
| 160 | HookedNtVdmControl | ||
| 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 | |||
| 211 | BOOLEAN | ||
| 212 | InitVdmHooks() | ||
| 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 | } | ||
| @@ -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 | |||
| 31 | typedef 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 | |||
| 40 | NTSTATUS | ||
| 41 | NTAPI | ||
| 42 | HookedNtSetLdtEntries( | ||
| 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 | |||
| 56 | typedef NTSTATUS (*fpZwVdmControl) ( | ||
| 57 | IN ULONG ControlCode, | ||
| 58 | IN PVOID ControlData | ||
| 59 | ); | ||
| 60 | |||
| 61 | NTSTATUS | ||
| 62 | NTAPI | ||
| 63 | HookedNtVdmControl( | ||
| 64 | IN ULONG ControlCode, | ||
| 65 | IN PVOID ControlData | ||
| 66 | ); | ||
| 67 | |||
| 68 | |||
| 69 | BOOLEAN 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 | |||
| 37 | PVOID WirelessNotificationEntry = NULL; | ||
| 38 | |||
| 39 | /* removable wireless flags defined in drive.h (READONLY, etc) */ | ||
| 40 | UCHAR WirelessRemovableFlags = 0; | ||
| 41 | |||
| 42 | |||
| 43 | typedef 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 | |||
| 66 | VOID | ||
| 67 | AddDrive(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 | |||
| 141 | VOID | ||
| 142 | RemoveDrive(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 | |||
| 185 | VOID | ||
| 186 | PnpWorker(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 | |||
| 225 | NTSTATUS | ||
| 226 | PnpCallback(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 | |||
| 293 | BOOLEAN | ||
| 294 | InitWirelessHooks(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 | |||
| 332 | VOID | ||
| 333 | RemoveWirelessHooks() | ||
| 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 | |||
| 32 | extern UCHAR WirelessRemovableFlags; | ||
| 33 | |||
| 34 | |||
| 35 | BOOLEAN InitWirelessHooks(IN PDRIVER_OBJECT pDriverObject, IN PDEVICE_OBJECT pDeviceObject); | ||
| 36 | VOID RemoveRemovableWirelessHooks(); | ||
| 37 | VOID MonitorDriveLinks(const PCHAR Link); | ||
| 38 | |||
| 39 | |||
| 40 | #endif /* __WIRELESS_H__ */ | ||
