I want to find the path of every running process in windows. I tried to use the psutil module but it doesn't show me all the paths. It can't find many processes' paths because of the error: "psutil.AccessDenied"
c = wmi.WMI()
for process in c.Win32_Process():
p = psutil.Process(int(process.ProcessId))
try:
path = p.exe()
except:
path = "-"
Is there another way to get a path of a process?
As an administrator you might be able to get PROCESS_QUERY_LIMITED_INFORMATION
(0x1000) access for a given process if you can't get PROCESS_QUERY_INFORMATION
(0x400). QueryFullProcessImageNameW
only requires limited access. However, not even this will work in all cases. For example, the security descriptor on csrss.exe only grants access to the SYSTEM account, not administrators. Another example is services.exe, which runs at System
(S-1-16-16384) integrity level, while an administrator token is only at High
(S-1-16-12288) integrity level.
You normally can't open a handle to such processes. But as an administrator you have the almost omnipotent SeDebugPrivilege
. If you enable this privilege, Windows AccessCheck
will suddenly become your best friend (but even best friends have their limits).
Below is some ctypes code to enable and disable a privilege in the current process access token. The privilege has to be present in the token to begin with, so be sure to run this using the Administrator account or as an elevated administrator if using UAC.
from ctypes import *
from ctypes.wintypes import *
kernel32 = WinDLL('kernel32', use_last_error=True)
advapi32 = WinDLL('advapi32', use_last_error=True)
SE_PRIVILEGE_ENABLED = 0x00000002
TOKEN_ALL_ACCESS = 0x000F0000 | 0x01FF
class LUID(Structure):
_fields_ = (('LowPart', DWORD),
('HighPart', LONG))
class LUID_AND_ATTRIBUTES(Structure):
_fields_ = (('Luid', LUID),
('Attributes', DWORD))
class TOKEN_PRIVILEGES(Structure):
_fields_ = (('PrivilegeCount', DWORD),
('Privileges', LUID_AND_ATTRIBUTES * 1))
def __init__(self, PrivilegeCount=1, *args):
super(TOKEN_PRIVILEGES, self).__init__(PrivilegeCount, *args)
PDWORD = POINTER(DWORD)
PHANDLE = POINTER(HANDLE)
PLUID = POINTER(LUID)
PTOKEN_PRIVILEGES = POINTER(TOKEN_PRIVILEGES)
def errcheck_bool(result, func, args):
if not result:
raise WinError(get_last_error())
return args
kernel32.CloseHandle.argtypes = (HANDLE,)
kernel32.GetCurrentProcess.errcheck = errcheck_bool
kernel32.GetCurrentProcess.restype = HANDLE
# https://msdn.microsoft.com/en-us/library/aa379295
advapi32.OpenProcessToken.errcheck = errcheck_bool
advapi32.OpenProcessToken.argtypes = (
HANDLE, # _In_ ProcessHandle
DWORD, # _In_ DesiredAccess
PHANDLE) # _Out_ TokenHandle
# https://msdn.microsoft.com/en-us/library/aa379180
advapi32.LookupPrivilegeValueW.errcheck = errcheck_bool
advapi32.LookupPrivilegeValueW.argtypes = (
LPCWSTR, # _In_opt_ lpSystemName
LPCWSTR, # _In_ lpName
PLUID) # _Out_ lpLuid
# https://msdn.microsoft.com/en-us/library/aa375202
advapi32.AdjustTokenPrivileges.errcheck = errcheck_bool
advapi32.AdjustTokenPrivileges.argtypes = (
HANDLE, # _In_ TokenHandle
BOOL, # _In_ DisableAllPrivileges
PTOKEN_PRIVILEGES, # _In_opt_ NewState
DWORD, # _In_ BufferLength
PTOKEN_PRIVILEGES, # _Out_opt_ PreviousState
PDWORD) # _Out_opt_ ReturnLength
def enable_privilege(privilege):
hToken = HANDLE()
luid = LUID()
advapi32.LookupPrivilegeValueW(None, privilege, byref(luid))
try:
advapi32.OpenProcessToken(kernel32.GetCurrentProcess(),
TOKEN_ALL_ACCESS,
byref(hToken))
tp = TOKEN_PRIVILEGES()
tp.Privileges[0].Luid = luid
tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED
advapi32.AdjustTokenPrivileges(hToken, False,
byref(tp),
sizeof(tp),
None, None)
finally:
if hToken:
kernel32.CloseHandle(hToken)
def disable_privilege(privilege):
hToken = HANDLE()
luid = LUID()
advapi32.LookupPrivilegeValueW(None, privilege, byref(luid))
try:
advapi32.OpenProcessToken(kernel32.GetCurrentProcess(),
TOKEN_ALL_ACCESS,
byref(hToken))
tp = TOKEN_PRIVILEGES()
tp.Privileges[0].Luid = luid
tp.Privileges[0].Attributes = 0
advapi32.AdjustTokenPrivileges(hToken, False,
byref(tp),
sizeof(tp),
None, None)
finally:
if hToken:
kernel32.CloseHandle(hToken)
Test:
if __name__ == '__main__':
import psutil
system_process_names = {'smss.exe',
'csrss.exe',
'wininit.exe',
'winlogon.exe',
'services.exe',
'lsass.exe',
'lsm.exe'}
system_processes = []
print('SeDebugPrivilege Enabled')
enable_privilege('SeDebugPrivilege')
for proc in psutil.process_iter():
try:
name = proc.name().lower()
path = proc.exe()
except psutil.AccessDenied:
print('{:04d} ACCESS_DENIED'.format(proc.pid))
continue
if name in system_process_names:
system_process_names.remove(name)
system_processes.append(proc)
print('{:04d} {}'.format(proc.pid, path))
assert not system_process_names
print('\nSeDebugPrivilege Disabled')
disable_privilege('SeDebugPrivilege')
for proc in system_processes:
try:
path = psutil.Process(proc.pid).exe() # avoid cache
except psutil.AccessDenied:
path = 'ACCESS DENIED'
print('{:04d} {}'.format(proc.pid, path))
Output
SeDebugPrivilege Enabled
0000 ACCESS_DENIED
0004 ACCESS_DENIED
0256 C:\Windows\System32\smss.exe
0404 C:\Windows\System32\csrss.exe
0492 C:\Windows\System32\wininit.exe
0540 C:\Windows\System32\winlogon.exe
0588 C:\Windows\System32\services.exe
0596 C:\Windows\System32\lsass.exe
0604 C:\Windows\System32\lsm.exe
4704 ACCESS_DENIED
SeDebugPrivilege Disabled
0256 ACCESS DENIED
0404 ACCESS DENIED
0492 ACCESS DENIED
0540 ACCESS DENIED
0588 ACCESS DENIED
0596 ACCESS DENIED
0604 ACCESS DENIED
It's understandable to be denied access to the Idle (0) and System (4) processes. However, it's interesting that access was denied to PID 4704, even to a debugger. This is audiodg.exe, which is a protected process, as described in the "Protected Processes" white paper available for download at the Windows Hardware Dev Center Archive. Protected processes allow querying limited information, such as the image path. Let's quickly verify that this is the case:
>>> kernel32.OpenProcess(0x1000, 0, 4704)
304
>>> path = (c_wchar * 260)()
>>> size = c_uint(260)
>>> kernel32.QueryFullProcessImageNameW(304, 0, path, byref(size))
1
>>> path.value
'C:\\Windows\\System32\\audiodg.exe'