Leaked source code of windows server 2003
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.

284 lines
7.1 KiB

  1. /*++
  2. Copyright (c) 2000 Microsoft Corporation
  3. Module Name:
  4. AddWritePermissionsToDeviceFiles.cpp
  5. Abstract:
  6. Add write permissions for IOCTL_SCSI_PASS_THROUGH under SECUROM.
  7. SecuRom can be debugged under a user-mode debugger but the following must
  8. be done before hitting 'g' after attach:
  9. 1. sxi av <- ignore access violations
  10. 2. sxi sse <- ignore single step exception
  11. 3. sxi ssec <- ignore single step exception continue
  12. 4. sxi dz <- ignore divide by zero
  13. It checksums it's executable, so breakpoints in certain places don't work.
  14. Notes:
  15. This is a general purpose shim.
  16. History:
  17. 09/03/1999 v-johnwh Created
  18. 03/09/2001 linstev Rewrote DeviceIoControl to handle bad buffers and added
  19. debugging comments
  20. --*/
  21. #include "precomp.h"
  22. #include "CharVector.h"
  23. IMPLEMENT_SHIM_BEGIN(AddWritePermissionsToDeviceFiles)
  24. #include "ShimHookMacro.h"
  25. APIHOOK_ENUM_BEGIN
  26. APIHOOK_ENUM_ENTRY(CreateFileA)
  27. APIHOOK_ENUM_ENTRY(DeviceIoControl)
  28. APIHOOK_ENUM_ENTRY(CloseHandle)
  29. APIHOOK_ENUM_END
  30. VectorT<HANDLE> * g_hDevices;
  31. CRITICAL_SECTION g_CriticalSection;
  32. // Is this letter a valid drive letter?
  33. inline BOOL IsDriveLetter(char letter)
  34. {
  35. return (letter != '\0') &&
  36. ((letter >= 'a') && (letter <= 'z')) ||
  37. ((letter >= 'A') && (letter <= 'Z'));
  38. }
  39. /*++
  40. We need to add write permission to all CD-ROM devices
  41. --*/
  42. HANDLE
  43. APIHOOK(CreateFileA)(
  44. LPCSTR lpFileName,
  45. DWORD dwDesiredAccess,
  46. DWORD dwShareMode,
  47. LPSECURITY_ATTRIBUTES lpSecurityAttributes,
  48. DWORD dwCreationDisposition,
  49. DWORD dwFlagsAndAttributes,
  50. HANDLE hTemplateFile
  51. )
  52. {
  53. // Same behavior as the real CreateFileA
  54. if (lpFileName == NULL) {
  55. return INVALID_HANDLE_VALUE;
  56. }
  57. DWORD dwAccessMode = dwDesiredAccess;
  58. // Look for a device name: \\.\C:
  59. if ((lpFileName[0] == '\\') &&
  60. (lpFileName[1] == '\\') &&
  61. (lpFileName[2] == '.') &&
  62. (lpFileName[3] == '\\') &&
  63. IsDriveLetter(lpFileName[4]) &&
  64. (lpFileName[5] == ':')
  65. ) {
  66. //
  67. // This file starts with \\.\ so it must be a device file.
  68. //
  69. if (!(dwAccessMode & GENERIC_WRITE)) {
  70. //
  71. // Make sure this device is a CD-ROM
  72. //
  73. char diskRootName[4];
  74. diskRootName[0] = lpFileName[4];
  75. diskRootName[1] = ':';
  76. diskRootName[2] = '\\';
  77. diskRootName[3] = 0;
  78. DWORD dwDriveType = GetDriveTypeA(diskRootName);
  79. if (DRIVE_CDROM == dwDriveType) {
  80. //
  81. // Add write permissions to give us NT4 behavior for device
  82. // files
  83. //
  84. dwAccessMode |= GENERIC_WRITE;
  85. }
  86. }
  87. }
  88. HANDLE hRet = ORIGINAL_API(CreateFileA)(lpFileName, dwAccessMode,
  89. dwShareMode, lpSecurityAttributes, dwCreationDisposition,
  90. dwFlagsAndAttributes, hTemplateFile);
  91. if ((hRet != INVALID_HANDLE_VALUE) && (dwAccessMode != dwDesiredAccess)) {
  92. //
  93. // Add the handle to our list so we can clean it up later.
  94. //
  95. CAutoCrit autoCrit(&g_CriticalSection);
  96. g_hDevices->Append(hRet);
  97. LOGN( eDbgLevelError, "[CreateFileA] Added GENERIC_WRITE permission on device(%s)", lpFileName);
  98. }
  99. return hRet;
  100. }
  101. /*++
  102. Since we added write permission to CD-ROM devices for IOCTL_SCSI_PASS_THROUGH,
  103. we need to remove the write permission for all other IOCTLs passed to that device.
  104. --*/
  105. BOOL
  106. APIHOOK(DeviceIoControl)(
  107. HANDLE hDevice,
  108. DWORD dwIoControlCode,
  109. LPVOID lpInBuffer,
  110. DWORD nInBufferSize,
  111. LPVOID lpOutBuffer,
  112. DWORD nOutBufferSize,
  113. LPDWORD lpBytesReturned,
  114. LPOVERLAPPED lpOverlapped
  115. )
  116. {
  117. LPVOID lpOut = lpOutBuffer;
  118. if (lpOutBuffer && nOutBufferSize && lpBytesReturned) {
  119. //
  120. // Create a new output buffer, if this fails we just keep the original
  121. // buffer.
  122. //
  123. lpOut = malloc(nOutBufferSize);
  124. if (lpOut) {
  125. MoveMemory(lpOut, lpOutBuffer, nOutBufferSize);
  126. } else {
  127. DPFN( eDbgLevelError, "Out of memory");
  128. lpOut = lpOutBuffer;
  129. }
  130. }
  131. BOOL bRet;
  132. if (IOCTL_SCSI_PASS_THROUGH != dwIoControlCode) {
  133. //
  134. // We don't care about IOCTL_SCSI_PASS_THROUGH
  135. //
  136. EnterCriticalSection(&g_CriticalSection);
  137. int existing = g_hDevices->Find(hDevice);
  138. LeaveCriticalSection(&g_CriticalSection);
  139. if (existing >= 0) {
  140. //
  141. // Check to see if this is a device that we added Write permissions
  142. // If it is, we need to create a handle with only Read permissions
  143. //
  144. HANDLE hDupped;
  145. bRet = DuplicateHandle(GetCurrentProcess(), hDevice,
  146. GetCurrentProcess(), &hDupped, GENERIC_READ, FALSE, 0);
  147. if (bRet) {
  148. //
  149. // Call the IOCTL with the original (Read) permissions
  150. //
  151. bRet = ORIGINAL_API(DeviceIoControl)(hDupped, dwIoControlCode,
  152. lpInBuffer, nInBufferSize, lpOut, nOutBufferSize,
  153. lpBytesReturned, lpOverlapped);
  154. CloseHandle(hDupped);
  155. goto Exit;
  156. }
  157. }
  158. }
  159. bRet = ORIGINAL_API(DeviceIoControl)(hDevice, dwIoControlCode, lpInBuffer,
  160. nInBufferSize, lpOut, nOutBufferSize, lpBytesReturned, lpOverlapped);
  161. Exit:
  162. if (lpOut && (lpOut != lpOutBuffer)) {
  163. //
  164. // Need to copy the output back into the true output buffer
  165. //
  166. if (bRet && lpBytesReturned && *lpBytesReturned) {
  167. __try {
  168. MoveMemory(lpOutBuffer, lpOut, *lpBytesReturned);
  169. } __except(1) {
  170. DPFN( eDbgLevelError, "Failed to copy data into output buffer, perhaps it's read-only");
  171. }
  172. }
  173. free(lpOut);
  174. }
  175. return bRet;
  176. }
  177. /*++
  178. If this handle is in our list, remove it.
  179. --*/
  180. BOOL
  181. APIHOOK(CloseHandle)(
  182. HANDLE hObject
  183. )
  184. {
  185. CAutoCrit autoCrit(&g_CriticalSection);
  186. int index = g_hDevices->Find(hObject);
  187. if (index >= 0) {
  188. g_hDevices->Remove(index);
  189. }
  190. return ORIGINAL_API(CloseHandle)(hObject);
  191. }
  192. /*++
  193. Register hooked functions
  194. --*/
  195. BOOL
  196. NOTIFY_FUNCTION(
  197. DWORD fdwReason)
  198. {
  199. if (fdwReason == DLL_PROCESS_ATTACH) {
  200. g_hDevices = new VectorT<HANDLE>;
  201. if (g_hDevices == NULL)
  202. {
  203. return FALSE;
  204. }
  205. return InitializeCriticalSectionAndSpinCount(&g_CriticalSection, 0x80000000);
  206. }
  207. return TRUE;
  208. }
  209. HOOK_BEGIN
  210. CALL_NOTIFY_FUNCTION
  211. APIHOOK_ENTRY(KERNEL32.DLL, CreateFileA)
  212. APIHOOK_ENTRY(KERNEL32.DLL, DeviceIoControl)
  213. APIHOOK_ENTRY(KERNEL32.DLL, CloseHandle)
  214. HOOK_END
  215. IMPLEMENT_SHIM_END