2024-09-28 21:09:40 发布
网友
为了从Python请求UAC提升的权限,当调用外部程序时,您可以
ctypes.windll.shell32.ShellExecuteW(None, "runas", my_binary_file_path, "", None, 1)
然而,假设您的Python脚本是使用管理权限执行,那么在没有管理权限的情况下,如何调用外部程序?
我更喜欢的一种方法是以shell用户的身份运行。首先打开shell进程并复制其令牌。{{cd2>然后调用默认情况下,管理员帐户没有SeAssignPrimaryTokenPrivilege,在这种情况下,您不能直接调用CreateProcessAsUser。你必须请求一个更有特权的进程来代表你打电话。CreateProcessWithTokenW通过对辅助登录服务进行远程过程调用来实现这一点。在PyWin32不包装GetShellWindow和CreateProcessWithTokenW,因此需要使用ctypes来调用它们。在Windows系统很少在没有常规shell的情况下运行,或者使用shell无法通过SetShellWindow[Ex]注册其窗口。在本例中,GetShellWindow返回NULL。作为这种情况的备用方法,您可以使用一个有点可疑(但有效)的方法来获取会话用户的令牌并调用CreateProcessAsUser。在首先获取会话的Windows子系统进程的PID,csrss.exe文件. 最简单的方法是调用未记录(但稳定的)函数CsrGetProcessId。启用SeDebugPrivilege以有限的查询访问权限打开此进程。然后打开它的令牌,复制它,并模拟它。现在您有了通过WTSQueryUserToken获取会话用户令牌所需的SeTcbPrivilege,并且您还拥有SeAssignPrimaryTokenPrivilege来调用CreateProcessAsUser。在导入和ctypes定义import os import contextlib import win32con import winerror import win32api import win32process import win32security import win32ts import pywintypes import ctypes from ctypes import wintypes ntdll = ctypes.WinDLL('ntdll') kernel32 = ctypes.WinDLL('kernel32', use_last_error=True) advapi32 = ctypes.WinDLL('advapi32', use_last_error=True) user32 = ctypes.WinDLL('user32', use_last_error=True) TOKEN_ADJUST_SESSIONID = 0x0100 PROCESS_QUERY_LIMITED_INFORMATION = 0x1000 LPBYTE = ctypes.POINTER(wintypes.BYTE) class STARTUPINFO(ctypes.Structure): """https://msdn.microsoft.com/en-us/library/ms686331""" __slots__ = () _fields_ = (('cb', wintypes.DWORD), ('lpReserved', wintypes.LPWSTR), ('lpDesktop', wintypes.LPWSTR), ('lpTitle', wintypes.LPWSTR), ('dwX', wintypes.DWORD), ('dwY', wintypes.DWORD), ('dwXSize', wintypes.DWORD), ('dwYSize', wintypes.DWORD), ('dwXCountChars', wintypes.DWORD), ('dwYCountChars', wintypes.DWORD), ('dwFillAttribute', wintypes.DWORD), ('dwFlags', wintypes.DWORD), ('wShowWindow', wintypes.WORD), ('cbReserved2', wintypes.WORD), ('lpReserved2', LPBYTE), ('hStdInput', wintypes.HANDLE), ('hStdOutput', wintypes.HANDLE), ('hStdError', wintypes.HANDLE)) def __init__(self, **kwds): self.cb = ctypes.sizeof(self) super(STARTUPINFO, self).__init__(**kwds) LPSTARTUPINFO = ctypes.POINTER(STARTUPINFO) class PROCESS_INFORMATION(ctypes.Structure): """https://msdn.microsoft.com/en-us/library/ms684873""" __slots__ = () _fields_ = (('hProcess', wintypes.HANDLE), ('hThread', wintypes.HANDLE), ('dwProcessId', wintypes.DWORD), ('dwThreadId', wintypes.DWORD)) LPPROCESS_INFORMATION = ctypes.POINTER(PROCESS_INFORMATION) kernel32.CloseHandle.argtypes = (wintypes.HANDLE,) # https://msdn.microsoft.com/en-us/library/ms682434 advapi32.CreateProcessWithTokenW.argtypes = ( wintypes.HANDLE, # _In_ hToken wintypes.DWORD, # _In_ dwLogonFlags wintypes.LPCWSTR, # _In_opt_ lpApplicationName wintypes.LPWSTR, # _Inout_opt_ lpCommandLine wintypes.DWORD, # _In_ dwCreationFlags wintypes.LPCWSTR, # _In_opt_ lpEnvironment wintypes.LPCWSTR, # _In_opt_ lpCurrentDirectory LPSTARTUPINFO, # _In_ lpStartupInfo LPPROCESS_INFORMATION) # _Out_ lpProcessInformation # https://msdn.microsoft.com/en-us/library/ms633512 user32.GetShellWindow.restype = wintypes.HWND 帮助函数 ^{pr2}$ 主要功能def runas_session_user(cmd, executable=None, creationflags=0, cwd=None, startupinfo=None, return_handles=False): if not creationflags & win32con.DETACHED_PROCESS: creationflags |= win32con.CREATE_NEW_CONSOLE if cwd is None: cwd = os.getcwd() si = win32process.STARTUPINFO() if startupinfo: startupinfo_update(startupinfo, si) with impersonate_system(): htoken_user = win32ts.WTSQueryUserToken( win32ts.WTS_CURRENT_SESSION) hProcess, hThread, dwProcessId, dwThreadId = ( win32process.CreateProcessAsUser( htoken_user, executable, cmd, None, None, False, creationflags, None, cwd, si)) if return_handles: return hProcess, hThread return dwProcessId, dwThreadId def runas_shell_user(cmd, executable=None, creationflags=0, cwd=None, startupinfo=None, return_handles=False): if not creationflags & win32con.DETACHED_PROCESS: creationflags |= win32con.CREATE_NEW_CONSOLE if cwd is None: cwd = os.getcwd() si = STARTUPINFO() if startupinfo: startupinfo_update(startupinfo, si) pi = PROCESS_INFORMATION() try: htoken = duplicate_shell_token() except pywintypes.error as e: if e.winerror != winerror.ERROR_FILE_NOT_FOUND: raise return runas_session_user(cmd, executable, creationflags, cwd, startupinfo, return_handles) with enable_privileges(win32security.SE_IMPERSONATE_NAME): if not advapi32.CreateProcessWithTokenW( int(htoken), 0, executable, cmd, creationflags, None, cwd, ctypes.byref(si), ctypes.byref(pi)): error = ctypes.get_last_error() raise pywintypes.error( error, 'CreateProcessWithTokenW', win32api.FormatMessageW(error)) hProcess = pywintypes.HANDLE(pi.hProcess) hThread = pywintypes.HANDLE(pi.hThread) if return_handles: return hProcess, hThread return pi.dwProcessId, pi.dwThreadId
默认情况下,管理员帐户没有SeAssignPrimaryTokenPrivilege,在这种情况下,您不能直接调用CreateProcessAsUser。你必须请求一个更有特权的进程来代表你打电话。CreateProcessWithTokenW通过对辅助登录服务进行远程过程调用来实现这一点。在
CreateProcessAsUser
CreateProcessWithTokenW
PyWin32不包装GetShellWindow和CreateProcessWithTokenW,因此需要使用ctypes来调用它们。在
GetShellWindow
Windows系统很少在没有常规shell的情况下运行,或者使用shell无法通过SetShellWindow[Ex]注册其窗口。在本例中,GetShellWindow返回NULL。作为这种情况的备用方法,您可以使用一个有点可疑(但有效)的方法来获取会话用户的令牌并调用CreateProcessAsUser。在
SetShellWindow[Ex]
NULL
首先获取会话的Windows子系统进程的PID,csrss.exe文件. 最简单的方法是调用未记录(但稳定的)函数CsrGetProcessId。启用SeDebugPrivilege以有限的查询访问权限打开此进程。然后打开它的令牌,复制它,并模拟它。现在您有了通过WTSQueryUserToken获取会话用户令牌所需的SeTcbPrivilege,并且您还拥有SeAssignPrimaryTokenPrivilege来调用CreateProcessAsUser。在
CsrGetProcessId
WTSQueryUserToken
导入和ctypes定义
import os import contextlib import win32con import winerror import win32api import win32process import win32security import win32ts import pywintypes import ctypes from ctypes import wintypes ntdll = ctypes.WinDLL('ntdll') kernel32 = ctypes.WinDLL('kernel32', use_last_error=True) advapi32 = ctypes.WinDLL('advapi32', use_last_error=True) user32 = ctypes.WinDLL('user32', use_last_error=True) TOKEN_ADJUST_SESSIONID = 0x0100 PROCESS_QUERY_LIMITED_INFORMATION = 0x1000 LPBYTE = ctypes.POINTER(wintypes.BYTE) class STARTUPINFO(ctypes.Structure): """https://msdn.microsoft.com/en-us/library/ms686331""" __slots__ = () _fields_ = (('cb', wintypes.DWORD), ('lpReserved', wintypes.LPWSTR), ('lpDesktop', wintypes.LPWSTR), ('lpTitle', wintypes.LPWSTR), ('dwX', wintypes.DWORD), ('dwY', wintypes.DWORD), ('dwXSize', wintypes.DWORD), ('dwYSize', wintypes.DWORD), ('dwXCountChars', wintypes.DWORD), ('dwYCountChars', wintypes.DWORD), ('dwFillAttribute', wintypes.DWORD), ('dwFlags', wintypes.DWORD), ('wShowWindow', wintypes.WORD), ('cbReserved2', wintypes.WORD), ('lpReserved2', LPBYTE), ('hStdInput', wintypes.HANDLE), ('hStdOutput', wintypes.HANDLE), ('hStdError', wintypes.HANDLE)) def __init__(self, **kwds): self.cb = ctypes.sizeof(self) super(STARTUPINFO, self).__init__(**kwds) LPSTARTUPINFO = ctypes.POINTER(STARTUPINFO) class PROCESS_INFORMATION(ctypes.Structure): """https://msdn.microsoft.com/en-us/library/ms684873""" __slots__ = () _fields_ = (('hProcess', wintypes.HANDLE), ('hThread', wintypes.HANDLE), ('dwProcessId', wintypes.DWORD), ('dwThreadId', wintypes.DWORD)) LPPROCESS_INFORMATION = ctypes.POINTER(PROCESS_INFORMATION) kernel32.CloseHandle.argtypes = (wintypes.HANDLE,) # https://msdn.microsoft.com/en-us/library/ms682434 advapi32.CreateProcessWithTokenW.argtypes = ( wintypes.HANDLE, # _In_ hToken wintypes.DWORD, # _In_ dwLogonFlags wintypes.LPCWSTR, # _In_opt_ lpApplicationName wintypes.LPWSTR, # _Inout_opt_ lpCommandLine wintypes.DWORD, # _In_ dwCreationFlags wintypes.LPCWSTR, # _In_opt_ lpEnvironment wintypes.LPCWSTR, # _In_opt_ lpCurrentDirectory LPSTARTUPINFO, # _In_ lpStartupInfo LPPROCESS_INFORMATION) # _Out_ lpProcessInformation # https://msdn.microsoft.com/en-us/library/ms633512 user32.GetShellWindow.restype = wintypes.HWND
帮助函数
主要功能
def runas_session_user(cmd, executable=None, creationflags=0, cwd=None, startupinfo=None, return_handles=False): if not creationflags & win32con.DETACHED_PROCESS: creationflags |= win32con.CREATE_NEW_CONSOLE if cwd is None: cwd = os.getcwd() si = win32process.STARTUPINFO() if startupinfo: startupinfo_update(startupinfo, si) with impersonate_system(): htoken_user = win32ts.WTSQueryUserToken( win32ts.WTS_CURRENT_SESSION) hProcess, hThread, dwProcessId, dwThreadId = ( win32process.CreateProcessAsUser( htoken_user, executable, cmd, None, None, False, creationflags, None, cwd, si)) if return_handles: return hProcess, hThread return dwProcessId, dwThreadId def runas_shell_user(cmd, executable=None, creationflags=0, cwd=None, startupinfo=None, return_handles=False): if not creationflags & win32con.DETACHED_PROCESS: creationflags |= win32con.CREATE_NEW_CONSOLE if cwd is None: cwd = os.getcwd() si = STARTUPINFO() if startupinfo: startupinfo_update(startupinfo, si) pi = PROCESS_INFORMATION() try: htoken = duplicate_shell_token() except pywintypes.error as e: if e.winerror != winerror.ERROR_FILE_NOT_FOUND: raise return runas_session_user(cmd, executable, creationflags, cwd, startupinfo, return_handles) with enable_privileges(win32security.SE_IMPERSONATE_NAME): if not advapi32.CreateProcessWithTokenW( int(htoken), 0, executable, cmd, creationflags, None, cwd, ctypes.byref(si), ctypes.byref(pi)): error = ctypes.get_last_error() raise pywintypes.error( error, 'CreateProcessWithTokenW', win32api.FormatMessageW(error)) hProcess = pywintypes.HANDLE(pi.hProcess) hThread = pywintypes.HANDLE(pi.hThread) if return_handles: return hProcess, hThread return pi.dwProcessId, pi.dwThreadId
您可以使用类似于:
import os os.system('calc.exe')
或如果要使用ctypes,请调用CreateProcessAPI函数
我更喜欢的一种方法是以shell用户的身份运行。首先打开shell进程并复制其令牌。{{cd2>然后调用
默认情况下,管理员帐户没有SeAssignPrimaryTokenPrivilege,在这种情况下,您不能直接调用
CreateProcessAsUser
。你必须请求一个更有特权的进程来代表你打电话。CreateProcessWithTokenW
通过对辅助登录服务进行远程过程调用来实现这一点。在PyWin32不包装
GetShellWindow
和CreateProcessWithTokenW
,因此需要使用ctypes来调用它们。在Windows系统很少在没有常规shell的情况下运行,或者使用shell无法通过
SetShellWindow[Ex]
注册其窗口。在本例中,GetShellWindow
返回NULL
。作为这种情况的备用方法,您可以使用一个有点可疑(但有效)的方法来获取会话用户的令牌并调用CreateProcessAsUser
。在首先获取会话的Windows子系统进程的PID,csrss.exe文件. 最简单的方法是调用未记录(但稳定的)函数
CsrGetProcessId
。启用SeDebugPrivilege以有限的查询访问权限打开此进程。然后打开它的令牌,复制它,并模拟它。现在您有了通过WTSQueryUserToken
获取会话用户令牌所需的SeTcbPrivilege,并且您还拥有SeAssignPrimaryTokenPrivilege来调用CreateProcessAsUser
。在导入和ctypes定义
帮助函数
^{pr2}$主要功能
您可以使用类似于:
或如果要使用ctypes,请调用CreateProcessAPI函数
^{pr2}$相关问题 更多 >
编程相关推荐