-1

I need know how enumarate handles on 64 bits applicatio, i made it on32 bits and works perfectly, but the same code compiled as 64 bits only show some handles. i already changed variables to longword for example but without success. i read about SystemHandleInformation on x64 should be another value instead $10 (16 dec) but tried without success.

program Project1;

{$APPTYPE CONSOLE}

{$R *.res}

uses
  System.SysUtils,
  Windows,
  Classes,
  PsApi;

const
  SystemHandleInformation       = $10;
  STATUS_SUCCESS                = $00000000;
  STATUS_BUFFER_OVERFLOW        = $80000005;
  STATUS_INFO_LENGTH_MISMATCH   = $C0000004;
  //
  type
  NTSTATUS = Cardinal;
  OBJECT_INFORMATION_CLASS = (ObjectBasicInformation, ObjectNameInformation,
                              ObjectTypeInformation, ObjectAllTypesInformation, ObjectHandleInformation);
  //
  SYSTEM_HANDLE = packed record
    UniqueProcessId       : USHORT;
    CreatorBackTraceIndex : USHORT;
    ObjectTypeIndex       : UCHAR;
    HandleAttributes      : UCHAR;
    HandleValue           : USHORT;
    HObject               : PVOID;
    GrantedAccess         : ULONG;
  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;

  var
  NTQueryObject             : TNtQueryObject;
  NTQuerySystemInformation  : TNtQuerySystemInformation;

Procedure EnumerateOpenFiles();
const
  HANDLE_BUFFER_INCREASE_CHUNK = 5000 * 1024;
var
  sDummy      : string;
  hProcess    : THandle;
  hObject     : THandle;
  ResultLength: DWORD;
  aBufferSize : DWORD;
  aIndex      : LONG;//Integer;
  pHandleInfo : PSYSTEM_HANDLE_INFORMATION;
  HDummy      : THandle;

  lpszProcess : PWideChar;
begin
  AbufferSize      := HANDLE_BUFFER_INCREASE_CHUNK;
  pHandleInfo      := AllocMem(AbufferSize);
  HDummy           := NTQuerySystemInformation(DWORD(SystemHandleInformation), pHandleInfo, AbufferSize, @ResultLength);  //Get the list of handles

  if(HDummy = STATUS_SUCCESS) then
  begin
    for aIndex:=0 to pHandleInfo^.uCount-1 do
    begin
      hProcess := OpenProcess(PROCESS_DUP_HANDLE or PROCESS_QUERY_INFORMATION or PROCESS_VM_READ, FALSE, pHandleInfo.Handles[aIndex].UniqueProcessId);  //open the process to get aditional info
      if(hProcess <> INVALID_HANDLE_VALUE) then
      begin
        hObject := 0;

        if DuplicateHandle(hProcess, pHandleInfo.Handles[aIndex].HandleValue, GetCurrentProcess(), @hObject, STANDARD_RIGHTS_REQUIRED, FALSE, 0) then  //Get  a copy of the original handle
        begin
          lpszProcess := AllocMem(MAX_PATH);
          if GetModuleFileNameEx(hProcess, 0,lpszProcess, MAX_PATH) <> 0 then
            sDummy:=lpszProcess
          else
            sDummy:= 'System Process';

            WriteLn(Format('PID [%d] Process [%s]',  [pHandleInfo.Handles[aIndex].UniqueProcessId, sDummy]));

          FreeMem(lpszProcess);
          CloseHandle(hObject);
        end;

        CloseHandle(hProcess);
      end;
    end;
  end;

  WriteLn('Finish');
  FreeMem(pHandleInfo);
end;

begin
  NTQueryObject            := GetProcAddress(GetModuleHandle('NTDLL.DLL'), 'NtQueryObject');
  NTQuerySystemInformation := GetProcAddress(GetModuleHandle('NTDLL.DLL'), 'NtQuerySystemInformation');
  if (@NTQuerySystemInformation <> nil) and (@NTQuerySystemInformation <> nil) then EnumerateOpenFiles() else WriteLn('falhou no inicio');
  ReadLn;
end.

That works perfectly on x86 application, but when i change to x64 he don't show the same results as x86, anyone know why?

Sertac Akyuz
  • 54,131
  • 4
  • 102
  • 169
