在Python中查找每个正在运行的进程的路径

时间:2015-06-18 07:48:53

标签: python windows process path psutil

我想在Windows中找到每个正在运行的进程的路径。 我试图使用psutil模块,但它并没有向我显示所有路径。它找不到很多流程'路径因为错误:" psutil.AccessDenied"

c = wmi.WMI()
for process in c.Win32_Process():
        p = psutil.Process(int(process.ProcessId))
        try:
            path = p.exe()
        except:
            path = "-"

是否有另一种获取流程路径的方法?

1 个答案:

答案 0 :(得分:5)

作为管理员,如果无法获得PROCESS_QUERY_LIMITED_INFORMATION(0x400),您可以获得给定进程的PROCESS_QUERY_INFORMATION(0x1000)访问权限。 QueryFullProcessImageNameW只需要有限的访问权限。但是,即使这样也不会适用于所有情况。例如,csrss.exe上的安全描述符仅授予对SYSTEM帐户的访问权限,而不授予管理员权限。另一个例子是services.exe,它运行在System(S-1-16-16384)完整性级别,而管理员令牌只在High(S-1-16-12288)完整性级别。

您通常无法打开此类进程的句柄。但作为管理员,你几乎无所不能SeDebugPrivilege。如果您启用此权限,Windows AccessCheck将突然成为您最好的朋友(但即使是最好的朋友也有其限制)。

下面是一些ctypes代码,用于启用和禁用当前进程访问令牌中的权限。该权限必须始终存在于令牌中,因此请确保使用管理员帐户运行此权限,或者如果使用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)

<强>测试

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))

<强>输出

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

拒绝访问空闲(0)和系统(4)进程是可以理解的。然而,有趣的是,PID 4704的访问被拒绝,甚至是调试器。这是audiodg.exe,这是受保护的进程,如“{Protected Processes”白皮书中所述,可在Windows Hardware Dev Center Archive下载。受保护的进程允许查询有限的信息,例如图像路径。让我们快速验证是这种情况:

>>> 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'