HoShiMin
4/9/2015 - 7:27 PM

Многофункциональный API для работы с процессами

Многофункциональный API для работы с процессами

unit ProcessAPI;

interface

//{$DEFINE DEBUG_PRIVILEGE}

uses
  Windows, TlHelp32, CodepageAPI;


// Результат функции GetProcessList - массив процессов:
type
  // Информация о процессе (TlHelp32):
  PROCESSENTRY32A = record
    Size            : DWORD;
    Usage           : DWORD;
    ProcessID       : DWORD;
    DefaultHeapID   : ULONG_PTR;
    ModuleID        : DWORD;
    ThreadsCount    : DWORD;
    ParentProcessID : DWORD;
    Priority        : Longint;
    Flags           : DWORD;
    ExeFile         : array [0 .. MAX_PATH - 1] of AnsiChar;
  end;
  TProcessEntry32A = PROCESSENTRY32A;

  // Информация о потоке (TlHelp32):
  THREADENTRY32 = record
    Size           : DWORD;
    Usage          : DWORD;
    ThreadID       : DWORD;
    OwnerProcessID : DWORD;
    Priority       : Longint;
    DeltaPriority  : Longint;
    Flags          : DWORD;
  end;
  TThreadEntry32 = THREADENTRY32;

  TProcessInfo = TProcessEntry32A;
  TProcessList = array of TProcessInfo;

// Информация о загруженноых модулях:
  TModuleInfo = record
    FullPath     : AnsiString; // Полный путь к модулю
    ModuleName   : AnsiString; // Имя модуля
    BaseAddress  : UInt64;     // Базовый адрес загрузки (начало распакованного файла в ОЗУ)
    EntryAddress : UInt64;     // Точка входа
    SizeOfImage  : Cardinal;   // Размер образа в байтах
  end;

// Базовая информация о процессе:
  TProcessBasicInfo = record
    ExitStatus      : LongWord;
    AffinityMask    : UInt64;
    BasePriority    : LongWord;
    UniqueProcessId : UInt64;
    InheritedFromUniqueProcessId : UInt64;
  end;

  TModulesList = record
    Length: Cardinal;               // Всего загруженных модулей
    Modules: array of TModuleInfo;  // Массив из информации о каждом модуле
  end;

// Структура результата функции GetProcessInfo:
  PROCESS_INFO = record
  // Идентификаторы:
    Handle          : LongWord; // Хэндл процесса при получении информации
    ID              : UInt64;   // Идентификатор процесса
    InheritedFromID : UInt64;   // Идентификатор процесса-родителя
    SessionID       : LongWord; // Идентификатор сессии

  // Свойства процесса:
    Priority     : UInt64; // Приоритет процесса
    AffinityMask : UInt64; // Маска соответствия процесса ядрам (число надо перевести в двоичный вид)

  // Разное:
    IsDebugged     : Boolean;  // Отлаживается ли процесс
    ExitStatus     : LongWord; // Код выхода
    ThreadsCount   : LongWord; // Количество потоков
    HandlesCount   : LongWord; // Количество открытых хэндлов
    ReservedMemory : LongWord; // Зарезервированная память в байтах

  // Адреса:
    ImageBaseAddress : UInt64; // Адрес загрузки образа в оперативной памяти
    LdrAddress       : UInt64; // Адрес загрузочной информации
    PEBAddress       : UInt64; // Адрес блока окружения процесса (структура PEB)

  // Хэндлы ввода-вывода:
    ConsoleHandle   : UInt64; // Хэндл консоли
    StdInputHandle  : UInt64; // Стандартный хэндл ввода
    StdOutputHandle : UInt64; // Стандартный хэндл вывода
    StdErrorHandle  : UInt64; // Стандартный хэндл вывода ошибок

  // Строковые параметры:
    ProcessName          : AnsiString; // Имя процесса
    CurrentDirectoryPath : AnsiString; // Текущая папка
    ImagePathName        : AnsiString; // Имя образа процесса
    CommandLine          : AnsiString; // Командная строка

  // Список загруженных модулей:
    ModulesList: TModulesList;

  // Глобальные системные свойства:
    Is64BitProcess: BOOL; // 64х-битный ли процесс
  end;

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

// Преобразование ProcessID в Handle:
function ProcessIDToHandle(ProcessID: LongWord; AccessRights: LongWord = PROCESS_VM_READ or PROCESS_QUERY_INFORMATION): THandle;

// Преобразование Handle в ProcessID:
function HandleToProcessID(ProcessHandle: THandle): LongWord;

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

// 64х-битная ли ОС:
function Is64BitWindows: BOOL;

// Получение подробной информации о процессе по его ID:
function GetProcessInfo(ProcessID: LongWord; out ProcessInfo: PROCESS_INFO; Process32_64CompatibleMode: Boolean = false): Boolean;

// Получение базовой информации о процессе по его ID:
function GetProcessBasicInfo(ProcessID: LongWord; out ProcessBasicInfo: TProcessBasicInfo): Boolean;

// 64х-битный ли процесс:
function Is64BitProcess(ProcessID: LongWord): LongBool;

// Запущен ли процесс (по имени процесса):
function IsProcessLaunched(ProcessName: AnsiString): Boolean; overload;

// Запущен ли процесс (по ID процесса):
function IsProcessLaunched(ProcessID: LongWord): Boolean; overload;

// Есть ли библиотека в процессе:
function IsLibInProcess(LibName: AnsiString; ProcessID: LongWord): Boolean;

// Получить список запущенных процессов с краткой информацией:
procedure GetProcessList(out ProcessList: TProcessList);

// Получить информацию из TlHelp32 по ID процесса:
function GetTlHelp32ProcessInfo(ProcessID: LongWord): TProcessInfo; overload;

// Получить информацию из TlHelp32 по имени процесса:
function GetTlHelp32ProcessInfo(ProcessName: AnsiString): TProcessInfo; overload;

// Запуск процесса:
procedure StartProcess(const CommandLine: string; out ProcessHandle: THandle; out ProcessID: LongWord);

// Ожидание завершения процесса:
procedure WaitProcess(ProcessID: LongWord);

// Убить процесс по ID:
procedure KillProcess(ProcessID: LongWord); overload;

// Убить процесс по имени:
procedure KillProcess(ProcessName: AnsiString; CanKillSelf: Boolean = False); overload;

// Получить загрузку ЦП данным процессом (Delay ставить в пределах от 25 до 500, меньше - неточно, больше - ни к чему):
function GetProcessCPULoading(ProcessID: LongWord; Delay: Cardinal): Single;

//HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH

type
  Pointer64 = UInt64;
  Pointer32 = UInt;

// Структура для получения данных о процессе под Win32
  PROCESS_BASIC_INFORMATION = record
    ExitStatus: LongWord;
    PebBaseAddress: Pointer;
    AffinityMask: Cardinal;
    BasePriority: Integer;
    UniqueProcessId: LongWord;
    InheritedFromUniqueProcessId: LongWord;
  end;

  PROCESS_BASIC_INFORMATION64 = record
    ExitStatus: LongWord;
    Reserved0: LongWord;
    PebBaseAddress: UInt64;
    AffinityMask: UInt64;
    BasePriority: LongWord;
    Reserved1: LongWord;
    UniqueProcessId: UInt64;
    InheritedFromUniqueProcessId: UInt64;
  end;

  PROCESS_BASIC_INFORMATION_WOW64 = record
    Wow64PebAddress: UInt64;
  end;


  UCHAR = AnsiChar;

