// // Template driver user-mode controller // Copyright (c) Microsoft Corporation, 1999. // // Module: tcontrol.cxx // Author: Silviu Calinoiu (SilviuC) // Created: 4/20/1999 3:40pm // // This module contains a user-mode controller for a template // driver. // // --- History --- // // 4/20/1999 (SilviuC): initial version. // #include #include #include #include #include #include #define NO_BUGGY_FUNCTIONS #define FUNS_DEFINITION_MODULE #include "..\driver\tdriver.h" #include "..\driver\funs.h" // // Get rid of performance warnings for BOOL to bool conversions // #pragma warning (disable: 4800) bool TdCreateService (LPCTSTR DriverName); bool TdDeleteService (LPCTSTR DriverName); bool TdStartService (LPCTSTR DriverName); bool TdStopService (LPCTSTR DriverName); bool TdOpenDevice (LPCTSTR DriverName, PHANDLE DeviceHandle); bool TdCloseDevice (HANDLE Device); bool TdSendIoctl (IN HANDLE Device, IN DWORD Ioctl, IN PVOID pData OPTIONAL, IN ULONG uDataSize OPTIONAL); void TdSectMapProcessAddressSpaceTest(); void TdSectMapSystemAddressSpaceTest(); VOID TdReservedMapSetSize( int argc, char *argv[] ); VOID TdReservedMapRead( VOID ); BOOL ProcessCommandLine ( LPCTSTR Option ); ULONG_PTR UtilHexStringToUlongPtr( char *szHexNumber ); /////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////// Main() /////////////////////////////////////////////////////////////////////////////// void _cdecl main (int argc, char *argv[]) { BOOL DisplayHelp; HANDLE Device; DWORD Index; char *pCrtChar; DisplayHelp = FALSE; try { if (argc == 3 && _stricmp (argv[1], "/create") == 0) { TdCreateService (argv[2]); } else if (argc == 3 && _stricmp (argv[1], "/delete") == 0) { TdDeleteService (argv[2]); } else if (argc == 3 && _stricmp (argv[1], "/start") == 0) { TdStartService (argv[2]); } else if (argc == 3 && _stricmp (argv[1], "/stop") == 0) { TdStopService (argv[2]); } else if (argc == 2 && _stricmp (argv[1], "/sectionmaptest") == 0) { TdSectMapProcessAddressSpaceTest(); } else if (argc == 2 && _stricmp (argv[1], "/sectionmaptestsysspace") == 0) { TdSectMapSystemAddressSpaceTest(); } else if ( _stricmp (argv[1], "/ReservedMapSetSize") == 0) { TdReservedMapSetSize( argc, argv ); } else if ( _stricmp (argv[1], "/ReservedMapRead") == 0) { TdReservedMapRead(); } else if (argc >= 2 && _stricmp (argv[1], "/ioctlbugcheck") == 0) { // // Send the bugcheck parameters from the command line // BUGCHECK_PARAMS BugcheckParams; ZeroMemory( &BugcheckParams, sizeof( BugcheckParams ) ); // // Bugcheck code // if( argc >= 3 ) { BugcheckParams.BugCheckCode = (ULONG)UtilHexStringToUlongPtr( argv[ 2 ] ); } // // Bugcheck paramaters // for( int nCrtCommandLineArg = 3; nCrtCommandLineArg < argc; nCrtCommandLineArg++ ) { BugcheckParams.BugCheckParameters[ nCrtCommandLineArg - 3 ] = UtilHexStringToUlongPtr( argv[ nCrtCommandLineArg ] ); } // // Send the IOCTL to the driver // HANDLE Device; if ( TdOpenDevice ("buggy", &Device) ) { TdSendIoctl ( Device, IOCTL_TD_BUGCHECK, &BugcheckParams, sizeof( BugcheckParams ) ); TdCloseDevice (Device); } } else { if (ProcessCommandLine (argv[1]) == FALSE) { DisplayHelp = TRUE; } } } catch (char * Message) { printf ("Error: s", GetLastError(), Message); } if ( DisplayHelp == TRUE ) { printf ("ctlbuggy /create DRIVER \n"); printf ("ctlbuggy /delete DRIVER \n"); printf ("ctlbuggy /start DRIVER \n"); printf ("ctlbuggy /stop DRIVER \n"); printf (" \n"); printf ("ctlbuggy /sectionmaptest \n"); printf ("ctlbuggy /sectionmaptestsysspace \n"); printf (" \n"); printf ("ctlbuggy IOCTL-NAME \n"); printf ("\n\n"); for (Index = 0; BuggyFuns[Index].Ioctl != 0; Index++) { printf("ctlbuggy %s \n", BuggyFuns[Index].Command); } printf ("\n"); exit (1); } exit( 0 ); } BOOL ProcessCommandLine ( LPCTSTR Option ) /*++ Routine Description: This routine tries to figure out if the command line option is specifies one of the ioctls that can be processed. Arguments: `Option' - command line option. Return Value: TRUE if an option has been found and processed. FALSE otherwise. Environment: Nothing special. --*/ { DWORD Index; HANDLE Device; BOOL Result = FALSE; for (Index = 0; BuggyFuns[Index].Ioctl != 0; Index++) { if (_stricmp (BuggyFuns[Index].Command, Option) == 0) { if ( TdOpenDevice ("buggy", &Device) ) { TdSendIoctl (Device, BuggyFuns[Index].Ioctl, NULL, 0); TdCloseDevice (Device); Result = TRUE; break; } } } return Result; } /////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////// Driver load/unload /////////////////////////////////////////////////////////////////////////////// bool TdCreateService ( LPCTSTR DriverName) { SC_HANDLE ServiceManager = NULL; SC_HANDLE ServiceHandle = NULL; BOOL ReturnValue; HANDLE Driver; TCHAR ScratchBuffer [MAX_PATH]; TCHAR DriverPath [MAX_PATH]; TCHAR DevicePath [MAX_PATH]; try { GetSystemDirectory (ScratchBuffer, sizeof ScratchBuffer); _stprintf (DriverPath, "%s\\drivers\\%s.sys", ScratchBuffer, DriverName); _stprintf (DevicePath, "\\\\.\\%s", DriverName); // // Open the service control manager // ServiceManager = OpenSCManager ( NULL, NULL, SC_MANAGER_ALL_ACCESS); if (ServiceManager == NULL) { throw "OpenScManager()"; } // // Create the service // printf("Driver path: %s \n", DriverPath); printf("Device path: %s \n", DevicePath); ServiceHandle = CreateService ( ServiceManager, // handle to SC manager DriverName, // name of service DriverName, // display name SERVICE_ALL_ACCESS, // access mask SERVICE_KERNEL_DRIVER, // service type SERVICE_DEMAND_START, // start type SERVICE_ERROR_NORMAL, // error control DriverPath, // full path to driver NULL, // load ordering NULL, // tag id NULL, // dependency NULL, // account name NULL); // password if (ServiceHandle == NULL && GetLastError() != ERROR_SERVICE_EXISTS) { throw "CreateService()"; } ReturnValue = TRUE; } catch (char * Msg) { printf("Error: %u: %s\n", GetLastError(), Msg); fflush (stdout); ReturnValue = FALSE; } // // Close handles and return. // if (ServiceHandle) { CloseServiceHandle (ServiceHandle); } if (ServiceManager) { CloseServiceHandle (ServiceManager); } return ReturnValue; } bool TdStartService ( LPCTSTR DriverName) { SC_HANDLE ServiceManager = NULL; SC_HANDLE ServiceHandle = NULL; BOOL ReturnValue; HANDLE Driver; TCHAR ScratchBuffer [MAX_PATH]; TCHAR DriverPath [MAX_PATH]; TCHAR DevicePath [MAX_PATH]; try { GetSystemDirectory (ScratchBuffer, sizeof ScratchBuffer); _stprintf (DriverPath, "%s\\drivers\\%s.sys", ScratchBuffer, DriverName); _stprintf (DevicePath, "\\\\.\\%s", DriverName); // // Open the service control manager // ServiceManager = OpenSCManager ( NULL, NULL, SC_MANAGER_ALL_ACCESS); if (ServiceManager == NULL) { throw "OpenScManager()"; } // // Open the service. The function assumes that // TdCreateService has been called before this one // and the service is already installed. // ServiceHandle = OpenService ( ServiceManager, DriverName, SERVICE_ALL_ACCESS); if (ServiceHandle == NULL) { throw "OpenService()"; } // // Start the service // if (! StartService (ServiceHandle, 0, NULL)) { if (GetLastError() != ERROR_SERVICE_ALREADY_RUNNING) { throw "StartService()"; } } ReturnValue = TRUE; } catch (char * Msg) { printf("Error: %u: %s\n", GetLastError(), Msg); fflush (stdout); ReturnValue = FALSE; } // // Close handles and return. // if (ServiceHandle) { CloseServiceHandle (ServiceHandle); } if (ServiceManager) { CloseServiceHandle (ServiceManager); } return ReturnValue; } bool TdStopService ( LPCTSTR DriverName) { SC_HANDLE ServiceManager = NULL; SC_HANDLE ServiceHandle = NULL; SERVICE_STATUS ServiceStatus; BOOL ReturnValue; try { // // Open the service control manager // ServiceManager = OpenSCManager ( NULL, NULL, SC_MANAGER_ALL_ACCESS); if (ServiceManager == NULL) { throw "OpenSCManager()"; } // // Open the service so we can stop it // ServiceHandle = OpenService ( ServiceManager, DriverName, SERVICE_ALL_ACCESS); if (ServiceHandle == NULL) { throw "OpenService()"; } // // Stop the service // if (! ControlService (ServiceHandle, SERVICE_CONTROL_STOP, &ServiceStatus)) { throw "ControlService()"; } ReturnValue = TRUE; } catch (char * Msg) { printf("Error: %u: %s\n", GetLastError(), Msg); fflush (stdout); ReturnValue = FALSE; } // // Close handles ans return. // if (ServiceHandle) { CloseServiceHandle (ServiceHandle); } if (ServiceManager) { CloseServiceHandle (ServiceManager); } return ReturnValue; } bool TdDeleteService ( LPCTSTR DriverName) { SC_HANDLE ServiceManager = NULL; SC_HANDLE ServiceHandle = NULL; SERVICE_STATUS ServiceStatus; BOOL ReturnValue; try { // // Open the service control manager // ServiceManager = OpenSCManager ( NULL, NULL, SC_MANAGER_ALL_ACCESS); if (ServiceManager == NULL) { throw "OpenSCManager()"; } // // Open the service so we can stop it // ServiceHandle = OpenService ( ServiceManager, DriverName, SERVICE_ALL_ACCESS); if (ServiceHandle == NULL) { throw "OpenService()"; } // // Delete the service // if (! DeleteService (ServiceHandle)) { if (GetLastError() != ERROR_SERVICE_MARKED_FOR_DELETE) { throw "DeleteService()"; } } ReturnValue = TRUE; } catch (char * Msg) { printf("Error: %u: %s\n", GetLastError(), Msg); fflush (stdout); ReturnValue = FALSE; } // // Close handles ans return. // if (ServiceHandle) { CloseServiceHandle (ServiceHandle); } if (ServiceManager) { CloseServiceHandle (ServiceManager); } return ReturnValue; } bool TdOpenDevice ( LPCTSTR DriverName, PHANDLE DeviceHandle) { SC_HANDLE ServiceManager = NULL; SC_HANDLE ServiceHandle = NULL; BOOL ReturnValue; HANDLE Device; TCHAR ScratchBuffer [MAX_PATH]; TCHAR DriverPath [MAX_PATH]; TCHAR DevicePath [MAX_PATH]; // // Sanity checks // if (DeviceHandle == NULL) { return FALSE; } try { GetSystemDirectory (ScratchBuffer, sizeof ScratchBuffer); _stprintf (DriverPath, "%s\\drivers\\%s.sys", ScratchBuffer, DriverName); _stprintf (DevicePath, "\\\\.\\%s", DriverName); // // Open the service control manager // ServiceManager = OpenSCManager ( NULL, NULL, SC_MANAGER_ALL_ACCESS); if (ServiceManager == NULL) { throw "OpenScManager()"; } // // Service should already exist. // ServiceHandle = OpenService ( ServiceManager, DriverName, SERVICE_ALL_ACCESS); if (ServiceHandle == NULL) { throw "OpenService()"; } // // Open the device // Device = CreateFile ( DevicePath, GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (Device == INVALID_HANDLE_VALUE) { throw "CreateFile()"; } ReturnValue = TRUE; } catch (char * Msg) { printf("Error: %u: %s\n", GetLastError(), Msg); fflush (stdout); ReturnValue = FALSE; } // // Close handles and return. // if (ServiceHandle) { CloseServiceHandle (ServiceHandle); } if (ServiceManager) { CloseServiceHandle (ServiceManager); } if (Device != INVALID_HANDLE_VALUE) { *DeviceHandle = Device; } return ReturnValue; } bool TdCloseDevice ( HANDLE Device) { if (Device == INVALID_HANDLE_VALUE) { return false; } return CloseHandle(Device); } // // Function: // // SendIoctl // // Description: // // This function sends an ioctl code to the driver. // bool TdSendIoctl ( IN HANDLE Driver, IN DWORD Ioctl, IN PVOID pData OPTIONAL, IN ULONG uDataSize OPTIONAL ) { DWORD BytesReturned; BOOL Result; if (Driver == INVALID_HANDLE_VALUE) { return false; } Result = DeviceIoControl ( Driver, Ioctl, pData, uDataSize, NULL, 0, &BytesReturned, NULL); return Result == TRUE; } // // // #if _MSC_FULL_VER >= 13008827 #pragma warning(push) #pragma warning(disable:4715) // Not all control paths return (due to infinite loop) #endif DWORD MapProcessAddressSpaceThread( LPVOID lpData ) { HANDLE hDevice; DWORD dwTimeToSleep; hDevice = (HANDLE)lpData; while( TRUE ) { dwTimeToSleep = rand() % 5000; Sleep( dwTimeToSleep ); TdSendIoctl (hDevice, IOCTL_TD_SECTION_MAP_TEST_PROCESS_SPACE, NULL, 0); } return 0; } #if _MSC_FULL_VER >= 13008827 #pragma warning(pop) #endif // // // #define TD_MAPSECT_TEST_THREADS 4 void TdSectMapProcessAddressSpaceTest() { HANDLE Device; time_t theTime; int nCrtThread; DWORD dwThreadId; TCHAR strMessage[ 128 ]; time( &theTime ); _stprintf( strMessage, "Process %u, rand seed = %u\n", GetCurrentProcessId(), (unsigned int)theTime ); OutputDebugString( strMessage ); srand( (unsigned int)theTime ); if( TdOpenDevice ("buggy", &Device) ) { for( nCrtThread = 0; nCrtThread < TD_MAPSECT_TEST_THREADS - 1; nCrtThread++ ) { CreateThread( NULL, 0, MapProcessAddressSpaceThread, (LPVOID)Device, 0, &dwThreadId ); } // // reuse the main thread // MapProcessAddressSpaceThread( (LPVOID)Device ); TdCloseDevice (Device); } } // // // #if _MSC_FULL_VER >= 13008827 #pragma warning(push) #pragma warning(disable:4715) // Not all control paths return (due to infinite loop) #endif DWORD MapSystemAddressSpaceThread( LPVOID lpData ) { HANDLE hDevice; DWORD dwTimeToSleep; hDevice = (HANDLE)lpData; while( TRUE ) { dwTimeToSleep = rand() % 5000; Sleep( dwTimeToSleep ); TdSendIoctl (hDevice, IOCTL_TD_SECTION_MAP_TEST_SYSTEM_SPACE, NULL, 0); } return 0; } #if _MSC_FULL_VER >= 13008827 #pragma warning(pop) #endif // // // void TdSectMapSystemAddressSpaceTest() { HANDLE Device; time_t theTime; int nCrtThread; DWORD dwThreadId; TCHAR strMessage[ 128 ]; time( &theTime ); _stprintf( strMessage, "Process %u, rand seed = %u\n", GetCurrentProcessId(), (unsigned int)theTime ); OutputDebugString( strMessage ); srand( (unsigned int)theTime ); if( TdOpenDevice ("buggy", &Device) ) { for( nCrtThread = 0; nCrtThread < TD_MAPSECT_TEST_THREADS - 1; nCrtThread++ ) { CreateThread( NULL, 0, MapProcessAddressSpaceThread, (LPVOID)Device, 0, &dwThreadId ); } // // reuse the main thread - only this thread will map into system address space // MapSystemAddressSpaceThread( (LPVOID)Device ); TdCloseDevice (Device); } } // // Convert a hex string from the command line to an UNLONG_PTR // ULONG_PTR UtilHexStringToUlongPtr( char *szHexNumber ) { ULONG_PTR uNewDigit; ULONG_PTR uResult = 0; char *pCrtChar = szHexNumber; while( ( *pCrtChar ) != (char)0 ) { uNewDigit = 0; if( ( *pCrtChar ) >= '0' && ( *pCrtChar ) <= '9' ) { uNewDigit = ( *pCrtChar ) - '0'; } else { if( ( *pCrtChar ) >= 'A' && ( *pCrtChar ) <= 'F' ) { uNewDigit = ( *pCrtChar ) - 'A' + 10; } else { if( ( *pCrtChar ) >= 'a' && ( *pCrtChar ) <= 'f' ) { uNewDigit = ( *pCrtChar ) - 'a' + 10; } } } uResult = uResult * 16 + uNewDigit; pCrtChar++; } return uResult; } // // Set the current reserved size and address as asked by the user // VOID TdReservedMapSetSize( int argc, char *argv[] ) { SIZE_T NewSize; HANDLE Device; time_t theTime; TCHAR strMessage[ 128 ]; if( argc >= 3 ) { // // User-specified buffer size // NewSize = atoi( argv[ 2 ] ); } else { // // Seed the random numbers generator // time( &theTime ); _stprintf( strMessage, "Process %u, rand seed = %u\n", GetCurrentProcessId(), (unsigned int)theTime ); OutputDebugString( strMessage ); srand( (unsigned int)theTime ); // // New size is random, up to 10 pages // NewSize = ( abs( rand() ) % 10 + 1 ) * 0x1000; } if( TdOpenDevice ("buggy", &Device) ) { printf( "TdReservedMapSetSize: sending size %p\n", NewSize ); TdSendIoctl ( Device, IOCTL_TD_RESERVEDMAP_SET_SIZE, &NewSize, sizeof( NewSize ) ); TdCloseDevice (Device); } } // // Ask for a "read" operation from our driver // VOID TdReservedMapRead( VOID ) { HANDLE Device; time_t theTime; SIZE_T ReadBufferSize; SIZE_T ReadPages; SIZE_T CrtReadPage; PSIZE_T CrtPageAddress; PVOID UserBuffer; BOOL Success; SYSTEM_INFO SystemInfo; TCHAR strMessage[ 128 ]; // // Get the page size // GetSystemInfo( &SystemInfo ); // // Seed the random numbers generator // time( &theTime ); _stprintf( strMessage, "Process %u, rand seed = %u\n", GetCurrentProcessId(), (unsigned int)theTime ); //OutputDebugString( strMessage ); puts( strMessage ); srand( (unsigned int)theTime ); // // Choose a size >= PAGE_SIZE and <= ~1 Mb // ReadBufferSize = abs( rand() * rand() * rand() ) % ( 1024 * 1024 ) + SystemInfo.dwPageSize; UserBuffer = VirtualAlloc( NULL, ReadBufferSize, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE ); if( NULL != UserBuffer ) { if( TdOpenDevice ("buggy", &Device) ) { // // Prepare the parameters to the driver // USER_READ_BUFFER UserReadBuffer; UserReadBuffer.UserBuffer = UserBuffer; UserReadBuffer.UserBufferSize = ReadBufferSize; _stprintf( strMessage, "TdReservedMapRead: sending buffer %p, size %p\n", UserReadBuffer.UserBuffer, UserReadBuffer.UserBufferSize ); //OutputDebugString( strMessage ); puts( strMessage ); // // Send the request to the driver // Success = TdSendIoctl ( Device, IOCTL_TD_RESERVEDMAP_READ_OP, &UserReadBuffer, sizeof( UserReadBuffer ) ); if( TRUE == Success ) { // // If the call succeeded then we check the validity of data returned by the driver // ReadPages = ReadBufferSize / SystemInfo.dwPageSize; CrtPageAddress = (PSIZE_T)UserBuffer; for( CrtReadPage = 1; CrtReadPage <= ReadPages; CrtReadPage++ ) { if( *CrtPageAddress != CrtReadPage ) { _stprintf( strMessage, "Incorrect data received from buggy.sys: page %p, expected %p, actual data %p\n", CrtPageAddress, CrtReadPage, *CrtPageAddress ); OutputDebugString( strMessage ); DebugBreak(); } CrtPageAddress = (PSIZE_T) ( (PCHAR)CrtPageAddress + SystemInfo.dwPageSize ); ReadPages -= 1; } } TdCloseDevice (Device); } VirtualFree( UserBuffer, 0, MEM_RELEASE ); } } // // End of file //