Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

344 lines
10 KiB

  1. /*++
  2. Copyright (c) 2001 Microsoft Corporation
  3. Module Name:
  4. KernelModeDriverInstall.cpp
  5. Abstract:
  6. This AppVerifier shim detects if an application
  7. is attempting to install a kernel mode driver.
  8. It monitors calls to CreateService and monitors
  9. the registry where information about drivers is
  10. stored.
  11. Notes:
  12. This is a general purpose shim.
  13. History:
  14. 09/30/2001 rparsons Created
  15. 10/03/2001 rparsons Fixed Raid bug # 476193
  16. 11/29/2001 rparsons Fixed Raid bug # 499824
  17. --*/
  18. #include "precomp.h"
  19. IMPLEMENT_SHIM_BEGIN(KernelModeDriverInstall)
  20. #include "ShimHookMacro.h"
  21. BEGIN_DEFINE_VERIFIER_LOG(KernelModeDriverInstall)
  22. VERIFIER_LOG_ENTRY(VLOG_KMODEDRIVER_INST)
  23. END_DEFINE_VERIFIER_LOG(KernelModeDriverInstall)
  24. INIT_VERIFIER_LOG(KernelModeDriverInstall);
  25. APIHOOK_ENUM_BEGIN
  26. APIHOOK_ENUM_ENTRY(CreateServiceA)
  27. APIHOOK_ENUM_ENTRY(CreateServiceW)
  28. APIHOOK_ENUM_ENTRY(NtSetValueKey)
  29. APIHOOK_ENUM_END
  30. //
  31. // Initial size to use for a stack based buffer when
  32. // performing a Nt registry API call.
  33. //
  34. #define MAX_INFO_LENGTH 512
  35. //
  36. // Constant for the 'ControlSet' & 'CurrentrControlSet' key path in the registry.
  37. //
  38. #define KMDI_CONTROLSET_KEY L"REGISTRY\\MACHINE\\SYSTEM\\ControlSet"
  39. #define KMDI_CURCONTROLSET_KEY L"REGISTRY\\MACHINE\\SYSTEM\\CurrentControlSet"
  40. //
  41. // Constant for the 'Services' key path.
  42. //
  43. #define KMDI_SERVICES_KEY L"Services\\"
  44. //
  45. // Constant for the ValueName that we need to look for.
  46. //
  47. #define KMDI_VALUE_NAME L"Type"
  48. //
  49. // Constant for the Value that we need to look for.
  50. //
  51. #define KMDI_TYPE_VALUE 0x00000001L
  52. //
  53. // Macros for memory allocation/deallocation.
  54. //
  55. #define MemAlloc(s) RtlAllocateHeap(RtlProcessHeap(), HEAP_ZERO_MEMORY, (s));
  56. #define MemFree(b) RtlFreeHeap(RtlProcessHeap(), 0, (b));
  57. SC_HANDLE
  58. APIHOOK(CreateServiceA)(
  59. SC_HANDLE hSCManager, // handle to SCM database
  60. LPCSTR lpServiceName, // name of service to start
  61. LPCSTR lpDisplayName, // display name
  62. DWORD dwDesiredAccess, // type of access to service
  63. DWORD dwServiceType, // type of service
  64. DWORD dwStartType, // when to start service
  65. DWORD dwErrorControl, // severity of service failure
  66. LPCSTR lpBinaryPathName, // name of binary file
  67. LPCSTR lpLoadOrderGroup, // name of load ordering group
  68. LPDWORD lpdwTagId, // tag identifier
  69. LPCSTR lpDependencies, // array of dependency names
  70. LPCSTR lpServiceStartName, // account name
  71. LPCSTR lpPassword // account password
  72. )
  73. {
  74. SC_HANDLE scHandle;
  75. scHandle = ORIGINAL_API(CreateServiceA)(hSCManager,
  76. lpServiceName,
  77. lpDisplayName,
  78. dwDesiredAccess,
  79. dwServiceType,
  80. dwStartType,
  81. dwErrorControl,
  82. lpBinaryPathName,
  83. lpLoadOrderGroup,
  84. lpdwTagId,
  85. lpDependencies,
  86. lpServiceStartName,
  87. lpPassword);
  88. if (scHandle) {
  89. //
  90. // If the ServiceType flag specifies that this is a kernel
  91. // mode driver, raise a flag.
  92. //
  93. if (dwServiceType & SERVICE_KERNEL_DRIVER) {
  94. VLOG(VLOG_LEVEL_INFO,
  95. VLOG_KMODEDRIVER_INST,
  96. "CreateServiceA was called. The path to the driver is %hs",
  97. lpBinaryPathName);
  98. }
  99. }
  100. return scHandle;
  101. }
  102. SC_HANDLE
  103. APIHOOK(CreateServiceW)(
  104. SC_HANDLE hSCManager, // handle to SCM database
  105. LPCWSTR lpServiceName, // name of service to start
  106. LPCWSTR lpDisplayName, // display name
  107. DWORD dwDesiredAccess, // type of access to service
  108. DWORD dwServiceType, // type of service
  109. DWORD dwStartType, // when to start service
  110. DWORD dwErrorControl, // severity of service failure
  111. LPCWSTR lpBinaryPathName, // name of binary file
  112. LPCWSTR lpLoadOrderGroup, // name of load ordering group
  113. LPDWORD lpdwTagId, // tag identifier
  114. LPCWSTR lpDependencies, // array of dependency names
  115. LPCWSTR lpServiceStartName, // account name
  116. LPCWSTR lpPassword // account password
  117. )
  118. {
  119. SC_HANDLE scHandle;
  120. scHandle = ORIGINAL_API(CreateServiceW)(hSCManager,
  121. lpServiceName,
  122. lpDisplayName,
  123. dwDesiredAccess,
  124. dwServiceType,
  125. dwStartType,
  126. dwErrorControl,
  127. lpBinaryPathName,
  128. lpLoadOrderGroup,
  129. lpdwTagId,
  130. lpDependencies,
  131. lpServiceStartName,
  132. lpPassword);
  133. if (scHandle) {
  134. //
  135. // If the ServiceType flag specifies that this is a kernel
  136. // mode driver, raise a flag.
  137. //
  138. if (dwServiceType & SERVICE_KERNEL_DRIVER) {
  139. VLOG(VLOG_LEVEL_INFO,
  140. VLOG_KMODEDRIVER_INST,
  141. "CreateServiceW was called. The path to the driver is %ls",
  142. lpBinaryPathName);
  143. }
  144. }
  145. return scHandle;
  146. }
  147. /*++
  148. Validate the registry data we received and warn the user if a driver is being installed.
  149. --*/
  150. void
  151. WarnUserIfKernelModeDriver(
  152. IN HANDLE hKey,
  153. IN PUNICODE_STRING pstrValueName,
  154. IN ULONG ulType,
  155. IN PVOID pData
  156. )
  157. {
  158. NTSTATUS status;
  159. ULONG ulSize;
  160. BYTE KeyNameInfo[MAX_INFO_LENGTH];
  161. PKEY_NAME_INFORMATION pKeyNameInfo;
  162. pKeyNameInfo = (PKEY_NAME_INFORMATION)KeyNameInfo;
  163. //
  164. // RegSetValue allows for NULL value names.
  165. // Ensure that we don't have one before going any further.
  166. //
  167. if (!pstrValueName->Buffer) {
  168. return;
  169. }
  170. //
  171. // Determine if the ValueName is 'Type'.
  172. // If not, we don't need to go any further.
  173. //
  174. if (_wcsicmp(pstrValueName->Buffer, KMDI_VALUE_NAME)) {
  175. DPFN(eDbgLevelInfo,
  176. "[WarnUserIfKernelModeDriver] ValueName is not '%ls'",
  177. KMDI_VALUE_NAME);
  178. return;
  179. }
  180. //
  181. // Determine if the type of the value is DWORD.
  182. // If not, we need don't need to go any further.
  183. //
  184. if (REG_DWORD != ulType) {
  185. DPFN(eDbgLevelInfo,
  186. "[WarnUserIfKernelModeDriver] ValueType is not REG_DWORD");
  187. return;
  188. }
  189. //
  190. // At this point, we have a value that is of type REG_DWORD and
  191. // has a name of 'Type'. Now we see if the key is a subkey of 'Services'.
  192. //
  193. status = NtQueryKey(hKey,
  194. KeyNameInformation,
  195. pKeyNameInfo,
  196. MAX_INFO_LENGTH,
  197. &ulSize);
  198. if ((STATUS_BUFFER_OVERFLOW == status) ||
  199. (STATUS_BUFFER_TOO_SMALL == status)) {
  200. //
  201. // Our stack based buffer wasn't large enough.
  202. // Allocate from the heap and call it again.
  203. //
  204. pKeyNameInfo = (PKEY_NAME_INFORMATION)MemAlloc(ulSize);
  205. if (!pKeyNameInfo) {
  206. DPFN(eDbgLevelError,
  207. "[WarnUserIfKernelModeDriver] Failed to allocate memory");
  208. return;
  209. }
  210. status = NtQueryKey(hKey,
  211. KeyNameInformation,
  212. pKeyNameInfo,
  213. ulSize,
  214. &ulSize);
  215. }
  216. if (NT_SUCCESS(status)) {
  217. //
  218. // See if this key points to CurrentControlSet or ControlSet.
  219. //
  220. if (wcsistr(pKeyNameInfo->Name, KMDI_CURCONTROLSET_KEY) ||
  221. wcsistr(pKeyNameInfo->Name, KMDI_CONTROLSET_KEY)) {
  222. //
  223. // Now see if this key points to Services.
  224. //
  225. if (wcsistr(pKeyNameInfo->Name, KMDI_SERVICES_KEY)) {
  226. //
  227. // We've got a key under 'Services'.
  228. // If the Data has a value of 0x00000001,
  229. // we've got a kernel mode driver being installed.
  230. //
  231. if ((*(DWORD*)pData == KMDI_TYPE_VALUE)) {
  232. VLOG(VLOG_LEVEL_ERROR,
  233. VLOG_KMODEDRIVER_INST,
  234. "The driver was installed via the registry.");
  235. }
  236. }
  237. }
  238. }
  239. if (pKeyNameInfo != (PKEY_NAME_INFORMATION)KeyNameInfo) {
  240. MemFree(pKeyNameInfo);
  241. }
  242. }
  243. NTSTATUS
  244. APIHOOK(NtSetValueKey)(
  245. IN HANDLE KeyHandle,
  246. IN PUNICODE_STRING ValueName,
  247. IN ULONG TitleIndex OPTIONAL,
  248. IN ULONG Type,
  249. IN PVOID Data,
  250. IN ULONG DataSize
  251. )
  252. {
  253. NTSTATUS status;
  254. status = ORIGINAL_API(NtSetValueKey)(KeyHandle,
  255. ValueName,
  256. TitleIndex,
  257. Type,
  258. Data,
  259. DataSize);
  260. if (NT_SUCCESS(status)) {
  261. WarnUserIfKernelModeDriver(KeyHandle, ValueName, Type, Data);
  262. }
  263. return status;
  264. }
  265. SHIM_INFO_BEGIN()
  266. SHIM_INFO_DESCRIPTION(AVS_KMODEDRIVER_DESC)
  267. SHIM_INFO_FRIENDLY_NAME(AVS_KMODEDRIVER_FRIENDLY)
  268. SHIM_INFO_VERSION(1, 1)
  269. SHIM_INFO_INCLUDE_EXCLUDE("I:advapi32.dll")
  270. SHIM_INFO_END()
  271. /*++
  272. Register hooked functions
  273. --*/
  274. HOOK_BEGIN
  275. DUMP_VERIFIER_LOG_ENTRY(VLOG_KMODEDRIVER_INST,
  276. AVS_KMODEDRIVER_INST,
  277. AVS_KMODEDRIVER_INST_R,
  278. AVS_KMODEDRIVER_INST_URL)
  279. APIHOOK_ENTRY(ADVAPI32.DLL, CreateServiceA)
  280. APIHOOK_ENTRY(ADVAPI32.DLL, CreateServiceW)
  281. APIHOOK_ENTRY(NTDLL.DLL, NtSetValueKey)
  282. HOOK_END
  283. IMPLEMENT_SHIM_END