阅读:3523回复:12
请高手看看在RP_MJ_CLOSE增加文件标识的问题(附代码)
代码如下
//增加文件尾部 NTSTATUS sfAddfileCauda(IN PCWSTR FileName, IN UCHAR * KeyBuf, IN ULONG KeyBufLen, IN PVOID AttachedToDeviceObject) { HANDLE FileHandle = NULL; WCHAR RetFileName[MAX_PATH]; OBJECT_ATTRIBUTES ObjectAttributes; UNICODE_STRING ObjectName; //FILE_STANDARD_INFORMATION fileinfo; FILE_END_OF_FILE_INFORMATION fileEOFinfo; LARGE_INTEGER FileEOFPos; IO_STATUS_BLOCK IoStatus; NTSTATUS Status= STATUS_SUCCESS; if (!(FileName && AttachedToDeviceObject)) { KdPrint(("Add!(FileName && AttachedToDeviceObject) Unsuccess\n ")); return STATUS_INSUFFICIENT_RESOURCES;//两相参数验证出其不错 } RetFileName[0] = L'\\'; RetFileName[1] = L'?'; RetFileName[2] = L'?'; RetFileName[3] = L'\\'; RetFileName[4] = L'\0'; wcscat(RetFileName, FileName); if (RetFileName[wcslen(RetFileName) - 1] == L'\\') RetFileName[wcslen(RetFileName) - 1] = L'\0'; RtlInitUnicodeString(&ObjectName, RetFileName); //Arguments: // FileName - \??\x:\xxx\...\xxx.xxx InitializeObjectAttributes(&ObjectAttributes, &ObjectName, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL ); Status = IoCreateFileSpecifyDeviceObjectHint(&FileHandle, GENERIC_WRITE|SYNCHRONIZE|GENERIC_READ, &ObjectAttributes, &IoStatus, NULL, FILE_ATTRIBUTE_NORMAL, 0, FILE_OPEN, FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT | FILE_NO_INTERMEDIATE_BUFFERING, NULL, 0, CreateFileTypeNone, NULL, IO_IGNORE_SHARE_ACCESS_CHECK, AttachedToDeviceObject ); //打开文件 if (NT_SUCCESS(Status)) { FileEOFPos.LowPart = FILE_WRITE_TO_END_OF_FILE; FileEOFPos.HighPart = -1; Status = ZwWriteFile(FileHandle, NULL, NULL, NULL, &IoStatus, (PVOID)KeyBuf, FILEHEADLEN, &FileEOFPos, NULL );//写尾部* KdPrint(("sfWriteEncryptKey : %ws He's cauda is :%s\n Status :%x IoStatus.Status :%x IoStatus.Information :%x \n",FileName,KeyBuf,Status,IoStatus.Status,IoStatus.Information)); //ZwClose(FileHandle);//文件使用结束 if(!(NT_SUCCESS(Status))) { KdPrint(("AddZwWriteFile Unsuccess\n ")); return STATUS_INSUFFICIENT_RESOURCES;//得到文件长度失败 } } else { KdPrint(("AddIoCreateFileSpecifyDeviceObjectHint Unsuccess\n ")); return STATUS_INSUFFICIENT_RESOURCES;//打开文件失败 } return Status; } 我在RP_MJ_CLOSE完程以后调有以上代码 时而可用时而不可以 不能用时是在ZwWriteFile里出的错 返可代码是c0000002STATUS_NOT_IMPLEMENTED 请问大牛们怎么样保证ZwWriteFile被正确运行 万分感谢 |
|
沙发#
发布于:2007-05-15 15:28
IoCreateFileSpecifyDeviceObjectHint只支持XP以上,可以直接发IRP来处理!
|
|
|
板凳#
发布于:2007-05-15 16:02
知道啊
我没有在2k下使用啊 |
|
地板#
发布于:2007-05-15 16:05
我跟踪发现文件过64k就不能成功
我用64k文件加1个字节就不能成功写了 还发现psd文件怎么也写不成功 想问问大牛们psd文件和txt文件本质有什么不同 |
|
地下室#
发布于:2007-05-15 16:22
我又发现 els文件是每次都能成功
txt文件小于64k psd文件什么大小都不行 |
|
5楼#
发布于:2007-05-15 22:03
Quoted from IFS document:
"Callers of ZwWriteFile must be running at IRQL = PASSIVE_LEVEL and with APCs enabled." MJ_CLOSE may be called at APC level where it cannot meet the above requirement. |
|
6楼#
发布于:2007-05-16 09:14
那是不是通过直接发IRP来处理就不会有这些问题呢?
希望devia 和michaelgz 回答 谢谢 |
|
7楼#
发布于:2007-05-16 09:42
cleanup后只能对文件进行paging read/write,所以自己构造irp需要注意这一点。
|
|
8楼#
发布于:2007-05-16 10:41
谢谢tooflat回答
我也不想自己构造irp因为这样比较烦 加上自己水平有限不到没办法真的不想去用 这里还是想问问 我上面写的代码为什么会c0000002STATUS_NOT_IMPLEMENTED 对于是michaelgz 所说的"MJ_CLOSE may be called at APC level where it cannot meet the above requirement" 我对APC不是非常了解我现在正在查有关文件 但我认为关系不大 因为 ZwWriteFile是否成功我文件类型关系很大 doc els比较大的都没问题 txt在64k中比较敏感 psd就没有成功过 在这里谢谢大家的关注 为了将加密标识加上去我还在努力 希望得到更多的帮助 |
|
9楼#
发布于:2007-05-16 11:56
自己发IRP这个最好~
|
|
|
10楼#
发布于:2007-06-12 17:26
NTSTATUS OSR_FILTER_API OsrFilterForwardCreateIrp(OUT PHANDLE FileHandle,
IN ACCESS_MASK DesiredAccess,IN POBJECT_ATTRIBUTES ObjectAttributes, OUT PIO_STATUS_BLOCK IoStatusBlock,IN PLARGE_INTEGER AllocationSize OPTIONAL, IN ULONG FileAttributes,IN ULONG ShareAccess,IN ULONG Disposition,IN ULONG CreateOptions, IN PVOID EaBuffer OPTIONAL,IN ULONG EaLength, IN CREATE_FILE_TYPE CreateFileType,IN PVOID ExtraCreateParameters OPTIONAL, IN ULONG Options,IN PVOID DeviceObject) { NTSTATUS status; #ifdef NT_XP status = IoCreateFileSpecifyDeviceObjectHint(FileHandle, DesiredAccess,ObjectAttributes, IoStatusBlock,AllocationSize, FileAttributes,ShareAccess,Disposition,CreateOptions, EaBuffer,EaLength, CreateFileType,ExtraCreateParameters, Options,DeviceObject); #else // NT_XP UNICODE_STRING QQString = {sizeof(L"??")-sizeof(WCHAR),sizeof(L"??"),L"??"}; UNICODE_STRING DosDevString = {sizeof(L"DosDevices")-sizeof(WCHAR),sizeof(L"DosDevices"),L"DosDevices"}; UNICODE_STRING GlobalString = {sizeof(L"GLOBAL??")-sizeof(WCHAR),sizeof(L"GLOBAL??"),L"GLOBAL??"}; // // Well, the bad news is that this is not WXP or later so we have to implement the // functionality of IoCreateFileSpecifyDeviceObjectHint ourselves. This entails // parsing the input name into a name we can handle and then passing it to the // shadow device object that we created earlier which will forward the Irp to // a FS or Filter below us.. // if(DeviceObject) { UNICODE_STRING newFileName; UNICODE_STRING parsedFileName = {0,0,NULL}; OBJECT_ATTRIBUTES newObjectAttributes; ULONG sizeNeeded = ObjectAttributes->ObjectName->Length + (sizeof(DeviceObject) * (2 * sizeof(WCHAR))); UNICODE_STRING objectName; objectName = *ObjectAttributes->ObjectName; // // Parse the input name. // status = ParseInputName((PDEVICE_OBJECT) DeviceObject,&objectName); if(!NT_SUCCESS(status)) { // // An error occurred, tell the caller. // return status; } // // Determine how much memory we need for the name to be built. // sizeNeeded += sizeof(L"\\Device\\\\") + sizeof(WCHAR); // \Device\xxxxxxxx\....... newFileName.Buffer = (PWSTR) ExAllocatePool(PagedPool,sizeNeeded); if(!newFileName.Buffer) { // // No memory allocated, return the error. // return STATUS_INSUFFICIENT_RESOURCES; } // // Initialize the buffer to hold the name. // RtlZeroMemory(newFileName.Buffer,sizeNeeded); // // Build the appropriate name for the create, so that it goes to our // shadow device object.... // #if !defined(_WIN64) swprintf(newFileName.Buffer,L"\\Device\\%08.8X",(ULONG_PTR) DeviceObject); #else // !defined(_WIN64) swprintf(newFileName.Buffer,L"\\Device\\%016.16X",(ULONG_PTR) DeviceObject); #endif // !defined(_WIN64) wcsncat(newFileName.Buffer,objectName.Buffer,(objectName.Length)/sizeof(WCHAR)); newFileName.Length = (USHORT) wcslen(newFileName.Buffer)*sizeof(WCHAR); newFileName.MaximumLength = (USHORT) sizeNeeded; memcpy(&newObjectAttributes,ObjectAttributes,sizeof(OBJECT_ATTRIBUTES)); newObjectAttributes.ObjectName = &newFileName; #if DBG_NAME DbgPrint("OsrFilterForwardCreateIrp Create: File Name %wZ\n",&newFileName); #endif // // Perform the Create to the Shadow Object. // status = ZwCreateFile(FileHandle,DesiredAccess,&newObjectAttributes,IoStatusBlock, AllocationSize,FileAttributes,ShareAccess,Disposition, CreateOptions,EaBuffer,EaLength); // // Clean up the allocated memory... // ExFreePool(newFileName.Buffer); ExFreePool(objectName.Buffer); } else { // // No Hint specified, just do a normal create which will go to the top // of the stack.... // status = ZwCreateFile(FileHandle,DesiredAccess,ObjectAttributes,IoStatusBlock, AllocationSize,FileAttributes,ShareAccess,Disposition, CreateOptions,EaBuffer,EaLength); } #endif // NT_XP return status; } // // ParsePath // // This routine is an internal routine called to parse the input // file path into its constituent parts... // // Inputs: // PComponentHead - address of a ListHead which will receive the linked // list of PATH_ENTRY structures containing the parts // of the input name. // PPath - Path Name to parse. // // Outputs: // None. // // Returns: // STATUS_SUCCESS if the name is parsed successfully, an error otherwise. // // Notes: // This is only supported in W2K or later. // NTSTATUS ParsePath(PLIST_ENTRY PComponentHead, PUNICODE_STRING PPath) { PATH_ENTRY *pe; NTSTATUS status = STATUS_INSUFFICIENT_RESOURCES; UNICODE_STRING nextComponent; PUNICODE_STRING pNextComponent; UNICODE_STRING remainingName; BOOLEAN bFirstPass = TRUE; remainingName = *PPath; // // Loop through a name parsing it into its path pieces. We do this // using FsRtlDissectName. // while (remainingName.Length > 0) { pNextComponent = &nextComponent; FsRtlDissectName(remainingName, &nextComponent, &remainingName); // // Allocate a PATH_ENTRY structure to hold the dissected part of // the name. // pe = (PPATH_ENTRY) ExAllocatePoolWithTag(PagedPool,sizeof(PATH_ENTRY),'2RSO'); ULONG size = nextComponent.Length+sizeof(WCHAR); // // See if the memory was allocated. If not, cleanup after ourselves. // if(!pe) { EmptyPathList(PComponentHead); return status; } // // Got the memory, initialize it. // RtlZeroMemory(pe,sizeof(PATH_ENTRY)); // // see if this is the first pass through the list. If it is, see if // the name is preceeded by \?? or by \DosDevices. If it is, // we substitue \global?? // if(bFirstPass) { #ifdef NT_XP if(RtlCompareUnicodeString(&QQString,&nextComponent,FALSE) == 0) { pNextComponent = &GlobalString; #else // NT_XP if(RtlCompareUnicodeString(&GlobalString,&nextComponent,FALSE) == 0) { pNextComponent = &QQString; #endif // NT_XP } else if(RtlCompareUnicodeString(&DosDevString,&nextComponent,FALSE) == 0) { #ifdef NT_XP pNextComponent = &GlobalString; #else // NT_XP pNextComponent = &QQString; #endif // NT_XP } bFirstPass = FALSE; } // // Allocate memory for the path. // pe->Path = (PWCHAR) ExAllocatePoolWithTag(PagedPool,pNextComponent->MaximumLength+sizeof(WCHAR),'3RSO'); if(!pe->Path) { // // We failed to allocate memory, cleanup and exit. // ExFreePool(pe); EmptyPathList(PComponentHead); return STATUS_INSUFFICIENT_RESOURCES; } // // Add the part of the parsed name and then continue parsing. // RtlZeroMemory(pe->Path,pNextComponent->MaximumLength+sizeof(WCHAR)); wcsncpy(pe->Path,pNextComponent->Buffer,pNextComponent->Length/sizeof(WCHAR)); InsertTailList(PComponentHead,&pe->ListEntry); } return STATUS_SUCCESS; } // // EmptyPathList // // This routine is an internal routine called to delete all the // entries in a path list. // // Inputs: // PListHead - address of a ListHead which will receive the linked // list of PATH_ENTRY structures containing the parts // of the input name. // // Outputs: // None. // // Returns: // None. // // Notes: // None. // void EmptyPathList(PLIST_ENTRY PListHead) { while(!IsListEmpty(PListHead)) { PPATH_ENTRY pe = (PPATH_ENTRY) RemoveHeadList(PListHead); ExFreePool(pe->Path); ExFreePool(pe); } } #ifndef NT_XP // // AnalyzePath // // This routine is an internal routine called to analyze the input // file path in order to determine if there is a DeviceObject that will // handle the input name. // // Inputs: // PHintDeviceObject - address of the device object that must lie in the // path of the device object which handles this name. // PComponentHead - address of a ListHead which contains the linked // list of PATH_ENTRY structures containing the parts // of the input name. // // Outputs: // PFinalName - address to receive the PFinalName i.e. the part of the // name to be passed to the FS for handling. // // Returns: // STATUS_SUCCESS if the name is parsed successfully, an error otherwise. // // Notes: // This is only supported in W2K or later. // NTSTATUS AnalyzePath(PDEVICE_OBJECT PHintDeviceObject,PLIST_ENTRY PComponentListHead,PWCHAR* PFinalName) { PPATH_ENTRY ppe = (PPATH_ENTRY) PComponentListHead->Flink; PDEVICE_OBJECT pDeviceObject; PFILE_OBJECT pFileObject; ULONG size = 0; ULONG components = 0; PWCHAR pBuffer = NULL; UNICODE_STRING path = { 0, 0, NULL}; NTSTATUS status = STATUS_INSUFFICIENT_RESOURCES; *PFinalName = NULL; // // Figure out the full size of the name that can be built out of the parsed name // parts. // while(TRUE && ((PLIST_ENTRY) ppe != PComponentListHead)) { size += wcslen(ppe->Path)*sizeof(WCHAR); components++; ppe = (PPATH_ENTRY) ppe->ListEntry.Flink; } // // No Size, no problem, just exit with an error. // if(!size) { return STATUS_INSUFFICIENT_RESOURCES; } size += ((1 + components) * sizeof(WCHAR)); // // Allocate a name for the string, if we fail, we // exit. // pBuffer = (PWCHAR) ExAllocatePoolWithTag(PagedPool,size,'4RSO'); if(!pBuffer) { return STATUS_INSUFFICIENT_RESOURCES; } // // Initialize the memory and prepare to rebuild the // name piece by piece looking for a device that corresponds // to the built name. // RtlZeroMemory(pBuffer,size); ppe = (PPATH_ENTRY) PComponentListHead->Flink; components = 0; while((PLIST_ENTRY) ppe != PComponentListHead) { components++; // // Prefix the name piece being built with a '\'. // wcscat(pBuffer,L"\\"); wcscat(pBuffer,ppe->Path); // // Set up the unicode string which represents the // name we will query with. // path.Length = wcslen(pBuffer)*sizeof(WCHAR); path.MaximumLength = path.Length; path.Buffer = pBuffer; // // See if we find a device object which corresponds to the name. // status = IoGetDeviceObjectPointer(&path,FILE_ANY_ACCESS,&pFileObject,&pDeviceObject); // // See if we found a match. // if(NT_SUCCESS(status)) { BOOLEAN bFound = FALSE; PDEVICE_OBJECT pFsObject = NULL; PDEVICE_OBJECT pNextDeviceObject; // // We have a match, see if we can find the Base File System Device // object from the input file object. // pFsObject = IoGetBaseFileSystemDeviceObject(pFileObject); if(!pFsObject) { // // Well this did not work, so exit with an error. // ObDereferenceObject(pFileObject); ExFreePool(pBuffer); return STATUS_OBJECT_NAME_NOT_FOUND; } // // Get the FS Device Object from the VPB in order to start out start our // search. // if(pFsObject->Vpb) { pNextDeviceObject = pFsObject->Vpb->DeviceObject; } else { // // There is no VPB. Let's assume this is a Network device // we have been handed. pNextDeviceObject = pFsObject; } // // Okay, I've found a device object. Let's see if we can find the hint. // while(pNextDeviceObject) { if(pNextDeviceObject == PHintDeviceObject) { bFound = TRUE; break; } pNextDeviceObject = pNextDeviceObject->AttachedDevice; } ObDereferenceObject(pFileObject); if(!bFound) { // // Didn't find the hint, so abort the create.... // ExFreePool(pBuffer); return STATUS_OBJECT_NAME_NOT_FOUND; } // // We found a handler for the input name and we found // the hint device object. Build the left over parts // of the name into the Final Name and return that to // to the caller so that the caller can get it passed // to the handler for this create call. // RtlZeroMemory(pBuffer,size); wcscat(pBuffer,L"\\"); ppe = (PPATH_ENTRY) ppe->ListEntry.Flink; while(TRUE && ((PLIST_ENTRY) ppe != PComponentListHead)) { wcscat(pBuffer,ppe->Path); ppe = (PPATH_ENTRY) ppe->ListEntry.Flink; if((PLIST_ENTRY) ppe != PComponentListHead) { wcscat(pBuffer,L"\\"); } else { break; } } // // Return the handled name and tell the caller how happy we // were to process his function call. // *PFinalName = pBuffer; return status; } // // No handler for the name found, continue appending parts of the name. // ppe = (PPATH_ENTRY) ppe->ListEntry.Flink; } ExFreePool(pBuffer); return status; } // // ParseInputName // // This routine is an internal routine called to Parse the input name. // // Inputs: // PHintDeviceObject - address of the device object that must lie in the // path of the device object which handles this name. // PPathName - path name to parse. // // Outputs: // None. // // Returns: // STATUS_SUCCESS if the name is parsed successfully, an error otherwise. // // Notes: // This is only supported in W2K or later. // NTSTATUS ParseInputName(PDEVICE_OBJECT HintDeviceObject,PUNICODE_STRING PPathName) { PWCHAR pBuffer = NULL; ULONG tokenCount = 0; LIST_ENTRY ComponentListHead; NTSTATUS status; PWCHAR pFinalName = NULL; if(!PPathName) { return STATUS_OBJECT_NAME_NOT_FOUND; } if(!PPathName->Buffer) { return STATUS_OBJECT_NAME_NOT_FOUND; } // // Initialize the ListHead which will contain the parsed name parts. // InitializeListHead(&ComponentListHead); // // Parse the input name into the name parts. // status = ParsePath(&ComponentListHead,PPathName); if(!NT_SUCCESS(status)) { ExFreePool(pBuffer); return status; } // // Analyze the components of the name.... // status = AnalyzePath(HintDeviceObject,&ComponentListHead,&pFinalName); if(NT_SUCCESS(status)) { // // Set up the new path name we are going to use.... // PPathName->Buffer = pFinalName; PPathName->Length = wcslen(pFinalName)*sizeof(WCHAR); PPathName->MaximumLength = PPathName->Length; } // // Clean up the components of the name.... // EmptyPathList(&ComponentListHead); // // Tell them how happy we are. // return status; } NTSTATUS GetFullPathName(PFILE_OBJECT PFileObject,PUNICODE_STRING PNameString) { PFILE_OBJECT relatedFileObject; ULONG pathLen; PWCHAR pathOffset; NTSTATUS status = STATUS_OBJECT_NAME_NOT_FOUND; PNameString->Length = 0; PNameString->MaximumLength = 0; PNameString->Buffer = 0; // // Do this in an exception handling block, in case of mangled names in the // file object // __try { // // Now, create the full path name. First, calculate the length taking into // account space for seperators and the leading drive letter plus ':' // pathLen = PFileObject->FileName.Length; relatedFileObject = PFileObject->RelatedFileObject; // // Only look at related file object if this is a relative name // if( PFileObject->FileName.Length && PFileObject->FileName.Buffer[0] != L'\\' ) { while( relatedFileObject ) { pathLen += relatedFileObject->FileName.Length; if((relatedFileObject->FileName.Length) && (relatedFileObject->FileName.Buffer[(relatedFileObject->FileName.Length/sizeof(WCHAR))-1] != L'\\')) { pathLen += sizeof(WCHAR); } relatedFileObject = relatedFileObject->RelatedFileObject; } } PWCHAR pBuffer = (PWCHAR) ExAllocatePoolWithTag(PagedPool,pathLen,'nRSO'); if(!pBuffer) { return STATUS_INSUFFICIENT_RESOURCES; } RtlZeroMemory(pBuffer,pathLen); PNameString->Buffer = pBuffer; PNameString->MaximumLength = (USHORT) pathLen; PNameString->Length = (USHORT) pathLen; // // If there is no deviceInfo, it means that it is a network drive. // //sprintf( fullPathName, L"\\." ); // // Now, start at the end and work back to the beginning of the path // pathOffset = (PWCHAR) ((PUCHAR) pBuffer + pathLen - PFileObject->FileName.Length); wcsncpy( pathOffset, PFileObject->FileName.Buffer, PFileObject->FileName.Length/sizeof(WCHAR) ); relatedFileObject = PFileObject->RelatedFileObject; if( PFileObject->FileName.Buffer[0] != L'\\' ) { while( relatedFileObject ) { if((relatedFileObject->FileName.Length) && (relatedFileObject->FileName.Buffer[(relatedFileObject->FileName.Length/sizeof(WCHAR))-1] != L'\\')) { *(pathOffset - 1) = L'\\'; pathOffset = (PWCHAR) ((PUCHAR) pathOffset - (relatedFileObject->FileName.Length + sizeof(WCHAR))); } else { pathOffset = (PWCHAR) ((PUCHAR) pathOffset - (relatedFileObject->FileName.Length)); } wcsncpy( pathOffset, relatedFileObject->FileName.Buffer, relatedFileObject->FileName.Length/sizeof(WCHAR) ); relatedFileObject = relatedFileObject->RelatedFileObject; } } // // If we added two '\' to the front because there was a relative file object // that specified the root directory, remove one // // if( pathLen > 3 && fullPathName[2] == '\\' && fullPathName[3] == '\\' ) { // strcpy( fullPathName + 2, fullPathName + 3 ); // } status = STATUS_SUCCESS; } __except( EXCEPTION_EXECUTE_HANDLER ) { } return status; } // // SendCreateIrpBelowOurFilter // // This routine is an internal routine called to Send the input IRP // to the specified device object. // // Inputs: // DeviceObject - address of the device object that will receive the input // irp. // Irp - irp to send // // Outputs: // None. // // Returns: // returns whatever IoCallDriver returns. // // Notes: // This is only supported in XP or later. // NTSTATUS SendCreateIrpBelowOurFilter(PDEVICE_OBJECT DeviceObject,PIRP Irp) { NTSTATUS status = STATUS_UNSUCCESSFUL; PIO_STACK_LOCATION currentStackLocation = IoGetCurrentIrpStackLocation(Irp); PIO_STACK_LOCATION nextStackLocation = IoGetNextIrpStackLocation(Irp); POSR_FILTER_EXT shadowExt = (POSR_FILTER_EXT) DeviceObject->DeviceExtension; PFILE_OBJECT pFileObject = currentStackLocation->FileObject; (void) GetExtension(DeviceObject, &shadowExt); OsrAssert(shadowExt); OsrAssert(shadowExt->ShadowedDeviceObject); // // Set up the Irp to be sent down to the filtered Device Object.... // IoCopyCurrentIrpStackLocationToNext(Irp); nextStackLocation->DeviceObject = shadowExt->FilteredDeviceObject; // // Send it below..... // status = IoCallDriver(shadowExt->FilteredDeviceObject,Irp); // // Release the extension // DereferenceExtension(shadowExt, __LINE__); return status; } #endif // NT_XP |
|
11楼#
发布于:2007-06-13 18:20
IoCreateFileSpecifyDeviceObjectHint得到的handle除了ZwClose以外其他的Zw×××是不能使用这个handle的。你需要自己构建IRP去读写的
|
|
12楼#
发布于:2007-06-15 17:42
我在IRP_MJ_CLEANUP中构造IRP也会出现像你这样的问题,返回0xC0000002,只有在flag设为IRP_NOCACHE才会出现,当设为0时就会成功!!
|
|