OpenProcessToken()运用心得

本文探讨了在使用OpenProcessToken()获取进程访问令牌时遇到的问题。错误示例中,由于错误地将HANDLE定义为指针,导致函数调用失败并返回998错误(拒绝访问)。通过对比正确示例,我们了解到应将HANDLE定义为变量而非指针。深入WinNT.h头文件的定义,理解STRICT宏如何影响HANDLE的类型,揭示了问题的根源。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

    使用OpenProcessToken()用于得到指定进程的访问令牌,而第三个参数定义设置不正确可能导致该函数调用失败,以下举例说明:

 

HANDLE hProc;
hProc = GetCurrentProcess();

 

// Method1 - Error(998)
HANDLE *hToken;
OpenProcessToken(hProc, TOKEN_ADJUST_PRIVILEGES, hToken);

 

// Method2 - Success
HANDLE hToken;
OpenProcessToken(hProc, TOKEN_ADJUST_PRIVILEGES, &hToken);

 

以上是获取访问令牌的调用,OpenProcessToken()函数原型如下:

 

BOOL WINAPI OpenProcessToken(
  __in          HANDLE ProcessHandle,
  __in          DWORD DesiredAccess,
  __out         PHANDLE TokenHandle
);

 

方法1和方法2都使用HANDLE类型定义,方法1定义指针,方法2定义变量,但方法1调用函数返回失败(通过GetLastError()可知错误代码为998——拒绝访问);方法2调用函数则能成功获取访问令牌。为什么出现这种情况呢?WinNT.h中相关的定义引起,如下:

 

#ifdef STRICT
typedef void *HANDLE;
#define DECLARE_HANDLE(name) struct name##__ { int unused; }; typedef struct name##__ *name
#else
typedef PVOID HANDLE;
#define DECLARE_HANDLE(name) typedef HANDLE name
#endif
typedef HANDLE *PHANDLE;

 

由此可见可以把任意一种类型的指针赋值给PVOID型,因此PVOID*赋给PVOID型是可以的,而把PVOID型赋值给PVOID*型也可以。 

### ctypes 中 `windll.advapi32.OpenProcessToken` 的功能解析 `OpenProcessToken` 是 Windows API 提供的一个函数,用于打开一个现有进程的访问令牌。该函数允许程序获取与特定进程关联的安全上下文(即访问令牌),以便进一步操作,比如调整权限或查询安全信息。 以下是关于 `OpenProcessToken` 函数及其参数的具体说明: #### 函数原型 ```c BOOL OpenProcessToken( HANDLE ProcessHandle, DWORD DesiredAccess, PHANDLE TokenHandle ); ``` #### 参数解释 1. **ProcessHandle**: 这是一个指向目标进程句柄的有效句柄。通常情况下,可以通过调用 `GetCurrentProcess()` 来获得当前进程的句柄[^1]。此句柄必须具有足够的权限来执行请求的操作。 2. **DesiredAccess**: 此参数指定了希望对访问令牌拥有的访问权利。常见的标志位包括但不限于: - `TOKEN_QUERY`: 查询令牌属性的权利。 - `TOKEN_ADJUST_PRIVILEGES`: 调整令牌特权的权利。 - `TOKEN_DUPLICATE`: 复制令牌的权利。 完整列表可以参考 Win32 文档中的定义[^4]。 3. **TokenHandle**: 如果函数成功,则返回一个指向新创建的访问令牌对象的句柄。这个句柄随后可用于其他需要令牌的 API 调用,例如 `AdjustTokenPrivileges` 或者 `GetTokenInformation`。 #### 返回值 如果函数成功完成,它会返回非零值;否则返回零,并可通过调用 `GetLastError()` 获取更多错误详情。 #### 使用示例 下面展示如何利用 Python 的 `ctypes` 库调用 `OpenProcessToken`: ```python import ctypes from ctypes import wintypes # 加载所需的库 advapi32 = ctypes.windll.Advapi32 kernel32 = ctypes.windll.Kernel32 # 定义常量 TOKEN_QUERY = 0x0008 TOKEN_ADJUST_PRIVILEGES = 0x0020 # 声明函数原型 OpenProcessToken = advapi32.OpenProcessToken OpenProcessToken.argtypes = [wintypes.HANDLE, wintypes.DWORD, ctypes.POINTER(wintypes.HANDLE)] OpenProcessToken.restype = wintypes.BOOL # 获取当前进程句柄 current_process_handle = kernel32.GetCurrentProcess() token_handle = wintypes.HANDLE() if not OpenProcessToken(current_process_handle, TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES, ctypes.byref(token_handle)): raise Exception(f"Failed to open process token! Error code: {ctypes.WinError()}") print("Successfully opened process token.") ``` 以上代码片段展示了如何加载必要的 DLL 文件并设置适当的数据类型以匹配 C 风格接口的要求。注意这里我们组合了两个不同的访问掩码 (`TOKEN_QUERY`, `TOKEN_ADJUST_PRIVILEGES`) ,这使得我们可以既查询又修改所得到的令牌状态。 #### 关键点补充 当处理像 `TOKEN_USER` 结构这样的复杂数据结构时,需要注意它们可能包含动态长度字段或者嵌套指针的情况[^2]。因此,在分配缓冲区大小之前应该先计算好所需空间总量。 另外值得注意的是,虽然上面例子演示了基本流程,但在实际应用过程中还需要考虑异常情况以及资源释放等问题,确保不会因为未关闭句柄而导致内存泄漏或其他潜在风险。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值