О SystemHandleInformation для 64-битного приложения

Мне нужно знать, как enumarate обрабатывает 64-битные приложения, я сделал это на 32-битных и работает отлично, но тот же код, скомпилированный как 64-битные, показывает только некоторые дескрипторы. Я уже изменил переменные на длинное слово, например, но безуспешно. я читал о SystemHandleInformation на x64 должен быть другое значение вместо $10 (16 декабря), но пытался безуспешно.

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.

Это прекрасно работает в приложении x86, но когда я перехожу на x64, он не показывает те же результаты, что и x86, кто-нибудь знает почему?

1 ответ

Решение

Имена локальных переменных и два не удаленных комментария позволяют предположить, что это вариант кода, размещенного RRUZ в 2009 году здесь. В то время не было 64-битной версии Delphi, поэтому он не мог протестировать код на 64-битной версии. Во всяком случае, я смог проверить это с XE2 на W7x64, используя "jwanative.pas" для пропавших без вести NtQuerySystemInformation из вашего образца. У вас также есть один end слишком много, вам нужно удалить end что приходит раньше FreeMem(lpszProcess);, В противном случае код не скомпилируется - возможно, ошибка копирования / вставки с вашей стороны.

Ошибка - неправильная упаковка SYSTEM_HANDLE а также SYSTEM_HANDLE_INFORMATION записи, их макеты перепутаны на 64 бит при упаковке. Эта страница Джеффа Чаппелла (должна быть подтверждена в соответствии с условиями сайта) предполагает, что

SYSTEM_HANDLE_INFORMATION составляет 0x14 и 0x20 байтов в 32-битной и 64-битной Windows, соответственно.

Распакуйте его, чтобы иметь 32 байта в x64 вместо 28 во время упаковки.

Точно так же эта страница предлагает:

Структура SYSTEM_HANDLE_TABLE_ENTRY_INFO составляет 0x10 или 0x18 байтов в 32-битной и 64-битной Windows соответственно.

Распакуйте свою запись, и она будет 24 байта на x64 вместо 20 во время упаковки. Хотя члены немного отличаются, вы сможете увидеть, что он работает примерно так же, как на x32.


Обратите внимание, что код может запускаться или не запускаться в более поздних / будущих версиях ОС. Microsoft не только полностью документирует поиск информации о системе, но и предупреждает, что

Функция NtQuerySystemInformation и возвращаемые ей структуры являются внутренними для операционной системы и могут изменяться от одного выпуска Windows к другому.

Другие вопросы по тегам