0

i'm actually programming an app to see what files are opened .

He is a part of a code that is not by me , i'm trying to using it but i don't understand it ... I'm trying to get the file names opened by the process , but the function is always resulting like : /Default or /Sessions/1/Windows ... Something like that.Please help me and sorry for my bad english

const
SystemHandleInformation = $10;
STATUS_SUCCESS = $00000000;
STATUS_BUFFER_OVERFLOW = $80000005;
STATUS_INFO_LENGTH_MISMATCH = $C0000004;
DefaulBUFFERSIZE = $100000;

type
OBJECT_INFORMATION_CLASS = (ObjectBasicInformation, ObjectNameInformation,
ObjectTypeInformation, ObjectAllTypesInformation, ObjectHandleInformation);

SYSTEM_HANDLE = packed record
uIdProcess: ULONG;
ObjectType: UCHAR;
Flags: UCHAR;
Handle: Word;
pObject: Pointer;
GrantedAccess: ACCESS_MASK;
end;

PSYSTEM_HANDLE = ^SYSTEM_HANDLE;
SYSTEM_HANDLE_ARRAY = Array [0 .. 0] of SYSTEM_HANDLE;
PSYSTEM_HANDLE_ARRAY = ^SYSTEM_HANDLE_ARRAY;

SYSTEM_HANDLE_INFORMATION = packed record
uCount: ULONG;
Handles: SYSTEM_HANDLE_ARRAY;
end;

PSYSTEM_HANDLE_INFORMATION = ^SYSTEM_HANDLE_INFORMATION;

TNtQuerySystemInformation = function(SystemInformationClass: DWORD;
SystemInformation: Pointer; SystemInformationLength: DWORD;
ReturnLength: PDWORD): THandle; stdcall;
TNtQueryObject = function(ObjectHandle: cardinal;
ObjectInformationClass: OBJECT_INFORMATION_CLASS;
ObjectInformation: Pointer; Length: ULONG; ResultLength: PDWORD)
: THandle; stdcall;

UNICODE_STRING = packed record
Length: Word;
MaximumLength: Word;
Buffer: PWideChar;
 end;

OBJECT_NAME_INFORMATION = UNICODE_STRING;
POBJECT_NAME_INFORMATION = ^OBJECT_NAME_INFORMATION;

Var
NTQueryObject: TNtQueryObject;
NTQuerySystemInformation: TNtQuerySystemInformation;


Procedure EnumerateOpenFiles();
var
sDummy: string;
hProcess: THandle;
hObject: THandle;
ResultLength: DWORD;
aBufferSize: DWORD;
aIndex: Integer;
pHandleInfo: PSYSTEM_HANDLE_INFORMATION;
HDummy: THandle;
lpwsName: PWideChar;
lpwsType: PWideChar;
lpszProcess: pchar;
begin
aBufferSize := DefaulBUFFERSIZE;
pHandleInfo := AllocMem(aBufferSize);
HDummy := NTQuerySystemInformation(DWORD(SystemHandleInformation),
pHandleInfo, aBufferSize, @ResultLength); // Get the list of handles

if (HDummy = STATUS_SUCCESS) then // If no error continue
begin

for aIndex := 0 to pHandleInfo^.uCount - 1 do // iterate the list
begin
  hProcess := OpenProcess(PROCESS_DUP_HANDLE or PROCESS_QUERY_INFORMATION or
    PROCESS_VM_READ, False, pHandleInfo.Handles[aIndex].uIdProcess);
  // open the process to get aditional info
  if (hProcess <> INVALID_HANDLE_VALUE) then // Check valid handle
  begin

    hObject := 0;
    if DuplicateHandle(hProcess, pHandleInfo.Handles[aIndex].Handle,
      GetCurrentProcess, @hObject, STANDARD_RIGHTS_REQUIRED, False, 0) then
    // Get  a copy of the original handle
    begin

      lpwsName := GetObjectInfo(hObject, ObjectTypeInformation);

      // Get the filename linked to the handle
      if (lpwsName <> nil) then
      begin
        lpwsType := GetObjectInfo(hObject, ObjectNameInformation);
        lpszProcess := AllocMem(MAX_PATH);

        if GetModuleFileNameEx(hProcess, 0, lpszProcess, MAX_PATH) <> 0 then
          // get the name of the process
          sDummy := ExtractFileName(lpszProcess)
        else
          sDummy := 'System Process';


          with MainForm.UsedFilesListView.Items.add do
          begin

            // Ajout
            Caption := sDummy;

            ImageIndex := -1;

            SubItems.add(lpwsName);

          end;


        // Writeln('PID      ', pHandleInfo.Handles[aIndex].uIdProcess);
        // Writeln('Handle   ', pHandleInfo.Handles[aIndex].Handle);
        // Writeln('Process  ', sDummy);
        // Writeln('FileName ', string(lpwsName));
        // Writeln;

        FreeMem(lpwsName);
        FreeMem(lpwsType);
        FreeMem(lpszProcess);
      end;
      CloseHandle(hObject);
    end;
    CloseHandle(hProcess);
  end;