// Юникодная строка в Win32
  UNICODE_STRING = record
    Length: Word;
    MaximumLength: Word;
    Buffer: Pointer;
  end;

  UNICODE_STRING_WOW64 = record
    Length: Word;
    MaximumLength: Word;
    Buffer: Pointer32;
  end;

  UNICODE_STRING64 = record
    Length: Word;
    MaximumLength: Word;
    Fill: LongWord;
    Buffer: UInt64;
  end;

  PLDR_MODULE = Pointer;
  TModuleListEntry = record
    ForwardLDRModule: PLDR_MODULE;
    BackwardLDRModule: PLDR_MODULE;
  end;

  LDR_MODULE = record
    InLoadModuleOrderList: TModuleListEntry;
    InMemoryModuleOrderList: TModuleListEntry;
    InInitializationModuleOrderList: TModuleListEntry;
    BaseAddress: Pointer;
    EntryPoint: Pointer;
    SizeOfImage: UInt;
    FullDLLName: UNICODE_STRING;
    BaseDLLName: UNICODE_STRING;
    Flags: ULONG;
    LoadCount: Short;
    TlsIndex: Short;
    TimeDateStamp: ULONG;
  end;

  PEB_LDR_DATA = record
    Size: ULong;
    Initialized: Boolean;
    SsHandle: Pointer;
    InLoadModuleOrderList: TModuleListEntry;
    InMemoryModuleOrderList: TModuleListEntry;
    InInitializationModuleOrderList: TModuleListEntry;
  end;
  PPEB_LDR_DATA = ^PEB_LDR_DATA;

// LDR WOW64:

  PLDR_MODULE_WOW64 = Pointer32;
  TModuleListEntryWow64 = record
    ForwardLDRModule: PLDR_MODULE_WOW64;
    BackwardLDRModule: PLDR_MODULE_WOW64;
  end;

  LDR_MODULE_WOW64 = record
    InLoadModuleOrderList: TModuleListEntryWow64;
    InMemoryModuleOrderList: TModuleListEntryWow64;
    InInitializationModuleOrderList: TModuleListEntryWow64;
    BaseAddress: Pointer32;
    EntryPoint: Pointer32;
    SizeOfImage: UInt;
    FullDLLName: UNICODE_STRING_WOW64;
    BaseDLLName: UNICODE_STRING_WOW64;
    Flags: ULONG;
    LoadCount: Short;
    TlsIndex: Short;
    TimeDateStamp: ULONG;
  end;

  PEB_LDR_DATA_WOW64 = record
    Size: ULong;
    Initialized: Boolean;
    SsHandle: Pointer32;
    InLoadModuleOrderList: TModuleListEntryWow64;
    InMemoryModuleOrderList: TModuleListEntryWow64;
    InInitializationModuleOrderList: TModuleListEntryWow64;
  end;
  PPEB_LDR_DATA_WOW64 = Pointer32;


// LDR x64:

  PLDR_MODULE64 = UInt64;
  TModuleListEntry64 = record
    ForwardLDRModule: PLDR_MODULE64;
    BackwardLDRModule: PLDR_MODULE64;
  end;

  LDR_MODULE64 = record
    InLoadModuleOrderList: TModuleListEntry64;
    InMemoryModuleOrderList: TModuleListEntry64;
    InInitializationModuleOrderList: TModuleListEntry64;
    BaseAddress: Pointer64;
    EntryPoint: Pointer64;
    SizeOfImage: ULong;
    FullDLLName: UNICODE_STRING64;
    BaseDLLName: UNICODE_STRING64;
    Flags: ULONG;
    LoadCount: Short;
    TlsIndex: Short;
    TimeDateStamp: ULONG;
  end;

  PEB_LDR_DATA64 = record
    Size: UInt;
    Initialized: Boolean;
    SsHandle: UInt64;
    InLoadModuleOrderList: TModuleListEntry64;
    InMemoryModuleOrderList: TModuleListEntry64;
    InInitializationModuleOrderList: TModuleListEntry64;
  end;


  PEB = record
    InheritedAddressSpace: UCHAR;
    ReadImageFileExecOptions: UCHAR;
    BeingDebugged: Boolean;
    BitField: UChar;
    Mutant: Pointer;
    ImageBaseAddress: Pointer;
    Ldr: PPEB_LDR_DATA;
    ProcessParameters: Pointer;
    Reserved0: array [0..103] of Byte;
    Reserved1: array [0..51] of Pointer;
    PostProcessInitRoutine: Pointer;
    Reserved2: array [0..127] of Byte;
    Reserved3: Pointer;
    SessionID: LongWord;
  end;

  PEB_WOW64 = record
    InheritedAddressSpace: UCHAR;
    ReadImageFileExecOptions: UCHAR;
    BeingDebugged: Boolean;
    BitField: UChar;
    Mutant: Pointer32;
    ImageBaseAddress: Pointer32;
    Ldr: PPEB_LDR_DATA_WOW64;
    ProcessParameters: Pointer32;
    Reserved0: array [0..103] of Byte;
    Reserved1: array [0..51] of Pointer32;
    PostProcessInitRoutine: Pointer32;
    Reserved2: array [0..127] of Byte;
    Reserved3: Pointer32;
    SessionID: LongWord;
  end;

  PEB64 = record
    InheritedAddressSpace: Byte;
    ReadImageFileExecOptions: Byte;
    BeingDebugged: Boolean;
    BitField: Byte;
    Reserved0: LongWord;
    Mutant: UInt64;
    ImageBaseAddress: UInt64;
    Ldr: UInt64;
    ProcessParameters: UInt64;
    Reserved1: array [0..519] of Byte;
    PostProcessInitRoutine: UInt64;
    Reserved2: array [0..135] of Byte;
    SessionID: LongWord;
  end;

// Структура RTL_USER_PROCESS_PARAMETERS под Win32
  RTL_USER_PROCESS_PARAMETERS = record
    MaximumLength: LongWord;
    Length: LongWord;
    Flags: LongWord;
    DebugFlags: LongWord;
    ConsoleHandle: THandle;
    ConsoleFlags: LongWord;
    StdInputHandle: THandle;
    StdOutputHandle: THandle;
    StdErrorHandle: THandle;
    CurrentDirectoryPath: UNICODE_STRING;
    CurrentDirectoryHandle: THandle;
    DllPath: UNICODE_STRING;
    ImagePathName: UNICODE_STRING;
    CommandLine: UNICODE_STRING;
  end;

  RTL_USER_PROCESS_PARAMETERS_WOW64 = record
    MaximumLength: LongWord;
    Length: LongWord;
    Flags: LongWord;
    DebugFlags: LongWord;
    ConsoleHandle: LongWord;
    ConsoleFlags: LongWord;
    StdInputHandle: LongWord;
    StdOutputHandle: LongWord;
    StdErrorHandle: LongWord;
    CurrentDirectoryPath: UNICODE_STRING_WOW64;
    CurrentDirectoryHandle: LongWord;
    DllPath: UNICODE_STRING_WOW64;
    ImagePathName: UNICODE_STRING_WOW64;
    CommandLine: UNICODE_STRING_WOW64;
  end;

  RTL_USER_PROCESS_PARAMETERS64 = record
    MaximumLength: LongWord;
    Length: LongWord;
    Flags: LongWord;
    DebugFlags: LongWord;
    ConsoleHandle: UInt64;
    ConsoleFlags: LongWord;
    Reserved: LongWord;
    StdInputHandle: UInt64;
    StdOutputHandle: UInt64;
    StdErrorHandle: UInt64;
    CurrentDirectoryPath: UNICODE_STRING64;
    CurrentDirectoryHandle: UInt64;
    DllPath: UNICODE_STRING64;
    ImagePathName: UNICODE_STRING64;
    CommandLine: UNICODE_STRING64;
  end;


  VM_COUNTERS = record
    PeakVirtualSize: LongWord;
    VirtualSize: LongWord;
    PageFaultCount: LongWord;
    PeakWorkingSetSize: LongWord;
    WorkingSetSize: LongWord;
    QuotaPeakPagedPoolUsage: LongWord;
    QuotaPagedPoolUsage: LongWord;
    QuotaPeakNonPagedPoolUsage: LongWord;
    QuotaNonPagedPoolUsage: LongWord;
    PagefileUsage: LongWord;
    PeakPagefileUsage: LongWord;
  end;

  PROCESSINFOCLASS = (
    ProcessBasicInformation,
    ProcessQuotaLimits,
    ProcessIoCounters,
    ProcessVmCounters,
    ProcessTimes,
    ProcessBasePriority,
    ProcessRaisePriority,
    ProcessDebugPort,
    ProcessExceptionPort,
    ProcessAccessToken,
    ProcessLdtInformation,
    ProcessLdtSize,
    ProcessDefaultHardErrorMode,
    ProcessIoPortHandlers,          // Note: this is kernel mode only
    ProcessPooledUsageAndLimits,
    ProcessWorkingSetWatch,
    ProcessUserModeIOPL,
    ProcessEnableAlignmentFaultFixup,
    ProcessPriorityClass,
    ProcessWx86Information,
    ProcessHandleCount,
    ProcessAffinityMask,
    ProcessPriorityBoost,
    ProcessDeviceMap,
    ProcessSessionInformation,
    ProcessForegroundInformation,
    ProcessWow64Information,
    ProcessImageFileName,
    ProcessLUIDDeviceMapsEnabled,
    ProcessBreakOnTermination,
    ProcessDebugObjectHandle,
    ProcessDebugFlags,
    ProcessHandleTracing,
    ProcessIoPriority,
    ProcessExecuteFlags,
    ProcessTlsInformation,
    ProcessCookie,
    ProcessImageInformation,
    ProcessCycleTime,
    ProcessPagePriority,
    ProcessInstrumentationCallback,
    ProcessThreadStackAllocation,
    ProcessWorkingSetWatchEx,
    ProcessImageFileNameWin32,
    ProcessImageFileMapping,
    ProcessAffinityUpdateMode,
    ProcessMemoryAllocationMode,
    ProcessGroupInformation,
    ProcessTokenVirtualizationEnabled,
    ProcessOwnerInformation,
    ProcessWindowInformation,
    ProcessHandleInformation,
    ProcessMitigationPolicy,
    ProcessDynamicFunctionTableInformation,
    ProcessHandleCheckingMode,
    ProcessKeepAliveCount,
    ProcessRevokeFileHandles,
    ProcessWorkingSetControl,
    ProcessHandleTable,
    ProcessCheckStackExtentsMode,
    ProcessCommandLineInformation,
    ProcessProtectionInformation,
    MaxProcessInfoClass
  );

  SYSTEMINFOCLASS = (
    SystemBasicInformation,
    Unknown,
    SystemPerformanceInformation,
    SystemInformationClassMax
  );

  NTStatus = LongWord;

  SIZE_T = Cardinal;

  _PROCESS_MEMORY_COUNTERS_EX = record
    cb: LongWord;
    PageFaultCount: LongWord;
    PeakWorkingSetSize: SIZE_T;
    WorkingSetSize: SIZE_T;
    QuotaPeakPagedPoolUsage: SIZE_T;
    QuotaPagedPoolUsage: SIZE_T;
    QuotaPeakNonPagedPoolUsage: SIZE_T;
    QuotaNonPagedPoolUsage: SIZE_T;
    PagefileUsage: SIZE_T;
    PeakPagefileUsage: SIZE_T;
    PrivateUsage: SIZE_T;
  end;

