285 lines
7.1 KiB
C++
285 lines
7.1 KiB
C++
/*++
|
|
|
|
Copyright (c) 2000 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
AddWritePermissionsToDeviceFiles.cpp
|
|
|
|
Abstract:
|
|
|
|
Add write permissions for IOCTL_SCSI_PASS_THROUGH under SECUROM.
|
|
|
|
SecuRom can be debugged under a user-mode debugger but the following must
|
|
be done before hitting 'g' after attach:
|
|
|
|
1. sxi av <- ignore access violations
|
|
2. sxi sse <- ignore single step exception
|
|
3. sxi ssec <- ignore single step exception continue
|
|
4. sxi dz <- ignore divide by zero
|
|
|
|
It checksums it's executable, so breakpoints in certain places don't work.
|
|
|
|
Notes:
|
|
|
|
This is a general purpose shim.
|
|
|
|
History:
|
|
|
|
09/03/1999 v-johnwh Created
|
|
03/09/2001 linstev Rewrote DeviceIoControl to handle bad buffers and added
|
|
debugging comments
|
|
|
|
--*/
|
|
|
|
#include "precomp.h"
|
|
#include "CharVector.h"
|
|
|
|
IMPLEMENT_SHIM_BEGIN(AddWritePermissionsToDeviceFiles)
|
|
#include "ShimHookMacro.h"
|
|
|
|
APIHOOK_ENUM_BEGIN
|
|
APIHOOK_ENUM_ENTRY(CreateFileA)
|
|
APIHOOK_ENUM_ENTRY(DeviceIoControl)
|
|
APIHOOK_ENUM_ENTRY(CloseHandle)
|
|
APIHOOK_ENUM_END
|
|
|
|
VectorT<HANDLE> * g_hDevices;
|
|
|
|
CRITICAL_SECTION g_CriticalSection;
|
|
|
|
|
|
// Is this letter a valid drive letter?
|
|
inline BOOL IsDriveLetter(char letter)
|
|
{
|
|
return (letter != '\0') &&
|
|
((letter >= 'a') && (letter <= 'z')) ||
|
|
((letter >= 'A') && (letter <= 'Z'));
|
|
}
|
|
|
|
/*++
|
|
|
|
We need to add write permission to all CD-ROM devices
|
|
|
|
--*/
|
|
|
|
HANDLE
|
|
APIHOOK(CreateFileA)(
|
|
LPCSTR lpFileName,
|
|
DWORD dwDesiredAccess,
|
|
DWORD dwShareMode,
|
|
LPSECURITY_ATTRIBUTES lpSecurityAttributes,
|
|
DWORD dwCreationDisposition,
|
|
DWORD dwFlagsAndAttributes,
|
|
HANDLE hTemplateFile
|
|
)
|
|
{
|
|
// Same behavior as the real CreateFileA
|
|
if (lpFileName == NULL) {
|
|
return INVALID_HANDLE_VALUE;
|
|
}
|
|
|
|
DWORD dwAccessMode = dwDesiredAccess;
|
|
|
|
// Look for a device name: \\.\C:
|
|
if ((lpFileName[0] == '\\') &&
|
|
(lpFileName[1] == '\\') &&
|
|
(lpFileName[2] == '.') &&
|
|
(lpFileName[3] == '\\') &&
|
|
IsDriveLetter(lpFileName[4]) &&
|
|
(lpFileName[5] == ':')
|
|
) {
|
|
//
|
|
// This file starts with \\.\ so it must be a device file.
|
|
//
|
|
|
|
if (!(dwAccessMode & GENERIC_WRITE)) {
|
|
//
|
|
// Make sure this device is a CD-ROM
|
|
//
|
|
char diskRootName[4];
|
|
diskRootName[0] = lpFileName[4];
|
|
diskRootName[1] = ':';
|
|
diskRootName[2] = '\\';
|
|
diskRootName[3] = 0;
|
|
|
|
DWORD dwDriveType = GetDriveTypeA(diskRootName);
|
|
if (DRIVE_CDROM == dwDriveType) {
|
|
//
|
|
// Add write permissions to give us NT4 behavior for device
|
|
// files
|
|
//
|
|
dwAccessMode |= GENERIC_WRITE;
|
|
}
|
|
}
|
|
}
|
|
|
|
HANDLE hRet = ORIGINAL_API(CreateFileA)(lpFileName, dwAccessMode,
|
|
dwShareMode, lpSecurityAttributes, dwCreationDisposition,
|
|
dwFlagsAndAttributes, hTemplateFile);
|
|
|
|
if ((hRet != INVALID_HANDLE_VALUE) && (dwAccessMode != dwDesiredAccess)) {
|
|
//
|
|
// Add the handle to our list so we can clean it up later.
|
|
//
|
|
CAutoCrit autoCrit(&g_CriticalSection);
|
|
g_hDevices->Append(hRet);
|
|
LOGN( eDbgLevelError, "[CreateFileA] Added GENERIC_WRITE permission on device(%s)", lpFileName);
|
|
}
|
|
|
|
return hRet;
|
|
}
|
|
|
|
/*++
|
|
|
|
Since we added write permission to CD-ROM devices for IOCTL_SCSI_PASS_THROUGH,
|
|
we need to remove the write permission for all other IOCTLs passed to that device.
|
|
|
|
--*/
|
|
|
|
BOOL
|
|
APIHOOK(DeviceIoControl)(
|
|
HANDLE hDevice,
|
|
DWORD dwIoControlCode,
|
|
LPVOID lpInBuffer,
|
|
DWORD nInBufferSize,
|
|
LPVOID lpOutBuffer,
|
|
DWORD nOutBufferSize,
|
|
LPDWORD lpBytesReturned,
|
|
LPOVERLAPPED lpOverlapped
|
|
)
|
|
{
|
|
LPVOID lpOut = lpOutBuffer;
|
|
if (lpOutBuffer && nOutBufferSize && lpBytesReturned) {
|
|
//
|
|
// Create a new output buffer, if this fails we just keep the original
|
|
// buffer.
|
|
//
|
|
|
|
lpOut = malloc(nOutBufferSize);
|
|
if (lpOut) {
|
|
MoveMemory(lpOut, lpOutBuffer, nOutBufferSize);
|
|
} else {
|
|
DPFN( eDbgLevelError, "Out of memory");
|
|
lpOut = lpOutBuffer;
|
|
}
|
|
}
|
|
|
|
BOOL bRet;
|
|
if (IOCTL_SCSI_PASS_THROUGH != dwIoControlCode) {
|
|
//
|
|
// We don't care about IOCTL_SCSI_PASS_THROUGH
|
|
//
|
|
|
|
EnterCriticalSection(&g_CriticalSection);
|
|
int existing = g_hDevices->Find(hDevice);
|
|
LeaveCriticalSection(&g_CriticalSection);
|
|
|
|
if (existing >= 0) {
|
|
//
|
|
// Check to see if this is a device that we added Write permissions
|
|
// If it is, we need to create a handle with only Read permissions
|
|
//
|
|
|
|
HANDLE hDupped;
|
|
|
|
bRet = DuplicateHandle(GetCurrentProcess(), hDevice,
|
|
GetCurrentProcess(), &hDupped, GENERIC_READ, FALSE, 0);
|
|
|
|
if (bRet) {
|
|
//
|
|
// Call the IOCTL with the original (Read) permissions
|
|
//
|
|
bRet = ORIGINAL_API(DeviceIoControl)(hDupped, dwIoControlCode,
|
|
lpInBuffer, nInBufferSize, lpOut, nOutBufferSize,
|
|
lpBytesReturned, lpOverlapped);
|
|
|
|
CloseHandle(hDupped);
|
|
|
|
goto Exit;
|
|
}
|
|
}
|
|
}
|
|
|
|
bRet = ORIGINAL_API(DeviceIoControl)(hDevice, dwIoControlCode, lpInBuffer,
|
|
nInBufferSize, lpOut, nOutBufferSize, lpBytesReturned, lpOverlapped);
|
|
|
|
Exit:
|
|
|
|
if (lpOut && (lpOut != lpOutBuffer)) {
|
|
//
|
|
// Need to copy the output back into the true output buffer
|
|
//
|
|
if (bRet && lpBytesReturned && *lpBytesReturned) {
|
|
__try {
|
|
MoveMemory(lpOutBuffer, lpOut, *lpBytesReturned);
|
|
} __except(1) {
|
|
DPFN( eDbgLevelError, "Failed to copy data into output buffer, perhaps it's read-only");
|
|
}
|
|
}
|
|
|
|
free(lpOut);
|
|
}
|
|
|
|
return bRet;
|
|
|
|
}
|
|
|
|
/*++
|
|
|
|
If this handle is in our list, remove it.
|
|
|
|
--*/
|
|
|
|
BOOL
|
|
APIHOOK(CloseHandle)(
|
|
HANDLE hObject
|
|
)
|
|
{
|
|
CAutoCrit autoCrit(&g_CriticalSection);
|
|
int index = g_hDevices->Find(hObject);
|
|
|
|
if (index >= 0) {
|
|
g_hDevices->Remove(index);
|
|
}
|
|
|
|
return ORIGINAL_API(CloseHandle)(hObject);
|
|
}
|
|
|
|
/*++
|
|
|
|
Register hooked functions
|
|
|
|
--*/
|
|
|
|
BOOL
|
|
NOTIFY_FUNCTION(
|
|
DWORD fdwReason)
|
|
{
|
|
if (fdwReason == DLL_PROCESS_ATTACH) {
|
|
g_hDevices = new VectorT<HANDLE>;
|
|
if (g_hDevices == NULL)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
return InitializeCriticalSectionAndSpinCount(&g_CriticalSection, 0x80000000);
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
HOOK_BEGIN
|
|
|
|
CALL_NOTIFY_FUNCTION
|
|
|
|
APIHOOK_ENTRY(KERNEL32.DLL, CreateFileA)
|
|
APIHOOK_ENTRY(KERNEL32.DLL, DeviceIoControl)
|
|
APIHOOK_ENTRY(KERNEL32.DLL, CloseHandle)
|
|
|
|
HOOK_END
|
|
|
|
IMPLEMENT_SHIM_END
|
|
|