На главную Наши проекты:
Журнал   ·   Discuz!ML   ·   Wiki   ·   DRKB   ·   Помощь проекту
ПРАВИЛА FAQ Помощь Участники Календарь Избранное RSS
msm.ru
! user posted image
Пожалуйста, выделяйте текст программы тегом [сode=pas] ... [/сode]. Для этого используйте кнопку [code=pas] в форме ответа или комбобокс, если нужно вставить код на языке, отличном от Дельфи/Паскаля.

Соблюдайте общие правила форума

Следующие вопросы задаются очень часто, подробно разобраны в FAQ и, поэтому, будут безжалостно удаляться:
1. Преобразовать переменную типа String в тип PChar (PAnsiChar)
2. Как "свернуть" программу в трей.
3. Как "скрыться" от Ctrl + Alt + Del (заблокировать их и т.п.)
4. Как запустить программу/файл? (и дождаться ее завершения)
5. Как перехватить API-функции, поставить hook? (перехват сообщений от мыши, клавиатуры - внедрение в удаленное адресное прстранство)
... (продолжение следует) ...

Внимание:
Попытки открытия обсуждений реализации вредоносного ПО, включая различные интерпретации спам-ботов, наказывается предупреждением на 30 дней.
Повторная попытка - 60 дней. Последующие попытки - бан.
Мат в разделе - бан на три месяца...

Полезные ссылки:
user posted image MSDN Library user posted image FAQ раздела user posted image Поиск по разделу user posted image Как правильно задавать вопросы


Выразить свое отношение к модераторам раздела можно здесь: user posted image Rouse_, user posted image Krid

Модераторы: Rouse_, Krid
  