end;
end;
FreeMem(pHandleInfo);

end;
user2785119
  • 13
  • 1
  • 4
  • We cannot run this code. Surely it would be easier for us if you posted a complete SSCCE that we could run? Since we cannot run it, and since you are using non-standard terminology in the header translation, we don't even know what this code does. What is SystemHandleInformation? We can guess, but we should not have to. – David Heffernan Oct 29 '13 at 14:34
  • The question you should have asked is, "How do I enumerate all the open file handles?" – David Heffernan Oct 29 '13 at 14:42
  • 1
    Omg i'm just asking how to convert a path Session\1\WIndows ... Why are you agressive – user2785119 Oct 29 '13 at 14:44
  • I'm not aggressive. I'd like to ask a better question. You want us to do something with the code, but it's not all there. Can we have an SSCCE please? – David Heffernan Oct 29 '13 at 14:45
  • The edit is not an SSCCE. You need to provide a complete program. In fact the program at the question to which I linked is a good example. And it's probably your SSCCE. I must advise you to slow down and take more care. I know you want an answer now but you need more haste and less speed. – David Heffernan Oct 29 '13 at 14:59

2 Answers2

2

First of all, you failed to provide SSCCE in your question, which greatly reduces chances for someone to take a look and try to fix your code. Because we would need to think about all missing declarations and what units to include to make compilable code, and yeah, thats boring.

Second, copy and paste programming is bad practice and it won't make your programming skills to improve. Try to consult MSDN about what certain APIs do and how to use them, then try to fiddle with the code by using informations you gathered through Google/MSDN.

About question itself, it's a tricky one, and widely undocumented.

Check this useful post on SysInternals forums which roughly explains what you have to do: HOWTO: Enumerate handles.

After acquiring file paths, you have to replace MS-DOS device paths with their mapped paths (e.g. \Device\HarddiskVolume1 > C:\). You can do that with GetLogicalDriveStrings and QueryDosDevice APIs.

Now the code itself. You would need JEDI API library to compile it. Tested on XE2:

{$APPTYPE CONSOLE}

program FileHandles;

uses
  Winapi.Windows,
  System.Classes,
  JwaNative,
  JwaNtStatus,
  JwaWinternl;

procedure EnumerateDevicePaths(const ADeviceNames, ADevicePaths: TStringList);
var
  drives     : array[0..4095] of Char;
  pdrive     : PChar;
  drive      : String;
  drive_path : array[0..4095] of Char;
  sdrive_path: String;
begin
  ADeviceNames.Clear;
  ADevicePaths.Clear;

  if GetLogicalDriveStrings(SizeOf(drives), drives) = 0 then
    Exit;

  pdrive := drives;
  while pdrive^ <> #0 do
  begin
    drive := Copy(pdrive, 0, 4);
    if drive <> '' then
    begin
      if drive[Length(drive)] = '\' then
        Delete(drive, Length(drive), 1);

      QueryDosDevice(PChar(drive), drive_path, SizeOf(drive_path));
      sdrive_path := drive_path;

      ADeviceNames.Add(drive);
      ADevicePaths.Add(sdrive_path);
    end;
    Inc(pdrive, 4);
  end;
end;

function EnumerateOpenFiles: Integer;
const
  HANDLE_BUFFER_INCREASE_CHUNK = 16 * 1024; // increase handles buffer by 16kb
type
  // this struct is missing in JEDI declarations (?)
  TSystemHandleInformations = record
    HandleCount: ULONG;
    Handles    : array[0..0] of TSystemHandleInformation;
  end;
  PSystemHandleInformations = ^TSystemHandleInformations;
var
  phandles_info : PSystemHandleInformations;
  phandles_size : DWORD;
  retcode       : DWORD;
  C1, C2        : Integer;
  phandle_info  : PSystemHandleInformation;
  process_handle: THandle;
  dup_handle    : THandle;
  obj_name_info : PObjectNameInformation;
  obj_name_size : DWORD;
  fname         : String;
  device_names  : TStringList;
  device_paths  : TStringList;
