Good day. It is necessary to track the emergence of new processes. Is there a slot in Windows that receives a signal when a new process appears? Otherwise, how can this be implemented? In psapi did not find this. There is a suggestion to check the PID list at regular intervals, but I hope to find a simpler solution.
- Maybe put a hook on CreateProcess? - Alexey Sarovsky
- Why do you need to track them? Write [anti] virus? - VTT
- oneThen check the process you do not need anything, because the running process does not mean that the user is working with him. Just check the windows. - VTT
- oneSince you do not need microsecond accuracy, it is enough to list the processes and check the appearance of new ones. This is definitely easier than getting a “signal” when starting a new process. - Vladimir Martyanov
- oneFor this you need WMI. msdn.microsoft.com/en-us/library/aa390425(VS.85).aspx - goldstar_labs
|
1 answer
You can do tracing through the system function ZwQuerySystemInformation . Attention! Microsoft does not recommend, starting with Windows 8, use it, offering a replacement, but, as has just been tested on Windows 10, it works.
I give an example of implementation and use on Delphi, in the form of a console application. As far as the WinAPI functions are concerned, rewriting to C / C ++ is easy.
program ListOfProcess; {$APPTYPE CONSOLE} uses SysUtils, windows, System.Generics.Collections; // поскольку подход писался очень давно (во времена Windows 2000), // типы и константы определены, поскольку в то время их ещё не было в // системных модулях Delphi. Хотя и сейчас, возможно, некоторых нет. type NTStatus = cardinal; PVOID = pointer; USHORT = WORD; UCHAR = byte; PWSTR = PWideChar; const STATUS_SUCCESS = NTStatus($00000000); STATUS_ACCESS_DENIED = NTStatus($C0000022); STATUS_INFO_LENGTH_MISMATCH = NTStatus($C0000004); const SystemProcessesAndThreadsInformation = 5; type PClientID = ^TClientID; TClientID = packed record UniqueProcess:cardinal; UniqueThread:cardinal; end; PUnicodeString = ^TUnicodeString; TUnicodeString = packed record Length: Word; MaximumLength: Word; Buffer: PWideChar; end; PVM_COUNTERS = ^VM_COUNTERS; VM_COUNTERS = packed record PeakVirtualSize, VirtualSize, PageFaultCount, PeakWorkingSetSize, WorkingSetSize, QuotaPeakPagedPoolUsage, QuotaPagedPoolUsage, QuotaPeakNonPagedPoolUsage, QuotaNonPagedPoolUsage, PagefileUsage, PeakPagefileUsage: dword; end; PIO_COUNTERS = ^IO_COUNTERS; IO_COUNTERS = packed record ReadOperationCount, WriteOperationCount, OtherOperationCount, ReadTransferCount, WriteTransferCount, OtherTransferCount: LARGE_INTEGER; end; PSYSTEM_THREADS = ^SYSTEM_THREADS; SYSTEM_THREADS = packed record KernelTime, UserTime, CreateTime: LARGE_INTEGER; WaitTime: dword; StartAddress: pointer; ClientId: TClientId; Priority, BasePriority, ContextSwitchCount: dword; State: dword; WaitReason: dword; end; PSYSTEM_PROCESSES = ^SYSTEM_PROCESSES; SYSTEM_PROCESSES = packed record NextEntryDelta, ThreadCount: dword; Reserved1 : array [0..5] of dword; CreateTime, UserTime, KernelTime: LARGE_INTEGER; ProcessName: TUnicodeString; BasePriority: dword; ProcessId, InheritedFromProcessId, HandleCount: dword; Reserved2: array [0..1] of dword; VmCounters: VM_COUNTERS; IoCounters: IO_COUNTERS; Threads: array [0..0] of SYSTEM_THREADS; end; // основная функция, которую мы будем использовать Function ZwQuerySystemInformation(ASystemInformationClass: dword; ASystemInformation: Pointer; ASystemInformationLength: dword; AReturnLength:PCardinal): NTStatus; stdcall;external 'ntdll.dll'; // Функция получения буфера с системной информацией Function GetInfoTable(ATableType:dword):Pointer; var mSize: dword; mPtr: pointer; St: NTStatus; begin Result := nil; mSize := $4000; //начальный размер буфера repeat // подгонка размера буфера mPtr := VirtualAlloc(nil, mSize, MEM_COMMIT or MEM_RESERVE, PAGE_READWRITE); if mPtr = nil then Exit; St := ZwQuerySystemInformation(ATableType, mPtr, mSize, nil); if St = STATUS_INFO_LENGTH_MISMATCH then begin VirtualFree(mPtr, 0, MEM_RELEASE); mSize := mSize * 2; end; until St <> STATUS_INFO_LENGTH_MISMATCH; if St = STATUS_SUCCESS then Result := mPtr else VirtualFree(mPtr, 0, MEM_RELEASE); end; // приведу пример использовании фунции: var info, info2: PSystem_Processes; i, j, k: integer; t, t1: LARGE_INTEGER; process_id:TDictionary<Integer,SYSTEM_PROCESSES>; // здесь будем хранить информацию begin process_id := TDictionary<Integer,SYSTEM_PROCESSES>.Create; // Список процессов на момент старта программы info := GetInfoTable(SystemProcessesAndThreadsInformation); info2 := info; while (info2^.NextEntryDelta <> 0) do begin if not process_id.ContainsKey(info2^.ProcessId) then process_id.Add(info2^.ProcessId, info2^); info2 := Pointer(dword(info2)+info2^.NextEntryDelta); end; VirtualFree(info, 0, MEM_RELEASE); while true do // нужно вставить вариант выхода из цикла. Разумеется, Ctrl+C всегда сработает :) begin Sleep(2000); // будем проверять наличие новых процессов каждые 2 секунды info := GetInfoTable(SystemProcessesAndThreadsInformation); info2 := info; while (info2^.NextEntryDelta <> 0) do begin if not process_id.ContainsKey(info2^.ProcessId) then begin writeln(info2^.ProcessId, ' - появился'); process_id.Add(info2^.ProcessId,info2^); // если будем постоянно добавлять, словарь разрастётся, // надо бы подумать и об удалении элементов, оставляю ТС :) end; info2 := Pointer(dword(info2)+info2^.NextEntryDelta); end; VirtualFree(info, 0, MEM_RELEASE); end; process_id.Free; end. |