> Как узнать все открытые дескрипторы , файлов
    Когда chkdsk.exe начинает проверять диск, он закрывает на нём все открытые файлы. Можно ли самому узнать их Thandle'ы и, если надо, закрыть. Существует ли какая-нибудь функция, наподобе EnumWindows для окон.
      Вот так:

      ExpandedWrap disabled
        ////////////////////////////////////////////////////////////////////////////////
        //
        //  ****************************************************************************
        //  * Unit Name : Unit15
        //  * Purpose   : Перечисление всех открытых файлов в системе
        //  *             (до которых получилось достучаться)
        //  * Author    : Александр (Rouse_) Багель
        //  * Version   : 1.00
        //  ****************************************************************************
        //
         
        unit Unit15;
         
        interface
         
        uses
          Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms,
          Dialogs, StdCtrls, ComCtrls;
         
        type
          TForm15 = class(TForm)
            Button1: TButton;
            Memo1: TMemo;
            ProgressBar1: TProgressBar;
            procedure Button1Click(Sender: TObject);
          public
            procedure ShowLockedProcess(FileName: String);
          end;
         
        var
          Form15: TForm15;
         
        implementation
         
        {$R *.dfm}
         
        type
          NT_STATUS = Cardinal;
         
          TFileDirectoryInformation = packed record
            NextEntryOffset: ULONG;
            FileIndex: ULONG;
            CreationTime: LARGE_INTEGER;
            LastAccessTime: LARGE_INTEGER;
            LastWriteTime: LARGE_INTEGER;
            ChangeTime: LARGE_INTEGER;
            EndOfFile: LARGE_INTEGER;
            AllocationSize: LARGE_INTEGER;
            FileAttributes: ULONG;
            FileNameLength: ULONG;
            FileName: array[0..0] of WideChar;
          end;
          FILE_DIRECTORY_INFORMATION = TFileDirectoryInformation;
          PFileDirectoryInformation = ^TFileDirectoryInformation;
          PFILE_DIRECTORY_INFORMATION = PFileDirectoryInformation;
         
          PSYSTEM_THREADS = ^SYSTEM_THREADS;
          SYSTEM_THREADS  = packed record
            KernelTime: LARGE_INTEGER;
            UserTime: LARGE_INTEGER;
            CreateTime: LARGE_INTEGER;
            WaitTime: ULONG;
            StartAddress: Pointer;
            UniqueProcess: DWORD;
            UniqueThread: DWORD;
            Priority: Integer;
            BasePriority: Integer;
            ContextSwitchCount: ULONG;
            State: Longint;
            WaitReason: Longint;
          end;
         
          PSYSTEM_PROCESS_INFORMATION = ^SYSTEM_PROCESS_INFORMATION;
          SYSTEM_PROCESS_INFORMATION = packed record
            NextOffset: ULONG;
            ThreadCount: ULONG;
            Reserved1: array [0..5] of ULONG;
            CreateTime: FILETIME;
            UserTime: FILETIME;
            KernelTime: FILETIME;
            ModuleNameLength: WORD;
            ModuleNameMaxLength: WORD;
            ModuleName: PWideChar;
            BasePriority: ULONG;
            ProcessID: ULONG;
            InheritedFromUniqueProcessID: ULONG;
            HandleCount: ULONG;
            Reserved2 : array[0..1] of ULONG;
            PeakVirtualSize : ULONG;
            VirtualSize : ULONG;
            PageFaultCount : ULONG;
            PeakWorkingSetSize : ULONG;
            WorkingSetSize : ULONG;
            QuotaPeakPagedPoolUsage : ULONG;
            QuotaPagedPoolUsage : ULONG;
            QuotaPeakNonPagedPoolUsage : ULONG;
            QuotaNonPagedPoolUsage : ULONG;
            PageFileUsage : ULONG;
            PeakPageFileUsage : ULONG;
            PrivatePageCount : ULONG;
            ReadOperationCount : LARGE_INTEGER;
            WriteOperationCount : LARGE_INTEGER;
            OtherOperationCount : LARGE_INTEGER;
            ReadTransferCount : LARGE_INTEGER;
            WriteTransferCount : LARGE_INTEGER;
            OtherTransferCount : LARGE_INTEGER;
            ThreadInfo: array [0..0] of SYSTEM_THREADS;
          end;
         
          PSYSTEM_HANDLE_INFORMATION = ^SYSTEM_HANDLE_INFORMATION;
          SYSTEM_HANDLE_INFORMATION = packed record
            ProcessId: DWORD;
            ObjectTypeNumber: Byte;
            Flags: Byte;
            Handle: Word;
            pObject: Pointer;
            GrantedAccess: DWORD;
          end;
         
          PSYSTEM_HANDLE_INFORMATION_EX = ^SYSTEM_HANDLE_INFORMATION_EX;
          SYSTEM_HANDLE_INFORMATION_EX = packed record
            NumberOfHandles: dword;
            Information: array [0..0] of SYSTEM_HANDLE_INFORMATION;
          end;
         
          PFILE_NAME_INFORMATION = ^FILE_NAME_INFORMATION;
          FILE_NAME_INFORMATION = packed record
            FileNameLength: ULONG;
            FileName: array [0..MAX_PATH - 1] of WideChar;
          end;
         
          PUNICODE_STRING = ^TUNICODE_STRING;
          TUNICODE_STRING = packed record
            Length : WORD;
            MaximumLength : WORD;
            Buffer : array [0..MAX_PATH - 1] of WideChar;
          end;
         
          POBJECT_NAME_INFORMATION = ^TOBJECT_NAME_INFORMATION;
          TOBJECT_NAME_INFORMATION = packed record
            Name : TUNICODE_STRING;
          end;
         
          PIO_STATUS_BLOCK = ^IO_STATUS_BLOCK;
          IO_STATUS_BLOCK = packed record
            Status: NT_STATUS;
            Information: DWORD;
          end;
         
          PGetFileNameThreadParam = ^TGetFileNameThreadParam;
          TGetFileNameThreadParam = packed record
            hFile: THandle;
            Data: array [0..MAX_PATH - 1] of Char;
            Status: NT_STATUS;
          end;
         
        const
          STATUS_SUCCESS = NT_STATUS($00000000);
          STATUS_INVALID_INFO_CLASS = NT_STATUS($C0000003);
          STATUS_INFO_LENGTH_MISMATCH = NT_STATUS($C0000004);
          STATUS_INVALID_DEVICE_REQUEST = NT_STATUS($C0000010);
          ObjectNameInformation = 1;
          FileDirectoryInformation = 1;
          FileNameInformation = 9;
          SystemProcessesAndThreadsInformation = 5;
          SystemHandleInformation = 16;
         
          function ZwQuerySystemInformation(ASystemInformationClass: DWORD;
            ASystemInformation: Pointer; ASystemInformationLength: DWORD;
            AReturnLength: PDWORD): NT_STATUS; stdcall; external 'ntdll.dll';
         
          function NtQueryInformationFile(FileHandle: THandle;
            IoStatusBlock: PIO_STATUS_BLOCK; FileInformation: Pointer;
            Length: DWORD; FileInformationClass: DWORD): NT_STATUS;
            stdcall; external 'ntdll.dll';
         
          function NtQueryObject(ObjectHandle: THandle;
            ObjectInformationClass: DWORD; ObjectInformation: Pointer;
            ObjectInformationLength: ULONG;
            ReturnLength: PDWORD): NT_STATUS; stdcall; external 'ntdll.dll';
         
          function GetLongPathNameA(lpszShortPath, lpszLongPath: PChar;
            cchBuffer: DWORD): DWORD; stdcall; external kernel32;
         
        procedure TForm15.Button1Click(Sender: TObject);
        begin
          ShowLockedProcess('');
        end;
         
        procedure TForm15.ShowLockedProcess(FileName: String);
         
          function GetInfoTable(ATableType: DWORD): Pointer;
          var
            dwSize: DWORD;
            pPtr: Pointer;
            ntStatus: NT_STATUS;
          begin
            Result := nil;
            dwSize := WORD(-1);
            GetMem(pPtr, dwSize);
            ntStatus := ZwQuerySystemInformation(ATableType, pPtr, dwSize, nil);
            while ntStatus = STATUS_INFO_LENGTH_MISMATCH do
            begin
              dwSize := dwSize * 2;
              ReallocMem(pPtr, dwSize);
              ntStatus := ZwQuerySystemInformation(ATableType, pPtr, dwSize, nil);
            end;
            if ntStatus = STATUS_SUCCESS then
              Result := pPtr
            else
              FreeMem(pPtr);
          end;
         
          function GetFileNameThread(lpParameters: Pointer): DWORD; stdcall;
          var
            FileNameInfo: FILE_NAME_INFORMATION;
            ObjectNameInfo: TOBJECT_NAME_INFORMATION;
            IoStatusBlock: IO_STATUS_BLOCK;
            pThreadParam: TGetFileNameThreadParam;
            dwReturn: DWORD;
          begin
            ZeroMemory(@FileNameInfo, SizeOf(FILE_NAME_INFORMATION));
            pThreadParam := PGetFileNameThreadParam(lpParameters)^;
            Result := NtQueryInformationFile(pThreadParam.hFile, @IoStatusBlock,
              @FileNameInfo, MAX_PATH * 2, FileNameInformation);
            if Result = STATUS_SUCCESS then
            begin
              Result := NtQueryObject(pThreadParam.hFile, ObjectNameInformation,
                @ObjectNameInfo, MAX_PATH * 2, @dwReturn);
              if Result = STATUS_SUCCESS then
              begin
                pThreadParam.Status := Result;
                WideCharToMultiByte(CP_ACP, 0,
                  @ObjectNameInfo.Name.Buffer[ObjectNameInfo.Name.MaximumLength -
                  ObjectNameInfo.Name.Length],
                  ObjectNameInfo.Name.Length, @pThreadParam.Data[0],
                  MAX_PATH, nil, nil);
              end
              else
              begin
                pThreadParam.Status := STATUS_SUCCESS;
                Result := STATUS_SUCCESS;
                WideCharToMultiByte(CP_ACP, 0,
                  @FileNameInfo.FileName[0], IoStatusBlock.Information,
                  @pThreadParam.Data[0],
                  MAX_PATH, nil, nil);
              end;
            end;
            PGetFileNameThreadParam(lpParameters)^ := pThreadParam;
            ExitThread(Result);
          end;
         
          function GetFileNameFromHandle(hFile: THandle): String;
          var
            lpExitCode: DWORD;
            pThreadParam: TGetFileNameThreadParam;
            hThread: THandle;
          begin
            Result := '';
            ZeroMemory(@pThreadParam, SizeOf(TGetFileNameThreadParam));
            pThreadParam.hFile := hFile;
            hThread := CreateThread(nil, 0, @GetFileNameThread, @pThreadParam, 0, PDWORD(nil)^);
            if hThread <> 0 then
            try
              case WaitForSingleObject(hThread, 100) of
                WAIT_OBJECT_0:
                begin
                  GetExitCodeThread(hThread, lpExitCode);
                  if lpExitCode = STATUS_SUCCESS then
                    Result := pThreadParam.Data;
                end;
                WAIT_TIMEOUT:
                  TerminateThread(hThread, 0);
              end;
            finally
              CloseHandle(hThread);
            end;
          end;
         
          function SetDebugPriv: Boolean;
          var
            Token: THandle;
            tkp: TTokenPrivileges;
          begin
            Result := false;
            if OpenProcessToken(GetCurrentProcess,
              TOKEN_ADJUST_PRIVILEGES or TOKEN_QUERY, Token) then
            begin
              if LookupPrivilegeValue(nil, PChar('SeDebugPrivilege'),
                tkp.Privileges[0].Luid) then
              begin
                tkp.PrivilegeCount := 1;
                tkp.Privileges[0].Attributes := SE_PRIVILEGE_ENABLED;
                Result := AdjustTokenPrivileges(Token, False,
                  tkp, 0, PTokenPrivileges(nil)^, PDWord(nil)^);
              end;
            end;
          end;
         
        type
          DriveQueryData = record
            DiskLabel: String;
            DiskDosQuery: String;
            DosQueryLen: Integer;
          end;
         
        var
          hFile, hProcess: THandle;
          pHandleInfo: PSYSTEM_HANDLE_INFORMATION_EX;
          I, Drive: Integer;
          ObjectTypeNumber: Byte;
          FileDirectory, FilePath, ProcessName: String;
          SystemInformation, TempSI: PSYSTEM_PROCESS_INFORMATION;
          DosDevices: array [0..25] of DriveQueryData;
          LongFileName, TmpFileName: String;
        begin
          SetLength(LongFileName, MAX_PATH);
          GetLongPathNameA(PChar(FileName), @LongFileName[1], MAX_PATH);
         
          for Drive := 0 to 25 do
          begin
            DosDevices[Drive].DiskLabel := Chr(Drive + Ord('a')) + ':';
            SetLength(DosDevices[Drive].DiskDosQuery, MAXCHAR);
            ZeroMemory(@DosDevices[Drive].DiskDosQuery[1], MAXCHAR);
            QueryDosDevice(PChar(DosDevices[Drive].DiskLabel),
              @DosDevices[Drive].DiskDosQuery[1], MAXCHAR);
            DosDevices[Drive].DosQueryLen := Length(PChar(DosDevices[Drive].DiskDosQuery));
            SetLength(DosDevices[Drive].DiskDosQuery, DosDevices[Drive].DosQueryLen);
          end;
         
          ObjectTypeNumber := 0;
          SetDebugPriv;
          hFile := CreateFile('NUL', GENERIC_READ, 0, nil, OPEN_EXISTING, 0, 0);
          if hFile = INVALID_HANDLE_VALUE then RaiseLastOSError;
          try
            pHandleInfo := GetInfoTable(SystemHandleInformation);
            if pHandleInfo = nil then RaiseLastOSError;
            try
              for I := 0 to pHandleInfo^.NumberOfHandles - 1 do
                if pHandleInfo^.Information[I].Handle = hFile then
                  if pHandleInfo^.Information[I].ProcessId = GetCurrentProcessId then
                  begin
                    ObjectTypeNumber := pHandleInfo^.Information[I].ObjectTypeNumber;
                    Break;
                  end;
            finally
              FreeMem(pHandleInfo);
            end;
          finally
            CloseHandle(hFile);
          end;
         
          SystemInformation := GetInfoTable(SystemProcessesAndThreadsInformation);
          if SystemInformation <> nil then
          try
            pHandleInfo := GetInfoTable(SystemHandleInformation);
            if pHandleInfo <> nil then
            try
              ProgressBar1.Position := 0;
              ProgressBar1.Max := pHandleInfo^.NumberOfHandles;
              for I := 0 to pHandleInfo^.NumberOfHandles - 1 do
              begin
                if pHandleInfo^.Information[I].ObjectTypeNumber = ObjectTypeNumber then
                begin
                  hProcess := OpenProcess(PROCESS_DUP_HANDLE, True,
                    pHandleInfo^.Information[I].ProcessId);
                  if hProcess > 0 then
                  try
                    if DuplicateHandle(hProcess, pHandleInfo^.Information[I].Handle,
                      GetCurrentProcess, @hFile, 0, False, DUPLICATE_SAME_ACCESS) then
                    try
                      if Application.Terminated then Exit;
                      
                      FilePath := GetFileNameFromHandle(hFile);
                      if FilePath <> '' then
                      begin
                        FileDirectory := '';
                        for Drive := 0 to 25 do
                          if DosDevices[Drive].DosQueryLen > 0 then
                            if Copy(FilePath, 1, DosDevices[Drive].DosQueryLen) =
                              DosDevices[Drive].DiskDosQuery then
                            begin
                              FileDirectory := DosDevices[Drive].DiskLabel;
                              Delete(FilePath, 1, DosDevices[Drive].DosQueryLen);
                              Break;
                            end;
         
                        if FileDirectory = '' then Continue;    
         
                        TempSI := SystemInformation;
                        repeat
                          if TempSI^.ProcessID =
                            pHandleInfo^.Information[I].ProcessId then
                          begin
                            ProcessName := TempSI^.ModuleName;
                            Break;
                          end;
                          TempSI := Pointer(DWORD(TempSI) + TempSI^.NextOffset);
                        until TempSI^.NextOffset = 0;
         
                        SetLength(TmpFileName, MAX_PATH);
                        GetLongPathNameA(PChar(FileDirectory + FilePath), @TmpFileName[1], MAX_PATH);
                        Memo1.Lines.Add(ProcessName + ': ' + TmpFileName);  
                      end;
                    finally
                      CloseHandle(hFile);
                    end;
                  finally
                    CloseHandle(hProcess);
                  end;
                end;
                ProgressBar1.Position := ProgressBar1.Position + 1;
                Application.ProcessMessages;
              end;
            finally
              FreeMem(pHandleInfo);
            end;
          finally
            FreeMem(SystemInformation);
          end;
          ShowMessage('All handles found.');
        end;
         
        end.


      Целиком проект в аттаче...
      Прикреплённый файлПрикреплённый файлEnumOpenFiles.zip (223.41 Кбайт, скачиваний: 370)
        Наконец-то с помощья дебаггера и IDAPro я разобрался как работает "chkdsk.exe"! По началу думал, что он знает все эти дескрипторы, а потом их закрывает. Но оказалось гораздо жухе. Вот структура: chkdsk.exe => vfat.dll => ifsutil.dll => ntdll.dll.

        Вот, что делается до того как написать "Том отключен. ВCE ОТКРЫТЫЕ ДЕСКРИПТОРЫ ТОМА СТАЛИ НЕВЕРНЫ." (перевёл на Delphi, упрощённо):

        ExpandedWrap disabled
          type
           WSTRING = record
            l0, l1 : Word;
            Str    : PWideChar;
           end;
           PWSTRING = ^WSTRING;
           
           OBJECT_ATTRIBUTES = record
            Length: ULONG;
            RootDirectory: THandle;
            ObjectName: PWSTRING;
            Attributes: ULONG;
            SecurityDescriptor: PSECURITY_DESCRIPTOR;
            SecurityQualityOfService: Pointer; ///PSECURITY_QUALITY_OF_SERVICE;
           end;
           POBJECT_ATTRIBUTES = ^OBJECT_ATTRIBUTES;
           
           IO_STATUS_BLOCK = record
            Status: Integer; ///NTSTATUS;
            Pointer: Pointer; ///PVOID;
            Information: ^ULONG;
           end;
           PIO_STATUS_BLOCK = ^IO_STATUS_BLOCK;
           
          Function NtOpenFile(
           FileHandle: PHANDLE;
           DesiredAccess: ACCESS_MASK;
           ObjectAttributes: POBJECT_ATTRIBUTES;
           IoStatusBlock: PIO_STATUS_BLOCK; // out
           ShareAccess: ULONG;
           OpenOptions: ULONG): Integer; stdcall; external 'ntdll.dll' name 'NtOpenFile';
           
          Function NtFsControlFile(
            FileHandle: THandle;
            Event: THandle;
            ApcRoutine: Pointer; ///PIO_APC_ROUTINE;
            ApcContext: Pointer;
            IoStatusBlock: PIO_STATUS_BLOCK; // out
            FsControlCode: ULONG;
            InputBuffer: Pointer;
            InputBufferLength: ULONG;
            OutputBuffer: Pointer; // out
            OutputBufferLength: ULONG): Integer; stdcall; external 'ntdll.dll' name 'NtFsControlFile';
           
          Function NtClose(FileHandle: THandle): Integer; stdcall; external 'ntdll.dll' name 'NtClose';
           
          // Закрывает дескрипторы устройства, возвращает успешность операции.
          //  пример вызова для диска "E": DismountVolume('\??\E:')
          Function DismountVolume(DriveStr: PWideChar): Boolean;
          Var
           f   : HFile;
           OA  : OBJECT_ATTRIBUTES;
           SB  : IO_STATUS_BLOCK;
           sX  : WSTRING;
          Begin
           sX.l0:=Length(DriveStr)*2;
           sX.l1:=sX.l0+2;
           sX.Str:=DriveStr;
           
           OA.Length:=sizeof(OBJECT_ATTRIBUTES);
           OA.RootDirectory:=0;
           OA.ObjectName:=@sX;
           OA.Attributes:=$40;
           OA.SecurityDescriptor:=nil;
           OA.SecurityQualityOfService:=nil;
           
           if( NtOpenFile(@f, $100003, @OA, @SB, 3, $10) <> 0 )then
           Begin
            Result:=False;
            Exit;
           end;
           
           Result:=(NtFsControlFile(f, 0,nil,nil, @SB, $00090020,nil,0,nil,0)=0);
           NtClose(f);
          End;


        Для меня - это бесполезный код. Но может кому-то понадобится (например, для удаления неудаляющихся файлов). С диском 'C:' почему-то не работает.
          Цитата
          NtFsControlFile(f, 0,nil,nil, @SB, $00090020,nil,0,nil,0)=0);

          Лучше писать так:
          ExpandedWrap disabled
            NtFsControlFile(f, 0,nil,nil, @SB, FSCTL_DISMOUNT_VOLUME, nil,0,nil,0)=0);

          Потом в будуших версиях Винды будите долго думать почему не работает...если вдруг IOCTL код изменится...
            Ну если он измениться, то всеравно, как минимум, придется пересобирать исходник :)
              Вы правы! Но гораздо приятней и информативней читать FSCTL_DISMOUNT_VOLUME, нежели гадать что такое 0x00090020 ! ;)
                Абсолютно согласен :yes:
                  Все ведет к тому:

                  Любая дисковая утилита должна перед тем как записать на носитель
                  она должна заблокировать носитель для записи
                  Но OC также закрывает доступ!
                  Хотя досуп с ядра всегда есть в обоих случаях :)
                    Цитата Arazel @
                    Все ведет к тому:

                    Любая дисковая утилита должна перед тем как записать на носитель
                    она должна заблокировать носитель для записи
                    Но OC также закрывает доступ!
                    Хотя досуп с ядра всегда есть в обоих случаях

                    Что сказал?
                      На сколько я понимаю, 'NtFsControlFile' - недокументированная функция Windows. Где-то можно скачать описание таких функций в .pas или .h? Может кто знает.
                        В гугле поискать не пробовал? :)
                        http://www.google.ru/search?q=NtFsControlFile&start=0&ie=utf-8&oe=utf-8&client=firefox-a&rls=org.mozilla:ru:official
                        0 пользователей читают эту тему (0 гостей и 0 скрытых пользователей)
                        0 пользователей:


                        Рейтинг@Mail.ru
                        [ Script execution time: 0,0601 ]   [ 16 queries used ]   [ Generated: 28.04.24, 11:57 GMT ]