begin
  device_names := TStringList.Create;
  try
    device_paths := TStringList.Create;
    try
      EnumerateDevicePaths(device_names, device_paths); // enumerate devices list, so we can use these later on to replace MS-DOS paths with mapped ones

      phandles_size := HANDLE_BUFFER_INCREASE_CHUNK; // start with HANDLE_BUFFER_INCREASE_CHUNK value
      phandles_info := AllocMem(phandles_size);
      try
        retcode := NtQuerySystemInformation(DWORD(SystemHandleInformation), phandles_info, phandles_size, nil);
        while retcode = STATUS_INFO_LENGTH_MISMATCH do // realloc handles buffer memory until it's big enough to accept all handles data
        begin
          Inc(phandles_size, HANDLE_BUFFER_INCREASE_CHUNK);
          ReallocMem(phandles_info, phandles_size);
          retcode := NtQuerySystemInformation(DWORD(SystemHandleInformation), phandles_info, phandles_size, nil);
        end;

        if retcode <> STATUS_SUCCESS then
          Exit(retcode);

        // iterate through opened handles
        for C1 := 0 to phandles_info^.HandleCount do
        begin
          phandle_info := pointer(Integer(@phandles_info^.Handles) + C1 * SizeOf(TSystemHandleInformation)); // get pointer to C1 handle info structure

          // if ObjectType is not file, or if handle is named pipe (which would make Nt*() function to block), we skip to the next handle
          // GrantedAccess mask here is very cryptic, I've been unable to find more information about it on Google, all codes use static hex numbers for check
          if (phandle_info^.ObjectTypeNumber <> 28) or
             (phandle_info^.GrantedAccess = $0012019F) or
             (phandle_info^.GrantedAccess = $001A019F) or
             (phandle_info^.GrantedAccess = $00120189) then
            Continue;

          process_handle := OpenProcess(PROCESS_DUP_HANDLE, FALSE, phandle_info^.ProcessId);
          if process_handle <> 0 then
          try
            if DuplicateHandle(process_handle, phandle_info^.Handle, GetCurrentProcess, @dup_handle, 0, FALSE, 0) then
            try
              obj_name_size := SizeOf(TObjectNameInformation);
              obj_name_info := AllocMem(obj_name_size);
              try
                // get path to the file
                retcode := NtQueryObject(dup_handle, ObjectNameInformation, obj_name_info, obj_name_size, @obj_name_size);
                if retcode <> STATUS_SUCCESS then
                begin
                  ReallocMem(obj_name_info, obj_name_size);
                  retcode := NtQueryObject(dup_handle, ObjectNameInformation, obj_name_info, obj_name_size, nil);
                end;

                if retcode <> STATUS_SUCCESS then
                  Continue;

                fname := obj_name_info^.Name.Buffer;

                // replace MS-DOS device names with their mappings
                for C2 := 0 to device_paths.Count - 1 do
                  if Copy(fname, 1, Length(device_paths[C2])) = device_paths[C2] then
                  begin
                    Delete(fname, 1, Length(device_paths[C2]));
                    fname := device_names[C2] + fname;
                    Break;
                  end;

                // do necessary processing with fname here
                WriteLn(phandle_info^.ProcessId, ': ', fname);
              finally
                FreeMem(obj_name_info, obj_name_size);
              end;
            finally
              CloseHandle(dup_handle);
            end;
          finally
            CloseHandle(process_handle);
          end;
        end;
      finally
        FreeMem(phandles_info, phandles_size);
      end;

      Exit(STATUS_SUCCESS);
    finally
      device_paths.Free;
    end;
  finally
    device_names.Free;
  end;
end;

begin
  EnumerateOpenFiles;
  Write('Done!');
  ReadLn;
end.

This code can be improved in several more ways, but I gave you enough to start. For example, one of the optimizations would be to avoid opening same process multiple times by sorting handle list by PID, then opening process only once to check the handle group with those same PIDs.

rsrx
  • 1,433
  • 1
  • 13
  • 25
0

It appears that you are using code from here: Delphi - get what files are opened by an application. This code claims to:

list all open handles from all processes

In other words it lists handles that are associated with objects other than file objects. The file names that you see that do not look like file names are indeed so. They are the names of objects other than files, to which the process has handles.

Community
  • 1
  • 1
David Heffernan
  • 601,492
  • 42
  • 1,072
  • 1,490