function NtQueryInformationProcess(
                                    ProcessHandle: THandle;
                                    ProcessInformationClass: PROCESSINFOCLASS;
                                    ProcessInformation: Pointer;
                                    ProcessInformationLength: LongWord;
                                    out ReturnLength: LongWord
                                   ): NTStatus; stdcall; external 'ntdll.dll';

function NtReadVirtualMemory(
                              ProcessHandle: THandle;
                              BaseAddress: Pointer;
                              Buffer: Pointer;
                              BufferLength: LongWord;
                              out ReturnLength: LongWord
                             ): BOOL; stdcall; external 'ntdll.dll';


function NtQuerySystemInformation(
                                   SystemInformationClass: SYSTEMINFOCLASS;
                                   SystemInformation: Pointer;
                                   SystemInformationLength: ULONG;
                                   ReturnLength: PDWORD
                                  ): NTStatus; stdcall; external 'ntdll.dll';


// 64х-битные аналоги:
var
  NtWow64QueryInformationProcess64: function(
                                           ProcessHandle: THandle;
                                           ProcessInformationClass: PROCESSINFOCLASS;
                                           ProcessInformation: Pointer;
                                           ProcessInformationLength: LongWord;
                                           out ReturnLength: UInt64
                                          ): NTStatus; stdcall;

  NtWow64ReadVirtualMemory64: function(
                                     ProcessHandle: THandle;
                                     BaseAddress: UInt64;
                                     Buffer: Pointer;
                                     BufferLength: UInt64;
                                     out ReturnLength: UInt64
                                    ): BOOL; stdcall;

  IsWow64Process: function(ProcessHandle: THandle; out Wow64Process: BOOL): BOOL; stdcall;

procedure GetProcessMemoryInfo(ProcessHandle: THandle; out ProcessMemoryCounters: _PROCESS_MEMORY_COUNTERS_EX; ProcessMemoryCountersSize: LongWord); stdcall; external 'psapi.dll';
function GetProcessHandleCount(ProcessHandle: THandle; CounterPtr: Pointer): LongBool; stdcall; external 'kernel32.dll';

function GetProcessId(Handle: THandle): LongWord; stdcall; external 'kernel32.dll';

function Process32FirstA(hSnapshot: THandle; var lppe: TProcessEntry32A): BOOL; stdcall; external 'kernel32.dll' name 'Process32First';
function Process32NextA(hSnapshot: THandle; var lppe: TProcessEntry32A): BOOL; stdcall; external 'kernel32.dll' name 'Process32Next';

implementation

type
  {$IFDEF CPUX64}
  NativeUInt = UInt64;
  {$ELSE}
  NativeUInt = LongWord;
  {$ENDIF}

var
  _Is64BitWindows: BOOL = FALSE;

//HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH

function ProcessIDToHandle(ProcessID: LongWord; AccessRights: LongWord): THandle;
begin
  Result := OpenProcess(
                         AccessRights,
                         FALSE,
                         ProcessID
                        );
end;

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

function HandleToProcessID(ProcessHandle: THandle): LongWord;
begin
  Result := GetProcessID(ProcessHandle);
end;

//HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH

{$IFDEF DEBUG_PRIVILEGE}
const
  SE_DEBUG_NAME = 'SeDebugPrivilege';

// Установка привилегий
function NTSetPrivilege(sPrivilege: AnsiString; bEnabled: Boolean): Boolean;
var
  hToken: THandle;
  TokenPriv: TOKEN_PRIVILEGES;
  PrevTokenPriv: TOKEN_PRIVILEGES;
  ReturnLength: Cardinal;
begin
  if OpenProcessToken(GetCurrentProcess, TOKEN_ADJUST_PRIVILEGES or TOKEN_QUERY, hToken) then
  begin
    if LookupPrivilegeValueA(nil, PAnsiChar(sPrivilege), TokenPriv.Privileges[0].Luid) then
    begin
      TokenPriv.PrivilegeCount := 1;
      case bEnabled of
        True: TokenPriv.Privileges[0].Attributes := SE_PRIVILEGE_ENABLED;
        False: TokenPriv.Privileges[0].Attributes := 0;
      end;
      ReturnLength := 0;
      PrevTokenPriv := TokenPriv;
      AdjustTokenPrivileges(hToken, False, TokenPriv, SizeOf(PrevTokenPriv),
      PrevTokenPriv, ReturnLength);
    end;
    CloseHandle(hToken);
  end;
  Result := GetLastError = ERROR_SUCCESS;
end;
{$ENDIF}

//HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH

function Is64BitWindows: BOOL;
{$IFNDEF CPUX64}
var
  Wow64Process: Bool;
{$ENDIF}
begin
  IsWow64Process := GetProcAddress(GetModuleHandle(kernel32), 'IsWow64Process');
{$IFDEF CPUX64}
  Result := True;
{$ELSE}
  Wow64Process := false;
  if Assigned(IsWow64Process) then Wow64Process := IsWow64Process(GetCurrentProcess, Wow64Process) and Wow64Process;

  Result := Wow64Process;
{$ENDIF}
end;

//HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH

procedure _InitFunctions;
var
  NtdllHandle: THandle;
begin
  _Is64BitWindows := Is64BitWindows;
  if _Is64BitWindows then
  begin
    // Ищем адреса 64х-битных функций:
    NtdllHandle := GetModuleHandleA('ntdll.dll');
    {$IFDEF CPUX64}
    NtWow64QueryInformationProcess64 := GetProcAddress(NtdllHandle, 'NtQueryInformationProcess');
    NtWow64ReadVirtualMemory64 := GetProcAddress(NtdllHandle, 'NtReadVirtualMemory');
    {$ELSE}
    NtWow64QueryInformationProcess64 := GetProcAddress(NtdllHandle, 'NtWow64QueryInformationProcess64');
    NtWow64ReadVirtualMemory64 := GetProcAddress(NtdllHandle, 'NtWow64ReadVirtualMemory64');
    {$ENDIF}
  end
  else
  begin
    _Is64BitWindows := false;
  end;