PâM Bolsoni
  • 11
  • 1
  • 6
  • Wasn't this same question asked recently? – David Heffernan Jul 25 '18 at 14:46
  • @David Yes, and someone advised to delete prior and re-ask. – Jerry Dodge Jul 25 '18 at 15:19
  • Your structure declarations looks wrong. You should use ones that are known to be good. For instance from the JEDI header translations. – David Heffernan Jul 25 '18 at 15:24
  • 1
    I'd start by logging failures, but from experience GrantedAccess doesn't always allow access unless you run as TrustedInstaller. – FredS Jul 25 '18 at 16:03
  • 1
    `PROCESS_BASIC_INFORMATION` looks absolutely wrong. `DWORD` only happened to be the matching size in 32 bit, but it's not the case anymore for 64 bit. – Günther the Beautiful Jul 25 '18 at 16:12
  • 1
    Indeed nothing similar to the [actual api](https://learn.microsoft.com/en-us/windows/desktop/api/winternl/nf-winternl-ntqueryinformationprocess). Packing also looks suspicious. – Sertac Akyuz Jul 25 '18 at 16:38
  • Yes, on 32 bits works perfectly, i need know what need change to show the same results on 64 bits, PROCESS_BASIC_INFORMATION isn't used. – PâM Bolsoni Jul 25 '18 at 18:22
  • I told you what to do next. Get hold of correct header translations. – David Heffernan Jul 25 '18 at 19:12
  • already did it but don't work SYSTEM_HANDLE = packed record uIdProcess : ULONG_PTR;//ULONG; ObjectType : USHORT;//UCHAR; Flags : ULONG;//UCHAR; Handle : ULONG_PTR;//Word; pObject : PVOID;//Pointer; GrantedAccess : ULONG;//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_PTR;//ULONG; Handles : SYSTEM_HANDLE_ARRAY; end; – PâM Bolsoni Jul 25 '18 at 23:52
  • @pam did you read my answer, the records are not packed. – Sertac Akyuz Jul 26 '18 at 01:45
  • Do you know what a packed record and what a non-packed record is? – Sertac Akyuz Jul 26 '18 at 02:11
  • no i don't know. – PâM Bolsoni Jul 26 '18 at 15:02
  • Ok. Read it from the [documentation](http://docwiki.embarcadero.com/RADStudio/en/Structured_Types_(Delphi)#Alignment_of_Structured_Types) please. Meanwhile I replied to your comment under the answer for what modification you should do in your code. – Sertac Akyuz Jul 26 '18 at 15:10

1 Answers1

3

Local variable names and two unremoved comments suggest that this is a variation on code posted by RRUZ at 2009 here. At that time there was no 64 bit Delphi version so it was not possible for him to test the code on 64 bits. Anyway, I was able to test this with XE2 on W7x64 using "jwanative.pas" for the missing NtQuerySystemInformation from your sample. You also have one end too many, you need to remove the end that comes before FreeMem(lpszProcess);. Otherwise the code will not compile - probably a copy/paste error on your part.

The error is mis-packing the SYSTEM_HANDLE and SYSTEM_HANDLE_INFORMATION records, their layouts are messed up for 64 bit when packed. This page by Geoff Chappell (have to acknowledge according to the site's terms) suggests that

The SYSTEM_HANDLE_INFORMATION is 0x14 and 0x20 bytes in 32-bit and 64-bit Windows, respectively.

Unpack it to have 32 bytes in x64 instead of 28 while packed.

Similarly, this page suggests:

The SYSTEM_HANDLE_TABLE_ENTRY_INFO structure is 0x10 or 0x18 bytes in 32-bit and 64-bit Windows, respectively.

Unpack your record and it will be 24 bytes on x64 instead of 20 while packed. Although the members slightly differ, you'll be able to see it runs about the same as on x32.


Note that the code may or may not run on later/future versions of OS. Microsoft not only does not fully document system information retrieval but also warn that

The NtQuerySystemInformation function and the structures that it returns are internal to the operating system and subject to change from one release of Windows to another.

Sertac Akyuz
  • 54,131
  • 4
  • 102
  • 169
  • i changed structures to the same as said on sites who you said, x86 show the results as i expect, but on x64 still the same only show one result, not what i want who show on x86. what i mean on x64 is, i'm compiling this program as 64 bits, if i compile as 32 bits show the result as i expect, but if i compile as 64 bits don't show the same results as compiled in 32 bits. – PâM Bolsoni Jul 26 '18 at 00:03
  • Compiled as 64 bits DuplicateHandle return error 6 who is ERROR_INVALID_HANDLE, so change something from 32 bits, to 64 bits compilation. – PâM Bolsoni Jul 26 '18 at 00:20
  • 1
    Modify your post to include a [mcve]. That compiles. That's self inclusive - no snippets, whole program. That's minimal - no unused records, no unnecessary code, no forms or memos, a console application. Then we can talk about the same thing. – Sertac Akyuz Jul 26 '18 at 01:49
  • Modified topic to a console example who run, now the question is how made it show the same handles results compiled as 64 BITS like show compiled as 32 BITS – PâM Bolsoni Jul 26 '18 at 14:56
  • Thanks. Now find `SYSTEM_HANDLE = packed record` in your code and replace it with `SYSTEM_HANDLE = record`. Then find `SYSTEM_HANDLE_INFORMATION = packed record` and replace it with `SYSTEM_HANDLE_INFORMATION = record`. Use copy/paste, don't type it. Run again for 64 bits. – Sertac Akyuz Jul 26 '18 at 15:04
  • so much thanks. just a stupid "packed" who generate this problem. – PâM Bolsoni Jul 26 '18 at 15:22
  • @pam - I don't think it's specific to XP. I get around 67000 DuplicateHandle fails on W7, around 66000 when run elevated. I think the error it returns is accurate. – Sertac Akyuz Jul 26 '18 at 20:03
  • You know why OpenProcess consumn so much cpu on this code? i tried add some sleeps to reduce it but just add one and code stop working correctly. added a thread to do the job but the consumn it's the same. i checked the consumn is from OpenProcess. – PâM Bolsoni Aug 08 '18 at 00:07