text: #include "Misc.h"
  
  #ifdef __MISC_USE_KHEAP
   KHEAP               hKHeapMiscDefault = NULL;
  #endif //__MISC_USE_KHEAP
  
  //
  // Функции для работы с памятью
  //
  
  BOOLEAN AllocateSharedMemory(PSHARED_MEMORY lpSharedMemory, POOL_TYPE PoolType, ULONG dwSizeRegion)
  {
    if (!_MmIsAddressValid(lpSharedMemory))
      return FALSE;
    if (!dwSizeRegion)
      return FALSE;
  
    memset(lpSharedMemory, 0, sizeof(SHARED_MEMORY));
  
    #ifndef __MISC_USE_KHEAP
    lpSharedMemory->m_lpKernelMemory = ExAllocatePool(PoolType, dwSizeRegion);
    #else
    lpSharedMemory->m_lpKernelMemory = (CHAR*) _AllocatePoolFromKHeap(hKHeapMiscDefault, dwSizeRegion);
    #endif //!__MISC_USE_KHEAP
    if (!lpSharedMemory->m_lpKernelMemory)
      return FALSE;
  
    lpSharedMemory->m_Mdl = IoAllocateMdl(lpSharedMemory->m_lpKernelMemory, dwSizeRegion, FALSE, FALSE, NULL);
    if (!lpSharedMemory->m_Mdl)
    {
      #ifndef __MISC_USE_KHEAP
      ExFreePool(lpSharedMemory->m_lpKernelMemory);
      #else
      FreePoolToKHeap(hKHeapMiscDefault, lpSharedMemory->m_lpKernelMemory);
      #endif //!__MISC_USE_KHEAP
      memset(lpSharedMemory, 0, sizeof(SHARED_MEMORY));
      return FALSE;
    }
  
    MmBuildMdlForNonPagedPool(lpSharedMemory->m_Mdl);
  
    lpSharedMemory->m_lpUserPage = MmMapLockedPages(lpSharedMemory->m_Mdl, UserMode);
    lpSharedMemory->m_lpUserMemory = (PVOID) (((ULONG)PAGE_ALIGN(lpSharedMemory->m_lpUserPage))+MmGetMdlByteOffset(lpSharedMemory->m_Mdl));
    if (!_MmIsAddressValid(lpSharedMemory->m_lpUserMemory))
    {
      MmUnmapLockedPages(lpSharedMemory->m_lpUserPage, lpSharedMemory->m_Mdl);
      IoFreeMdl(lpSharedMemory->m_Mdl);
      #ifndef __MISC_USE_KHEAP
      ExFreePool(lpSharedMemory->m_lpKernelMemory);
      #else
      FreePoolToKHeap(hKHeapMiscDefault, lpSharedMemory->m_lpKernelMemory);
      #endif //!__MISC_USE_KHEAP
      memset(lpSharedMemory, 0, sizeof(SHARED_MEMORY));
      return FALSE;
    }
    lpSharedMemory->m_dwSizeRegion = dwSizeRegion;
  
    return TRUE;
  }
  
  BOOLEAN FreeSharedMemory(PSHARED_MEMORY lpSharedMemory)
  {
    if (!_MmIsAddressValid(lpSharedMemory))
      return FALSE;
    if (!_MmIsAddressValid(lpSharedMemory->m_lpUserMemory))
      return FALSE;
    if (!_MmIsAddressValid(lpSharedMemory->m_lpKernelMemory))
      return FALSE;
  
    MmUnmapLockedPages(lpSharedMemory->m_lpUserPage, lpSharedMemory->m_Mdl);
    IoFreeMdl(lpSharedMemory->m_Mdl);
    #ifndef __MISC_USE_KHEAP
    ExFreePool(lpSharedMemory->m_lpKernelMemory);
    #else
    FreePoolToKHeap(hKHeapMiscDefault, lpSharedMemory->m_lpKernelMemory);
    #endif //!__MISC_USE_KHEAP
    memset(lpSharedMemory, 0, sizeof(SHARED_MEMORY));
  
    return TRUE;
  }
  
  PVOID
  MapUserAddressToKernel(
     IN PVOID pUserModeAddress,
     IN ULONG ulSize,
     OUT PMDL* ppMdl
     )
  {
   PMDL  pUserModeMdl = NULL;
   PVOID pMappedKernelAddr = NULL;
  
   if (ppMdl == NULL)
     return NULL;
  
   __try
   {
     pUserModeMdl = IoAllocateMdl(pUserModeAddress, ulSize, FALSE, FALSE, NULL);
     if (pUserModeMdl != NULL)
     {
       MmProbeAndLockPages(pUserModeMdl, KernelMode, IoModifyAccess);
       pMappedKernelAddr = MmMapLockedPages(pUserModeMdl, KernelMode);  
       if (pMappedKernelAddr != NULL)
       {
         pMappedKernelAddr = (PVOID) (((ULONG)PAGE_ALIGN(pMappedKernelAddr))+MmGetMdlByteOffset(pUserModeMdl));
         *ppMdl = pUserModeMdl;
       }
       else
       {
         UnmapMappedKernelAddress(pUserModeMdl);
       }
     }
   }
   __except(EXCEPTION_EXECUTE_HANDLER)
   {
     if (pUserModeMdl != NULL)
       IoFreeMdl(pUserModeMdl);
     pMappedKernelAddr = NULL;
   }
    
   return pMappedKernelAddr;
  }
  
  
  VOID
  UnmapMappedKernelAddress(
     IN PMDL pMdl
     )
  {
    if (pMdl == NULL)
      return;
  
    MmUnlockPages(pMdl);
    IoFreeMdl(pMdl);
  }
  
  BOOLEAN IsBadWritePtr(PVOID Address, ULONG Length, ULONG Alignment)
  {
    __try
    {
      ProbeForWrite(Address, Length, Alignment);
    }
    __except(EXCEPTION_EXECUTE_HANDLER)
    {
      return TRUE;
    }
    return FALSE;
  }
  
  BOOLEAN _MmIsAddressValid(PVOID Address)
  {
    if (!Address)
      return FALSE;
    return MmIsAddressValid(Address);
  }
  
  //
  // функции для работы с объектами ядра
  //
  
  //----------------------------------------------------------------------
  //
  // GetPointer
  //
  // Translates a handle to an object pointer.
  //
  //----------------------------------------------------------------------
  POBJECT GetPointer(HANDLE handle)
  {
    POBJECT         pKey;
    NTSTATUS        NtStatus;
  
    //
    // Ignore null handles
    //
    if (!handle && KeGetCurrentIrql() != PASSIVE_LEVEL)
      return NULL;
  
    //
    // Get the pointer the handle refers to
    //
    NtStatus = ObReferenceObjectByHandle(handle, 0, NULL, KernelMode, &pKey, NULL);
    if (NtStatus != STATUS_SUCCESS)
    {
      DbgPrintMisc(("He4hookInv: GetPointer: Error %08x getting key pointer\n", NtStatus));
      pKey = NULL;
    } 
  
    return pKey;
  }
  
  
  //----------------------------------------------------------------------
  //
  // ReleasePointer
  //
  // Dereferences the object.
  //
  //----------------------------------------------------------------------
  VOID ReleasePointer(POBJECT object)
  {
    if (object && KeGetCurrentIrql() == PASSIVE_LEVEL)
      ObDereferenceObject(object);
  }
  
  ULONG GetObjectName(HANDLE hObject, PWSTR lpwszName, ULONG dwSize)
  {
    CHAR                   *tmpname;//[0x400];
    PUNICODE_STRING         fullUniName;
    NTSTATUS                NtStatus;
    ULONG                   dwObjectNameLen = 0; //(by bytes)
  
    DbgPrintMisc(("He4hookInv: GetObjectName started!!!!!!!\n"));
  
    if (!lpwszName || !dwSize || KeGetCurrentIrql() > PASSIVE_LEVEL)
      return 0;
  
    //
    // Translate the hkey into a pointer
    //
    lpwszName[0] = 0;
  
    #ifndef __MISC_USE_KHEAP
    tmpname = (CHAR*) ExAllocatePool(NonPagedPool, dwSize+sizeof(UNICODE_STRING));
    #else
    tmpname = (CHAR*) _AllocatePoolFromKHeap(hKHeapMiscDefault, dwSize+sizeof(UNICODE_STRING));
    #endif //!__MISC_USE_KHEAP
    if (!_MmIsAddressValid(tmpname))
      return 0;
    tmpname[0] = 0;
  
    NtStatus = ZwQueryObject(hObject, NameObjectInfo, tmpname, dwSize+sizeof(UNICODE_STRING), NULL);
  
    if (NT_SUCCESS(NtStatus))
    {
      fullUniName = &(((PNAME_OBJECT_INFO)tmpname)->Name);
      dwObjectNameLen = fullUniName->Length;
      if (dwSize < (sizeof(WCHAR)+dwObjectNameLen))
      {
        DbgPrintMisc(("He4hookInv: GetObjectName ended - ERROR!!!!!!!\n"));
        #ifndef __MISC_USE_KHEAP
        ExFreePool(tmpname);
        #else
        FreePoolToKHeap(hKHeapMiscDefault, tmpname);
        #endif //!__MISC_USE_KHEAP
        return 0;
      }
  //    memset(lpwszName, 0, (sizeof(WCHAR)+fullUniName->Length));
      memcpy(lpwszName, fullUniName->Buffer, dwObjectNameLen);
      lpwszName[dwObjectNameLen/sizeof(WCHAR)] = 0;
    }
  
    #ifndef __MISC_USE_KHEAP
    ExFreePool(tmpname);
    #else
    FreePoolToKHeap(hKHeapMiscDefault, tmpname);
    #endif //!__MISC_USE_KHEAP
  
    DbgPrintMisc(("He4hookInv: GetObjectName ended - OK!!!!!!!\n"));
  
    return dwObjectNameLen; 
  }
  
  ULONG GetObjectNameByObjectAttributes(POBJECT_ATTRIBUTES ObjectAttributes, PWSTR fullPathName, ULONG nfullPathNameSize)
  {
    ULONG                   dwDirSize, dwNtPathNameLen;
    int                     nObjectNameLen = 0;
    PWSTR                   DosPathName;
    NTSTATUS                NtStatus;
    PWSTR                   pwszObjectName = NULL;
  
    if (
        !_MmIsAddressValid(ObjectAttributes) ||
        !_MmIsAddressValid(fullPathName)     ||
        !nfullPathNameSize
       )
      return 0;
  
    fullPathName[0] = 0;
    dwDirSize = 0;
  
    if (_MmIsAddressValid(ObjectAttributes->ObjectName))
    {
      if (ObjectAttributes->ObjectName->Length != 0)
      {
        if (_MmIsAddressValid(ObjectAttributes->ObjectName->Buffer))
        {
          pwszObjectName = ObjectAttributes->ObjectName->Buffer;
          nObjectNameLen = ObjectAttributes->ObjectName->Length;
        }
      }
    }
  
    #ifndef __MISC_USE_KHEAP
    DosPathName = (PWSTR) ExAllocatePool(NonPagedPool, nfullPathNameSize);
    #else
    DosPathName = (PWSTR) _AllocatePoolFromKHeap(hKHeapMiscDefault, nfullPathNameSize);
    #endif //!__MISC_USE_KHEAP
  //  DosPathName = (PWSTR)_AllocatePoolFromKHeap(hKHeapFSDefault, nfullPathNameSize);
    if (DosPathName == NULL)
      return 0;
  
    DosPathName[0] = 0;
  
    DbgPrintMisc(("  GetFileNameByObjectAttributes: Attributes => %08x !!!\n", ObjectAttributes->Attributes));
  
    if (ObjectAttributes->RootDirectory)
    {
      dwDirSize = GetObjectName(ObjectAttributes->RootDirectory, DosPathName, nfullPathNameSize);
    }
  
    if (dwDirSize > 3 && pwszObjectName != NULL)
    {
      if (
          DosPathName[(dwDirSize/sizeof(WCHAR))-1] == L'\\' &&
          (pwszObjectName[0] == L'\\' || pwszObjectName[0] == L'/')
         )
      {
        DosPathName[(dwDirSize/sizeof(WCHAR))-1] = 0;
        dwDirSize -= sizeof(WCHAR);
      }
      else
      {
        if (
            DosPathName[(dwDirSize/sizeof(WCHAR))-1] != L'\\' &&
            (pwszObjectName[0] != L'\\' || pwszObjectName[0] != L'/')
           )
        {
          if (dwDirSize <= (nfullPathNameSize-2*sizeof(WCHAR)))
          {
            DosPathName[(dwDirSize/sizeof(WCHAR))] = L'\\';
            DosPathName[(dwDirSize/sizeof(WCHAR))+1] = 0;
            dwDirSize += sizeof(WCHAR);
          }
        }
      }
    }
  
    if (pwszObjectName != NULL)
    {
      if (nfullPathNameSize > (nObjectNameLen+dwDirSize))
      {
        memcpy(((PCHAR)DosPathName+dwDirSize), pwszObjectName, nObjectNameLen);
        ((PWSTR)((PCHAR)DosPathName+dwDirSize))[nObjectNameLen/sizeof(WCHAR)] = 0;
      }
    }
  
    dwNtPathNameLen = DosPathNameToNtPathName(DosPathName, fullPathName, nfullPathNameSize, 255, NULL);
  
    #ifndef __MISC_USE_KHEAP
    ExFreePool(DosPathName);
    #else
    FreePoolToKHeap(hKHeapMiscDefault, DosPathName);
    #endif //!__MISC_USE_KHEAP
    //FreePoolToKHeap(hKHeapFSDefault, DosPathName);
  
    return dwNtPathNameLen;
  }
  
  ULONG GetObjectNameByFileObject(PFILE_OBJECT fileObject, PWSTR fullPathName, ULONG nfullPathNameSize)
  {
    ULONG               pathLen, dwVolumeLen;
    PWSTR               pathOffset;
    PFILE_OBJECT        relatedFileObject;
  //  ANSI_STRING         componentName;
    PDEVICE_OBJECT      pDeviceObject;
    PUNICODE_STRING     fullUniName;
    UNICODE_STRING      FileNameUnicodeString;
    ULONG               dwFreeSize = nfullPathNameSize;
    ULONG               dwFullPathLen = 0;
  
    if (
        KeGetCurrentIrql() > PASSIVE_LEVEL ||
        !_MmIsAddressValid(fileObject) ||
        !_MmIsAddressValid(fullPathName)     ||
        !fileObject
       )
      return 0;
  
    fullPathName[0] = 0;
    dwVolumeLen = 0;
  
    __try
    {
      pDeviceObject = GetVolumeDeviceObject(fileObject);
      if (pDeviceObject == NULL)
      {
        pDeviceObject = IoGetRelatedDeviceObject(fileObject);
      }
  
      fullUniName = (PUNICODE_STRING)fullPathName;
      fullUniName->MaximumLength = (USHORT)(nfullPathNameSize*sizeof(WCHAR) - sizeof(UNICODE_STRING));
  
      if (NT_SUCCESS(ObQueryNameString(pDeviceObject, (POBJECT_NAME_INFORMATION)fullUniName, fullUniName->MaximumLength, &pathLen)))
      {
        dwVolumeLen = fullUniName->Length;
        memmove(fullPathName, fullUniName->Buffer, dwVolumeLen);
        fullPathName[dwVolumeLen/sizeof(WCHAR)] = 0;
      }
      else
      {
        return 0;
      }
  
  //    strcat(fullPathName, "\\");
      dwFreeSize -= dwVolumeLen;
  
      if (!fileObject->FileName.Length || fileObject->FileName.Length > dwFreeSize)
      {
  //      RtlInitUnicodeString(&FileNameUnicodeString, fullPathName);
  //      RtlUnicodeStringToAnsiString( &componentName, &FileNameUnicodeString, TRUE );    
  //      DbgPrint ("%s\n", componentName.Buffer);
  //      RtlFreeAnsiString( &componentName );
  
        return wcslen(fullPathName)*sizeof(WCHAR);
      }
  
    }
    __except(EXCEPTION_EXECUTE_HANDLER)
    {
      return 0;
    }
  
    __try
    {
      pathLen = fileObject->FileName.Length/sizeof(WCHAR) + 1;
  
      relatedFileObject = fileObject->RelatedFileObject;
    
      if (fileObject->FileName.Buffer[0] != L'\\' )
      {
        while (relatedFileObject)
        {
          if ((pathLen + relatedFileObject->FileName.Length/sizeof(WCHAR) + 1) >= dwFreeSize)
          {
            break;
          }
          pathLen += relatedFileObject->FileName.Length/sizeof(WCHAR) + 1;
          relatedFileObject = relatedFileObject->RelatedFileObject;
        }
      }
  
      if (dwFreeSize == nfullPathNameSize)
        wcscpy(fullPathName, L"\\");
    
      pathOffset = fullPathName + dwVolumeLen/sizeof(WCHAR) - 1 + pathLen - fileObject->FileName.Length/sizeof(WCHAR);
      memcpy(pathOffset, fileObject->FileName.Buffer, fileObject->FileName.Length);
      pathOffset[fileObject->FileName.Length/sizeof(WCHAR)] = 0;
  
      relatedFileObject = fileObject->RelatedFileObject;
    
      if (fileObject->FileName.Buffer[0] != L'\\')
      {
        while (relatedFileObject)
        {
          *(pathOffset - 1) = L'\\';
          pathOffset -= relatedFileObject->FileName.Length/sizeof(WCHAR) + 1;
  
          if (pathOffset <= fullPathName)
          {
            break;
          }
          memcpy(pathOffset, relatedFileObject->FileName.Buffer, relatedFileObject->FileName.Length);
  
          relatedFileObject = relatedFileObject->RelatedFileObject;
        }
      }  
  
      dwFullPathLen = wcslen(fullPathName)*sizeof(WCHAR);
  
  //    if (fullPathName[dwVolumeLen/sizeof(WCHAR)] == L'\\' && fullPathName[dwVolumeLen/sizeof(WCHAR)+1] == L'\\')
  //    {
  //      memmove(&fullPathName[dwVolumeLen/sizeof(WCHAR)], &fullPathName[dwVolumeLen/sizeof(WCHAR)+1], pathLen*sizeof(WCHAR));
  //    }
  
      pathOffset = wcsstr(fullPathName, L"\\\\");
      while (pathOffset)
      {
        memmove(pathOffset, &pathOffset[1], wcslen(pathOffset)*sizeof(WCHAR));
        pathOffset = wcsstr(pathOffset, L"\\\\");
      }
  
  //    RtlInitUnicodeString(&FileNameUnicodeString, fullPathName);
  //    RtlUnicodeStringToAnsiString( &componentName, &FileNameUnicodeString, TRUE );    
  //    DbgPrint ("%s\n", componentName.Buffer);
  //    RtlFreeAnsiString( &componentName );
  
    }
    __except(EXCEPTION_EXECUTE_HANDLER)
    {
      DbgPrintMisc(("GetFullPath: EXCEPTION\n"));
    }
  
    return dwFullPathLen;
  }
  
  PVOID GetObjectByPath(PWSTR pwszObjectName, PVOID pObjectType)
  {
    PVOID              pObject = NULL;
    UNICODE_STRING     DeviceName;
    NTSTATUS           NtStatus = 0;
  //  ANSI_STRING        FileNameAnsi;
  
    if (!pwszObjectName || KeGetCurrentIrql() > PASSIVE_LEVEL)
      return pObject;
  
  
    RtlInitUnicodeString(&DeviceName, pwszObjectName);
  
  //  RtlUnicodeStringToAnsiString(&FileNameAnsi, &DeviceName, TRUE);
  //  if (strlen(FileNameAnsi.Buffer))
  //    DbgPrint ("%s\n", FileNameAnsi.Buffer);
  //  RtlFreeAnsiString(&FileNameAnsi);
  
  
    __try
    {
      NtStatus = ObReferenceObjectByName(&DeviceName, OBJ_CASE_INSENSITIVE, NULL, 0, (POBJECT_TYPE)pObjectType, KernelMode, NULL, (PVOID*)&pObject);
    }
    __except(EXCEPTION_EXECUTE_HANDLER)
    {
      NtStatus = STATUS_ACCESS_VIOLATION;
  //    DbgPrint ("EXCEPTION into ObReferenceObjectByName\n");
    }
  //NTSYSAPI
  //NTSTATUS
  //NTAPI
  //ObReferenceObjectByName(
  //    IN PUNICODE_STRING ObjectPath,
  //    IN ULONG Attributes,
  //    IN PACCESS_STATE PassedAccessState OPTIONAL,
  //    IN ACCESS_MASK DesiredAccess OPTIONAL,
  //    IN POBJECT_TYPE ObjectType,
  //    IN KPROCESSOR_MODE AccessMode,
  //    IN OUT PVOID ParseContext OPTIONAL,
  //    OUT PVOID *ObjectPtr
  //    );  
    if (NT_SUCCESS(NtStatus))
    {
      ObDereferenceObject((PVOID)pObject);
    }
  //  DbgPrint ("He4HookInv: GetObjectByPath: pObject = %08X!!!\n", pObject);
  
    return pObject;
  }
  
  POBJECT_NAME GetNameOfObject(PVOID pObject)
  {
    POBJECT_NAME    pObjectName = NULL;
    POBJECT_HEADER  pObjectHdr;
  
    if (_MmIsAddressValid(pObject))
    {
      pObjectHdr = (POBJECT_HEADER) ((PBYTE)pObject - SIZE_OF_OBJECT_HEADER);
      if (_MmIsAddressValid(pObjectHdr))
      {
        if (pObjectHdr->SubHeaderInfo.NameOffset != 0)
        {
          pObjectName = (POBJECT_NAME) ((PBYTE)pObjectHdr - pObjectHdr->SubHeaderInfo.NameOffset);
        }
      }
    }
  
    return pObjectName;
  }
  
  //
  // функции для работы с объектами файловых систем
  //
  
  BOOLEAN GetFileNameNative(HANDLE hObject, PWSTR lpwszName, ULONG dwSize)
  {
    PFILE_OBJECT     pFileObject;
    PDEVICE_OBJECT   pDeviceObject;
    BOOLEAN          bRes = FALSE;
    PFILE_NAME_INFORMATION FileName;
  
    FileName = (PFILE_NAME_INFORMATION) ExAllocatePool(NonPagedPool, 2*dwSize);
    if (!_MmIsAddressValid(FileName))
      return bRes;
  
    pFileObject = (PFILE_OBJECT) GetPointer(hObject);
    if (_MmIsAddressValid(pFileObject))
    {
      pDeviceObject = IoGetRelatedDeviceObject(pFileObject);
      if (_MmIsAddressValid(pDeviceObject))
      {
        bRes = FilemonQueryFileName(pDeviceObject, pFileObject, FileName, dwSize);
        if (bRes)
        {
          memset(lpwszName, 0, dwSize);
          memcpy(lpwszName, FileName->FileName, FileName->FileNameLength);
        }
      }
      ReleasePointer((POBJECT)pFileObject);
    }
  
    ExFreePool(FileName);
  
    return bRes;
  }
  
  NTSTATUS FilemonQueryFileNameComplete(PDEVICE_OBJECT DeviceObject,
                                        PIRP Irp,
                                        PVOID Context)
  {
    //
    // Copy the status information back into the "user" IOSB.
    //
    *Irp->UserIosb = Irp->IoStatus;
  
  //  if( !NT_SUCCESS(Irp->IoStatus.Status) ) {
  //
  //      DbgPrint(("   ERROR ON IRP: %x\n", Irp->IoStatus.Status ));
  //  }
    
    //
    // Set the user event - wakes up the mainline code doing this.
    //
    KeSetEvent(Irp->UserEvent, 0, FALSE);
    
    //
    // Free the IRP now that we are done with it.
    //
    IoFreeIrp(Irp);
    
    //
    // We return STATUS_MORE_PROCESSING_REQUIRED because this "magic" return value
    // tells the I/O Manager that additional processing will be done by this driver
    // to the IRP - in fact, it might (as it is in this case) already BE done - and
    // the IRP cannot be completed.
    //
    return STATUS_MORE_PROCESSING_REQUIRED;
  }
  
  
  //----------------------------------------------------------------------
  //
  // FilemonQueryFileName
  //
  // This function retrieves the "standard" information for the
  // underlying file system, asking for the filename in particular.
  //
  //----------------------------------------------------------------------
  BOOLEAN FilemonQueryFileName(PDEVICE_OBJECT DeviceObject, 
                               PFILE_OBJECT FileObject,
                               PFILE_NAME_INFORMATION FileName, ULONG FileNameLength)
  {
    PIRP irp;
    KEVENT event;
    IO_STATUS_BLOCK IoStatusBlock;
    PIO_STACK_LOCATION ioStackLocation;
  
  //  DbgPrint(("Getting file name for %x\n", FileObject));
  
    //
    // Initialize the event
    //
    KeInitializeEvent(&event, SynchronizationEvent, FALSE);
  
    //
    // Allocate an irp for this request.  This could also come from a 
    // private pool, for instance.
    //
    irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
  
    if (!irp)
    {
      //
      // Failure!
      //
      return FALSE;
    }
    
    //
    // Build the IRP's main body
    //  
    irp->AssociatedIrp.SystemBuffer = FileName;
    irp->UserEvent = &event;
    irp->UserIosb = &IoStatusBlock;
    irp->Tail.Overlay.Thread = PsGetCurrentThread();
    irp->Tail.Overlay.OriginalFileObject = FileObject;
    irp->RequestorMode = KernelMode;
    irp->Flags = 0;
  
    //
    // Set up the I/O stack location.
    //
    ioStackLocation = IoGetNextIrpStackLocation(irp);
    ioStackLocation->MajorFunction = IRP_MJ_QUERY_INFORMATION;
    ioStackLocation->DeviceObject = DeviceObject;
    ioStackLocation->FileObject = FileObject;
    ioStackLocation->Parameters.QueryFile.Length = FileNameLength;
    ioStackLocation->Parameters.QueryFile.FileInformationClass = FileNameInformation;
  
    //
    // Set the completion routine.
    //
    IoSetCompletionRoutine(irp, FilemonQueryFileNameComplete, 0, TRUE, TRUE, TRUE);
  
    //
    // Send it to the FSD
    //
    (void) IoCallDriver(DeviceObject, irp);
  
    //
    // Wait for the I/O
    //
    KeWaitForSingleObject(&event, Executive, KernelMode, TRUE, 0);
  
    //
    // Done! Note that since our completion routine frees the IRP we cannot 
    // touch the IRP now.
    //
    return NT_SUCCESS( IoStatusBlock.Status );
  }
  
  NTSTATUS
  NativeQueryDirectoryFileComplete(
     PDEVICE_OBJECT DeviceObject,
     PIRP Irp,
     PVOID Context
     )
  {
    *Irp->UserIosb = Irp->IoStatus;
  
    KeSetEvent(Irp->UserEvent, 0, FALSE);
    
    IoFreeIrp(Irp);
    
    return STATUS_MORE_PROCESSING_REQUIRED;
  }
  
  NTSTATUS
  NativeQueryDirectoryFile(
     PDRIVER_DISPATCH pMajorFunction,
     PDEVICE_OBJECT pDeviceObject,
     PFILE_OBJECT pFileObject,
     PIO_STATUS_BLOCK pIoStatusBlock,
     PVOID Buffer,
     ULONG BufferLength,
     FILE_INFORMATION_CLASS DirectoryInfoClass,
     BOOLEAN ByOne,
     PUNICODE_STRING pSearchTemplate,
     BOOLEAN Reset,
     BOOLEAN Index,
     ULONG dwIndex
     )
  {
    PIRP irp;
    KEVENT event;
    PIO_STACK_LOCATION ioStackLocation;
    PQUERY_DIRECTORY pQueryDir;
  
    KeInitializeEvent(&event, SynchronizationEvent, FALSE);
  
    irp = IoAllocateIrp(pDeviceObject->StackSize, FALSE);
    if (!irp)
      return STATUS_NO_MEMORY;
  
    irp->MdlAddress = NULL;
    irp->UserBuffer = Buffer;
    irp->AssociatedIrp.SystemBuffer = Buffer;
    irp->UserEvent = &event;
    irp->UserIosb = pIoStatusBlock;
    irp->Tail.Overlay.Thread = PsGetCurrentThread();
    irp->Tail.Overlay.OriginalFileObject = pFileObject;
    irp->RequestorMode = KernelMode;
    irp->Flags = 0;
  
    ioStackLocation = IoGetNextIrpStackLocation(irp);
    ioStackLocation->MajorFunction = IRP_MJ_DIRECTORY_CONTROL;
    ioStackLocation->MinorFunction = IRP_MN_QUERY_DIRECTORY;
    ioStackLocation->DeviceObject = pDeviceObject;
    ioStackLocation->FileObject = pFileObject;
    ioStackLocation->Flags = 0;
    if (ByOne)
      ioStackLocation->Flags |= SL_RETURN_SINGLE_ENTRY;
    if (Reset)
      ioStackLocation->Flags |= SL_RESTART_SCAN;
    if (Index)
      ioStackLocation->Flags |= SL_INDEX_SPECIFIED;
  
    pQueryDir = (PQUERY_DIRECTORY)&ioStackLocation->Parameters;
    pQueryDir->Length = BufferLength;
    pQueryDir->FileName = pSearchTemplate;
    pQueryDir->FileInformationClass = DirectoryInfoClass;
    pQueryDir->FileIndex = dwIndex;
  
    IoSetCompletionRoutine(irp, NativeQueryDirectoryFileComplete, 0, TRUE, TRUE, TRUE);
  
    if (pMajorFunction == NULL)
    {
      (void) IoCallDriver(pDeviceObject, irp);
    }
    else
    {
      --(irp->CurrentLocation);
      if (irp->CurrentLocation <= 0)
      {
        KeBugCheckEx(NO_MORE_IRP_STACK_LOCATIONS, (ULONG)irp, 0, 0, 0);
      }
  
      --(irp->Tail.Overlay.CurrentStackLocation);
  
      irp->Tail.Overlay.CurrentStackLocation->DeviceObject = pDeviceObject;
      pMajorFunction(pDeviceObject, irp);
    }
  
    KeWaitForSingleObject(&event, Executive, KernelMode, TRUE, 0);
  
    return pIoStatusBlock->Status;
  }
  
  PDEVICE_OBJECT GetVolumeDeviceObject(PFILE_OBJECT pFileObject)
  {
    PDEVICE_OBJECT pVolumeDeviceObject = NULL;
  
    if (pFileObject != NULL)
    {
      if (pFileObject->Vpb != NULL)
      {
        pVolumeDeviceObject = pFileObject->Vpb->RealDevice;
      }
      else
      {
        if (pFileObject->DeviceObject != NULL && pFileObject->DeviceObject->Vpb != NULL)
          pVolumeDeviceObject = pFileObject->DeviceObject->Vpb->RealDevice;
      }
    }
  
    return pVolumeDeviceObject;
  }
  
  //
  // разное
  //
  
  BOOLEAN GetDirectoryFromPath(PWSTR lpwszFullFileName, ULONG dwSize)
  {
    ULONG i;
  
    if (!_MmIsAddressValid(lpwszFullFileName) || !dwSize)
      return FALSE;
  
    i = dwSize;
    while(1)
    {
      if (i == 0)
        break;
      if (lpwszFullFileName[i] == L'\\')
      {
        lpwszFullFileName[i] = 0;
        break;
      }
      --i;
    }
  
    return TRUE;
  }
  
  BOOLEAN GetDirectoryFromPathA(CHAR *lpszFullFileName, ULONG dwSize)
  {
    ULONG i;
  
    if (!_MmIsAddressValid(lpszFullFileName) || !dwSize)
      return FALSE;
  
    i = dwSize;
    while(1)
    {
      if (i == 0)
        break;
      if (lpszFullFileName[i] == '\\')
      {
        lpszFullFileName[i] = 0;
        break;
      }
      --i;
    }
  
    return TRUE;
  }
  
  int GetToken(WCHAR *lpInBuf, int dwInBufSize, WCHAR *lpOutBuf, int dwOutBufSize, WCHAR *lpDeliver, int nDeliverCount, int nNumber)
  {
    int      Count = 0, k, i, j;
    BOOLEAN  bFlagExit;
  
    if (!lpOutBuf || !lpInBuf || !lpDeliver)
      return 0;
    *lpOutBuf = 0;
  //  memset(lpOutBuf, 0, sizeof(WCHAR)*dwOutBufSize);
  
    for (i=0; i<dwInBufSize; ++i)
    {
      for (k=0; k<nDeliverCount; ++k)
      {
        if (lpInBuf[i] == lpDeliver[k])
        {
          if (i != 0)
            ++Count;
          if (Count == nNumber)
            ++i;
          break;
        }
      }
      if (Count == nNumber)
      {
        bFlagExit = FALSE;
        for (j=0; j<dwOutBufSize; ++j)
        {
          for (k=0; k<nDeliverCount; ++k)
          {
            if (lpInBuf[i] == lpDeliver[k])
            {
              bFlagExit = TRUE;
              break;
            }
          }
          if (bFlagExit)
            break;
          lpOutBuf[j] = lpInBuf[i];
          ++i;
          if (i >= dwInBufSize) 
          {
            ++j;
            break;
          }
        }
        lpOutBuf[j] = 0;
        return j;
      }
    }
  
    return 0;
  }
  
  NTQUERYDIRECTORYOBJECT GetPtrToZwQueryDirectoryObject(void)
  {
    static NTQUERYDIRECTORYOBJECT pFn = NULL;
    LPSSDT                 lpSSDT;
    LPSSD                  lpSSD;
    ULONG                  dwNtBuildNumber;
  
    if (pFn == NULL)
    {
      lpSSDT = (LPSSDT) KeServiceDescriptorTable;
      lpSSD = &(lpSSDT->SystemServiceDescriptors[0]);
      
      dwNtBuildNumber = (*NtBuildNumber) & 0x00ffffff;
      switch (dwNtBuildNumber)
      {
        case 1381: // WinNT 4.0
             pFn = (NTQUERYDIRECTORYOBJECT) *((PVOID*)(lpSSD->lpSystemServiceTableAddressTable)+0x66);
             break;
        case 2195: // Win2K
             pFn = (NTQUERYDIRECTORYOBJECT) *((PVOID*)(lpSSD->lpSystemServiceTableAddressTable)+0x7e);
             break;
        default:
             if (dwNtBuildNumber >= 1946)
               pFn = (NTQUERYDIRECTORYOBJECT) *((PVOID*)(lpSSD->lpSystemServiceTableAddressTable)+0x7e);
             else
               pFn = NULL;
             break;
      }
    }
  
    return pFn;
  }
  
  
  //
  // оптимизация по скорости
  //
  SHARED_MEMORY* InitQueryObjectNameType(void)
  {
    BOOLEAN               bRes;
    SHARED_MEMORY*        pSharedBuffer = NULL;
  
    #ifdef __MISC_USE_KHEAP
    pSharedBuffer = (SHARED_MEMORY*)_AllocatePoolFromKHeap(hKHeapMiscDefault, sizeof(SHARED_MEMORY));
    #else
    pSharedBuffer = ExAllocatePool(NonPagedPool, sizeof(SHARED_MEMORY));
    #endif
    if (pSharedBuffer != NULL)
    {
      bRes = AllocateSharedMemory(pSharedBuffer, NonPagedPool, 2048+4+4);
      if (bRes == FALSE)
      {
        #ifdef __MISC_USE_KHEAP
        FreePoolToKHeap(hKHeapMiscDefault, pSharedBuffer);
        #else
        ExFreePool(pSharedBuffer);
        #endif
        pSharedBuffer = NULL;
      }
    }
  
    return pSharedBuffer;
  }
  
  //
  // оптимизация по скорости
  //
  void DeinitQueryObjectNameType(SHARED_MEMORY* pSharedBuffer)
  {
    if (_MmIsAddressValid(pSharedBuffer))
    {
      FreeSharedMemory(pSharedBuffer);
      #ifdef __MISC_USE_KHEAP
      FreePoolToKHeap(hKHeapMiscDefault, pSharedBuffer);
      #else
      ExFreePool(pSharedBuffer);
      #endif
    }
  }
  
  BOOLEAN QueryObjectNameType(PVOID pObjTypeInfo, ULONG dwSizeOfObjTypeInfo, HANDLE hDir, PWSTR pwszObjectName, SHARED_MEMORY* pSharedBuffer)
  {
    CHAR*                  Buf;
    POBJECT_NAMETYPE_INFO  pObjName;
    ULONG*                 pObjectIndex = 0;
    ULONG*                 pLengthReturned = 0;
    ULONG                  Index = 0;
    BOOLEAN                bFirst = TRUE;
    int                    i;
    NTQUERYDIRECTORYOBJECT pZwQueryDirectoryObject = 0;
  
    if (
        !_MmIsAddressValid(pObjTypeInfo) ||
        !_MmIsAddressValid(pwszObjectName) ||
        !_MmIsAddressValid(pSharedBuffer)
       )
      return FALSE;
       
  
    pZwQueryDirectoryObject = GetPtrToZwQueryDirectoryObject();
    if (!_MmIsAddressValid(pZwQueryDirectoryObject))
    {
      return FALSE;
    }
  
    Buf = (CHAR*)pSharedBuffer->m_lpUserMemory;
    pObjName = (POBJECT_NAMETYPE_INFO) Buf;
    pObjectIndex = (ULONG*)(Buf+2048);
    pLengthReturned = (ULONG*)(Buf+2048+4);
  
    while (pZwQueryDirectoryObject(hDir, Buf, 2048, ObjectArray, bFirst, pObjectIndex, pLengthReturned) >= 0)
    {
      bFirst = FALSE;
      for (i=0; Index<*pObjectIndex; ++Index, ++i)
      {
        if (!_wcsnicmp(pObjName[i].ObjectName.Buffer, pwszObjectName, pObjName[i].ObjectName.Length/sizeof(WCHAR)))
        {
          *pObjectIndex = Index;
          if (pZwQueryDirectoryObject(hDir, Buf, dwSizeOfObjTypeInfo, ObjectByOne, bFirst, pObjectIndex, pLengthReturned) == STATUS_SUCCESS)
          {
            memcpy(pObjTypeInfo, Buf, *pLengthReturned);
            ((POBJECT_NAMETYPE_INFO)pObjTypeInfo)->ObjectName.Buffer = (PWSTR)((DWORD)pObjTypeInfo+((DWORD)(pObjName->ObjectName.Buffer)-(DWORD)pObjName));
            ((POBJECT_NAMETYPE_INFO)pObjTypeInfo)->ObjectType.Buffer = (PWSTR)((DWORD)pObjTypeInfo+((DWORD)(pObjName->ObjectType.Buffer)-(DWORD)pObjName));
            return TRUE;
          }
          return FALSE;
        }
      }
    }
    
    return FALSE;
  }
  
  ULONG DosPathNameToNtPathName(PWSTR pwszDosPath, PWSTR pwszNtPath, ULONG dwSizeNtPathByBytes, ULONG dwRecursiveDeep, PULONG pdwObjectSizeByBytes)
  {
    ULONG                 dwSizeOfNtPath = 0;
    ULONG                 dwSizeOfDosPath;
    PWSTR                 pwszCurrentDir, pwszPtrCurDir;
    PWSTR                 pwszPtrDosPath, pwszPtr;
    UNICODE_STRING        dirString;
    OBJECT_ATTRIBUTES     dirAttr;
    HANDLE                hDir;
    NTSTATUS              NtStatus;
    char                  Buf[512];
    POBJECT_NAMETYPE_INFO pObjName = (POBJECT_NAMETYPE_INFO) Buf;
    ULONG                 dwRestDosPath, dwFreeCurDir, dwSizeToken;
    ULONG                 _dwSizeNtPathByBytes = dwSizeNtPathByBytes;
    HANDLE                hSymLink;
    UNICODE_STRING        SymLinkString;
    OBJECT_ATTRIBUTES     SymAttr;
    ULONG                 dwSizeSymLinkObj = 0;
    PWSTR                 pwszNewNtPath;
    SHARED_MEMORY*        pSharedBuffer = NULL;
  
  //  return dwSizeOfNtPath;
  
    DbgPrintMisc(("DosPathNameToNtPathName - start\n"));
   
    if (KeGetCurrentIrql() > PASSIVE_LEVEL)
      return dwSizeOfNtPath;
  
    if (!_MmIsAddressValid(pwszNtPath))
      return dwSizeOfNtPath;
    memset(pwszNtPath, 0, dwSizeNtPathByBytes);
  
    dwSizeOfDosPath = wcslen(pwszDosPath);
    if (dwSizeOfDosPath <= 1)
      return dwSizeOfNtPath;
  
    #ifdef __MISC_USE_KHEAP
    pwszCurrentDir = (PWSTR)_AllocatePoolFromKHeap(hKHeapMiscDefault, sizeof(L"\\??\\")+(dwSizeOfDosPath+1)*sizeof(WCHAR));
    #else
    pwszCurrentDir = ExAllocatePool(NonPagedPool, sizeof(L"\\??\\")+(dwSizeOfDosPath+1)*sizeof(WCHAR));
    #endif
    if(!pwszCurrentDir)
       return dwSizeOfNtPath;
  
    memset(pwszCurrentDir, 0, sizeof(L"\\??\\")+(dwSizeOfDosPath+1)*sizeof(WCHAR));
  
    if (pwszDosPath[1] == L':')
      wcscpy(pwszCurrentDir, L"\\??");
    else
      wcscpy(pwszCurrentDir, L"\\");
  
    wcscpy(pwszNtPath, L"\\");
  
    pSharedBuffer = InitQueryObjectNameType();  // need for optimize by speed QueryObjectNameType() !!!!!!!
  
    RtlInitUnicodeString(&dirString, pwszCurrentDir);
    InitializeObjectAttributes(&dirAttr, &dirString, OBJ_CASE_INSENSITIVE, NULL, NULL);
    NtStatus = ZwOpenDirectoryObject(&hDir, DIRECTORY_QUERY, &dirAttr);
    if (NtStatus == STATUS_SUCCESS)
    {
      // хрен его знает - NT понимает оба разделителя '\', '/'
      // однако путь до ядра доходит вроде уже обработанный и все разделители
      // в нем '\'. однако я не уверен - поэтому добавил эту вещь.
      pwszPtr = pwszDosPath;
      while (*pwszPtr)
      {
        if (*pwszPtr == L'/')
          *pwszPtr = L'\\';
        ++pwszPtr;
      }
  
      if (pwszDosPath[1] == L':')
        wcscat(pwszCurrentDir, L"\\");
      pwszPtrCurDir = pwszCurrentDir + wcslen(pwszCurrentDir);
      pwszPtrDosPath = pwszDosPath;
      if (pwszPtrDosPath[0] == L'\\')
        ++pwszPtrDosPath;
      dwFreeCurDir = ((sizeof(L"\\??\\")/sizeof(WCHAR))+dwSizeOfDosPath+1) - (pwszPtrCurDir - pwszCurrentDir);
      dwRestDosPath = dwSizeOfDosPath - (pwszPtrDosPath - pwszDosPath);
      
      while ((dwSizeToken = GetToken(pwszPtrDosPath, dwRestDosPath,  pwszPtrCurDir, dwFreeCurDir, L"\\", 1, 0)))
      {
        dwFreeCurDir -= dwSizeToken;
        if (dwFreeCurDir != 0)
          --dwFreeCurDir;//sizeof(L'\\');
        dwRestDosPath -= dwSizeToken;
        if (dwRestDosPath != 0)
          --dwRestDosPath;//sizeof(L'\\');
  
        if (QueryObjectNameType(Buf, sizeof(Buf), hDir, pwszPtrCurDir, pSharedBuffer))
        {
          if (!wcsncmp(pObjName->ObjectType.Buffer, L"Directory", pObjName->ObjectType.Length/sizeof(WCHAR)))
          {
            if (_dwSizeNtPathByBytes < ((wcslen(pObjName->ObjectName.Buffer)+2)*sizeof(WCHAR)))
            {
              dwSizeOfNtPath = 0;
              break;
            }
            wcscat(pwszNtPath, pObjName->ObjectName.Buffer);
            wcscat(pwszNtPath, L"\\");
            _dwSizeNtPathByBytes -= ((wcslen(pObjName->ObjectName.Buffer)+1)*sizeof(WCHAR));
  
            ZwClose(hDir);
            RtlInitUnicodeString(&dirString, pwszCurrentDir);
            InitializeObjectAttributes(&dirAttr, &dirString, OBJ_CASE_INSENSITIVE, NULL, NULL);
            NtStatus = ZwOpenDirectoryObject(&hDir, DIRECTORY_QUERY, &dirAttr);
            if (NtStatus != STATUS_SUCCESS)
            {
              dwSizeOfNtPath = 0;
              break;
            }
          }
          else
          {
            if (!wcsncmp(pObjName->ObjectType.Buffer, L"SymbolicLink", pObjName->ObjectType.Length/sizeof(WCHAR)))
            {
              dwSizeOfNtPath = 0;
  
              RtlInitUnicodeString(&SymLinkString, pObjName->ObjectName.Buffer);
              InitializeObjectAttributes(&SymAttr, &SymLinkString, OBJ_CASE_INSENSITIVE, hDir, NULL);
              if (ZwOpenSymbolicLinkObject(&hSymLink, SYMBOLIC_LINK_QUERY, &SymAttr) == STATUS_SUCCESS)
              {
                SymLinkString.Buffer = (PWSTR)pwszNtPath;
                SymLinkString.Length = 0;
                SymLinkString.MaximumLength = (WORD)dwSizeNtPathByBytes - wcslen(pwszPtrDosPath)*sizeof(WCHAR);
  
                if (ZwQuerySymbolicLinkObject(hSymLink, &SymLinkString, &dwSizeSymLinkObj) == STATUS_SUCCESS)
                {
                  if (pwszNtPath[0] == L'\\' && memcmp(pwszDosPath, pwszNtPath, SymLinkString.Length))
                  {
                    if (_dwSizeNtPathByBytes < (wcslen(pwszPtrDosPath+dwSizeToken)*sizeof(WCHAR)))
                    {
                      dwSizeOfNtPath = 0;
                      ZwClose(hSymLink);
                      break;
                    }
                    wcscat(pwszNtPath, pwszPtrDosPath+dwSizeToken);
                    #ifdef __MISC_USE_KHEAP
                    pwszNewNtPath = (PWSTR) _AllocatePoolFromKHeap(hKHeapMiscDefault, dwSizeNtPathByBytes);
                    #else
                    pwszNewNtPath= (PWSTR) ExAllocatePool(NonPagedPool, dwSizeNtPathByBytes);
                    #endif
                    if (pwszNewNtPath)
                    {
                      DbgPrintMisc(("DosPathNameToNtPathName - recursive start\n"));
                      if (dwRecursiveDeep != 0)
                      {
                        dwSizeOfNtPath = DosPathNameToNtPathName(pwszNtPath, pwszNewNtPath, dwSizeNtPathByBytes, --dwRecursiveDeep, pdwObjectSizeByBytes);
                        if (dwSizeOfNtPath)
                        {
                          wcscpy(pwszNtPath, pwszNewNtPath);
                        }
                      }
                      #ifdef __MISC_USE_KHEAP
                      FreePoolToKHeap(hKHeapMiscDefault, pwszNewNtPath);
                      #else
                      ExFreePool(pwszNewNtPath);
                      #endif
                    }
                  }
                }
                ZwClose(hSymLink);
              }
              break;
            }
            else  // не директория и не ссылка
            {
              if (_MmIsAddressValid(pdwObjectSizeByBytes)) // возвращается длина имени объекта которому принадлежит остаток пути
              {
                *pdwObjectSizeByBytes = wcslen(pwszNtPath)*sizeof(WCHAR);
              }
  
              wcscat(pwszNtPath, pwszPtrDosPath);
              dwSizeOfNtPath = wcslen(pwszNtPath)*sizeof(WCHAR);
              break;
            }
          }
        }
        else
        {
          dwSizeOfNtPath = 0;
          break;
        }
  
        wcscat(pwszPtrCurDir, L"\\");
        pwszPtrCurDir += dwSizeToken + 1; // add wcslen(L"\\");
        pwszPtrDosPath += dwSizeToken + 1;
      }
      ZwClose(hDir);
    }
  
    DeinitQueryObjectNameType(pSharedBuffer);
  
    #ifdef __MISC_USE_KHEAP
    FreePoolToKHeap(hKHeapMiscDefault, pwszCurrentDir);
    #else
    ExFreePool(pwszCurrentDir);
    #endif
  
    DbgPrintMisc(("DosPathNameToNtPathName - end\n"));
  
    return dwSizeOfNtPath;
  }
  
  VOID FlushInstuctionCache(VOID)
  {
    ULONG                 pNextInstr;
  
  //  __asm _emit 0eah // data into code
    __asm
    {
      push eax
      mov  eax, offset __NextInstr
      mov  [pNextInstr], eax
      pop  eax
      jmp  dword ptr [pNextInstr]
    }
  __NextInstr:
  
    return;
  }
  
  //PDEVICE_OBJECT GetOwnDeviceObject(PDEVICE_OBJECT DeviceObject)
  //{
  //  __asm int 1h
  //  while (_MmIsAddressValid(DeviceObject))
  //  {
  //    if (_MmIsAddressValid(DeviceObject->DeviceObjectExtension))
  //    {
  //      if (_MmIsAddressValid(DeviceObject->DeviceObjectExtension->DeviceObject))
  //      {
  //        __asm int 1h
  //        if (DeviceObject != DeviceObject->DeviceObjectExtension->DeviceObject)
  //          DeviceObject = DeviceObject->DeviceObjectExtension->DeviceObject;
  //        else
  //          break;
  //      }
  //      else
  //        break;
  //    }
  //    else
  //    {
  //      break;
  //    }
  //  }
  //
  //  return DeviceObject;
  //}
  
  PDEVICE_OBJECT GetOwnDeviceObject(PDEVICE_OBJECT DeviceObject)
  {
    PDRIVER_OBJECT pDriverObject;
    PDEVICE_OBJECT pDevice, pDeviceAttached;
    BOOLEAN        bFind = FALSE;
  
    #if 0
    if (!_MmIsAddressValid(DeviceObject))
      return NULL;
  
    pDriverObject = DeviceObject->DriverObject;
  
    if (!_MmIsAddressValid(pDriverObject))
      return NULL;
  
    pDevice = pDriverObject->DeviceObject;
    while (_MmIsAddressValid(pDevice))
    {
      pDeviceAttached = pDevice;
      while (_MmIsAddressValid(pDeviceAttached))
      {
        if (pDeviceAttached->AttachedDevice == DeviceObject)
        {
          DeviceObject = GetOwnDeviceObject(pDeviceAttached);
          bFind = TRUE;
          break;
        }
        pDeviceAttached = pDeviceAttached->AttachedDevice;
      }
      if (bFind == TRUE)
        break;
  
      pDevice = pDevice->NextDevice;
    }
    #endif
  
    if (!DeviceObject)
      return NULL;
  
    pDriverObject = DeviceObject->DriverObject;
  
    if (!pDriverObject)
      return NULL;
  
    pDevice = pDriverObject->DeviceObject;
    while (pDevice)
    {
      pDeviceAttached = pDevice;
      while (pDeviceAttached)
      {
        if (pDeviceAttached->AttachedDevice == DeviceObject)
        {
          DeviceObject = GetOwnDeviceObject(pDeviceAttached);
          bFind = TRUE;
          break;
        }
        pDeviceAttached = pDeviceAttached->AttachedDevice;
      }
      if (bFind == TRUE)
        break;
  
      pDevice = pDevice->NextDevice;
    }
  
    return DeviceObject;
  }
  
  PDEVICE_OBJECT GetOwnDeviceObjectFromIrp(PIRP pIrp)
  {
    PDEVICE_OBJECT      pDevice = NULL;
    CHAR                CurrentLocation;
    PIO_STACK_LOCATION  CurrentIrpStack;
  
    if (pIrp == NULL)
      return pDevice;
  
    CurrentLocation = pIrp->CurrentLocation;
    CurrentIrpStack = IoGetCurrentIrpStackLocation(pIrp);
  
    pDevice = CurrentIrpStack->DeviceObject;
    while (--CurrentLocation)
    {
      --CurrentIrpStack;
      if (CurrentIrpStack->DeviceObject != NULL)
        pDevice = CurrentIrpStack->DeviceObject;
    }
  
    return pDevice;
  }
  
  NTSTATUS DefaultDriverObjectDispatch(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
  {
    Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST;
  
    IoCompleteRequest(Irp, IO_NO_INCREMENT);
  
    return STATUS_INVALID_DEVICE_REQUEST;
  }
  
  PDRIVER_OBJECT CreateInvisibleDriverObject(PVOID pBaseAddress, ULONG dwDriverSize, HANDLE hSystemImage, PDRIVER_INITIALIZE DriverEntry)
  {
    NTSTATUS          NtStatus;
    OBJECT_ATTRIBUTES ObjectAttributes;
    WCHAR             DriverName[] = L"\\Driver\\HiddenDriver";
    UNICODE_STRING    UniDriverName;
    PDRIVER_OBJECT    pObjectBody = NULL;
    HANDLE            hDriver;
    int               i;
  
    RtlInitUnicodeString(&UniDriverName, DriverName);
    InitializeObjectAttributes(&ObjectAttributes, NULL/*&UniDriverName*/, OBJ_PERMANENT, NULL, NULL);
  
    NtStatus = ObCreateObject(KernelMode, (POBJECT_TYPE)IoDriverObjectType, &ObjectAttributes,   
                              KernelMode, 0, sizeof(DRIVER_OBJECT) + sizeof(DRIVER_EXTENSION),
                              0, 0, (PVOID*)&pObjectBody);
    if (NtStatus != STATUS_SUCCESS)
    {
      DbgPrint ("CreateInvisibleDriverObject: NtStatus = %08x \n", NtStatus);
      return NULL;
    }
  
    memset(pObjectBody, 0, sizeof(DRIVER_OBJECT) + sizeof(DRIVER_EXTENSION));
  
    pObjectBody->DriverExtension = (PDRIVER_EXTENSION)((PCHAR)pObjectBody + sizeof(DRIVER_OBJECT));
    pObjectBody->DriverExtension->DriverObject = pObjectBody; // ??????
  
    pObjectBody->DriverStart = pBaseAddress;
    pObjectBody->DriverSize = dwDriverSize;
    pObjectBody->DriverSection = hSystemImage;
  
    pObjectBody->DriverInit = DriverEntry;
  
    for (i = 0; i<IRP_MJ_MAXIMUM_FUNCTION; ++i)
      pObjectBody->MajorFunction[i] = DefaultDriverObjectDispatch;
  
    pObjectBody->Type = IO_TYPE_DRIVER;
    pObjectBody->Size = sizeof(DRIVER_OBJECT);
  
    NtStatus = ObInsertObject(pObjectBody, NULL, 1, 0, 0, &hDriver);
    if (NtStatus != STATUS_SUCCESS)
    {
      // delete object
      DbgPrint ("CreateInvisibleDriverObject: NtStatus = %08x \n", NtStatus);
      return NULL;
    }
  
    return pObjectBody;
  }
  
  HANDLE LoadDevice(PWSTR pwszDeviceFileName)
  {
    SYSTEM_LOAD_DRIVER  LoadDriverInfo;
    NTSTATUS            NtStatus;
  
    if (pwszDeviceFileName == NULL)
      return NULL;
  
    memset(&LoadDriverInfo, 0, sizeof(LoadDriverInfo));
  
    RtlInitUnicodeString(&LoadDriverInfo.usImageFile, pwszDeviceFileName);
  
    NtStatus = ZwSetSystemInformation(SystemLoadDriver, &LoadDriverInfo, sizeof(LoadDriverInfo));
  
    DbgPrint ("Loadevice: \n  pBaseAddress = %08x\n  hSystemImage = %08x\n  pEntryPoint = %08x\n  pDirectoryEntry = %08x\n",
                               LoadDriverInfo.pBaseAddress, LoadDriverInfo.hSystemImage, LoadDriverInfo.pEntryPoint, LoadDriverInfo.pDirectoryEntry);
  
  //  if (NtStatus == STATUS_SUCCESS)
  //    *((CHAR*)LoadDriverInfo.pBaseAddress) = 'M';
  
    return LoadDriverInfo.hSystemImage;
  }
  
  NTSTATUS UnloadDevice(HANDLE hSystemImage)
  {
    SYSTEM_UNLOAD_DRIVER  UnLoadDriverInfo;
    NTSTATUS              NtStatus;
  
    UnLoadDriverInfo.hSystemImage = hSystemImage;
  
    NtStatus = ZwSetSystemInformation(SystemUnloadDriver, &UnLoadDriverInfo, sizeof(UnLoadDriverInfo));
  
    return NtStatus;
  }
  
  BOOLEAN DeleteItemFromQueryDirectoryBuffer(PFQD_SmallCommonBlock pQueryDirPrev, PFQD_SmallCommonBlock pQueryDir, PVOID Buffer, ULONG BufferLength, PIO_STATUS_BLOCK IoStatusBlock, FILE_INFORMATION_CLASS DirectoryInfoClass, NTSTATUS* NtStatus)
  {
    BOOLEAN               bRes = FALSE;
    PFQD_SmallCommonBlock pQueryDirSave;
    ULONG                 dwSizeItem;
  
    if (pQueryDir->NextEntryOffset == 0)
    {
      if (pQueryDir != Buffer)
      {
        pQueryDirPrev->NextEntryOffset = 0;
        if (_MmIsAddressValid(IoStatusBlock))
        {
          dwSizeItem = 0;
          switch (DirectoryInfoClass)
          {
            case 0:
                 dwSizeItem = (SIZE_OF_FILE_NAMES_INFORMATION + ((PFILE_NAMES_INFORMATION)pQueryDir)->FileNameLength);
                 break;
            case FileDirectoryInformation:
                 dwSizeItem = (SIZE_OF_FILE_DIRECTORY_INFORMATION + ((PFILE_DIRECTORY_INFORMATION)pQueryDir)->CommonBlock.FileNameLength);
                 break;
            case FileFullDirectoryInformation:
                 dwSizeItem = (SIZE_OF_FILE_FULL_DIR_INFORMATION + ((PFILE_FULL_DIR_INFORMATION)pQueryDir)->CommonBlock.FileNameLength);
                 break;
            case FileBothDirectoryInformation:
                 dwSizeItem = (SIZE_OF_FILE_BOTH_DIR_INFORMATION + ((PFILE_BOTH_DIR_INFORMATION)pQueryDir)->CommonBlock.FileNameLength);
                 break;
          }
          if (IoStatusBlock->Information > dwSizeItem)
          {
            IoStatusBlock->Information -= dwSizeItem;
  //          memset(pQueryDir, 0, dwSizeItem);
          }
          else
          {
            *NtStatus = STATUS_NO_MORE_FILES;
            IoStatusBlock->Status = STATUS_NO_MORE_FILES;
            IoStatusBlock->Information = 0;
          }
        }
      }
      else
      {
        *NtStatus = STATUS_NO_MORE_FILES;
        if (_MmIsAddressValid(IoStatusBlock))
        {
          IoStatusBlock->Status = STATUS_NO_MORE_FILES;
          IoStatusBlock->Information = 0;
        }
      }
      bRes = TRUE;
    }
    else
    {
      pQueryDirSave = pQueryDir;
      if (_MmIsAddressValid(IoStatusBlock))
      {
        if (IoStatusBlock->Information >= pQueryDir->NextEntryOffset)
          IoStatusBlock->Information -= pQueryDir->NextEntryOffset;
        else
          IoStatusBlock->Information = 0;
      }
      pQueryDir = (PFQD_SmallCommonBlock)((CHAR*)pQueryDir + pQueryDir->NextEntryOffset);
      memmove(pQueryDirSave, pQueryDir, BufferLength - ((CHAR*)pQueryDir-(CHAR*)Buffer));
    }
  
    return bRes;
  }
  
  LPSSDT FindShadowTable(void)
  {
    BYTE*       pCheckArea = (BYTE*) KeAddSystemServiceTable;
    int         i;
    PSRVTABLE   pSrvTable = NULL;
  
    for (i=0; i<100; i++)
    {
      __try
      {
        pSrvTable = *(PSRVTABLE*)pCheckArea;
        if (
            !MmIsAddressValid(pSrvTable)            ||
            (pSrvTable == KeServiceDescriptorTable) ||
            (memcmp(pSrvTable, KeServiceDescriptorTable, sizeof (*pSrvTable)) != 0)
           )
        {
          pCheckArea++;
          pSrvTable = NULL;
        }
      }
      __except(EXCEPTION_EXECUTE_HANDLER)
      {
        pSrvTable = NULL;
      }
      if (pSrvTable)
        break;
    }
  
    if (pSrvTable == NULL)
    {
      pSrvTable = (PSRVTABLE)((char*)KeServiceDescriptorTable-0x230);
      if (MmIsAddressValid(pSrvTable))
      {
        __try
        {
          if (memcmp(pSrvTable, KeServiceDescriptorTable, sizeof (*pSrvTable)) != 0)
            pSrvTable = NULL;
        }
        __except(EXCEPTION_EXECUTE_HANDLER)
        {
          pSrvTable = NULL;
        }
      }
      else
      {
        pSrvTable = NULL;
      }
    }
  
    return (LPSSDT)pSrvTable;
  }
  
  
  #if 0
  ULONG GetFullPathbyFileObjectA(PFILE_OBJECT fileObject, PCHAR fullPathName, ULONG nfullPathNameSize)
  {
    ULONG               pathLen;
    PCHAR               pathOffset;
    PFILE_OBJECT        relatedFileObject;
    ANSI_STRING         componentName;
    PDEVICE_OBJECT      pDeviceObject;
    PUNICODE_STRING     fullUniName;
    ULONG               dwFreeSize = nfullPathNameSize;
  
    if (!fullPathName || !nfullPathNameSize)
      return 0;
  
    fullPathName[0] = 0;
  
    try
    {
      if (fileObject == 0)
      {
        return 0;
      }
  
      pDeviceObject = GetVolumeDeviceObject(fileObject);
      if (pDeviceObject == NULL)
      {
        pDeviceObject = IoGetRelatedDeviceObject(fileObject);
      }
  
      fullUniName = (PUNICODE_STRING)_AllocatePoolFromKHeap(hKHeapDHDefault, nfullPathNameSize*sizeof(WCHAR)+sizeof(UNICODE_STRING));
      fullUniName->MaximumLength = (USHORT)nfullPathNameSize*sizeof(WCHAR);
  
      if (NT_SUCCESS(ObQueryNameString(pDeviceObject, (POBJECT_NAME_INFORMATION)fullUniName, fullUniName->MaximumLength, &pathLen)))
      {
        RtlUnicodeStringToAnsiString( &componentName, fullUniName, TRUE ); 
        if (componentName.Buffer[0])
        {         
          strncatZ(fullPathName, componentName.Buffer, fullUniName->MaximumLength - 2);
          DbgPrint ("%s\n", fullPathName);
        }
        RtlFreeAnsiString(&componentName);
      }
      else
      {
        return 0;
      }
  
      if (!fileObject->FileName.Length || fileObject->FileName.Length > nfullPathNameSize)
      {
        return strlen(fullPathName);
      }
  
  //    strcat(fullPathName, "\\");
      dwFreeSize -= strlen(fullPathName);
    }
    except(EXCEPTION_EXECUTE_HANDLER)
    {
      return 0;
    }
  
    try
    {
      pathLen = fileObject->FileName.Length/sizeof(WCHAR) + 1;
  
      relatedFileObject = fileObject->RelatedFileObject;
    
      if (fileObject->FileName.Buffer[0] != L'\\' )
      {
        while (relatedFileObject)
        {
          if ((pathLen + relatedFileObject->FileName.Length/sizeof(WCHAR) + 1) >= dwFreeSize)
          {
            break;
          }
          pathLen += relatedFileObject->FileName.Length/sizeof(WCHAR) + 1;
          relatedFileObject = relatedFileObject->RelatedFileObject;
        }
      }
  
      if (dwFreeSize == nfullPathNameSize)
        sprintf(fullPathName, "\\");
    
      pathOffset = fullPathName + strlen(fullPathName) - sizeof(char) + pathLen - fileObject->FileName.Length/sizeof(WCHAR);
      RtlUnicodeStringToAnsiString( &componentName, &fileObject->FileName, TRUE );    
      strncpy( pathOffset, componentName.Buffer, componentName.Length + 1 );
      RtlFreeAnsiString( &componentName );
  
      relatedFileObject = fileObject->RelatedFileObject;
    
      if (fileObject->FileName.Buffer[0] != L'\\')
      {
        while (relatedFileObject)
        {
          *(pathOffset - 1) = '\\';
          pathOffset -= relatedFileObject->FileName.Length/sizeof(WCHAR) + 1;
  
          if (pathOffset <= fullPathName)
          {
            break;
          }
          RtlUnicodeStringToAnsiString(&componentName, &relatedFileObject->FileName, TRUE);
          strncpy(pathOffset, componentName.Buffer, componentName.Length);
          RtlFreeAnsiString(&componentName);
  
          relatedFileObject = relatedFileObject->RelatedFileObject;
        }
      }  
  
    }
    except(EXCEPTION_EXECUTE_HANDLER)
    {
       DbgPrint ("He4Hook: GetFullPath: EXCEPTION\n");
    }
  
  //  __asm int 1h
    return strlen(fullPathName);
  }
  #endif //0