end;


//HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH


procedure _GetModulesList32(ProcessHandle: THandle; LDRAddress: Pointer; out Modules: TModulesList);
var
  LdrInfo: PEB_LDR_DATA;
  ModuleInfo: LDR_MODULE;

  StringBuffer: Pointer;
  StringPointer: Pointer;
  StringLength: Word;

  BytesRead: LongWord;
begin
// Читаем PEB_LDR_DATA:
  NtReadVirtualMemory(ProcessHandle, LDRAddress, @LdrInfo, SizeOf(LdrInfo), BytesRead);

// Читаем LDR_MODULE_INFO:
  NtReadVirtualMemory(ProcessHandle, LdrInfo.InLoadModuleOrderList.ForwardLDRModule, @ModuleInfo, SizeOf(ModuleInfo), BytesRead);

  FillChar(Modules, SizeOf(Modules), #0);

  while (LdrInfo.InLoadModuleOrderList.ForwardLDRModule <> nil) and (BytesRead <> 0) and (ModuleInfo.BaseAddress <> nil) do
  begin
    Inc(Modules.Length);
    SetLength(Modules.Modules, Modules.Length);

  // Получаем численную информацию:
    with Modules do
    begin
      Modules[Length - 1].BaseAddress := UInt64(ModuleInfo.BaseAddress);
      Modules[Length - 1].EntryAddress := UInt64(ModuleInfo.EntryPoint);
      Modules[Length - 1].SizeOfImage := UInt64(ModuleInfo.SizeOfImage);
    end;

  // Читаем полный путь:
    StringPointer := ModuleInfo.FullDLLName.Buffer;
    StringLength := ModuleInfo.FullDLLName.Length;
    GetMem(StringBuffer, StringLength + 2);
    FillChar(StringBuffer^, StringLength + 2, #0);
    NtReadVirtualMemory(ProcessHandle, StringPointer, StringBuffer, StringLength, BytesRead);
    Modules.Modules[Modules.Length - 1].FullPath := WideToAnsi(PWideChar(StringBuffer));
    FreeMem(StringBuffer);

  // Читаем имя библиотеки:
    StringPointer := ModuleInfo.BaseDLLName.Buffer;
    StringLength := ModuleInfo.BaseDLLName.Length;
    GetMem(StringBuffer, StringLength + 2);
    FillChar(StringBuffer^, StringLength + 2, #0);
    NtReadVirtualMemory(ProcessHandle, StringPointer, StringBuffer, StringLength, BytesRead);
    Modules.Modules[Modules.Length - 1].ModuleName := WideToAnsi(PWideChar(StringBuffer));
    FreeMem(StringBuffer);

  // Читаем следующий в списке LDR_MODULE_INFO:
    NtReadVirtualMemory(ProcessHandle, ModuleInfo.InLoadModuleOrderList.ForwardLDRModule, @ModuleInfo, SizeOf(ModuleInfo), BytesRead);
  end;
end;


// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -


procedure _GetProcessInfo32(ProcessID: LongWord; out ProcessInfo: PROCESS_INFO);
var
  ProcessHandle: THandle;
  ProcessBasicInfo: PROCESS_BASIC_INFORMATION;
  PEBInfo: PEB;
  UserParameters: RTL_USER_PROCESS_PARAMETERS;

  BytesRead: UInt;
  ReturnLength: UInt;

  //ReturnStatus: LongWord;

  _Is64BitProcess: BOOL;

  CurrentDirectory: AnsiString;
  ImageName: AnsiString;
  CmdLine: AnsiString;

  StringBuffer: Pointer;
  StringPointer: Pointer;
  StringLength: Word;

  TlHelp32Info: TProcessInfo;
  LocalHandlesCount: LongWord;

  MemoryCounters: _PROCESS_MEMORY_COUNTERS_EX;
begin
  FillChar(ProcessBasicInfo, SizeOf(ProcessBasicInfo), #0);
  FillChar(PEBInfo, SizeOf(PEBInfo), #0);
  FillChar(UserParameters, SizeOf(UserParameters), #0);
  FillChar(ProcessInfo, SizeOf(ProcessInfo), #0);

  ProcessHandle := ProcessIDToHandle(ProcessID);

// Получаем разрядность процесса:
  _Is64BitProcess := FALSE; // Процессы заведомо 32х-битные

// Заполняем PROCESS_BASIC_INFORMATION:
  NtQueryInformationProcess(ProcessHandle, ProcessBasicInformation, @ProcessBasicInfo, SizeOf(ProcessBasicInfo), ReturnLength);
// Читаем PEB:
  NtReadVirtualMemory(ProcessHandle, ProcessBasicInfo.PebBaseAddress, @PEBInfo, SizeOf(PEBInfo), BytesRead);
// Читаем RTL_USER_PROCESS_PARAMETERS:
  NtReadVirtualMemory(ProcessHandle, PEBInfo.ProcessParameters, @UserParameters, SizeOf(UserParameters), BytesRead);

// Получаем список загруженных модулей:
  _GetModulesList32(ProcessHandle, PEBInfo.Ldr, ProcessInfo.ModulesList);

// Читаем строки:
  // CommandLine:
  StringPointer := UserParameters.CommandLine.Buffer;
  StringLength := UserParameters.CommandLine.Length;
  GetMem(StringBuffer, StringLength + 2);
  FillChar(StringBuffer^, StringLength + 2, #0);
  NtReadVirtualMemory(ProcessHandle, StringPointer, StringBuffer, StringLength, BytesRead);
  CmdLine := WideToAnsi(PWideChar(StringBuffer));
  FreeMem(StringBuffer);

  // ImageFilePath:
  StringPointer := UserParameters.ImagePathName.Buffer;
  StringLength := UserParameters.ImagePathName.Length;
  GetMem(StringBuffer, StringLength + 2);
  FillChar(StringBuffer^, StringLength + 2, #0);
  NtReadVirtualMemory(ProcessHandle, StringPointer, StringBuffer, StringLength, BytesRead);
  ImageName := WideToAnsi(PWideChar(StringBuffer));
  FreeMem(StringBuffer);

  //CurrentDirectoryPath:
  StringPointer := UserParameters.CurrentDirectoryPath.Buffer;
  StringLength := UserParameters.CurrentDirectoryPath.Length;
  GetMem(StringBuffer, StringLength + 2);
  FillChar(StringBuffer^, StringLength + 2, #0);
  NtReadVirtualMemory(ProcessHandle, StringPointer, StringBuffer, StringLength, BytesRead);
  CurrentDirectory := WideToAnsi(PWideChar(StringBuffer));
  FreeMem(StringBuffer);

// Получаем информацию о памяти процесса:
  FillChar(MemoryCounters, SizeOf(MemoryCounters), #0);
  GetProcessMemoryInfo(ProcessHandle, MemoryCounters, SizeOf(MemoryCounters));

// Получаем информацию из TlHelp32:
  FillChar(TlHelp32Info, SizeOf(TlHelp32Info), #0);
  TlHelp32Info := GetTlHelp32ProcessInfo(ProcessID);

// Получаем количество открытых хэндлов:
  GetProcessHandleCount(ProcessHandle, @LocalHandlesCount);

  // Возвращаем результат:
  with ProcessInfo do
  begin
    Handle := ProcessHandle;
    ID := ProcessBasicInfo.UniqueProcessId;
    InheritedFromID := ProcessBasicInfo.InheritedFromUniqueProcessId;
    SessionID := PEBInfo.SessionID;

    Priority := ProcessBasicInfo.BasePriority;
    AffinityMask := ProcessBasicInfo.AffinityMask;

    IsDebugged := PEBInfo.BeingDebugged;
    ExitStatus := ProcessBasicInfo.ExitStatus;
    ThreadsCount := TlHelp32Info.ThreadsCount;
    HandlesCount := LocalHandlesCount;
    ReservedMemory := MemoryCounters.PrivateUsage;

    ImageBaseAddress := UInt64(PEBInfo.ImageBaseAddress);
    LdrAddress := UInt64(PEBInfo.Ldr);
    PEBAddress := UInt64(ProcessBasicInfo.PebBaseAddress);

    ConsoleHandle := UserParameters.ConsoleHandle;
    StdInputHandle := UserParameters.StdInputHandle;
    StdOutputHandle := UserParameters.StdOutputHandle;
    StdErrorHandle := UserParameters.StdErrorHandle;

    ProcessName := TlHelp32Info.ExeFile;
    CurrentDirectoryPath := CurrentDirectory;
    ImagePathName := ImageName;
    CommandLine := CmdLine;

    Is64BitProcess := _Is64BitProcess;
  end;

  CloseHandle(ProcessHandle);
end;


//HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH


procedure _GetModulesList64(ProcessHandle: THandle; LDRAddress: UInt64; out Modules: TModulesList);
var
  LdrInfo: PEB_LDR_DATA64;
  ModuleInfo: LDR_MODULE64;

  StringBuffer: Pointer;
  StringPointer: UInt64;
  StringLength: Word;

  BytesRead: UInt64;
begin
// Читаем PEB_LDR_DATA:
  NtWow64ReadVirtualMemory64(ProcessHandle, LDRAddress, @LdrInfo, SizeOf(LdrInfo), BytesRead);
// Читаем LDR_MODULE_INFO:
  NtWow64ReadVirtualMemory64(ProcessHandle, UInt64(LdrInfo.InLoadModuleOrderList.ForwardLDRModule), @ModuleInfo, SizeOf(ModuleInfo), BytesRead);

  FillChar(Modules, SizeOf(Modules), #0);

  while (LdrInfo.InLoadModuleOrderList.ForwardLDRModule <> 0) and (BytesRead <> 0) and (ModuleInfo.BaseAddress <> 0) do
  begin
    Inc(Modules.Length);
    SetLength(Modules.Modules, Modules.Length);

  // Получаем численную информацию:
    with Modules do
    begin
      Modules[Length - 1].BaseAddress := ModuleInfo.BaseAddress;
      Modules[Length - 1].EntryAddress := ModuleInfo.EntryPoint;
      Modules[Length - 1].SizeOfImage := ModuleInfo.SizeOfImage;
    end;

  // Читаем полный путь:
    StringPointer := ModuleInfo.FullDLLName.Buffer;
    StringLength := ModuleInfo.FullDLLName.Length;
    GetMem(StringBuffer, StringLength + 2);
    FillChar(StringBuffer^, StringLength + 2, #0);
    NtWow64ReadVirtualMemory64(ProcessHandle, StringPointer, StringBuffer, StringLength, BytesRead);
    Modules.Modules[Modules.Length - 1].FullPath := WideToAnsi(PWideChar(StringBuffer));
    FreeMem(StringBuffer);

  // Читаем имя библиотеки:
    StringPointer := ModuleInfo.BaseDLLName.Buffer;
    StringLength := ModuleInfo.BaseDLLName.Length;
    GetMem(StringBuffer, StringLength + 2);
    FillChar(StringBuffer^, StringLength + 2, #0);
    NtWow64ReadVirtualMemory64(ProcessHandle, StringPointer, StringBuffer, StringLength, BytesRead);
    Modules.Modules[Modules.Length - 1].ModuleName := WideToAnsi(PWideChar(StringBuffer));
    FreeMem(StringBuffer);

  // Читаем следующий в списке LDR_MODULE_INFO:
    NtWow64ReadVirtualMemory64(ProcessHandle, ModuleInfo.InLoadModuleOrderList.ForwardLDRModule, @ModuleInfo, SizeOf(ModuleInfo), BytesRead);
  end;
end;


// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -


procedure _GetProcessInfo64(ProcessID: LongWord; out ProcessInfo: PROCESS_INFO);
var
  ProcessHandle: THandle;
  ProcessBasicInfo: PROCESS_BASIC_INFORMATION64;
  PEBInfo: PEB64;
  UserParameters: RTL_USER_PROCESS_PARAMETERS64;
  BytesRead: UInt64;
  ReturnLength: UInt64;

  //ReturnStatus: LongWord;

  _Is64BitProcess: BOOL;

  CurrentDirectory: AnsiString;
  ImageName: AnsiString;
  CmdLine: AnsiString;

  StringBuffer: Pointer;
  StringPointer: UInt64;
  StringLength: Word;

  TlHelp32Info: TProcessInfo;
  LocalHandlesCount: LongWord;

  MemoryCounters: _PROCESS_MEMORY_COUNTERS_EX;
begin
  FillChar(ProcessBasicInfo, SizeOf(ProcessBasicInfo), #0);
  FillChar(PEBInfo, SizeOf(PEBInfo), #0);
  FillChar(UserParameters, SizeOf(UserParameters), #0);
  FillChar(ProcessInfo, SizeOf(ProcessInfo), #0);

  ProcessHandle := ProcessIDToHandle(ProcessID);

// Получаем разрядность процесса:
  IsWow64Process(ProcessHandle, _Is64BitProcess);
  _Is64BitProcess := not _Is64BitProcess;

// Заполняем PROCESS_BASIC_INFORMATION:
  NtWow64QueryInformationProcess64(ProcessHandle, ProcessBasicInformation, @ProcessBasicInfo, SizeOf(ProcessBasicInfo), ReturnLength);
// Читаем PEB:
  NtWow64ReadVirtualMemory64(ProcessHandle, ProcessBasicInfo.PebBaseAddress, @PEBInfo, SizeOf(PEBInfo), BytesRead);
// Читаем RTL_USER_PROCESS_PARAMETERS:
  NtWow64ReadVirtualMemory64(ProcessHandle, PEBInfo.ProcessParameters, @UserParameters, SizeOf(UserParameters), BytesRead);

// Получаем список загруженных модулей:
  _GetModulesList64(ProcessHandle, PEBInfo.Ldr, ProcessInfo.ModulesList);

// Читаем строки:
  // CommandLine:
  StringPointer := UserParameters.CommandLine.Buffer;
  StringLength := UserParameters.CommandLine.Length;
  GetMem(StringBuffer, StringLength + 2);
  FillChar(StringBuffer^, StringLength + 2, #0);
  NtWow64ReadVirtualMemory64(ProcessHandle, StringPointer, StringBuffer, StringLength, BytesRead);
  CmdLine := WideToAnsi(PWideChar(StringBuffer));
  FreeMem(StringBuffer);

  // ImageFilePath:
  StringPointer := UserParameters.ImagePathName.Buffer;
  StringLength := UserParameters.ImagePathName.Length;
  GetMem(StringBuffer, StringLength + 2);
  FillChar(StringBuffer^, StringLength + 2, #0);
  NtWow64ReadVirtualMemory64(ProcessHandle, StringPointer, StringBuffer, StringLength, BytesRead);
  ImageName := WideToAnsi(PWideChar(StringBuffer));
  FreeMem(StringBuffer);

  //CurrentDirectoryPath:
  StringPointer := UserParameters.CurrentDirectoryPath.Buffer;
  StringLength := UserParameters.CurrentDirectoryPath.Length;
  GetMem(StringBuffer, StringLength + 2);
  FillChar(StringBuffer^, StringLength + 2, #0);
  NtWow64ReadVirtualMemory64(ProcessHandle, StringPointer, StringBuffer, StringLength, BytesRead);
  CurrentDirectory := WideToAnsi(PWideChar(StringBuffer));
  FreeMem(StringBuffer);

// Получаем информацию о памяти процесса:
  FillChar(MemoryCounters, SizeOf(MemoryCounters), #0);
  GetProcessMemoryInfo(ProcessHandle, MemoryCounters, SizeOf(MemoryCounters));

// Получаем информацию из TlHelp32:
  FillChar(TlHelp32Info, SizeOf(TlHelp32Info), #0);
  TlHelp32Info := GetTlHelp32ProcessInfo(ProcessID);

// Получаем количество открытых хэндлов:
  GetProcessHandleCount(ProcessHandle, @LocalHandlesCount);

  // Возвращаем результат:
  with ProcessInfo do
  begin
    Handle := ProcessHandle;
    ID := ProcessBasicInfo.UniqueProcessId;
    InheritedFromID := ProcessBasicInfo.InheritedFromUniqueProcessId;
    SessionID := PEBInfo.SessionID;

    Priority := ProcessBasicInfo.BasePriority;
    AffinityMask := ProcessBasicInfo.AffinityMask;

    IsDebugged := PEBInfo.BeingDebugged;
    ExitStatus := ProcessBasicInfo.ExitStatus;
    ThreadsCount := TlHelp32Info.ThreadsCount;
    handlesCount := LocalHandlesCount;
    ReservedMemory := MemoryCounters.PrivateUsage;

    ImageBaseAddress := PEBInfo.ImageBaseAddress;
    LdrAddress := PEBInfo.Ldr;
    PEBAddress := ProcessBasicInfo.PebBaseAddress;

    ConsoleHandle := UserParameters.ConsoleHandle;
    StdInputHandle := UserParameters.StdInputHandle;
    StdOutputHandle := UserParameters.StdOutputHandle;
    StdErrorHandle := UserParameters.StdErrorHandle;

    ProcessName := TlHelp32Info.ExeFile;
    CurrentDirectoryPath := CurrentDirectory;
    ImagePathName := ImageName;
    CommandLine := CmdLine;

    Is64BitProcess := _Is64BitProcess;
  end;

  CloseHandle(ProcessHandle);
end;


//HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH


procedure _GetModulesListWow64(ProcessHandle: THandle; LDRAddress: Pointer32; out Modules: TModulesList);
var
  LdrInfo: PEB_LDR_DATA_WOW64;
  ModuleInfo: LDR_MODULE_WOW64;

  StringBuffer: Pointer;
  StringPointer: UInt64;
  StringLength: Word;

  BytesRead: UInt64;
begin
// Читаем PEB_LDR_DATA:
  NtWow64ReadVirtualMemory64(ProcessHandle, UInt64(LDRAddress), @LdrInfo, SizeOf(LdrInfo), BytesRead);
// Читаем LDR_MODULE_INFO:
  NtWow64ReadVirtualMemory64(ProcessHandle, UInt64(LdrInfo.InLoadModuleOrderList.ForwardLDRModule), @ModuleInfo, SizeOf(ModuleInfo), BytesRead);

  FillChar(Modules, SizeOf(Modules), #0);

  while (LdrInfo.InLoadModuleOrderList.ForwardLDRModule <> 0) and (BytesRead <> 0) and (ModuleInfo.BaseAddress <> 0) do
  begin
    Inc(Modules.Length);
    SetLength(Modules.Modules, Modules.Length);

  // Получаем численную информацию:
    with Modules do
    begin
      Modules[Length - 1].BaseAddress := ModuleInfo.BaseAddress;
      Modules[Length - 1].EntryAddress := ModuleInfo.EntryPoint;
      Modules[Length - 1].SizeOfImage := ModuleInfo.SizeOfImage;
    end;

  // Читаем полный путь:
    StringPointer := ModuleInfo.FullDLLName.Buffer;
    StringLength := ModuleInfo.FullDLLName.Length;
    GetMem(StringBuffer, StringLength + 2);
    FillChar(StringBuffer^, StringLength + 2, #0);
    NtWow64ReadVirtualMemory64(ProcessHandle, StringPointer, StringBuffer, StringLength, BytesRead);
    Modules.Modules[Modules.Length - 1].FullPath := WideToAnsi(PWideChar(StringBuffer));
    FreeMem(StringBuffer);

  // Читаем имя библиотеки:
    StringPointer := ModuleInfo.BaseDLLName.Buffer;
    StringLength := ModuleInfo.BaseDLLName.Length;
    GetMem(StringBuffer, StringLength + 2);
    FillChar(StringBuffer^, StringLength + 2, #0);
    NtWow64ReadVirtualMemory64(ProcessHandle, StringPointer, StringBuffer, StringLength, BytesRead);
    Modules.Modules[Modules.Length - 1].ModuleName := WideToAnsi(PWideChar(StringBuffer));
    FreeMem(StringBuffer);

  // Читаем следующий в списке LDR_MODULE_INFO:
    NtWow64ReadVirtualMemory64(ProcessHandle, ModuleInfo.InLoadModuleOrderList.ForwardLDRModule, @ModuleInfo, SizeOf(ModuleInfo), BytesRead);
  end;
end;


// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -


procedure _GetProcessInfoWow64(ProcessID: LongWord; out ProcessInfo: PROCESS_INFO);
var
  ProcessHandle: THandle;
  ProcessBasicInfo: PROCESS_BASIC_INFORMATION64;
  ProcessBasicInfoWow64: PROCESS_BASIC_INFORMATION_WOW64;
  PEBInfo: PEB_WOW64;
  UserParameters: RTL_USER_PROCESS_PARAMETERS_WOW64;
  BytesRead: UInt64;
  ReturnLength: UInt64;

  //ReturnStatus: LongWord;

  _Is64BitProcess: BOOL;

  CurrentDirectory: AnsiString;
  ImageName: AnsiString;
  CmdLine: AnsiString;

  StringBuffer: Pointer;
  StringPointer: UInt64;
  StringLength: Word;

  TlHelp32Info: TProcessInfo;
  LocalHandlesCount: LongWord;

  MemoryCounters: _PROCESS_MEMORY_COUNTERS_EX;
begin
  FillChar(ProcessBasicInfo, SizeOf(ProcessBasicInfo), #0);
  FillChar(PEBInfo, SizeOf(PEBInfo), #0);
  FillChar(UserParameters, SizeOf(UserParameters), #0);
  FillChar(ProcessInfo, SizeOf(ProcessInfo), #0);

  ProcessHandle := ProcessIDToHandle(ProcessID);

// Получаем разрядность процесса:
  IsWow64Process(ProcessHandle, _Is64BitProcess);
  _Is64BitProcess := not _Is64BitProcess;

// Заполняем PROCESS_BASIC_INFORMATION:
  NtWow64QueryInformationProcess64(ProcessHandle, ProcessBasicInformation, @ProcessBasicInfo, SizeOf(ProcessBasicInfo), ReturnLength);
// Получаем адрес 32х-битного PEB:
  NtWow64QueryInformationProcess64(ProcessHandle, ProcessWow64Information, @ProcessBasicInfoWow64, SizeOf(ProcessBasicInfoWow64), ReturnLength);
// Читаем PEB:
  //NtWow64ReadVirtualMemory64(ProcessHandle, ProcessBasicInfo.PebBaseAddress, @PEBInfo, SizeOf(PEBInfo), BytesRead);
  NtWow64ReadVirtualMemory64(ProcessHandle, ProcessBasicInfoWow64.Wow64PebAddress, @PEBInfo, SizeOf(PEBInfo), BytesRead);
// Читаем RTL_USER_PROCESS_PARAMETERS:
  NtWow64ReadVirtualMemory64(ProcessHandle, UInt64(PEBInfo.ProcessParameters), @UserParameters, SizeOf(UserParameters), BytesRead);

// Получаем список загруженных модулей:
  _GetModulesListWow64(ProcessHandle, UInt64(PEBInfo.Ldr), ProcessInfo.ModulesList);

// Читаем строки:
  // CommandLine:
  StringPointer := UserParameters.CommandLine.Buffer;
  StringLength := UserParameters.CommandLine.Length;
  GetMem(StringBuffer, StringLength + 2);
  FillChar(StringBuffer^, StringLength + 2, #0);
  NtWow64ReadVirtualMemory64(ProcessHandle, StringPointer, StringBuffer, StringLength, BytesRead);
  CmdLine := WideToAnsi(PWideChar(StringBuffer));
  FreeMem(StringBuffer);

  // ImageFilePath:
  StringPointer := UserParameters.ImagePathName.Buffer;
  StringLength := UserParameters.ImagePathName.Length;
  GetMem(StringBuffer, StringLength + 2);
  FillChar(StringBuffer^, StringLength + 2, #0);
  NtWow64ReadVirtualMemory64(ProcessHandle, StringPointer, StringBuffer, StringLength, BytesRead);
  ImageName := WideToAnsi(PWideChar(StringBuffer));
  FreeMem(StringBuffer);

  //CurrentDirectoryPath:
  StringPointer := UserParameters.CurrentDirectoryPath.Buffer;
  StringLength := UserParameters.CurrentDirectoryPath.Length;
  GetMem(StringBuffer, StringLength + 2);
  FillChar(StringBuffer^, StringLength + 2, #0);
  NtWow64ReadVirtualMemory64(ProcessHandle, StringPointer, StringBuffer, StringLength, BytesRead);
  CurrentDirectory := WideToAnsi(PWideChar(StringBuffer));
  FreeMem(StringBuffer);

// Получаем информацию о памяти процесса:
  FillChar(MemoryCounters, SizeOf(MemoryCounters), #0);
  GetProcessMemoryInfo(ProcessHandle, MemoryCounters, SizeOf(MemoryCounters));

// Получаем информацию из TlHelp32:
  FillChar(TlHelp32Info, SizeOf(TlHelp32Info), #0);
  TlHelp32Info := GetTlHelp32ProcessInfo(ProcessID);

// Получаем количество открытых хэндлов:
  GetProcessHandleCount(ProcessHandle, @LocalHandlesCount);

  // Возвращаем результат:
  with ProcessInfo do
  begin
    Handle := ProcessHandle;
    ID := ProcessBasicInfo.UniqueProcessId;
    InheritedFromID := ProcessBasicInfo.InheritedFromUniqueProcessId;
    SessionID := PEBInfo.SessionID;

    Priority := ProcessBasicInfo.BasePriority;
    AffinityMask := ProcessBasicInfo.AffinityMask;

    IsDebugged := PEBInfo.BeingDebugged;
    ExitStatus := ProcessBasicInfo.ExitStatus;
    ThreadsCount := TlHelp32Info.ThreadsCount;
    HandlesCount := LocalHandlesCount;
    ReservedMemory := MemoryCounters.PrivateUsage;

    ImageBaseAddress := UInt64(PEBInfo.ImageBaseAddress);
    LdrAddress := UInt64(PEBInfo.Ldr);
    PEBAddress := ProcessBasicInfo.PebBaseAddress;

    ConsoleHandle := UserParameters.ConsoleHandle;
    StdInputHandle := UserParameters.StdInputHandle;
    StdOutputHandle := UserParameters.StdOutputHandle;
    StdErrorHandle := UserParameters.StdErrorHandle;

    ProcessName := TlHelp32Info.ExeFile;
    CurrentDirectoryPath := CurrentDirectory;
    ImagePathName := ImageName;
    CommandLine := CmdLine;

    Is64BitProcess := _Is64BitProcess;
  end;

  CloseHandle(ProcessHandle);
end;


//HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH


function GetProcessInfo(ProcessID: LongWord; out ProcessInfo: PROCESS_INFO; Process32_64CompatibleMode: Boolean = false): Boolean;
var
  IsTarget64Bit: LongBool;
  TargetHandle: THandle;
begin
  FillChar(ProcessInfo, SizeOf(ProcessInfo), #0);

  TargetHandle := ProcessIDToHandle(ProcessID);
  Result := (TargetHandle <> INVALID_HANDLE_VALUE) or (TargetHandle <> 0);
  if not Result then Exit;

  IsWow64Process(TargetHandle, IsTarget64Bit);
  IsTarget64Bit := not IsTarget64Bit;
  CloseHandle(TargetHandle);

  {$IFDEF CPUX64}
  if IsTarget64Bit then
    _GetProcessInfo64(ProcessID, ProcessInfo)
  else
    if Process32_64CompatibleMode then
      _GetProcessInfo64(ProcessID, ProcessInfo)
    else
      _GetProcessInfoWow64(ProcessID, ProcessInfo);
  {$ELSE}
  if _Is64BitWindows then
    if IsTarget64Bit then
      _GetProcessInfo64(ProcessID, ProcessInfo)
    else
      if Process32_64CompatibleMode then
        _GetProcessInfo64(ProcessID, ProcessInfo)
      else
        _GetProcessInfo32(ProcessID, ProcessInfo)
  else
    _GetProcessInfo32(ProcessID, ProcessInfo);
  {$ENDIF}
end;


// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -


function GetProcessBasicInfo(ProcessID: LongWord; out ProcessBasicInfo: TProcessBasicInfo): Boolean;
var
  ProcessBasicInfo32: {$IFDEF CPUX64}PROCESS_BASIC_INFORMATION64{$ELSE}PROCESS_BASIC_INFORMATION{$ENDIF};
  ProcessBasicInfo64: PROCESS_BASIC_INFORMATION64;
  ProcessHandle: THandle;
  ReturnLength32: LongWord;
  ReturnLength64: UInt64;
begin
  ProcessHandle := ProcessIDtoHandle(ProcessID);
  Result := (ProcessHandle <> INVALID_HANDLE_VALUE) or (ProcessHandle <> 0);
  if not Result then Exit;


  if Is64BitProcess(ProcessID) then
  begin
    NtWow64QueryInformationProcess64(ProcessHandle, ProcessBasicInformation, @ProcessBasicInfo64, SizeOf(ProcessBasicInfo64), ReturnLength64);

    ProcessBasicInfo.ExitStatus := ProcessBasicInfo64.ExitStatus;
    ProcessBasicInfo.AffinityMask := ProcessBasicInfo64.AffinityMask;
    ProcessBasicInfo.BasePriority := ProcessBasicInfo64.BasePriority;
    ProcessBasicInfo.UniqueProcessId := ProcessBasicInfo64.UniqueProcessId;
    ProcessBasicInfo.InheritedFromUniqueProcessId := ProcessBasicInfo64.InheritedFromUniqueProcessId;
  end
  else
  begin
    NtQueryInformationProcess(ProcessHandle, ProcessBasicInformation, @ProcessBasicInfo32, SizeOf(ProcessBasicInfo32), ReturnLength32);

    ProcessBasicInfo.ExitStatus := ProcessBasicInfo32.ExitStatus;
    ProcessBasicInfo.AffinityMask := ProcessBasicInfo32.AffinityMask;
    ProcessBasicInfo.BasePriority := ProcessBasicInfo32.BasePriority;
    ProcessBasicInfo.UniqueProcessId := ProcessBasicInfo32.UniqueProcessId;
    ProcessBasicInfo.InheritedFromUniqueProcessId := ProcessBasicInfo32.InheritedFromUniqueProcessId;
  end;

  CloseHandle(ProcessHandle);
end;


//HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH


function Is64BitProcess(ProcessID: LongWord): LongBool;
var
  ProcessHandle: NativeUInt;
begin
  ProcessHandle := ProcessIDtoHandle(ProcessID);

  if _Is64BitWindows then
  begin
    IsWow64Process(ProcessHandle, Result);
    Result := not Result;
  end
  else
  begin
    Result := False;
  end;

  CloseHandle(ProcessHandle);
end;


// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -


function IsProcessLaunched(ProcessName: AnsiString): Boolean;
var
  hSnapshot: THandle;
  ProcessInfo: TProcessInfo;
begin
  Result := false;
  ProcessInfo.Size := SizeOf(ProcessInfo);
  hSnapshot := CreateToolHelp32Snapshot(TH32CS_SNAPPROCESS, 0);
  if Process32FirstA(hSnapshot, ProcessInfo) then
  begin
    if ProcessInfo.ExeFile = ProcessName then
    begin
      Result := true;
    end
    else
    begin
      while Process32NextA(hSnapshot, ProcessInfo) do
      begin
        if ProcessInfo.ExeFile = ProcessName then
        begin
          Result := true;
          Break;
        end;
      end;
    end;
  end;
  CloseHandle(hSnapshot);
end;


// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -


function IsProcessLaunched(ProcessID: LongWord): Boolean;
var
  ProcessHandle: THandle;
begin
  ProcessHandle := OpenProcess(PROCESS_VM_READ, FALSE, ProcessID);
  Result := ProcessHandle <> 0;
  if Result then CloseHandle(ProcessHandle);
end;


// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -


function IsLibInProcess(LibName: AnsiString; ProcessID: LongWord): Boolean;
var
  ProcessInfo: PROCESS_INFO;
  I: LongWord;
begin
  Result := False;

  GetProcessInfo(ProcessID, ProcessInfo);
  if ProcessInfo.ModulesList.Length > 0 then
    for I := 0 to ProcessInfo.ModulesList.Length - 1 do
      if ProcessInfo.ModulesList.Modules[I].ModuleName = LibName then
      begin
        Result := True;
        Exit;
      end;
end;


// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -


function GetProcessIdFromThreadID(ThreadID: LongWord): LongWord;
var
  TlHelpHandle: LongWord;
  ThreadEntry32: TThreadEntry32;
begin
  Result := 0;

  TlHelpHandle := CreateToolHelp32Snapshot(TH32CS_SNAPTHREAD, 0);

  if TlHelpHandle <> INVALID_HANDLE_VALUE then
  begin
    ThreadEntry32.Size := SizeOf(TThreadEntry32);
    if Thread32First(TlHelpHandle, tagTHREADENTRY32(ThreadEntry32)) then
    repeat
      if ThreadEntry32.ThreadID = ThreadID then
        Result := ThreadEntry32.OwnerProcessID;

    until not Thread32Next(TlHelpHandle, tagTHREADENTRY32(ThreadEntry32));

    CloseHandle(TlHelpHandle);
  end;
end;

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

procedure GetProcessList(out ProcessList: TProcessList);
var
  hSnapshot: THandle;
  ProcessInfo: TProcessInfo;
  Size: LongWord;
begin
  Size := 0;
  SetLength(ProcessList, Size);

  ProcessInfo.Size := SizeOf(ProcessInfo);
  hSnapshot := CreateToolHelp32Snapshot(TH32CS_SNAPPROCESS, 0);
  if Process32FirstA(hSnapshot, ProcessInfo) then
  begin
    Inc(Size);
    SetLength(ProcessList, Size);
    ProcessList[Size - 1] := ProcessInfo;

    while Process32NextA(hSnapshot, ProcessInfo) do
    begin
      Inc(Size);
      SetLength(ProcessList, Size);
      ProcessList[Size - 1] := ProcessInfo;
    end;
  end;
  CloseHandle(hSnapshot);
end;

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

function GetTlHelp32ProcessInfo(ProcessID: LongWord): TProcessInfo; overload;
var
  hSnapshot: THandle;
  ProcessInfo: TProcessInfo;
begin
  FillChar(Result, SizeOf(Result), #0);

  ProcessInfo.Size := SizeOf(ProcessInfo);
  hSnapshot := CreateToolHelp32Snapshot(TH32CS_SNAPPROCESS, 0);
  if Process32FirstA(hSnapshot, ProcessInfo) then
  begin
    if ProcessInfo.ProcessID = ProcessID then
    begin
      Result := ProcessInfo;
    end
    else
    begin
      while Process32NextA(hSnapshot, ProcessInfo) do
      begin
        if ProcessInfo.ProcessID = ProcessID then
        begin
          Result := ProcessInfo;
          Break;
        end;
      end;
    end;
  end;
  CloseHandle(hSnapshot);
end;

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

function GetTlHelp32ProcessInfo(ProcessName: AnsiString): TProcessInfo; overload;
var
  hSnapshot: THandle;
  ProcessInfo: TProcessInfo;
begin
  FillChar(Result, SizeOf(Result), #0);

  ProcessInfo.Size := SizeOf(ProcessInfo);
  hSnapshot := CreateToolHelp32Snapshot(TH32CS_SNAPPROCESS, 0);
  if Process32FirstA(hSnapshot, ProcessInfo) then
  begin
    if ProcessInfo.ExeFile = ProcessName then
    begin
      Result := ProcessInfo;
    end
    else
    begin
      while Process32NextA(hSnapshot, ProcessInfo) do
      begin
        if ProcessInfo.ExeFile = ProcessName then
        begin
          Result := ProcessInfo;
          Break;
        end;
      end;
    end;
  end;
  CloseHandle(hSnapshot);
end;

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

procedure StartProcess(const CommandLine: string; out ProcessHandle: THandle; out ProcessID: LongWord);
var
  ProcessInfo: _PROCESS_INFORMATION;
  StartupInfo: _STARTUPINFO;
begin
  FillChar(StartupInfo, SizeOf(StartupInfo), #0);
  FillChar(ProcessInfo, SizeOf(ProcessInfo), #0);

  StartupInfo.wShowWindow := SW_SHOWNORMAL;

  CreateProcess(
                 nil,
                 PChar(CommandLine),
                 nil,
                 nil,
                 FALSE,
                 0,
                 nil,
                 nil,
                 StartupInfo,
                 ProcessInfo
                );

  CloseHandle(ProcessInfo.hThread);

  ProcessHandle := ProcessInfo.hProcess;
  ProcessID := ProcessInfo.dwProcessId;
end;

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

procedure WaitProcess(ProcessID: LongWord); inline;
var
  ProcessHandle: THandle;
begin
  ProcessHandle := OpenProcess(SYNCHRONIZE, FALSE, ProcessID);
  if ProcessHandle = 0 then Exit;

  WaitForSingleObject(ProcessHandle, INFINITE);
  CloseHandle(ProcessHandle);
end;

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

procedure KillProcess(ProcessID: LongWord); overload;
var
  ProcessHandle: THandle;
begin
  ProcessHandle := ProcessIDToHandle(ProcessID, PROCESS_TERMINATE);
  TerminateProcess(ProcessHandle, 0);
  CloseHandle(ProcessHandle);
end;

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

procedure KillProcess(ProcessName: AnsiString; CanKillSelf: Boolean = False); overload;
var
  ProcessList: TProcessList;
  ProcessListCount: Integer;
  I: Integer;
  CurrentID: LongWord;
  NeedToKillSelf: Boolean;
begin
  GetProcessList(ProcessList);
  CurrentID := GetCurrentProcessID;
  ProcessListCount := Length(ProcessList);
  if ProcessListCount = 0 then Exit;

  NeedToKillSelf := False;
  for I := 0 to ProcessListCount - 1 do
  begin
    if ProcessList[I].ExeFile = ProcessName then
      if ProcessList[I].ProcessID = CurrentID then
        NeedToKillSelf := True
      else
        KillProcess(ProcessList[I].ProcessID);
  end;

  if CanKillSelf and NeedToKillSelf then ExitProcess(0);
end;

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

function GetProcessCPULoading(ProcessID: LongWord; Delay: Cardinal): Single;
var
  SystemInfo: SYSTEM_INFO;
  ProcessorsCount: Byte;

  lpCreationTime, lpExitTime,
  lpKernelTime, lpUserTime: TFileTime;

  WorkingTime: Int64;
  WorkingInterval, LifeInterval: Single;

  FirstUpdateTime, SecondUpdateTime: Cardinal;
  FirstWorkingTime: Int64;

  ProcessHandle: THandle;
begin
  ProcessHandle := ProcessIDtoHandle(ProcessID);

  // Получаем количество ядер:
  GetSystemInfo(SystemInfo);
  ProcessorsCount := SystemInfo.dwNumberOfProcessors;

  // Получаем времена процесса:
  GetProcessTimes(ProcessHandle, lpCreationTime, lpExitTime, lpKernelTime, lpUserTime);
  FirstUpdateTime := GetTickCount;
  // Рабочее время в начале интервала:
  FirstWorkingTime := Int64(lpKernelTime) + Int64(lpUserTime);

  Sleep(Delay);

  // Получаем времена процесса через интервал:
  GetProcessTimes(ProcessHandle, lpCreationTime, lpExitTime, lpKernelTime, lpUserTime);
  SecondUpdateTime := GetTickCount;

  // Интервал, во время которого будем измерять нагрузку:
  LifeInterval := SecondUpdateTime - FirstUpdateTime;
  if LifeInterval <= 0 then LifeInterval := 0.01;

  // Рабочее время в конце интервала:
  WorkingTime := Int64(lpKernelTime) + Int64(lpUserTime);

  // Разность между рабочими временами в конце и начале интервала:
  WorkingInterval := WorkingTime - FirstWorkingTime;

  // Выводим результат:
  Result := WorkingInterval / (LifeInterval * 100 * ProcessorsCount);

  CloseHandle(ProcessHandle);
end;


//HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH

initialization
  {$IFDEF DEBUG_PRIVILEGE}
  NTSetPrivilege(SE_DEBUG_NAME, True);
  {$ENDIF}
  _InitFunctions;


end.