/* Query file info from a handle, storing it in Entry */ NTSTATUS ApphelpCacheQueryInfo( _In_ HANDLE ImageHandle, _Out_ PSHIM_CACHE_ENTRY Entry) { IO_STATUS_BLOCK IoStatusBlock; FILE_BASIC_INFORMATION FileBasic; FILE_STANDARD_INFORMATION FileStandard; NTSTATUS Status; Status = ZwQueryInformationFile(ImageHandle, &IoStatusBlock, &FileBasic, sizeof(FileBasic), FileBasicInformation); if (!NT_SUCCESS(Status)) { return Status; } Status = ZwQueryInformationFile(ImageHandle, &IoStatusBlock, &FileStandard, sizeof(FileStandard), FileStandardInformation); if (NT_SUCCESS(Status)) { Entry->Persistent.DateTime = FileBasic.LastWriteTime; Entry->Persistent.FileSize = FileStandard.EndOfFile; } return Status; }
co_rc_t co_os_file_block_get_size(co_monitor_file_block_dev_t *fdev, unsigned long long *size) { NTSTATUS status; HANDLE FileHandle; IO_STATUS_BLOCK IoStatusBlock; FILE_STANDARD_INFORMATION fsi; co_rc_t rc; bool_t opened = PFALSE; co_debug("%s: device %s\n", __FUNCTION__, fdev->pathname); if (fdev->sysdep == NULL) { status = co_os_open_file(fdev->pathname, &FileHandle); if (status != STATUS_SUCCESS) return CO_RC(ERROR); opened = TRUE; } else { FileHandle = (HANDLE)(fdev->sysdep); } status = ZwQueryInformationFile(FileHandle, &IoStatusBlock, &fsi, sizeof(fsi), FileStandardInformation); if (status == STATUS_SUCCESS) { *size = fsi.EndOfFile.QuadPart; co_debug("%s: reported size: %llu KBs\n", __FUNCTION__, (*size >> 10)); rc = CO_RC(OK); }
NTSTATUS Log_WriteLine(PLOG_COUNTED_STRING Line) { NTSTATUS Status = STATUS_SUCCESS; IO_STATUS_BLOCK StatusBlock; FILE_STANDARD_INFORMATION Info; if (!LogFile) return STATUS_INVALID_HANDLE; if (!InterlockedCompareExchange(&LogRotationInProgress, 1, 0)) { Status = ZwQueryInformationFile(LogFile, &StatusBlock, &Info, sizeof(Info), FileStandardInformation); if (!NT_SUCCESS(Status)) { return Status; } if (Info.DeletePending && LogFileName) { ZwClose(LogFile); LogFile = NULL; Status = Log_StartFileLogging(LogFileName); if (!NT_SUCCESS(Status)) return Status; } else if (Info.EndOfFile.QuadPart >= LogSettings.MaxFileSize) { Status = Log_Rotate(); } LogRotationInProgress = 0; } if (NT_SUCCESS(Status) && LogFile) Status = ZwWriteFile(LogFile, NULL, NULL, NULL, &StatusBlock, Line->Data, Line->DataLength, NULL, NULL); return Status; }
static co_rc_t co_os_change_file_information(char *filename, IO_STATUS_BLOCK *io_status, VOID *buffer, ULONG len, FILE_INFORMATION_CLASS info_class, co_os_change_file_info_func_t func, void *data) { NTSTATUS status; HANDLE handle; co_rc_t rc; rc = co_os_file_open(filename, &handle, FILE_READ_ATTRIBUTES | FILE_WRITE_ATTRIBUTES); if (!CO_OK(rc)) return rc; status = ZwQueryInformationFile(handle, io_status, buffer, len, info_class); if (status == STATUS_SUCCESS) { func(data, buffer, len); status = ZwSetInformationFile(handle, io_status, buffer, len, info_class); } co_os_file_close(handle); return co_status_convert(status); }
// // Get actual file size // VDKSTAT VdkGetFileSize( HANDLE FileHandle, PINT64 FileSize) { IO_STATUS_BLOCK io_status; VDKSTAT status; FILE_STANDARD_INFORMATION file_standard; status = ZwQueryInformationFile( FileHandle, &io_status, &file_standard, sizeof(FILE_STANDARD_INFORMATION), FileStandardInformation); if (!VDKSUCCESS(status)) { VDKTRACE(VDKOPEN, ("[VDK] ZwQueryInformationFile - FILE_STANDARD_INFORMATION %s\n", VdkStatusStr(status))); return status; } *FileSize = file_standard.EndOfFile.QuadPart; return status; }
DWORD WINAPI _AvpSetFilePointer( HANDLE hFile, // handle of file LONG lDistanceToMove, // number of bytes to move file pointer PLONG lpDistanceToMoveHigh, // address of high-order word of distance to move DWORD dwMoveMethod // how to move ) { NTSTATUS ntStatus; IO_STATUS_BLOCK IoStatus; FILE_POSITION_INFORMATION FileInformation; DWORD newPos; DWORD fLen=_AvpGetFileSize(hFile,NULL); if (fLen==-1)return -1; ntStatus = ZwQueryInformationFile( hFile, &IoStatus, &FileInformation, sizeof( FILE_POSITION_INFORMATION ), FilePositionInformation ); if (!NT_SUCCESS(ntStatus))return -1; switch ( dwMoveMethod ) { case 1: newPos= FileInformation.CurrentByteOffset.LowPart + lDistanceToMove; break; case 2: newPos= fLen + lDistanceToMove; break; case 0: default: newPos= lDistanceToMove; break; } if( (lDistanceToMove < 0) && (newPos & 0x80000000)) return -1; FileInformation.CurrentByteOffset.LowPart = newPos; ntStatus = ZwSetInformationFile( hFile, &IoStatus, &FileInformation, sizeof( FILE_POSITION_INFORMATION ), FilePositionInformation ); /* _DebugTrace(TraceInfo,"AvpSetFilePointer h=%d met=%d ofs=%d :pos=%d ok=%d\n", (int)hFile, dwMoveMethod, lDistanceToMove, FileInformation.CurrentByteOffset.LowPart, NT_SUCCESS(ntStatus) ); */ if(!NT_SUCCESS(ntStatus)) return -1; return FileInformation.CurrentByteOffset.LowPart; }
BOOL WINAPI _AvpReadFile ( HANDLE hFile, // handle of file to read LPVOID lpBuffer, // address of buffer that receives data DWORD nNumberOfBytesToRead, // number of bytes to read LPDWORD lpNumberOfBytesRead, // address of number of bytes read OVERLAPPED FAR* lpOverlapped // address of structure for data BYTE Disk, WORD Sector ,BYTE Head ,LPBYTE Buffer) ) { NTSTATUS ntStatus; IO_STATUS_BLOCK IoStatus; FILE_POSITION_INFORMATION FileInformation; if(lpNumberOfBytesRead)*lpNumberOfBytesRead=0; DWORD fLen=_AvpGetFileSize(hFile,NULL); if (fLen==-1)return FALSE; ntStatus = ZwQueryInformationFile( hFile, &IoStatus, &FileInformation, sizeof( FILE_POSITION_INFORMATION ), FilePositionInformation ); if (!NT_SUCCESS(ntStatus))return FALSE; if(fLen <= FileInformation.CurrentByteOffset.LowPart ) nNumberOfBytesToRead=0; else{ DWORD nBytesToEnd = fLen-FileInformation.CurrentByteOffset.LowPart; if( nBytesToEnd < nNumberOfBytesToRead) nNumberOfBytesToRead = nBytesToEnd; } if(nNumberOfBytesToRead == 0){ *lpNumberOfBytesRead=0; return TRUE; } ntStatus = ZwReadFile( hFile, NULL, NULL, NULL, &IoStatus, lpBuffer, nNumberOfBytesToRead, NULL, NULL ); if(lpNumberOfBytesRead)*lpNumberOfBytesRead=IoStatus.Information; // _DebugTrace(TraceInfo,"AvpReadFile %d %d:%d Ok:%d\n",(int)hFile,nNumberOfBytesToRead,*lpNumberOfBytesRead,NT_SUCCESS(ntStatus)); if (NT_SUCCESS(ntStatus)) return TRUE; return FALSE; }
NTSTATUS getFileIdHandle(HANDLE hfile, PLARGE_INTEGER result) { IO_STATUS_BLOCK iostatus; FILE_INTERNAL_INFORMATION info; NTSTATUS status; status = ZwQueryInformationFile(hfile, &iostatus, &info, sizeof(info), 6 /* FileInternalInformation*/ ); if (status == STATUS_SUCCESS) { *result = info.FileId; } return status; }
static NTSTATUS QueryFileInfo( _In_ HANDLE FileHandle, _Out_ PVOID *Info, _Inout_ PSIZE_T Length, _In_ FILE_INFORMATION_CLASS FileInformationClass) { NTSTATUS Status; IO_STATUS_BLOCK IoStatus; PVOID Buffer; *Info = NULL; if (*Length) { Buffer = KmtAllocateGuarded(*Length); if (skip(Buffer != NULL, "Failed to allocate %Iu bytes\n", *Length)) return STATUS_INSUFFICIENT_RESOURCES; } else { Buffer = NULL; } RtlFillMemory(Buffer, *Length, 0xDD); RtlFillMemory(&IoStatus, sizeof(IoStatus), 0x55); _SEH2_TRY { Status = ZwQueryInformationFile(FileHandle, &IoStatus, Buffer, *Length, FileInformationClass); } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { Status = _SEH2_GetExceptionCode(); ok(0, "Exception %lx querying class %d with length %Iu\n", Status, FileInformationClass, *Length); } _SEH2_END; if (Status == STATUS_PENDING) { Status = ZwWaitForSingleObject(FileHandle, FALSE, NULL); ok_eq_hex(Status, STATUS_SUCCESS); Status = IoStatus.Status; } *Length = IoStatus.Information; *Info = Buffer; return Status; }
NTSTATUS AddDenyFileAccessByCreateFile(__in PUNICODE_STRING puszFileFullPath) { NTSTATUS nsStatus = STATUS_UNSUCCESSFUL; IO_STATUS_BLOCK IoStatus = {0x00}; HANDLE hKeFile = NULL; OBJECT_ATTRIBUTES oa = {0x00}; FILE_BASIC_INFORMATION FileAttributes = {0x00}; do { InitializeObjectAttributes( &oa, puszFileFullPath, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL ); nsStatus = ZwCreateFile( &hKeFile, GENERIC_READ, &oa, &IoStatus, NULL, FILE_ATTRIBUTE_SYSTEM, 0, FILE_OPEN_IF, FILE_SYNCHRONOUS_IO_NONALERT | FILE_DELETE_ON_CLOSE, NULL, 0); BDKit_If_Not_Break(NT_SUCCESS(nsStatus) && hKeFile != NULL); nsStatus = ZwQueryInformationFile (hKeFile, &IoStatus, &FileAttributes, sizeof(FileAttributes), FileBasicInformation); FileAttributes.FileAttributes = FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN; nsStatus = ZwSetInformationFile (hKeFile, &IoStatus, &FileAttributes, sizeof(FileAttributes), FileBasicInformation); } while (FALSE); //BDKitCloseHandle(hKeFile); if ( puszFileFullPath->Buffer != NULL ) { PWSTR pszFilePath = NULL; BDKitAllocateNonpagePool(pszFilePath, puszFileFullPath->Length + sizeof(WCHAR)); RtlCopyMemory(pszFilePath, puszFileFullPath->Buffer, puszFileFullPath->Length); BDKitAddDeleteFileList (pszFilePath); } return nsStatus; }
NTSTATUS FileInfo_GetLastWriteTime (IN LPCWSTR wszFilePath, OUT LARGE_INTEGER * pliTime) { HANDLE hFile ; PROC pfnIoCreateFile ; UNICODE_STRING usFilePath ; OBJECT_ATTRIBUTES oa ; IO_STATUS_BLOCK iostatus ; NTSTATUS nStatus ; FILE_BASIC_INFORMATION fbi ; pliTime->QuadPart = 0 ; pfnIoCreateFile = Hooks_GetStubAddress (HOOKS_IOCREATEFILE) ; if( pfnIoCreateFile==NULL ) pfnIoCreateFile = (PROC)IoCreateFile ; RtlInitUnicodeString (&usFilePath, wszFilePath) ; InitializeObjectAttributes (&oa, &usFilePath, OBJ_KERNEL_HANDLE, NULL, NULL) ; nStatus = (NTSTATUS)pfnIoCreateFile (&hFile, GENERIC_READ, &oa, &iostatus, 0, 0, FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, FILE_OPEN, 0, NULL, 0, CreateFileTypeNone, NULL, 0) ; if( FAILED(nStatus) ) { TRACE_ERROR(TEXT("IoCreateFile failed (status=0x%08X)\n"), nStatus) ; return nStatus ; } nStatus = ZwQueryInformationFile (hFile, &iostatus, &fbi, sizeof(fbi), FileBasicInformation) ; if( FAILED(nStatus) ) TRACE_ERROR(TEXT("ZwQueryInformationFile failed (status=0x%08X)\n"), nStatus) ; if( SUCCEEDED(nStatus) ) *pliTime = fbi.LastWriteTime ; ZwClose (hFile) ; return nStatus ; }
BOOL GetHandleFileName(PGET_HANDLE_FILENAME Finfo) { NTSTATUS status; FILE_NAME_INFORMATION * psi = {0}; IO_STATUS_BLOCK ioStatus; psi = (FILE_NAME_INFORMATION*)new WCHAR[sizeof(FILE_NAME_INFORMATION) + 1024]; memset(psi, 0, (sizeof(FILE_NAME_INFORMATION) + 1024)*2); //psi->FileNameLength = 1024; status = ZwQueryInformationFile(Finfo->FileHandle, &ioStatus, psi, sizeof(FILE_NAME_INFORMATION) + 1024 * sizeof(WCHAR), FileNameInformation); //status = ZwQueryInformationFile(FileHandle, &ioStatus, psi, 2000, FileNameInformation); if(NT_SUCCESS(status)) { wcscpy(Finfo->FileName,psi->FileName); delete[] psi; return TRUE; } delete[] psi; return FALSE; }
static void RestoreTimeStamp (PEXTENSION Extension) { NTSTATUS ntStatus; FILE_BASIC_INFORMATION FileBasicInfo; IO_STATUS_BLOCK IoStatusBlock; if (Extension->hDeviceFile != NULL && Extension->bRawDevice == FALSE && Extension->bReadOnly == FALSE && Extension->bTimeStampValid) { ntStatus = ZwQueryInformationFile (Extension->hDeviceFile, &IoStatusBlock, &FileBasicInfo, sizeof (FileBasicInfo), FileBasicInformation); if (!NT_SUCCESS (ntStatus)) { Dump ("ZwQueryInformationFile failed in RestoreTimeStamp: NTSTATUS 0x%08x\n", ntStatus); } else { FileBasicInfo.CreationTime = Extension->fileCreationTime; FileBasicInfo.LastAccessTime = Extension->fileLastAccessTime; FileBasicInfo.LastWriteTime = Extension->fileLastWriteTime; FileBasicInfo.ChangeTime = Extension->fileLastChangeTime; ntStatus = ZwSetInformationFile( Extension->hDeviceFile, &IoStatusBlock, &FileBasicInfo, sizeof (FileBasicInfo), FileBasicInformation); if (!NT_SUCCESS (ntStatus)) Dump ("ZwSetInformationFile failed in RestoreTimeStamp: NTSTATUS 0x%08x\n",ntStatus); } } }
// // Check file attribute // VDKSTAT VdkCheckAttribute( HANDLE FileHandle) { IO_STATUS_BLOCK io_status; VDKSTAT status; FILE_BASIC_INFORMATION file_basic; // // The NT cache manager can deadlock if a filesystem that is using // the cache manager is used in a virtual disk that stores its file // on a filesystem that is also using the cache manager, this is why // we open the file with FILE_NO_INTERMEDIATE_BUFFERING above, however // if the file is compressed or encrypted NT will not honor this // request and cache it anyway since it need to store the // decompressed/unencrypted data somewhere, therefor we put an extra // check here and don't alow disk images to be compressed/encrypted. // status = ZwQueryInformationFile( FileHandle, &io_status, &file_basic, sizeof(FILE_BASIC_INFORMATION), FileBasicInformation); if (!VDKSUCCESS(status)) { VDKTRACE(VDKOPEN, ("[VDK] ZwQueryInformationFile - FILE_BASIC_INFORMATION %s\n", VdkStatusStr(status))); return status; } if (file_basic.FileAttributes & VDK_INVALID_ATTRIBUTES) { VDKTRACE(VDKOPEN,("[VDK] File is compressed and/or encrypted\n")); return STATUS_ACCESS_DENIED; } return STATUS_SUCCESS; }
NTSTATUS FileInfo_GetLastWriteTimeFromHandle (IN HANDLE hFile, OUT LARGE_INTEGER * pliTime) { IO_STATUS_BLOCK iostatus ; NTSTATUS nStatus ; FILE_BASIC_INFORMATION fbi ; pliTime->QuadPart = 0 ; nStatus = ZwQueryInformationFile (hFile, &iostatus, &fbi, sizeof(fbi), FileBasicInformation) ; if( FAILED(nStatus) ) TRACE_ERROR(TEXT("ZwQueryInformationFile failed (status=0x%08X)\n"), nStatus) ; if( SUCCEEDED(nStatus) ) *pliTime = fbi.LastWriteTime ; return nStatus ; }
HRESULT WINAPI MyGetFileTime(HANDLE hFile, LPFILETIME lpCreationTime, LPFILETIME lpLastAccessTime, LPFILETIME lpLastWriteTime) { if (IsCallerMainModule(&hFile) && bGetFileTime == False) { bGetFileTime = True; } if (((DWORD)hFile & 0x10000003) == 3) { SetLastError(0xC0000008); return S_FALSE; } NTSTATUS NtStatus; IO_STATUS_BLOCK IoStatusBlock; FILE_BASIC_INFORMATION FileBasicInfo; NtStatus = ZwQueryInformationFile(hFile, &IoStatusBlock, &FileBasicInfo, sizeof(FileBasicInfo), FileBasicInformation); if (!NT_SUCCESS(NtStatus)) { SetLastError(NtStatus); return S_FALSE; } if (lpCreationTime) { *(PLARGE_INTEGER)lpCreationTime = FileBasicInfo.ChangeTime; } if (lpLastAccessTime) { *(PLARGE_INTEGER)lpLastAccessTime = FileBasicInfo.LastAccessTime; } if (lpLastWriteTime) { *(PLARGE_INTEGER)lpLastWriteTime = FileBasicInfo.LastWriteTime; } return S_OK; }
DWORD WINAPI _AvpGetFileSize( HANDLE hFile, // handle of file LPDWORD lpHigh ) { NTSTATUS ntStatus; IO_STATUS_BLOCK IoStatus; FILE_STANDARD_INFORMATION FileInformation; ntStatus = ZwQueryInformationFile( hFile, &IoStatus, &FileInformation, sizeof( FILE_STANDARD_INFORMATION ), FileStandardInformation ); if ( ntStatus == STATUS_SUCCESS ){ if(lpHigh!=NULL)*lpHigh=FileInformation.EndOfFile.HighPart; return ( FileInformation.EndOfFile.LowPart ); } return (DWORD)-1L; }
LARGE_INTEGER sysGetFileSize(IN FILE_HANDLE handle) { IO_STATUS_BLOCK IoStatusBlock; FILE_STANDARD_INFORMATION FileInformation; NTSTATUS status; status = ZwQueryInformationFile( handle, &IoStatusBlock, &FileInformation, sizeof(FileInformation), FileStandardInformation ); if(status != STATUS_SUCCESS) { LARGE_INTEGER retVal; retVal.QuadPart = -1; return retVal; } return(FileInformation.EndOfFile); }
BOOL WINAPI _AvpSetEndOfFile( HANDLE hFile // handle of file ) { /* DWORD count; _AvpWriteFile(hFile,"",0,&count,0); return TRUE; */ NTSTATUS ntStatus; IO_STATUS_BLOCK IoStatus; FILE_POSITION_INFORMATION FileInformation; // DWORD newPos; DWORD fLen=_AvpGetFileSize(hFile,NULL); if (fLen==-1)return FALSE; ntStatus = ZwQueryInformationFile( hFile, &IoStatus, &FileInformation, sizeof( FILE_POSITION_INFORMATION ), FilePositionInformation ); if (!NT_SUCCESS(ntStatus))return FALSE; ntStatus = ZwSetInformationFile( hFile, &IoStatus, &FileInformation, sizeof( FILE_END_OF_FILE_INFORMATION ), FileEndOfFileInformation ); if(!NT_SUCCESS(ntStatus)) return FALSE; return TRUE; }
NTSTATUS LcFetchRemoteFile ( _In_ PCFLT_RELATED_OBJECTS FltObjects, _In_ PUNICODE_STRING SourceFile, _In_ PUNICODE_STRING TargetFile, _In_ BOOLEAN UseCustomHandler, _Out_ PLARGE_INTEGER BytesCopied ) /*++ Summary: This function copies the remote file content to the current file object. In order for the remote file to be fetched, make sure that the network redirector device is used, i.e. the 'SourceFile' root points to the '\Device\Mup\<path>'. Arguments: FltObjects - Pointer to the 'FLT_RELATED_OBJECTS' data structure containing opaque handles to this filter, instance, its associated volume and file object. SourceFile - Path to the file to fetch content from. TargetFile - Path to the file to store content to. UseCustomHandler - Whether the file should be fetched by the user-mode client. BytesCopied - The amount of bytes copied. Return Value: The return value is the status of the operation. --*/ { NTSTATUS status = STATUS_SUCCESS; HANDLE sourceFileHandle = NULL; IO_STATUS_BLOCK statusBlock = { 0 }; FILE_STANDARD_INFORMATION standardInfo = { 0 }; FILE_END_OF_FILE_INFORMATION eofInfo = { 0 }; PAGED_CODE(); IF_FALSE_RETURN_RESULT(FltObjects != NULL, STATUS_INVALID_PARAMETER_1); IF_FALSE_RETURN_RESULT(SourceFile != NULL, STATUS_INVALID_PARAMETER_2); IF_FALSE_RETURN_RESULT(TargetFile != NULL, STATUS_INVALID_PARAMETER_3); IF_FALSE_RETURN_RESULT(BytesCopied != NULL, STATUS_INVALID_PARAMETER_5); FLT_ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL); *BytesCopied = RtlConvertLongToLargeInteger(0); __try { LOG((DPFLTR_IHVDRIVER_ID, DPFLTR_TRACE_LEVEL, "[LazyCopy] Fetching content from: '%wZ' -> '%wZ'\n", SourceFile, TargetFile)); if (UseCustomHandler) { NT_IF_FAIL_LEAVE(LcFetchFileInUserMode(SourceFile, TargetFile, BytesCopied)); } else { // // Open the source file and make sure it's not empty. // NT_IF_FAIL_LEAVE(LcOpenFile(SourceFile, TargetFile, &sourceFileHandle)); NT_IF_FAIL_LEAVE(ZwQueryInformationFile(sourceFileHandle, &statusBlock, &standardInfo, sizeof(FILE_STANDARD_INFORMATION), FileStandardInformation)); if (standardInfo.EndOfFile.QuadPart == 0) { // No need to copy an empty file. __leave; } // Extend the target file, so all readers that wait for the content to be copied will get the actual file size information. // Remote file system may return incorrect information, but we are doing it only for the cases, when multiple threads // try to access the same file, while we are fetching it. eofInfo.EndOfFile.QuadPart = standardInfo.EndOfFile.QuadPart; NT_IF_FAIL_LEAVE(FltSetInformationFile(FltObjects->Instance, FltObjects->FileObject, &eofInfo, sizeof(eofInfo), FileEndOfFileInformation)); // // Copy source file contents into the local (target) file. // NT_IF_FAIL_LEAVE(LcFetchFileByChunks( FltObjects, sourceFileHandle, &standardInfo.EndOfFile, BytesCopied)); } } __finally { if (sourceFileHandle != NULL) { ZwClose(sourceFileHandle); } } return status; }
/** * 先检测黑名单,如果在黑名单内,直接拒,否则放行。 如果不在黑名单,则检查白名单,在白名单内,无操作。 如果不在白名单内,则将文件全路径及hash值传递到上层 * @param filename 文件全路径。 * return 如果文件安全则返回true,否则返回false。 */ bool CheckIsFileHashSecure(const PUNICODE_STRING filename) { /////////////////////////////////////////////比较已经过滤的文件名 if(IsInBlackCache(filename) == true) return false; if( MODULE_FILTERED == GetModuleFilter((ULONG)PsGetCurrentProcessId(),filename) ) return true; /////////////////////////////////////// HANDLE hFile; OBJECT_ATTRIBUTES oaFile; InitializeObjectAttributes(&oaFile, filename, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL); // 读权限打开文件,如果失败则认为文件不安全,返回false。 IO_STATUS_BLOCK ioStatus; NTSTATUS status = ZwOpenFile(&hFile, GENERIC_READ, &oaFile, &ioStatus, FILE_SHARE_READ, FILE_SYNCHRONOUS_IO_NONALERT); if(!NT_SUCCESS(status)) { KdPrint(("VerifyModule: ZwOpenFile: %ws %08x\n", filename->Buffer, status)); return false; } unsigned char* fileBuf = (unsigned char*)ExAllocatePoolWithTag(PagedPool, FILE_BUFFER_SIZE, 'knab'); if(fileBuf == NULL) { ZwClose(hFile); return false; } // 获取文件hash。 MD5_CTX md5; MD5Init(&md5); ULONG sizeAll=0; FILE_STANDARD_INFORMATION fsi; ZwQueryInformationFile(hFile,&ioStatus,&fsi,sizeof(FILE_STANDARD_INFORMATION),FileStandardInformation); while(1) { NTSTATUS status = ZwReadFile(hFile, NULL, NULL, NULL, &ioStatus, fileBuf, FILE_BUFFER_SIZE, NULL, NULL); if(!NT_SUCCESS(status)) break; if(ioStatus.Information == 0) break; sizeAll += ioStatus.Information; MD5Update(&md5, fileBuf, ioStatus.Information); } ExFreePoolWithTag(fileBuf, 'knab'); unsigned char final[16]; MD5Final(final, &md5); ZwClose(hFile); //黑白名单校验 // bool bOK = IsHashBlack(final); // // if( bOK ) // { // if(!IsInBlackCache(filename)) // { // WriteSysLog(LOG_TYPE_DEBUG,L" Fileter Module :%s", filename->Buffer); // AddBlackCache(filename); // } // return false; // } // else if( !IsHashSecure(final) )//传递到上层 // { // if( setData(filename->Buffer,filename->Length,final,16) ) // setSigned(); // } bool bOK = IsHashBlack(final); bool bReturn = true; if( bOK ) { if(!IsInBlackCache(filename)) { WriteSysLog(LOG_TYPE_INFO,L" Fileter Module :%s", filename->Buffer); AddBlackCache(filename); } bReturn = false; } else if( !IsHashSecure(final) )//传递到上层 { if( !IsInstall() ) { if( setData(filename->Buffer,filename->Length,final,16) ) setSigned(); LARGE_INTEGER lWaitTimeOuts; lWaitTimeOuts.QuadPart = -10 * 1000 * 1000; //DbgPrint("###kernel wait event!"); WriteSysLog(LOG_TYPE_INFO,L" kernel is waitint for event signal!"); if( STATUS_TIMEOUT == KeWaitForSingleObject(g_pEventFilterGo, Executive, KernelMode, FALSE, &lWaitTimeOuts) ) { IsInstall(true); if( GetPIDNumber() > 2) bReturn = false; else bReturn = true; } else bReturn = g_bPassFilter; //DbgPrint("###kernel continue: file path : %ws is %ws \n", filename->Buffer, bReturn? L"pass":L"noPass"); WriteSysLog(LOG_TYPE_INFO,L" kernel continue: file path : %ws is %ws", filename->Buffer, bReturn? L"pass":L"noPass"); if( bReturn ) if( MODULE_FILTERED != GetModuleFilter((ULONG)PsGetCurrentProcessId(),filename) && (GetPIDNumber() > 2) ) SetModuleFilter((ULONG)PsGetCurrentProcessId(), filename, true); } } // return bReturn; }
/**************************************************************************** REMARKS: Function to get the file attributes for a specific file. ****************************************************************************/ uint PMAPI PM_getFileAttr( const char *filename) { NTSTATUS status; ACCESS_MASK DesiredAccess = GENERIC_READ | GENERIC_WRITE; OBJECT_ATTRIBUTES ObjectAttributes; ULONG ShareAccess = FILE_SHARE_READ; ULONG CreateDisposition = FILE_OPEN; HANDLE FileHandle = NULL; UNICODE_STRING *uniFile = NULL; IO_STATUS_BLOCK IoStatusBlock; FILE_BASIC_INFORMATION FileBasic; char kernelFilename[PM_MAX_PATH+5]; ULONG FileAttributes = 0; uint retval = 0; // Add prefix for addressing the file system. "\??\" is short for "\DosDevices\" strcpy(kernelFilename, "\\??\\"); strcat(kernelFilename, filename); // Convert filename string to ansi string if ((uniFile = _PM_CStringToUnicodeString(kernelFilename)) == NULL) goto Exit; // Must open a file to query it's attributes InitializeObjectAttributes (&ObjectAttributes, uniFile, OBJ_CASE_INSENSITIVE, NULL, NULL ); status = ZwCreateFile( &FileHandle, DesiredAccess | SYNCHRONIZE, &ObjectAttributes, &IoStatusBlock, NULL, //AllocationSize OPTIONAL, FILE_ATTRIBUTE_NORMAL, ShareAccess, CreateDisposition, FILE_RANDOM_ACCESS, //CreateOptions, NULL, //EaBuffer OPTIONAL, 0 //EaLength (required if EaBuffer) ); if (!NT_SUCCESS (status)) goto Exit; // Query timestamps status = ZwQueryInformationFile(FileHandle, &IoStatusBlock, &FileBasic, sizeof(FILE_BASIC_INFORMATION), FileBasicInformation ); if (!NT_SUCCESS (status)) goto Exit; // Translate the file attributes if (FileBasic.FileAttributes & FILE_ATTRIBUTE_READONLY) retval |= PM_FILE_READONLY; if (FileBasic.FileAttributes & FILE_ATTRIBUTE_ARCHIVE) retval |= PM_FILE_ARCHIVE; if (FileBasic.FileAttributes & FILE_ATTRIBUTE_HIDDEN) retval |= PM_FILE_HIDDEN; if (FileBasic.FileAttributes & FILE_ATTRIBUTE_SYSTEM) retval |= PM_FILE_SYSTEM; Exit: if (FileHandle) ZwClose(FileHandle); if (uniFile) _PM_FreeUnicodeString(uniFile); return retval; }
NTSTATUS NTAPI CmpOpenHiveFiles(IN PCUNICODE_STRING BaseName, IN PCWSTR Extension OPTIONAL, OUT PHANDLE Primary, OUT PHANDLE Log, OUT PULONG PrimaryDisposition, OUT PULONG LogDisposition, IN BOOLEAN CreateAllowed, IN BOOLEAN MarkAsSystemHive, IN BOOLEAN NoBuffering, OUT PULONG ClusterSize OPTIONAL) { HANDLE EventHandle; PKEVENT Event; NTSTATUS Status; UNICODE_STRING FullName, ExtensionName; PWCHAR NameBuffer; USHORT Length; OBJECT_ATTRIBUTES ObjectAttributes; IO_STATUS_BLOCK IoStatusBlock; ULONG AttributeFlags, ShareMode, DesiredAccess, CreateDisposition, IoFlags; USHORT CompressionState; FILE_STANDARD_INFORMATION FileInformation; FILE_FS_SIZE_INFORMATION FsSizeInformation; /* Create event */ Status = CmpCreateEvent(NotificationEvent, &EventHandle, &Event); if (!NT_SUCCESS(Status)) return Status; /* Initialize the full name */ RtlInitEmptyUnicodeString(&FullName, NULL, 0); Length = BaseName->Length; /* Check if we have an extension */ if (Extension) { /* Update the name length */ Length += (USHORT)wcslen(Extension) * sizeof(WCHAR) + sizeof(UNICODE_NULL); /* Allocate the buffer for the full name */ NameBuffer = ExAllocatePoolWithTag(PagedPool, Length, TAG_CM); if (!NameBuffer) { /* Fail */ ObDereferenceObject(Event); ZwClose(EventHandle); return STATUS_NO_MEMORY; } /* Build the full name */ FullName.Buffer = NameBuffer; FullName.MaximumLength = Length; RtlAppendUnicodeStringToString(&FullName, BaseName); } else { /* The base name is the full name */ FullName = *BaseName; NameBuffer = NULL; } /* Initialize the attributes */ InitializeObjectAttributes(&ObjectAttributes, &FullName, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL); /* Check if we can create the hive */ if ((CreateAllowed) && !(CmpShareSystemHives)) { /* Open only or create */ CreateDisposition = FILE_OPEN_IF; } else { /* Open only */ CreateDisposition = FILE_OPEN; } /* Setup the flags */ // FIXME : FILE_OPEN_FOR_BACKUP_INTENT is unimplemented and breaks 3rd stage boot IoFlags = //FILE_OPEN_FOR_BACKUP_INTENT | FILE_NO_COMPRESSION | FILE_RANDOM_ACCESS | (NoBuffering ? FILE_NO_INTERMEDIATE_BUFFERING : 0); /* Set share and access modes */ if ((CmpMiniNTBoot) && (CmpShareSystemHives)) { /* We're on Live CD or otherwise sharing */ DesiredAccess = FILE_READ_DATA; ShareMode = FILE_SHARE_READ; } else { /* We want to write exclusively */ ShareMode = 0; DesiredAccess = FILE_READ_DATA | FILE_WRITE_DATA; } /* Default attributes */ AttributeFlags = FILE_ATTRIBUTE_NORMAL; /* Now create the file */ Status = ZwCreateFile(Primary, DesiredAccess | SYNCHRONIZE, &ObjectAttributes, &IoStatusBlock, NULL, AttributeFlags, ShareMode, CreateDisposition, FILE_SYNCHRONOUS_IO_NONALERT | IoFlags, NULL, 0); /* Check if anything failed until now */ if (!NT_SUCCESS(Status)) { /* Close handles and free buffers */ if (NameBuffer) ExFreePoolWithTag(NameBuffer, TAG_CM); ObDereferenceObject(Event); ZwClose(EventHandle); DPRINT1("ZwCreateFile failed : %lx.\n", Status); *Primary = NULL; return Status; } if (MarkAsSystemHive) { /* We opened it, mark it as a system hive */ Status = ZwFsControlFile(*Primary, EventHandle, NULL, NULL, &IoStatusBlock, FSCTL_MARK_AS_SYSTEM_HIVE, NULL, 0, NULL, 0); if (Status == STATUS_PENDING) { /* Wait for completion */ KeWaitForSingleObject(Event, Executive, KernelMode, FALSE, NULL); Status = IoStatusBlock.Status; } /* If we don't support it, ignore the failure */ if (Status == STATUS_INVALID_DEVICE_REQUEST) Status = STATUS_SUCCESS; if (!NT_SUCCESS(Status)) { /* Close handles and free buffers */ if (NameBuffer) ExFreePoolWithTag(NameBuffer, TAG_CM); ObDereferenceObject(Event); ZwClose(EventHandle); ZwClose(*Primary); *Primary = NULL; return Status; } } /* Disable compression */ CompressionState = 0; Status = ZwFsControlFile(*Primary, EventHandle, NULL, NULL, &IoStatusBlock, FSCTL_SET_COMPRESSION, &CompressionState, sizeof(CompressionState), NULL, 0); if (Status == STATUS_PENDING) { /* Wait for completion */ KeWaitForSingleObject(Event, Executive, KernelMode, FALSE, NULL); } /* Get the disposition */ *PrimaryDisposition = (ULONG)IoStatusBlock.Information; if (IoStatusBlock.Information != FILE_CREATED) { /* Check how large the file is */ Status = ZwQueryInformationFile(*Primary, &IoStatusBlock, &FileInformation, sizeof(FileInformation), FileStandardInformation); if (NT_SUCCESS(Status)) { /* Check if it's 0 bytes */ if (!FileInformation.EndOfFile.QuadPart) { /* Assume it's a new file */ *PrimaryDisposition = FILE_CREATED; } } } /* Check if the caller wants cluster size returned */ if (ClusterSize) { /* Query it */ Status = ZwQueryVolumeInformationFile(*Primary, &IoStatusBlock, &FsSizeInformation, sizeof(FsSizeInformation), FileFsSizeInformation); if (!NT_SUCCESS(Status)) { /* Close handles and free buffers */ if (NameBuffer) ExFreePoolWithTag(NameBuffer, TAG_CM); ObDereferenceObject(Event); ZwClose(EventHandle); return Status; } /* Check if the sector size is invalid */ if (FsSizeInformation.BytesPerSector > HBLOCK_SIZE) { /* Close handles and free buffers */ if (NameBuffer) ExFreePoolWithTag(NameBuffer, TAG_CM); ObDereferenceObject(Event); ZwClose(EventHandle); return STATUS_CANNOT_LOAD_REGISTRY_FILE; } /* Return cluster size */ *ClusterSize = max(1, FsSizeInformation.BytesPerSector / HSECTOR_SIZE); } /* Check if we don't need to create a log file */ if (!Extension) { /* We're done, close handles */ ObDereferenceObject(Event); ZwClose(EventHandle); return STATUS_SUCCESS; } /* Check if we can create the hive */ CreateDisposition = CmpShareSystemHives ? FILE_OPEN : FILE_OPEN_IF; if (*PrimaryDisposition == FILE_CREATED) { /* Over-write the existing log file, since this is a new hive */ CreateDisposition = FILE_SUPERSEDE; } /* Setup the name */ RtlInitUnicodeString(&ExtensionName, Extension); RtlAppendUnicodeStringToString(&FullName, &ExtensionName); /* Initialize the attributes */ InitializeObjectAttributes(&ObjectAttributes, &FullName, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL); /* Setup the flags */ IoFlags = FILE_NO_COMPRESSION | FILE_NO_INTERMEDIATE_BUFFERING; /* Check if this is a log file */ if (!_wcsnicmp(Extension, L".log", 4)) { /* Hide log files */ AttributeFlags |= FILE_ATTRIBUTE_HIDDEN; } /* Now create the file */ Status = ZwCreateFile(Log, DesiredAccess, &ObjectAttributes, &IoStatusBlock, NULL, AttributeFlags, ShareMode, CreateDisposition, IoFlags, NULL, 0); if ((NT_SUCCESS(Status)) && (MarkAsSystemHive)) { /* We opened it, mark it as a system hive */ Status = ZwFsControlFile(*Log, EventHandle, NULL, NULL, &IoStatusBlock, FSCTL_MARK_AS_SYSTEM_HIVE, NULL, 0, NULL, 0); if (Status == STATUS_PENDING) { /* Wait for completion */ KeWaitForSingleObject(Event, Executive, KernelMode, FALSE, NULL); Status = IoStatusBlock.Status; } /* If we don't support it, ignore the failure */ if (Status == STATUS_INVALID_DEVICE_REQUEST) Status = STATUS_SUCCESS; /* If we failed, close the handle */ if (!NT_SUCCESS(Status)) ZwClose(*Log); } /* Check if anything failed until now */ if (!NT_SUCCESS(Status)) { /* Clear the handle */ *Log = NULL; } else { /* Disable compression */ Status = ZwFsControlFile(*Log, EventHandle, NULL, NULL, &IoStatusBlock, FSCTL_SET_COMPRESSION, &CompressionState, sizeof(CompressionState), NULL, 0); if (Status == STATUS_PENDING) { /* Wait for completion */ KeWaitForSingleObject(Event, Executive, KernelMode, FALSE, NULL); } /* Return the disposition */ *LogDisposition = (ULONG)IoStatusBlock.Information; } /* We're done, close handles and free buffers */ if (NameBuffer) ExFreePoolWithTag(NameBuffer, TAG_CM); ObDereferenceObject(Event); ZwClose(EventHandle); return STATUS_SUCCESS; }
NTSTATUS NTAPI CmpInitializeHive(OUT PCMHIVE *RegistryHive, IN ULONG OperationType, IN ULONG HiveFlags, IN ULONG FileType, IN PVOID HiveData OPTIONAL, IN HANDLE Primary, IN HANDLE Log, IN HANDLE External, IN PCUNICODE_STRING FileName OPTIONAL, IN ULONG CheckFlags) { PCMHIVE Hive; FILE_STANDARD_INFORMATION FileInformation; IO_STATUS_BLOCK IoStatusBlock; FILE_FS_SIZE_INFORMATION FileSizeInformation; NTSTATUS Status; ULONG Cluster; /* Assume failure */ *RegistryHive = NULL; /* * The following are invalid: * An external hive that is also internal. * A log hive that's not a primary hive too. * A volatile hive that's linked to permanent storage. * An in-memory initialization without hive data. * A log hive that's not linked to a correct file type. */ if (((External) && ((Primary) || (Log))) || ((Log) && !(Primary)) || ((HiveFlags & HIVE_VOLATILE) && ((Primary) || (External) || (Log))) || ((OperationType == HINIT_MEMORY) && (!HiveData)) || ((Log) && (FileType != HFILE_TYPE_LOG))) { /* Fail the request */ return STATUS_INVALID_PARAMETER; } /* Check if this is a primary hive */ if (Primary) { /* Get the cluster size */ Status = ZwQueryVolumeInformationFile(Primary, &IoStatusBlock, &FileSizeInformation, sizeof(FILE_FS_SIZE_INFORMATION), FileFsSizeInformation); if (!NT_SUCCESS(Status)) return Status; /* Make sure it's not larger then the block size */ if (FileSizeInformation.BytesPerSector > HBLOCK_SIZE) { /* Fail */ return STATUS_REGISTRY_IO_FAILED; } /* Otherwise, calculate the cluster */ Cluster = FileSizeInformation.BytesPerSector / HSECTOR_SIZE; Cluster = max(1, Cluster); } else { /* Otherwise use cluster 1 */ Cluster = 1; } /* Allocate the hive */ Hive = ExAllocatePoolWithTag(NonPagedPool, sizeof(CMHIVE), TAG_CMHIVE); if (!Hive) return STATUS_INSUFFICIENT_RESOURCES; /* Setup null fields */ Hive->UnloadEvent = NULL; Hive->RootKcb = NULL; Hive->Frozen = FALSE; Hive->UnloadWorkItem = NULL; Hive->GrowOnlyMode = FALSE; Hive->GrowOffset = 0; Hive->CellRemapArray = NULL; Hive->UseCountLog.Next = 0; Hive->LockHiveLog.Next = 0; Hive->FileObject = NULL; Hive->NotifyList.Flink = NULL; Hive->NotifyList.Blink = NULL; /* Set loading flag */ Hive->HiveIsLoading = TRUE; /* Set the current thread as creator */ Hive->CreatorOwner = KeGetCurrentThread(); /* Initialize lists */ InitializeListHead(&Hive->KcbConvertListHead); InitializeListHead(&Hive->KnodeConvertListHead); InitializeListHead(&Hive->TrustClassEntry); /* Allocate the view log */ Hive->ViewLock = ExAllocatePoolWithTag(NonPagedPool, sizeof(KGUARDED_MUTEX), TAG_CMHIVE); if (!Hive->ViewLock) { /* Cleanup allocation and fail */ ExFreePoolWithTag(Hive, TAG_CMHIVE); return STATUS_INSUFFICIENT_RESOURCES; } /* Allocate the flush lock */ Hive->FlusherLock = ExAllocatePoolWithTag(NonPagedPool, sizeof(ERESOURCE), TAG_CMHIVE); if (!Hive->FlusherLock) { /* Cleanup allocations and fail */ ExFreePoolWithTag(Hive->ViewLock, TAG_CMHIVE); ExFreePoolWithTag(Hive, TAG_CMHIVE); return STATUS_INSUFFICIENT_RESOURCES; } /* Setup the handles */ Hive->FileHandles[HFILE_TYPE_PRIMARY] = Primary; Hive->FileHandles[HFILE_TYPE_LOG] = Log; Hive->FileHandles[HFILE_TYPE_EXTERNAL] = External; /* Initailize the guarded mutex */ KeInitializeGuardedMutex(Hive->ViewLock); Hive->ViewLockOwner = NULL; /* Initialize the flush lock */ ExInitializeResourceLite(Hive->FlusherLock); /* Setup hive locks */ ExInitializePushLock(&Hive->HiveLock); Hive->HiveLockOwner = NULL; ExInitializePushLock(&Hive->WriterLock); Hive->WriterLockOwner = NULL; ExInitializePushLock(&Hive->SecurityLock); Hive->HiveSecurityLockOwner = NULL; /* Clear file names */ RtlInitEmptyUnicodeString(&Hive->FileUserName, NULL, 0); RtlInitEmptyUnicodeString(&Hive->FileFullPath, NULL, 0); /* Initialize the view list */ CmpInitHiveViewList(Hive); /* Initailize the security cache */ CmpInitSecurityCache(Hive); /* Setup flags */ Hive->Flags = 0; Hive->FlushCount = 0; /* Set flags */ Hive->Flags = HiveFlags; /* Check if this is a primary */ if (Primary) { /* Check how large the file is */ ZwQueryInformationFile(Primary, &IoStatusBlock, &FileInformation, sizeof(FileInformation), FileStandardInformation); Cluster = FileInformation.EndOfFile.LowPart; } /* Initialize it */ Status = HvInitialize(&Hive->Hive, OperationType, FileType, HiveFlags, HiveData, CmpAllocate, CmpFree, CmpFileSetSize, CmpFileWrite, CmpFileRead, CmpFileFlush, Cluster, FileName); if (!NT_SUCCESS(Status)) { /* Cleanup allocations and fail */ ExDeleteResourceLite(Hive->FlusherLock); ExFreePoolWithTag(Hive->FlusherLock, TAG_CMHIVE); ExFreePoolWithTag(Hive->ViewLock, TAG_CMHIVE); ExFreePoolWithTag(Hive, TAG_CMHIVE); return Status; } /* Check if we should verify the registry */ if ((OperationType == HINIT_FILE) || (OperationType == HINIT_MEMORY) || (OperationType == HINIT_MEMORY_INPLACE) || (OperationType == HINIT_MAPFILE)) { /* Verify integrity */ ULONG CheckStatus = CmCheckRegistry(Hive, CheckFlags); if (CheckStatus != 0) { /* Cleanup allocations and fail */ ExDeleteResourceLite(Hive->FlusherLock); ExFreePoolWithTag(Hive->FlusherLock, TAG_CMHIVE); ExFreePoolWithTag(Hive->ViewLock, TAG_CMHIVE); ExFreePoolWithTag(Hive, TAG_CMHIVE); return STATUS_REGISTRY_CORRUPT; } } /* Lock the hive list */ ExAcquirePushLockExclusive(&CmpHiveListHeadLock); /* Insert this hive */ InsertHeadList(&CmpHiveListHead, &Hive->HiveList); /* Release the lock */ ExReleasePushLock(&CmpHiveListHeadLock); /* Return the hive and success */ *RegistryHive = (PCMHIVE)Hive; return STATUS_SUCCESS; }
/// <summary> /// System worker thread that performs actual mapping /// </summary> /// <param name="pArg">Path to the driver - PUNICODE_STRING type</param> /// <returns>Status code</returns> NTSTATUS BBMapWorker( IN PVOID pArg ) { NTSTATUS status = STATUS_SUCCESS; HANDLE hFile = NULL; PUNICODE_STRING pPath = (PUNICODE_STRING)pArg; OBJECT_ATTRIBUTES obAttr = { 0 }; IO_STATUS_BLOCK statusBlock = { 0 }; PVOID fileData = NULL; PIMAGE_NT_HEADERS pNTHeader = NULL; PVOID imageSection = NULL; PMDL pMDL = NULL; FILE_STANDARD_INFORMATION fileInfo = { 0 }; InitializeObjectAttributes( &obAttr, pPath, OBJ_KERNEL_HANDLE, NULL, NULL ); // Open driver file status = ZwCreateFile( &hFile, FILE_READ_DATA | SYNCHRONIZE, &obAttr, &statusBlock, NULL, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ, FILE_OPEN, FILE_SYNCHRONOUS_IO_NONALERT, NULL, 0 ); if (!NT_SUCCESS( status )) { DPRINT( "BlackBone: %s: Failed to open '%wZ'. Status: 0x%X\n", __FUNCTION__, pPath, status ); return status; } // Allocate memory for file contents status = ZwQueryInformationFile( hFile, &statusBlock, &fileInfo, sizeof( fileInfo ), FileStandardInformation ); if (NT_SUCCESS( status )) fileData = ExAllocatePoolWithTag( PagedPool, fileInfo.EndOfFile.QuadPart, BB_POOL_TAG ); else DPRINT( "BlackBone: %s: Failed to get '%wZ' size. Status: 0x%X\n", __FUNCTION__, pPath, status ); // Get file contents status = ZwReadFile( hFile, NULL, NULL, NULL, &statusBlock, fileData, fileInfo.EndOfFile.LowPart, NULL, NULL ); if (NT_SUCCESS( status )) { pNTHeader = RtlImageNtHeader( fileData ); if (!pNTHeader) { DPRINT( "BlackBone: %s: Failed to obtaint NT Header for '%wZ'\n", __FUNCTION__, pPath ); status = STATUS_INVALID_IMAGE_FORMAT; } } else DPRINT( "BlackBone: %s: Failed to read '%wZ'. Status: 0x%X\n", __FUNCTION__, pPath, status ); ZwClose( hFile ); __try { if (NT_SUCCESS( status )) { // // Allocate memory from System PTEs // PHYSICAL_ADDRESS start = { 0 }, end = { 0 }; end.QuadPart = MAXULONG64; pMDL = MmAllocatePagesForMdl( start, end, start, pNTHeader->OptionalHeader.SizeOfImage ); imageSection = MmGetSystemAddressForMdlSafe( pMDL, NormalPagePriority ); if (NT_SUCCESS( status ) && imageSection) { // Copy header RtlCopyMemory( imageSection, fileData, pNTHeader->OptionalHeader.SizeOfHeaders ); // Copy sections for (PIMAGE_SECTION_HEADER pSection = (PIMAGE_SECTION_HEADER)(pNTHeader + 1); pSection < (PIMAGE_SECTION_HEADER)(pNTHeader + 1) + pNTHeader->FileHeader.NumberOfSections; pSection++) { RtlCopyMemory( (PUCHAR)imageSection + pSection->VirtualAddress, (PUCHAR)fileData + pSection->PointerToRawData, pSection->SizeOfRawData ); } // Relocate image status = LdrRelocateImage( imageSection, STATUS_SUCCESS, STATUS_CONFLICTING_ADDRESSES, STATUS_INVALID_IMAGE_FORMAT ); if (!NT_SUCCESS( status )) DPRINT( "BlackBone: %s: Failed to relocate image '%wZ'. Status: 0x%X\n", __FUNCTION__, pPath, status ); // Fill IAT if (NT_SUCCESS( status )) status = BBResolveImageRefs( imageSection, TRUE, NULL, FALSE, NULL, 0 ); } else { DPRINT( "BlackBone: %s: Failed to allocate memory for image '%wZ'\n", __FUNCTION__, pPath ); status = STATUS_MEMORY_NOT_ALLOCATED; } } // Call entrypoint if (NT_SUCCESS( status ) && pNTHeader->OptionalHeader.AddressOfEntryPoint) { PDRIVER_INITIALIZE pEntryPoint = (PDRIVER_INITIALIZE)((ULONG_PTR)imageSection + pNTHeader->OptionalHeader.AddressOfEntryPoint); pEntryPoint( NULL, NULL ); } // Wipe header if (NT_SUCCESS( status ) && imageSection) RtlZeroMemory( imageSection, pNTHeader->OptionalHeader.SizeOfHeaders ); } __except (EXCEPTION_EXECUTE_HANDLER) { DPRINT( "BlackBone: %s: Exception: 0x%X \n", __FUNCTION__, GetExceptionCode() ); } // Erase info about allocated region if (pMDL) { // Free image memory in case of failure if(!NT_SUCCESS( status )) MmFreePagesFromMdl( pMDL ); ExFreePool( pMDL ); } if (fileData) ExFreePoolWithTag( fileData, BB_POOL_TAG ); if (NT_SUCCESS( status )) DPRINT( "BlackBone: %s: Successfully mapped '%wZ' at 0x%p\n", __FUNCTION__, pPath, imageSection ); return status; }
NTSTATUS ImScsiGetDiskSize( __in HANDLE FileHandle, __out __deref PIO_STATUS_BLOCK IoStatus, __inout __deref PLARGE_INTEGER DiskSize) { NTSTATUS status; { FILE_STANDARD_INFORMATION file_standard; status = ZwQueryInformationFile(FileHandle, IoStatus, &file_standard, sizeof(FILE_STANDARD_INFORMATION), FileStandardInformation); if (NT_SUCCESS(status)) { *DiskSize = file_standard.EndOfFile; return status; } KdPrint(("PhDskMnt::FileStandardInformation not supported for " "target device. %#x\n", status)); } // Retry with IOCTL_DISK_GET_LENGTH_INFO instead { GET_LENGTH_INFORMATION part_info = { 0 }; status = ZwDeviceIoControlFile(FileHandle, NULL, NULL, NULL, IoStatus, IOCTL_DISK_GET_LENGTH_INFO, NULL, 0, &part_info, sizeof(part_info)); if (status == STATUS_PENDING) { ZwWaitForSingleObject(FileHandle, FALSE, NULL); status = IoStatus->Status; } if (NT_SUCCESS(status)) { *DiskSize = part_info.Length; return status; } KdPrint(("PhDskMnt::IOCTL_DISK_GET_LENGTH_INFO not supported " "for target device. %#x\n", status)); } // Retry with IOCTL_DISK_GET_PARTITION_INFO instead { PARTITION_INFORMATION part_info = { 0 }; status = ZwDeviceIoControlFile(FileHandle, NULL, NULL, NULL, IoStatus, IOCTL_DISK_GET_PARTITION_INFO, NULL, 0, &part_info, sizeof(part_info)); if (status == STATUS_PENDING) { ZwWaitForSingleObject(FileHandle, FALSE, NULL); status = IoStatus->Status; } if (NT_SUCCESS(status)) { *DiskSize = part_info.PartitionLength; return status; } KdPrint(("PhDskMnt::IOCTL_DISK_GET_PARTITION_INFO not supported " "for target device. %#x\n", status)); } return status; }
BOOLEAN getSizeModified( _In_ PFLT_INSTANCE instance, _In_ PUNICODE_STRING fileName, _Inout_ LONGLONG *size, _Inout_ LONGLONG *modified ) { NTSTATUS status; HANDLE FileHandle = NULL; OBJECT_ATTRIBUTES objectAttributes; IO_STATUS_BLOCK ioStatus; FILE_BASIC_INFORMATION basicFileInfo; FILE_STANDARD_INFORMATION standardFileInfo; InitializeObjectAttributes(&objectAttributes, fileName, OBJ_CASE_INSENSITIVE | OBJ_OPENIF, NULL, NULL); status = FltCreateFile( ClaimsmanData.Filter, instance, &FileHandle, FILE_READ_DATA | FILE_READ_ATTRIBUTES, &objectAttributes, &ioStatus, NULL, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, FILE_OPEN, FILE_SYNCHRONOUS_IO_NONALERT, NULL, 0, IO_NO_PARAMETER_CHECKING ); if (!NT_SUCCESS(status)) { return FALSE; } status = ZwQueryInformationFile(FileHandle, &ioStatus, &basicFileInfo, sizeof(FILE_BASIC_INFORMATION), FileBasicInformation); if (!NT_SUCCESS(status)) { ZwClose(FileHandle); return FALSE; } status = ZwQueryInformationFile(FileHandle, &ioStatus, &standardFileInfo, sizeof(FILE_STANDARD_INFORMATION), FileStandardInformation); if (!NT_SUCCESS(status)) { ZwClose(FileHandle); return FALSE; } *modified = (basicFileInfo.ChangeTime.QuadPart - DIFF_TO_UNIX_EPOCH) / 10000; *size = standardFileInfo.EndOfFile.QuadPart; ZwClose(FileHandle); return TRUE; }
NTSTATUS GetNextReparseVolumePath( IN HANDLE Handle, OUT PUNICODE_STRING Path ) /*++ Routine Description: This routine queries the reparse index for the next volume mount point. Arguments: Handle - Supplies the handle. Path - Returns the path. Return Value: NTSTATUS --*/ { NTSTATUS status; IO_STATUS_BLOCK ioStatus; FILE_REPARSE_POINT_INFORMATION reparseInfo; UNICODE_STRING fileId; OBJECT_ATTRIBUTES oa; HANDLE h; PREPARSE_DATA_BUFFER reparse; UNICODE_STRING volumeName; ULONG nameInfoSize; PFILE_NAME_INFORMATION nameInfo; for (;;) { status = ZwQueryDirectoryFile(Handle, NULL, NULL, NULL, &ioStatus, &reparseInfo, sizeof(reparseInfo), FileReparsePointInformation, TRUE, NULL, FALSE); if (!NT_SUCCESS(status)) { return status; } if (reparseInfo.Tag != IO_REPARSE_TAG_MOUNT_POINT) { continue; } fileId.Length = sizeof(reparseInfo.FileReference); fileId.MaximumLength = fileId.Length; fileId.Buffer = (PWSTR) &reparseInfo.FileReference; InitializeObjectAttributes(&oa, &fileId, 0, Handle, NULL); status = ZwOpenFile(&h, SYNCHRONIZE | FILE_GENERIC_READ, &oa, &ioStatus, FILE_SHARE_READ | FILE_SHARE_WRITE, FILE_OPEN_BY_FILE_ID | FILE_OPEN_REPARSE_POINT | FILE_SYNCHRONOUS_IO_ALERT); if (!NT_SUCCESS(status)) { continue; } reparse = ExAllocatePool(PagedPool, MAXIMUM_REPARSE_DATA_BUFFER_SIZE); if (!reparse) { ZwClose(h); return STATUS_INSUFFICIENT_RESOURCES; } status = ZwFsControlFile(h, NULL, NULL, NULL, &ioStatus, FSCTL_GET_REPARSE_POINT, NULL, 0, reparse, MAXIMUM_REPARSE_DATA_BUFFER_SIZE); if (!NT_SUCCESS(status)) { ExFreePool(reparse); ZwClose(h); continue; } volumeName.Length = reparse->MountPointReparseBuffer.SubstituteNameLength - sizeof(WCHAR); volumeName.MaximumLength = volumeName.Length + sizeof(WCHAR); volumeName.Buffer = (PWCHAR) ((PCHAR) reparse->MountPointReparseBuffer.PathBuffer + reparse->MountPointReparseBuffer.SubstituteNameOffset); volumeName.Buffer[volumeName.Length/sizeof(WCHAR)] = 0; if (!IsVolumeName(&volumeName)) { ExFreePool(reparse); ZwClose(h); continue; } ExFreePool(reparse); nameInfoSize = 1024; nameInfo = ExAllocatePool(PagedPool, nameInfoSize); if (!nameInfo) { ZwClose(h); continue; } status = ZwQueryInformationFile(h, &ioStatus, nameInfo, nameInfoSize, FileNameInformation); ZwClose(h); if (!NT_SUCCESS(status)) { continue; } Path->Length = (USHORT) nameInfo->FileNameLength; Path->MaximumLength = Path->Length + sizeof(WCHAR); Path->Buffer = ExAllocatePool(PagedPool, Path->MaximumLength); if (!Path->Buffer) { ExFreePool(nameInfo); continue; } RtlCopyMemory(Path->Buffer, nameInfo->FileName, Path->Length); Path->Buffer[Path->Length/sizeof(WCHAR)] = 0; ExFreePool(nameInfo); break; } return status; }
BOOLEAN Primary_PassThrough( IN PLFS_DEVICE_EXTENSION LfsDeviceExt, IN PIRP Irp, OUT PNTSTATUS NtStatus ) { PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp); PFILE_OBJECT fileObject; KIRQL oldIrql; // Do not allow exclusive access to the volume when connected to secondaries. if(irpSp->MajorFunction == IRP_MJ_FILE_SYSTEM_CONTROL && (irpSp->MinorFunction == IRP_MN_USER_FS_REQUEST || irpSp->MinorFunction == IRP_MN_KERNEL_CALL)) { struct FileSystemControl *fileSystemControl =(struct FileSystemControl *)&(irpSp->Parameters.FileSystemControl); fileObject = irpSp->FileObject; // // Do not allow exclusive access to the volume and dismount volume to protect format // We allow exclusive access if secondaries are connected locally. // if( (fileSystemControl->FsControlCode == FSCTL_LOCK_VOLUME // 6 || fileSystemControl->FsControlCode == FSCTL_DISMOUNT_VOLUME) // 8 && NetdiskManager_ThisVolumeHasSecondary(GlobalLfs.NetdiskManager, LfsDeviceExt->EnabledNetdisk, LfsDeviceExt, FALSE) ) { SPY_LOG_PRINT( LFS_DEBUG_PRIMARY_INFO, ("Primary_PassThrough, IRP_MJ_FILE_SYSTEM_CONTROL: Trying to acquire the volume exclusively. \n")); ASSERT(fileObject && fileObject->FileName.Length == 0 && fileObject->RelatedFileObject == NULL); *NtStatus = Irp->IoStatus.Status = STATUS_ACCESS_DENIED; Irp->IoStatus.Information = 0; IoCompleteRequest(Irp, IO_DISK_INCREMENT); return TRUE; // // Do not support encryption. // } else if(fileSystemControl->FsControlCode == FSCTL_SET_ENCRYPTION) { SPY_LOG_PRINT( LFS_DEBUG_PRIMARY_INFO, ("Primary_PassThrough, IRP_MJ_FILE_SYSTEM_CONTROL: Setting encryption denied.\n")); *NtStatus = Irp->IoStatus.Status = STATUS_NOT_SUPPORTED; Irp->IoStatus.Information = 0; IoCompleteRequest(Irp, IO_DISK_INCREMENT); return TRUE; } } // Need to test much whether this is okay.. if (irpSp->MajorFunction == IRP_MJ_PNP && (irpSp->MinorFunction == IRP_MN_CANCEL_REMOVE_DEVICE || irpSp->MinorFunction == IRP_MN_REMOVE_DEVICE)) { PNETDISK_PARTITION Partition; Partition = LookUpNetdiskPartition(LfsDeviceExt->EnabledNetdisk, NULL, 0, LfsDeviceExt, NULL); if (Partition) { SPY_LOG_PRINT( LFS_DEBUG_LFS_ERROR, ("%s: Releasing Unplugging lock\n", (irpSp->MinorFunction == IRP_MN_CANCEL_REMOVE_DEVICE)?"CANCEL_REMOVE_DEVICE":"REMOVE_DEVICE")); InterlockedDecrement(&LfsDeviceExt->EnabledNetdisk->UnplugInProgressCount); NetdiskPartition_Dereference(Partition); // by LookUpNetdiskPartition } else { ASSERT(0); SPY_LOG_PRINT( LFS_DEBUG_LFS_ERROR, ("%s: Failed to find matching parition. Release unplugging lock anyway\n", (irpSp->MinorFunction == IRP_MN_CANCEL_REMOVE_DEVICE)?"CANCEL_REMOVE_DEVICE":"REMOVE_DEVICE")); InterlockedDecrement(&LfsDeviceExt->EnabledNetdisk->UnplugInProgressCount); } } // // Close files opened by secondary if unmount of primary host is requested . // This helps primary can unmount while secondary has mounted. // if (irpSp->MajorFunction == IRP_MJ_PNP && irpSp->MinorFunction == IRP_MN_QUERY_REMOVE_DEVICE) { int i; PLIST_ENTRY primarySessionListEntry; PLIST_ENTRY PrimarySessionList; POPEN_FILE openFile; PLIST_ENTRY OpenFileListEntry; NTSTATUS closeStatus; #if DBG int j; CHAR NameBuf[512] = {0}; #endif PPRIMARY_SESSION primarySession; PNETDISK_PARTITION Partition; Partition = LookUpNetdiskPartition(LfsDeviceExt->EnabledNetdisk, NULL, 0, LfsDeviceExt, NULL); if (Partition) { SPY_LOG_PRINT( LFS_DEBUG_LFS_ERROR, ("QUERY_REMOVE: Locking disks for removal\n")); InterlockedIncrement(&LfsDeviceExt->EnabledNetdisk->UnplugInProgressCount); // wait until DispatchInProgressCount becomes zero KeAcquireSpinLock(&LfsDeviceExt->EnabledNetdisk->SpinLock, &oldIrql); while(LfsDeviceExt->EnabledNetdisk->DispatchInProgressCount>0) { LARGE_INTEGER Timeout; SPY_LOG_PRINT( LFS_DEBUG_LFS_ERROR, ("QUERY_REMOVE: %d IO is in progress by secondary\n", LfsDeviceExt->EnabledNetdisk->DispatchInProgressCount)); Timeout.QuadPart = - HZ/10; // 100ms KeReleaseSpinLock(&LfsDeviceExt->EnabledNetdisk->SpinLock, oldIrql); KeDelayExecutionThread(KernelMode, FALSE, &Timeout); KeAcquireSpinLock(&LfsDeviceExt->EnabledNetdisk->SpinLock, &oldIrql); } KeReleaseSpinLock(&LfsDeviceExt->EnabledNetdisk->SpinLock, oldIrql); NetdiskPartition_Dereference(Partition); // by LookUpNetdiskPartition } else { SPY_LOG_PRINT( LFS_DEBUG_LFS_ERROR, ("QUERY_REMOVE: Failed to find matching parition\n")); } for(i=0;i<MAX_SOCKETLPX_INTERFACE;i++) { PrimarySessionList = &GlobalLfs.Primary->PrimarySessionQueue[i]; for (primarySessionListEntry = PrimarySessionList->Flink; primarySessionListEntry != PrimarySessionList; primarySessionListEntry = primarySessionListEntry->Flink) { primarySession = CONTAINING_RECORD (primarySessionListEntry, PRIMARY_SESSION, ListEntry); if (primarySession->NetdiskPartition == NULL || primarySession->NetdiskPartition->EnabledNetdisk == NULL) { SPY_LOG_PRINT( LFS_DEBUG_LFS_INFO, ("Primary is closed: Session=%p\n", primarySession )); continue; } // // Is there any way to check to get proper netdisk?? // if (primarySession->NetdiskPartition->EnabledNetdisk == LfsDeviceExt->EnabledNetdisk) { for (OpenFileListEntry = primarySession->OpenedFileQueue.Flink; OpenFileListEntry != &primarySession->OpenedFileQueue; OpenFileListEntry = OpenFileListEntry->Flink) { openFile = CONTAINING_RECORD (OpenFileListEntry, OPEN_FILE, ListEntry); // Close open files opened by secondary. if (openFile->AlreadyClosed == FALSE) { // Store file offset before close. if (openFile->CreateOptions &(FILE_SYNCHRONOUS_IO_ALERT |FILE_SYNCHRONOUS_IO_NONALERT)) { NTSTATUS QueryStatus; IO_STATUS_BLOCK IoStatus; FILE_POSITION_INFORMATION FileInfo; // File position is meaningful only in this open mode. QueryStatus = ZwQueryInformationFile( openFile->FileHandle, &IoStatus, (PVOID)&FileInfo, sizeof(FileInfo), FilePositionInformation ); if (NT_SUCCESS(QueryStatus)) { SPY_LOG_PRINT( LFS_DEBUG_LFS_INFO, ("Closing secondary files: Stroring offset %x\n", FileInfo.CurrentByteOffset)); openFile->CurrentByteOffset = FileInfo.CurrentByteOffset; } else { SPY_LOG_PRINT( LFS_DEBUG_LFS_ERROR, ("Closing secondary files: Failed to get current file offset\n")); openFile->CurrentByteOffset.HighPart = 0; openFile->CurrentByteOffset.LowPart = 0; } } closeStatus = ZwClose(openFile->FileHandle); ObDereferenceObject(openFile->FileObject); ASSERT(openFile->EventHandle !=NULL); ZwClose(openFile->EventHandle); openFile->EventHandle = NULL; openFile->AlreadyClosed = TRUE; } #if DBG // Print of unicode is available only PASSIVE_LEVEL. // So print in ASCII assuming file name is always ascii range. for(j=0;openFile->FullFileNameBuffer[j]!=0 && j<sizeof(NameBuf)-1;j++) { NameBuf[j]= (CHAR)openFile->FullFileNameBuffer[j]; } NameBuf[j] = 0; SPY_LOG_PRINT( LFS_DEBUG_LFS_INFO, ("Closing secondary files: Session=%p, FileId=%x, FileName=%s\n", primarySession, openFile->OpenFileId, NameBuf )); #endif } } } } } return FALSE; }
/* Attempt to impersonate a client and open a file for the filedisk. */ static VOID STDCALL WvFilediskOpenInThread_(IN OUT WVL_SP_THREAD_ITEM item) { WV_SP_FILEDISK_OPENER_ opener = CONTAINING_RECORD( item, WV_S_FILEDISK_OPENER_, item[0] ); OBJECT_ATTRIBUTES obj_attrs; HANDLE file = NULL; IO_STATUS_BLOCK io_status; FILE_STANDARD_INFORMATION file_info; /* Impersonate the user creating the filedisk. */ opener->status = WvFilediskImpersonate(opener->filedisk->impersonation); if (!NT_SUCCESS(opener->status)) { DBG("Couldn't impersonate!\n"); goto err_impersonate; } /* Open the file. */ InitializeObjectAttributes( &obj_attrs, opener->file_path, OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, NULL, NULL ); /* Open the file. The handle is closed when the thread finishes. */ opener->status = ZwCreateFile( &file, GENERIC_READ | GENERIC_WRITE, &obj_attrs, &io_status, NULL, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ | FILE_SHARE_DELETE | FILE_SHARE_WRITE, FILE_OPEN, FILE_NON_DIRECTORY_FILE | FILE_RANDOM_ACCESS | FILE_NO_INTERMEDIATE_BUFFERING | FILE_SYNCHRONOUS_IO_NONALERT, NULL, 0 ); if (!NT_SUCCESS(opener->status)) { DBG("Couldn't open file!\n"); goto err_open; } /* Determine the disk's size. */ opener->status = ZwQueryInformationFile( file, &io_status, &file_info, sizeof file_info, FileStandardInformation ); if (!NT_SUCCESS(opener->status)) { DBG("Couldn't query file size!\n"); goto err_query_info; } opener->filedisk->disk->LBADiskSize = file_info.EndOfFile.QuadPart / opener->filedisk->disk->SectorSize; /* * A really stupid "hash". RtlHashUnicodeString() would have been * good, but is only available >= Windows XP. */ opener->filedisk->hash = (UINT32) opener->filedisk->disk->LBADiskSize; { PWCHAR path_iterator = opener->file_path->Buffer; while (*path_iterator) opener->filedisk->hash += *path_iterator++; } /* Opened. */ opener->filedisk->file = file; goto out; err_query_info: ZwClose(file); err_open: out: WvFilediskStopImpersonating(); err_impersonate: KeSetEvent(opener->completion, 0, FALSE); return; }