#define UNICODE 1 #include #include #include #include #include #include #include #include #define _NTSCSI_USER_MODE_ #include #define PAGE_SIZE 4096 #define ROUND_TO_PAGE_SIZE(_x) (((_x) + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1)) #include #include #include #include #include #include #include #include #include #include #define SECTOR_SIZE 0x200 #define SECTORS_PER_TRACK 0x80 #define TRACKS_PER_CYLINDER 0x10 #define CYLINDER_SIZE (SECTOR_SIZE * SECTORS_PER_TRACK * TRACKS_PER_CYLINDER) #define arrayof(a) (sizeof(a)/sizeof(a[0])) typedef struct _RAMCTRL_HEADER { char Signature[8]; // "ramctrl" GUID DiskGuid; ULONG DiskOffset; ULONG DiskType; RAMDISK_CREATE_OPTIONS Options; } RAMCTRL_HEADER, *PRAMCTRL_HEADER; typedef union _RAMDISK_HEADER { RAMCTRL_HEADER Ramctrl; SDI_HEADER Sdi; } RAMDISK_HEADER, *PRAMDISK_HEADER; VOID PrintError( ULONG ErrorCode ) { WCHAR errorBuffer[512]; ULONG count; count = FormatMessage( FORMAT_MESSAGE_FROM_SYSTEM, NULL, ErrorCode, 0, errorBuffer, arrayof(errorBuffer), NULL ); if ( count != 0 ) { printf( "%ws\n", errorBuffer ); } else { printf( "Format message failed. Error: %d\n", GetLastError() ); } return; } // PrintError VOID ListDisks ( HANDLE ControlHandle ) { BOOL ok; WCHAR actualDeviceName[MAX_PATH]; WCHAR foundDeviceName[MAX_PATH]; WCHAR dosDeviceName[MAX_PATH]; WCHAR driveLetterString[3] = L"A:"; BOOL foundRamDisk; BOOL foundDriveLetter; LPCGUID interfaceGuid; GUID foundGuid; PWSTR guidPtr; UNICODE_STRING guidString; GUID diskGuid; HDEVINFO devinfo; SP_DEVICE_INTERFACE_DATA interfaceData; BYTE detailBuffer[sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA) + (MAX_PATH * sizeof(WCHAR))]; PSP_DEVICE_INTERFACE_DETAIL_DATA interfaceDetailData; SP_DEVINFO_DATA devinfoData; DWORD i; RAMDISK_QUERY_INPUT queryInput; BYTE queryOutputBuffer[sizeof(RAMDISK_QUERY_OUTPUT) + (MAX_PATH * sizeof(WCHAR))]; PRAMDISK_QUERY_OUTPUT queryOutput; DWORD returnedLength; interfaceDetailData = (PSP_DEVICE_INTERFACE_DETAIL_DATA)detailBuffer; queryOutput = (PRAMDISK_QUERY_OUTPUT)queryOutputBuffer; interfaceGuid = &RamdiskDiskInterface; foundRamDisk = FALSE; do { devinfo = SetupDiGetClassDevs( interfaceGuid, NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE ); if ( devinfo == NULL ) { printf( "ListDisks: SetupDiGetClassDevs failed: %d\n", GetLastError() ); return; } ZeroMemory( &interfaceData, sizeof(interfaceData) ); interfaceData.cbSize = sizeof(interfaceData); // // Enumerate the device interfaces of the class. // for (i = 0; SetupDiEnumDeviceInterfaces( devinfo, NULL, interfaceGuid, i, &interfaceData ); i++ ) { interfaceDetailData->cbSize = sizeof(*interfaceDetailData); devinfoData.cbSize = sizeof(devinfoData); if ( !SetupDiGetDeviceInterfaceDetail( devinfo, &interfaceData, interfaceDetailData, sizeof(detailBuffer), NULL, &devinfoData ) ) { //printf( "ListDisks: SetupDiGetDeviceInterfaceDetail failed for item %d. (%d)\n", i, GetLastError() ); wcscpy( interfaceDetailData->DevicePath, L"" ); } //printf( "Enumerated device %ws\n", interfaceDetailData->DevicePath ); if ( !SetupDiGetDeviceRegistryProperty( devinfo, &devinfoData, SPDRP_BUSTYPEGUID, NULL, (PBYTE)&foundGuid, sizeof(foundGuid), NULL ) ) { DWORD error = GetLastError(); //printf( "ListDisks: SetupDiGetDeviceRegistryProperty (bus GUID) failed for %ws: %d\n", interfaceDetailData->DevicePath, error ); continue; } if ( memcmp( &foundGuid, &GUID_BUS_TYPE_RAMDISK, sizeof(GUID) ) != 0 ) { //printf( "ListDisks: skipping non-ramdisk device %ws\n", interfaceDetailData->DevicePath ); continue; } if ( !SetupDiGetDeviceRegistryProperty( devinfo, &devinfoData, SPDRP_PHYSICAL_DEVICE_OBJECT_NAME, NULL, (PBYTE)actualDeviceName, sizeof(actualDeviceName), NULL ) ) { DWORD error = GetLastError(); printf( "ListDisks: SetupDiGetDeviceRegistryProperty (name) failed for %ws: %d\n", interfaceDetailData->DevicePath, error ); continue; } foundRamDisk = TRUE; printf( "\n%ws\n", interfaceDetailData->DevicePath ); printf( " Device name: %ws\n", actualDeviceName ); guidPtr = wcschr( actualDeviceName, L'{' ); swprintf( dosDeviceName, L"Ramdisk%ws", guidPtr ); if ( QueryDosDeviceW(dosDeviceName, foundDeviceName, arrayof(foundDeviceName)) ) { printf( " DosDevice name %ws is assigned to this device\n", dosDeviceName ); } else { printf( " No DosDevice name was assigned to this device\n" ); } foundDriveLetter = FALSE; for ( driveLetterString[0] = 'A'; driveLetterString[0] <= 'Z'; driveLetterString[0]++ ) { if ( QueryDosDeviceW(driveLetterString, foundDeviceName, arrayof(foundDeviceName)) && (_wcsicmp(actualDeviceName, foundDeviceName) == 0) ) { printf( " Drive letter %ws is assigned to this device\n", driveLetterString ); foundDriveLetter = TRUE; break; } } if ( !foundDriveLetter ) { printf( " No letter was assigned to this device\n" ); } guidString.Buffer = guidPtr; guidString.Length = (USHORT)(wcslen(guidPtr) * sizeof(WCHAR)); guidString.MaximumLength = guidString.Length; RtlGUIDFromString( &guidString, &diskGuid ); queryInput.Version = sizeof(RAMDISK_QUERY_INPUT); queryInput.DiskGuid = diskGuid; ok = DeviceIoControl( ControlHandle, FSCTL_QUERY_RAM_DISK, &queryInput, sizeof(queryInput), queryOutput, sizeof(queryOutputBuffer), &returnedLength, FALSE ); if ( !ok ) { DWORD errorCode = GetLastError(); printf( "Error querying RAM disk: %d\n", errorCode ); PrintError( errorCode ); } else { printf( " RAM disk information:\n" ); if ( queryOutput->DiskType == RAMDISK_TYPE_BOOT_DISK ) { printf( " Type: boot disk\n" ); printf( " Base page: 0x%x\n", queryOutput->BasePage ); } else { printf( " Type: %s\n", queryOutput->DiskType == RAMDISK_TYPE_FILE_BACKED_VOLUME ? "volume" : "disk" ); printf( " File: %ws\n", queryOutput->FileName ); } printf( " Length: 0x%I64x\n", queryOutput->DiskLength ); printf( " Offset: 0x%x\n", queryOutput->DiskOffset ); if ( queryOutput->DiskType != RAMDISK_TYPE_BOOT_DISK ) { printf( " View count: 0x%x\n", queryOutput->ViewCount ); printf( " View length: 0x%x\n", queryOutput->ViewLength ); } printf( " Options: " ); printf( "%s; ", queryOutput->Options.Fixed ? "fixed" : "removable" ); printf( "%s; ", queryOutput->Options.Readonly ? "readonly" : "writeable" ); printf( "%s; ", queryOutput->Options.NoDriveLetter ? "no drive letter" : "drive letter" ); printf( "%s; ", queryOutput->Options.Hidden ? "hidden" : "visible" ); printf( "%s\n", queryOutput->Options.NoDosDevice ? "no DosDevice" : "DosDevice" ); } } SetupDiDestroyDeviceInfoList( devinfo ); if ( interfaceGuid == &RamdiskDiskInterface ) { interfaceGuid = &MOUNTDEV_MOUNTED_DEVICE_GUID; } else { break; } } while ( TRUE ); if ( !foundRamDisk ) { printf( "No RAM disks found\n" ); } return; } // ListDisks VOID FindDisk ( ULONG DiskType, PUNICODE_STRING DiskGuidString, BOOL WaitForDeletion ) { WCHAR actualDeviceName[MAX_PATH]; WCHAR foundDeviceName[MAX_PATH]; WCHAR dosDeviceName[MAX_PATH]; WCHAR driveLetterString[3] = L"A:"; BOOL found; LPCGUID interfaceGuid; HDEVINFO devinfo; SP_DEVICE_INTERFACE_DATA interfaceData; BYTE detailBuffer[sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA) + (MAX_PATH * sizeof(WCHAR))]; PSP_DEVICE_INTERFACE_DETAIL_DATA interfaceDetailData; SP_DEVINFO_DATA devinfoData; DWORD i; interfaceDetailData = (PSP_DEVICE_INTERFACE_DETAIL_DATA)detailBuffer; swprintf( actualDeviceName, L"\\Device\\Ramdisk%wZ", DiskGuidString ); printf( "Waiting for device %ws to be %s...", actualDeviceName, WaitForDeletion ? "deleted" : "ready" ); if ( DiskType == RAMDISK_TYPE_FILE_BACKED_DISK ) { interfaceGuid = &RamdiskDiskInterface; } else { interfaceGuid = &MOUNTDEV_MOUNTED_DEVICE_GUID; } found = FALSE; do { devinfo = SetupDiGetClassDevs( interfaceGuid, NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE ); if ( devinfo == NULL ) { printf( "\nFindDisk: SetupDiGetClassDevs failed: %d\n", GetLastError() ); return; } ZeroMemory( &interfaceData, sizeof(interfaceData) ); interfaceData.cbSize = sizeof(interfaceData); // // Enumerate the device interfaces of the class. // for (i = 0; SetupDiEnumDeviceInterfaces( devinfo, NULL, interfaceGuid, i, &interfaceData ); i++ ) { interfaceDetailData->cbSize = sizeof(*interfaceDetailData); devinfoData.cbSize = sizeof(devinfoData); if ( !SetupDiGetDeviceInterfaceDetail( devinfo, &interfaceData, interfaceDetailData, sizeof(detailBuffer), NULL, &devinfoData ) ) { //printf( "\nFindDisk: SetupDiGetDeviceInterfaceDetail failed for item %d. (%d)\n", i, GetLastError() ); wcscpy( interfaceDetailData->DevicePath, L"" ); } //printf( "\nEnumerated device %ws\n", interfaceDetailData->DevicePath ); if ( !SetupDiGetDeviceRegistryProperty( devinfo, &devinfoData, SPDRP_PHYSICAL_DEVICE_OBJECT_NAME, NULL, (PBYTE)foundDeviceName, sizeof(foundDeviceName), NULL ) ) { DWORD error = GetLastError(); //printf( "\nFindDisk: SetupDiGetDeviceRegistryProperty (name) failed for %ws: %d\n", interfaceDetailData->DevicePath, error ); continue; } //printf( "\nTarget device %ws\n", foundDeviceName ); if ( _wcsicmp( actualDeviceName, foundDeviceName ) != 0 ) { continue; } found = TRUE; break; } SetupDiDestroyDeviceInfoList( devinfo ); if ( !found ) { if ( WaitForDeletion ) { printf( "\nRAM disk is now gone\n" ); return; } //printf( "Enumeration failed to find target device; sleeping\n" ); printf( "." ); Sleep( 500 ); } else { if ( !WaitForDeletion ) { printf( "\nRAM disk is now ready\n" ); break; } //printf( "Enumeration found target device; sleeping\n" ); printf( "." ); Sleep( 500 ); found = FALSE; } } while ( TRUE ); if ( found ) { swprintf( dosDeviceName, L"Ramdisk%wZ", DiskGuidString ); if ( QueryDosDeviceW(dosDeviceName, foundDeviceName, arrayof(foundDeviceName)) ) { printf( " DosDevice name %ws is assigned to this device\n", dosDeviceName ); } else { printf( " No DosDevice name was assigned to this device\n" ); } found = FALSE; for ( driveLetterString[0] = 'A'; driveLetterString[0] <= 'Z'; driveLetterString[0]++ ) { if ( QueryDosDeviceW(driveLetterString, foundDeviceName, arrayof(foundDeviceName)) && (_wcsicmp(actualDeviceName, foundDeviceName) == 0) ) { printf( " Drive letter %ws is assigned to this device\n", driveLetterString ); found = TRUE; break; } } if ( !found ) { printf( " No letter was assigned to this device\n" ); } } return; } // FindDisk VOID FullFilePath ( PWCHAR pwzPath ) { WCHAR wzDevPath[512] = L""; WCHAR wzDosPath[512] = L""; PWCHAR pwzDosName = wzDosPath; DWORD dw; WCHAR c; dw = GetFullPathNameW(pwzPath, arrayof(wzDosPath), wzDosPath, NULL); if (0 != dw) { if (NULL != (pwzDosName = wcschr(wzDosPath, ':'))) { pwzDosName++; c = *pwzDosName; *pwzDosName = '\0'; dw = QueryDosDeviceW(wzDosPath, wzDevPath, arrayof(wzDevPath)); if (0 != dw) { *pwzDosName = c; swprintf(pwzPath, L"%ls%ls", wzDevPath, pwzDosName); } else { printf("QueryDosDeviceW(%ls) failed: %d\n", wzDosPath, GetLastError()); PrintError(GetLastError()); } } } } BOOLEAN IsDriveLetter ( PWCHAR Name ) { if ((((Name[0] >= L'A') && (Name[0] <= L'Z')) || ((Name[0] >= L'a') && (Name[0] <= L'z'))) && (Name[1] == L':') && (Name[2] == 0)) { return TRUE; } return FALSE; } VOID DeleteRamdisk ( IN HANDLE ControlHandle, IN PWSTR FileName ) { BOOL ok; ULONG errorCode = 0; ULONG returnedLength = 0; UNICODE_STRING ustr; OBJECT_ATTRIBUTES obja; IO_STATUS_BLOCK iosb; NTSTATUS status; HANDLE imageFileHandle; HANDLE volumeHandle; RAMDISK_HEADER ramdiskHeader; UNICODE_STRING guidString; LARGE_INTEGER offset; LPCGUID diskGuid; ULONG diskType; RAMDISK_QUERY_INPUT queryInput; RAMDISK_MARK_FOR_DELETION_INPUT markInput; BYTE queryOutputBuffer[sizeof(RAMDISK_QUERY_OUTPUT) + (MAX_PATH * sizeof(WCHAR))]; PRAMDISK_QUERY_OUTPUT queryOutput; CONFIGRET cr; DEVNODE devnode; WCHAR devinst[MAX_PATH]; PNP_VETO_TYPE vetoType; WCHAR vetoName[MAX_PATH]; WCHAR foundDeviceName[MAX_PATH]; queryOutput = (PRAMDISK_QUERY_OUTPUT)queryOutputBuffer; if ( FileName[0] == L'{' ) { guidString.Buffer = FileName; guidString.Length = (USHORT)(wcslen(FileName) * sizeof(WCHAR)); guidString.MaximumLength = guidString.Length; queryInput.Version = sizeof(RAMDISK_QUERY_INPUT); RtlGUIDFromString( &guidString, &queryInput.DiskGuid ); ok = DeviceIoControl( ControlHandle, FSCTL_QUERY_RAM_DISK, &queryInput, sizeof(queryInput), queryOutput, sizeof(queryOutputBuffer), &returnedLength, FALSE ); if ( !ok ) { DWORD errorCode = GetLastError(); printf( "Error querying RAM disk: %d\n", errorCode ); PrintError( errorCode ); return; } diskGuid = &queryOutput->DiskGuid; diskType = queryOutput->DiskType; } else if (IsDriveLetter ( FileName ) ) { // // Treat FileName as a drive letter. See if this the supplied // drive letter corresponds to a ramdisk. // if ((QueryDosDeviceW(FileName, foundDeviceName, arrayof(foundDeviceName)) == 0) || wcsncmp(foundDeviceName, L"\\Device\\Ramdisk", wcslen(L"\\Device\\Ramdisk"))) { DWORD errorCode = GetLastError(); printf( "Drive letter \"%ws\" is not assigned to a RAM disk.\n", FileName); PrintError( errorCode ); return; } guidString.Buffer = wcschr( foundDeviceName, L'{' ); guidString.Length = (USHORT)(wcslen(guidString.Buffer) * sizeof(WCHAR)); guidString.MaximumLength = guidString.Length; RtlGUIDFromString( &guidString, &queryInput.DiskGuid ); ok = DeviceIoControl( ControlHandle, FSCTL_QUERY_RAM_DISK, &queryInput, sizeof(queryInput), queryOutput, sizeof(queryOutputBuffer), &returnedLength, FALSE ); if ( !ok ) { DWORD errorCode = GetLastError(); printf( "Error querying RAM disk: %d\n", errorCode ); PrintError( errorCode ); return; } diskGuid = &queryOutput->DiskGuid; diskType = queryOutput->DiskType; } else { RtlInitUnicodeString( &ustr, FileName ); InitializeObjectAttributes( &obja, &ustr, OBJ_CASE_INSENSITIVE, NULL, NULL ); status = NtOpenFile( &imageFileHandle, SYNCHRONIZE | FILE_READ_DATA | FILE_READ_ATTRIBUTES, &obja, &iosb, FILE_SHARE_READ, FILE_SYNCHRONOUS_IO_ALERT ); if ( !NT_SUCCESS(status) ) { printf( "Can't open target file %ws: %x\n", FileName, status ); errorCode = RtlNtStatusToDosError( status ); PrintError( errorCode ); return; } // // Read and verify the header. // offset.QuadPart = 0; status = NtReadFile( imageFileHandle, NULL, NULL, NULL, &iosb, &ramdiskHeader, sizeof(ramdiskHeader), &offset, NULL ); if ( !NT_SUCCESS(status) ) { printf( "Can't read header from target file %ws: %x\n", FileName, status ); errorCode = RtlNtStatusToDosError( status ); PrintError( errorCode ); return; } if ( strcmp( ramdiskHeader.Ramctrl.Signature, "ramctrl" ) == 0 ) { diskGuid = &ramdiskHeader.Ramctrl.DiskGuid; diskType = ramdiskHeader.Ramctrl.DiskType; } else if ( strncmp( ramdiskHeader.Sdi.Signature, SDI_SIGNATURE, strlen(SDI_SIGNATURE) ) == 0 ) { diskGuid = (LPCGUID)ramdiskHeader.Sdi.RuntimeGUID; diskType = RAMDISK_TYPE_FILE_BACKED_VOLUME; } else { printf( "Header in target file not recognized\n" ); return; } NtClose( imageFileHandle ); RtlStringFromGUID( diskGuid, &guidString ); } printf("Attempting to delete \\Device\\Ramdisk%wZ\n", &guidString ); swprintf( devinst, L"\\Device\\Ramdisk%ws", guidString.Buffer ); RtlInitUnicodeString( &ustr, devinst ); InitializeObjectAttributes( &obja, &ustr, OBJ_CASE_INSENSITIVE, NULL, NULL ); status = NtOpenFile( &volumeHandle, SYNCHRONIZE | FILE_READ_DATA | FILE_WRITE_DATA, &obja, &iosb, FILE_SHARE_READ | FILE_SHARE_WRITE, FILE_SYNCHRONOUS_IO_ALERT ); if ( !NT_SUCCESS(status) ) { printf( "Can't open target device %ws: %x\n", devinst, status ); errorCode = RtlNtStatusToDosError( status ); PrintError( errorCode ); return; } printf( "Syncing %ws ... ", devinst ); if ( !FlushFileBuffers( volumeHandle ) ) { errorCode = GetLastError(); // NOTE: [bassamt] FlushFileBuffers can fail with error code // ERROR_INVALID_FUNCTION if the volume is not formatted. // NOTE: [brimo] FlushFileBuffers can fail with error code // ERROR_WRITE_PROTECT if the volume is mounted read-only if ((errorCode != ERROR_INVALID_FUNCTION) && (errorCode != ERROR_WRITE_PROTECT)) { printf( "flush failed (%u)\n", errorCode ); PrintError( errorCode ); return; } } if ( !DeviceIoControl( volumeHandle, FSCTL_LOCK_VOLUME, NULL, 0, NULL, 0, &returnedLength, NULL ) ) { errorCode = GetLastError(); printf( "lock volume failed (%u)\n", errorCode ); PrintError( errorCode ); return; } if ( !DeviceIoControl( volumeHandle, FSCTL_DISMOUNT_VOLUME, NULL, 0, NULL, 0, &returnedLength, NULL ) ) { errorCode = GetLastError(); printf( "dismount volume failed (%u)\n", errorCode ); PrintError( errorCode ); return; } printf( "done\n" ); NtClose( volumeHandle ); markInput.Version = sizeof(RAMDISK_MARK_FOR_DELETION_INPUT); markInput.DiskGuid = *diskGuid; ok = DeviceIoControl( ControlHandle, FSCTL_MARK_RAM_DISK_FOR_DELETION, &markInput, sizeof(markInput), NULL, 0, &returnedLength, FALSE ); if ( !ok ) { DWORD errorCode = GetLastError(); printf( "Error marking RAM disk: %d\n", errorCode ); PrintError( errorCode ); return; } if ( diskType == RAMDISK_TYPE_FILE_BACKED_DISK ) { swprintf( devinst, L"Ramdisk\\Ramdisk\\%ws", guidString.Buffer ); } else { swprintf( devinst, L"Ramdisk\\Ramvolume\\%ws", guidString.Buffer ); } cr = CM_Locate_DevNode( &devnode, devinst, 0 ); if ( cr != CR_SUCCESS ) { printf( "Unable to locate devnode: %d\n", cr ); return; } cr = CM_Query_And_Remove_SubTree_Ex( devnode, &vetoType, vetoName, MAX_PATH, 0, NULL ); if ( cr != CR_SUCCESS ) { printf( "Unable to remove devnode: %d\n", cr ); if ( cr == CR_REMOVE_VETOED ) { printf( " veto type = 0x%x\n", vetoType ); printf( " veto name = %ws\n", vetoName ); } return; } FindDisk( diskType, &guidString, TRUE ); printf( "RAM disk %wZ deleted\n", &guidString ); return; } // DeleteRamdisk void AddBootFilesToSdi( PWCHAR SdiFile, PWCHAR StartromFile, PWCHAR OsloaderFile ) { NTSTATUS status; UNICODE_STRING ustr; OBJECT_ATTRIBUTES obja; IO_STATUS_BLOCK iosb; HANDLE imageFileHandle; HANDLE startromHandle; HANDLE osloaderHandle; WCHAR dataFileName[512]; FILE_STANDARD_INFORMATION fileInfo; FILE_ALLOCATION_INFORMATION allocInfo; SDI_HEADER sdiHeader; LARGE_INTEGER offset; ULONGLONG diskOffset; ULONGLONG diskLength; ULONGLONG startromOffset; ULONGLONG startromLength; ULONGLONG startromLengthAligned; ULONGLONG osloaderOffset; ULONGLONG osloaderLength; ULONGLONG osloaderLengthAligned; ULONGLONG finalFileLength; ULONG errorCode = 0; PUCHAR buffer; printf( "Adding boot files to SDI file %ws\n", SdiFile ); RtlInitUnicodeString( &ustr, SdiFile ); InitializeObjectAttributes( &obja, &ustr, OBJ_CASE_INSENSITIVE, NULL, NULL ); status = NtOpenFile( &imageFileHandle, SYNCHRONIZE | FILE_READ_DATA | FILE_WRITE_DATA | FILE_READ_ATTRIBUTES, &obja, &iosb, 0, FILE_SYNCHRONOUS_IO_ALERT ); if ( !NT_SUCCESS(status) ) { printf( "Can't open target file %ws: %x\n", SdiFile, status ); errorCode = RtlNtStatusToDosError( status ); PrintError( errorCode ); return; } // // Read and verify the header. // offset.QuadPart = 0; status = NtReadFile( imageFileHandle, NULL, NULL, NULL, &iosb, &sdiHeader, sizeof(sdiHeader), &offset, NULL ); if ( !NT_SUCCESS(status) ) { printf( "Can't read header from target file %ws: %x\n", SdiFile, status ); errorCode = RtlNtStatusToDosError( status ); PrintError( errorCode ); return; } if ( strncmp( sdiHeader.Signature, SDI_SIGNATURE, strlen(SDI_SIGNATURE) ) != 0 ) { printf( "Header in target file not recognized\n" ); return; } diskOffset = sdiHeader.ToC[0].llOffset.LowPart; diskLength = sdiHeader.ToC[0].llSize.QuadPart; startromOffset = ROUND_TO_PAGE_SIZE( diskOffset + diskLength ); // // Get the length of startrom.com. // wcscpy( dataFileName, StartromFile ); FullFilePath( dataFileName ); RtlInitUnicodeString( &ustr, dataFileName ); InitializeObjectAttributes( &obja, &ustr, OBJ_CASE_INSENSITIVE, NULL, NULL ); status = NtOpenFile( &startromHandle, SYNCHRONIZE | FILE_READ_DATA | FILE_WRITE_DATA | FILE_READ_ATTRIBUTES, &obja, &iosb, 0, FILE_SYNCHRONOUS_IO_ALERT ); if ( !NT_SUCCESS(status) ) { printf( "Can't open startrom file %ws: %x\n", dataFileName, status ); errorCode = RtlNtStatusToDosError( status ); PrintError( errorCode ); return; } status = NtQueryInformationFile( startromHandle, &iosb, &fileInfo, sizeof(fileInfo), FileStandardInformation ); if ( !NT_SUCCESS(status) ) { printf( "Can't query info for startrom file %ws: %x\n", dataFileName, status ); errorCode = RtlNtStatusToDosError( status ); PrintError( errorCode ); return; } startromLength = fileInfo.EndOfFile.QuadPart; startromLengthAligned = ROUND_TO_PAGE_SIZE( startromLength ); osloaderOffset = startromOffset + startromLengthAligned; // // Get the length of osloader.exe. // wcscpy( dataFileName, OsloaderFile ); FullFilePath( dataFileName ); RtlInitUnicodeString( &ustr, dataFileName ); InitializeObjectAttributes( &obja, &ustr, OBJ_CASE_INSENSITIVE, NULL, NULL ); status = NtOpenFile( &osloaderHandle, SYNCHRONIZE | FILE_READ_DATA | FILE_WRITE_DATA | FILE_READ_ATTRIBUTES, &obja, &iosb, 0, FILE_SYNCHRONOUS_IO_ALERT ); if ( !NT_SUCCESS(status) ) { printf( "Can't open osloader file %ws: %x\n", dataFileName, status ); errorCode = RtlNtStatusToDosError( status ); PrintError( errorCode ); return; } status = NtQueryInformationFile( osloaderHandle, &iosb, &fileInfo, sizeof(fileInfo), FileStandardInformation ); if ( !NT_SUCCESS(status) ) { printf( "Can't query info for osloader file %ws: %x\n", dataFileName, status ); errorCode = RtlNtStatusToDosError( status ); PrintError( errorCode ); return; } osloaderLength = fileInfo.EndOfFile.QuadPart; osloaderLengthAligned = ROUND_TO_PAGE_SIZE( startromLength ); finalFileLength = osloaderOffset + osloaderLengthAligned; // // Truncate the file at the end of the disk image, then extend it back. // printf( " truncating SDI file at end of ramdisk image %I64d [0x%I64x]\n", startromOffset, startromOffset ); allocInfo.AllocationSize.QuadPart = startromOffset; status = NtSetInformationFile( imageFileHandle, &iosb, &allocInfo, sizeof(allocInfo), FileAllocationInformation ); if ( !NT_SUCCESS(status) ) { printf( "Can't set allocation size for image file %ws: %x\n", SdiFile, status ); errorCode = RtlNtStatusToDosError( status ); PrintError( errorCode ); return; } allocInfo.AllocationSize.QuadPart = finalFileLength; status = NtSetInformationFile( imageFileHandle, &iosb, &allocInfo, sizeof(allocInfo), FileAllocationInformation ); if ( !NT_SUCCESS(status) ) { printf( "Can't set allocation size for image file %ws: %x\n", SdiFile, status ); errorCode = RtlNtStatusToDosError( status ); PrintError( errorCode ); return; } // // Copy startrom into the image file. // printf( " adding boot file %ws, length %I64d [0x%I64x]\n", StartromFile, startromLength, startromLength ); buffer = malloc( (ULONG)startromLength ); offset.QuadPart = 0; status = NtReadFile( startromHandle, NULL, NULL, NULL, &iosb, buffer, (ULONG)startromLength, &offset, NULL ); if ( !NT_SUCCESS(status) ) { printf( "Can't read from startrom file %ws: %x\n", SdiFile, status ); errorCode = RtlNtStatusToDosError( status ); PrintError( errorCode ); return; } offset.QuadPart = startromOffset; status = NtWriteFile( imageFileHandle, NULL, NULL, NULL, &iosb, buffer, (ULONG)startromLength, &offset, NULL ); if ( !NT_SUCCESS(status) ) { printf( "Can't write startrom to image file %ws: %x\n", SdiFile, status ); errorCode = RtlNtStatusToDosError( status ); PrintError( errorCode ); return; } free( buffer ); // // Copy osloader into the image file. // printf( " adding load file %ws, length %I64d [0x%I64x]\n", OsloaderFile, osloaderLength, osloaderLength ); buffer = malloc( (ULONG)osloaderLength ); offset.QuadPart = 0; status = NtReadFile( osloaderHandle, NULL, NULL, NULL, &iosb, buffer, (ULONG)osloaderLength, &offset, NULL ); if ( !NT_SUCCESS(status) ) { printf( "Can't read from osloader file %ws: %x\n", SdiFile, status ); errorCode = RtlNtStatusToDosError( status ); PrintError( errorCode ); return; } offset.QuadPart = osloaderOffset; status = NtWriteFile( imageFileHandle, NULL, NULL, NULL, &iosb, buffer, (ULONG)osloaderLength, &offset, NULL ); if ( !NT_SUCCESS(status) ) { printf( "Can't write osloader to image file %ws: %x\n", SdiFile, status ); errorCode = RtlNtStatusToDosError( status ); PrintError( errorCode ); return; } free( buffer ); // // Update the header. // printf( " updating header\n" ); sdiHeader.liBootCodeOffset.QuadPart = startromOffset; sdiHeader.liBootCodeSize.QuadPart = startromLength; sdiHeader.ToC[1].dwType = SDI_BLOBTYPE_BOOT; sdiHeader.ToC[1].llOffset.QuadPart = startromOffset; sdiHeader.ToC[1].llSize.QuadPart = startromLength; sdiHeader.ToC[2].dwType = SDI_BLOBTYPE_LOAD; sdiHeader.ToC[2].llOffset.QuadPart = osloaderOffset; sdiHeader.ToC[2].llSize.QuadPart = osloaderLength; offset.QuadPart = 0; status = NtWriteFile( imageFileHandle, NULL, NULL, NULL, &iosb, &sdiHeader, sizeof(sdiHeader), &offset, NULL ); if ( !NT_SUCCESS(status) ) { printf( "Can't write header to image file %ws: %x\n", SdiFile, status ); errorCode = RtlNtStatusToDosError( status ); PrintError( errorCode ); return; } printf( " done\n" ); NtClose( osloaderHandle ); NtClose( startromHandle ); NtClose( imageFileHandle ); return; } int __cdecl wmain ( ULONG argc, WCHAR *argv[]) { BOOL ok; HANDLE controlHandle = NULL; PUCHAR dataBuffer = NULL; UCHAR buffer[2048]; WCHAR string[25]; ULONG length = 0; ULONG errorCode = 0; ULONG returned = 0; ULONG sizeInMb; ULONG diskType; WCHAR fileName[512]; ULONG desiredSize; ULONG actualSize; ULONG controlSize; UNICODE_STRING ustr; OBJECT_ATTRIBUTES obja; IO_STATUS_BLOCK iosb; NTSTATUS status; PRAMDISK_CREATE_INPUT createInput; ULONG arg; BOOL fNeedHelp = FALSE; HANDLE imageFileHandle; LARGE_INTEGER allocation; BOOL fixed; BOOL readonly; BOOL delete = FALSE; ULONG diskNumber; BOOL noDriveLetter; BOOL hidden; BOOL noDosDevice; BOOL ignoreHeader; BOOL bootDisk; BOOL useSdi; ULONG diskOffset; RAMDISK_HEADER ramdiskHeader; UNICODE_STRING guidString; LARGE_INTEGER offset; PWCHAR startromFile = NULL; PWCHAR osloaderFile = NULL; sizeInMb = 64; diskType = RAMDISK_TYPE_FILE_BACKED_VOLUME; fileName[0] = 0; fixed = TRUE; readonly = FALSE; noDriveLetter = FALSE; hidden = FALSE; noDosDevice = FALSE; ignoreHeader = FALSE; bootDisk = FALSE; diskOffset = PAGE_SIZE; useSdi = FALSE; for ( arg = 1; arg < argc; arg++ ) { // process options if ( (argv[arg][0] == '-') || (argv[arg][0] == '/') ) { PWCHAR argn = argv[arg]+1; // Argument name PWCHAR argp = argn; // Argument parameter while ( *argp && (*argp != ':') ) { argp++; } if ( *argp == ':' ) { *argp++ = '\0'; } switch ( argn[0] ) { case 's': // Size in MB case 'S': if ( _wcsicmp( argn, L"sdi" ) == 0 ) { useSdi = TRUE; } else { sizeInMb = _wtoi(argp); } break; case 'a': if ( _wcsicmp( argn, L"addboot" ) == 0 ) { if ( arg+2 < argc ) { startromFile = argv[++arg]; osloaderFile = argv[++arg]; } else { printf( "Missing startrom/osloader file name\n" ); fNeedHelp = TRUE; arg = argc - 1; } } else { printf( "Unknown argument: %s\n", argv[arg] ); fNeedHelp = TRUE; arg = argc - 1; } case 'i': // ignore header case 'I': ignoreHeader = TRUE; break; case 'b': // use boot disk GUID case 'B': bootDisk = TRUE; break; case 'd': // disk offset case 'D': diskOffset = _wtol(argp); break; case 'o': case 'O': // Readonly, or options if ( *argp ) { BOOL sense = TRUE; do { if ( *argp == '-' ) { sense = FALSE; argp++; } else if ( *argp == '+' ) { sense = TRUE; argp++; } switch ( *argp ) { case 'v': case 'V': diskType = sense ? RAMDISK_TYPE_FILE_BACKED_VOLUME : RAMDISK_TYPE_FILE_BACKED_DISK; break; case 'r': case 'R': readonly = sense; break; case 'f': case 'F': fixed = sense; break; case 'l': case 'L': noDriveLetter = !sense; break; case 'h': case 'H': hidden = sense; break; case 'd': case 'D': noDosDevice = !sense; break; } sense = TRUE; argp++; } while ( *argp ); } else { readonly = TRUE; } break; case 'x': // Delete device, not create case 'X': delete = TRUE; break; case 'h': // Help case 'H': case '?': fNeedHelp = TRUE; arg = argc - 1; break; default: printf( "Unknown argument: %s\n", argv[arg] ); fNeedHelp = TRUE; arg = argc - 1; break; } } else { wcscpy( fileName, argv[arg] ); } } if ( fNeedHelp ) { printf( "Usage (to create):\n" " ramdiskctrl [options] win32_disk_file_name\n" "or (to delete)\n" " ramdiskctrl -x win32_disk_file_name | {guid} | drive_letter:\n" "\n" "Options:\n" " -s:N Set size of disk image in MB (default: 64)\n" " -i Ignore ramctrl header in existing ramdisk file.\n" " -d:N Ramdisk offset from start of file. (default: 4096).\n" " -o:options Options: (use - or + to set sense)\n" " v Volume (vs. disk) (default: volume)\n" " r Readonly (default: writeable)\n" " f Fixed (default: removable)\n" " l Assign drive letter (default: assign)\n" " h Hidden (default: visible)\n" " d Assign DosDevice name (default: assign)\n" " -h or -? Display this help text.\n" ); return 1; } if ( !delete || ((fileName[0] != L'{') && !IsDriveLetter(fileName))) { FullFilePath( fileName ); } if ( startromFile != NULL ) { AddBootFilesToSdi( fileName, startromFile, osloaderFile ); return 0; } wcscpy( string, L"\\device\\ramdisk" ); RtlInitUnicodeString( &ustr, string ); InitializeObjectAttributes( &obja, &ustr, OBJ_CASE_INSENSITIVE, NULL, NULL ); //printf( "Opening %ws\n", string ); status = NtOpenFile( &controlHandle, GENERIC_READ | GENERIC_WRITE, &obja, &iosb, FILE_SHARE_READ | FILE_SHARE_WRITE, FILE_OPEN ); if ( !NT_SUCCESS(status) ) { printf( "Error opening control device %ws. Error: %x\n", string, status ); errorCode = RtlNtStatusToDosError( status ); PrintError( errorCode ); return 1; } if ( delete ) { // // Delete the disk. // DeleteRamdisk( controlHandle, fileName ); return 0; } if ( fileName[0] == 0 ) { // // Just list the disks. // ListDisks( controlHandle ); return 0; } // // If SDI, force the disk type to emulated volume, etc. // if ( useSdi ) { diskType = RAMDISK_TYPE_FILE_BACKED_VOLUME; bootDisk = FALSE; fixed = TRUE; readonly = FALSE; noDriveLetter = FALSE; hidden = FALSE; noDosDevice = FALSE; } // // Create the disk. // desiredSize = sizeInMb * 1024 * 1024; actualSize = ((desiredSize + CYLINDER_SIZE - 1) / CYLINDER_SIZE) * CYLINDER_SIZE; if ( actualSize != desiredSize ) { printf( "Using rounded-up disk size of %d instead of %d\n", actualSize, desiredSize ); } controlSize = sizeof(RAMDISK_CREATE_INPUT) + (wcslen(fileName) * sizeof(WCHAR)); createInput = malloc( controlSize ); if ( createInput == NULL ) { printf( "Can't allocate %d bytes for RAMDISK_CREATE_INPUT struct\n", controlSize ); return 1; } RtlZeroMemory( createInput, controlSize ); createInput->Version = sizeof(RAMDISK_CREATE_INPUT); wcscpy( createInput->FileName, fileName ); allocation.QuadPart = actualSize + diskOffset; RtlInitUnicodeString( &ustr, fileName ); InitializeObjectAttributes( &obja, &ustr, OBJ_CASE_INSENSITIVE, NULL, NULL ); status = NtCreateFile( &imageFileHandle, SYNCHRONIZE | FILE_READ_DATA | FILE_WRITE_DATA | FILE_READ_ATTRIBUTES, &obja, &iosb, &allocation, 0, 0, FILE_OPEN_IF, FILE_SYNCHRONOUS_IO_ALERT, NULL, 0 ); if ( !NT_SUCCESS(status) ) { printf( "Can't create target file %ws: %x\n", fileName, status ); errorCode = RtlNtStatusToDosError( status ); PrintError( errorCode ); return 1; } if ( iosb.Information == FILE_CREATED || ignoreHeader ) { if ( !bootDisk ) { UuidCreate( &createInput->DiskGuid ); } else { createInput->DiskGuid = RamdiskBootDiskGuid; } createInput->DiskOffset = diskOffset; createInput->DiskLength = actualSize; createInput->DiskType = diskType; createInput->Options.Fixed = (BOOLEAN)fixed; createInput->Options.Readonly = (BOOLEAN)readonly; createInput->Options.NoDriveLetter = (BOOLEAN)noDriveLetter; createInput->Options.Hidden = (BOOLEAN)hidden; createInput->Options.NoDosDevice = (BOOLEAN)noDosDevice; } if ( iosb.Information == FILE_CREATED ) { UCHAR byte = 0; printf( "Created target file %ws\n", fileName ); // // Extend the file to the desired length. // offset.QuadPart = actualSize + diskOffset - 1; status = NtWriteFile( imageFileHandle, NULL, NULL, NULL, &iosb, &byte, 1, &offset, NULL ); if ( !NT_SUCCESS(status) ) { printf( "Can't write to target file %ws: %x\n", fileName, status ); errorCode = RtlNtStatusToDosError( status ); PrintError( errorCode ); return 0; } // // Write the header. // RtlZeroMemory( &ramdiskHeader, sizeof(ramdiskHeader) ); if ( !useSdi ) { strcpy( ramdiskHeader.Ramctrl.Signature, "ramctrl" ); ramdiskHeader.Ramctrl.DiskGuid = createInput->DiskGuid; ramdiskHeader.Ramctrl.DiskOffset = diskOffset; ramdiskHeader.Ramctrl.DiskType = diskType; ramdiskHeader.Ramctrl.Options = createInput->Options; } else { memcpy( ramdiskHeader.Sdi.Signature, SDI_SIGNATURE, strlen(SDI_SIGNATURE) ); ramdiskHeader.Sdi.dwMDBType = SDI_MDBTYPE_VOLATILE; memcpy( ramdiskHeader.Sdi.RuntimeGUID, &createInput->DiskGuid, sizeof(GUID) ); ramdiskHeader.Sdi.dwPageAlignmentFactor = SDI_DEFAULTPAGEALIGNMENT; ramdiskHeader.Sdi.ToC[0].dwType = SDI_BLOBTYPE_PART; ramdiskHeader.Sdi.ToC[0].llOffset.QuadPart = diskOffset; ramdiskHeader.Sdi.ToC[0].llSize.QuadPart = createInput->DiskLength; } offset.QuadPart = 0; status = NtWriteFile( imageFileHandle, NULL, NULL, NULL, &iosb, &ramdiskHeader, sizeof(ramdiskHeader), &offset, NULL ); if ( !NT_SUCCESS(status) ) { printf( "Can't write to target file %ws: %x\n", fileName, status ); errorCode = RtlNtStatusToDosError( status ); PrintError( errorCode ); return 0; } } else { FILE_STANDARD_INFORMATION fileInfo; printf( "Using existing target file %ws\n", fileName ); // // Get the length of the existing file. // status = NtQueryInformationFile( imageFileHandle, &iosb, &fileInfo, sizeof(fileInfo), FileStandardInformation ); if ( !NT_SUCCESS(status) ) { printf( "Can't query info for target file %ws: %x\n", fileName, status ); errorCode = RtlNtStatusToDosError( status ); PrintError( errorCode ); return 0; } // // Read and verify the header. // if ( !ignoreHeader ) { offset.QuadPart = 0; status = NtReadFile( imageFileHandle, NULL, NULL, NULL, &iosb, &ramdiskHeader, sizeof(ramdiskHeader), &offset, NULL ); if ( !NT_SUCCESS(status) ) { printf( "Can't read header from target file %ws: %x\n", fileName, status ); errorCode = RtlNtStatusToDosError( status ); PrintError( errorCode ); return 0; } if ( strcmp( ramdiskHeader.Ramctrl.Signature, "ramctrl" ) == 0 ) { createInput->DiskGuid = ramdiskHeader.Ramctrl.DiskGuid; createInput->DiskOffset = ramdiskHeader.Ramctrl.DiskOffset; createInput->DiskLength = fileInfo.EndOfFile.QuadPart - createInput->DiskOffset; diskType = createInput->DiskType = ramdiskHeader.Ramctrl.DiskType; createInput->Options = ramdiskHeader.Ramctrl.Options; } else if ( strncmp( ramdiskHeader.Sdi.Signature, SDI_SIGNATURE, strlen(SDI_SIGNATURE) ) == 0 ) { memcpy( &createInput->DiskGuid, ramdiskHeader.Sdi.RuntimeGUID, sizeof(GUID) ); createInput->DiskOffset = ramdiskHeader.Sdi.ToC[0].llOffset.LowPart; createInput->DiskLength = ramdiskHeader.Sdi.ToC[0].llSize.QuadPart; diskType = createInput->DiskType = RAMDISK_TYPE_FILE_BACKED_VOLUME; bootDisk = FALSE; fixed = TRUE; readonly = FALSE; noDriveLetter = FALSE; hidden = FALSE; noDosDevice = FALSE; createInput->Options.Fixed = (BOOLEAN)fixed; createInput->Options.Readonly = (BOOLEAN)readonly; createInput->Options.NoDriveLetter = (BOOLEAN)noDriveLetter; createInput->Options.Hidden = (BOOLEAN)hidden; createInput->Options.NoDosDevice = (BOOLEAN)noDosDevice; } else { printf( "Header in target file not recognized\n" ); return 0; } } } NtClose( imageFileHandle ); RtlStringFromGUID( &createInput->DiskGuid, &guidString ); printf( "Creating RAM disk:\n" ); printf( " File: %ws\n", createInput->FileName ); printf( " Type: %s\n", createInput->DiskType == RAMDISK_TYPE_FILE_BACKED_VOLUME ? "volume" : "disk" ); printf( " Length: 0x%I64x\n", createInput->DiskLength ); printf( " Offset: 0x%x\n", createInput->DiskOffset ); printf( " GUID: %wZ\n", &guidString ); printf( " Options:" ); printf( "%s; ", createInput->Options.Fixed ? "fixed" : "removable" ); printf( "%s; ", createInput->Options.Readonly ? "readonly" : "writeable" ); printf( "%s; ", createInput->Options.NoDriveLetter ? "no drive letter" : "drive letter" ); printf( "%s; ", createInput->Options.Hidden ? "hidden" : "visible" ); printf( "%s\n", createInput->Options.NoDosDevice ? "no DosDevice" : "DosDevice" ); ok = DeviceIoControl( controlHandle, FSCTL_CREATE_RAM_DISK, createInput, controlSize, NULL, 0, &returned, FALSE ); if ( !ok ) { errorCode = GetLastError(); printf( "Error creating RAM disk: %d\n", errorCode ); PrintError( errorCode ); return 1; } printf( "RAM disk created\n" ); FindDisk( createInput->DiskType, &guidString, FALSE ); return 0; } // wmain