WINDOWS下调用GetTokenInformation的奇怪之处--两次调用
就是用getLastErr可以得到错误号,同时,会将需要的长度写到参数里,再进行第二次调用,以此来节约内存空间。
神奇的长见识了。
相关说法如下:
======================
The error occurs because the buffer is insufficient. :-) It's not large enough for the content. Once again, I refer you to the documentation. If the function fails, the ReturnLength
parameter is set to the size of the buffer needed, so you can allocate sufficient memory and call the function again. The general rule for many API calls that have variable buffer requirements is "Call the function once with a NULL buffer to determine the buffer size needed, allocate the memory, and then call it again to actually retrieve the information"
======================
The TOKEN_USER
structure contains pointers (in particular, a pointer to a SID
that itself has variable length). Those pointers have to point somewhere. The API function will expect a buffer big enough to hold not only the the TOKEN_USER
structure, but also all the things that structure points to. The function tells you how much memory it needs for everything. It will all reside in adjacent memory.
======================
最近又在重新编写一些以前已经实现过的功能, 一来是温习之前学的一些东西, 二是希望多次重写一个功能的过程中提升自己现有的编程技术和水平, 今天这篇文章算是一个小的总结.
WINADVAPI
BOOL
WINAPI
GetTokenInformation (
_In_ HANDLE TokenHandle,
_In_ TOKEN_INFORMATION_CLASS TokenInformationClass,
_Out_opt_ LPVOID TokenInformation, _In_
DWORD TokenInformationLength, _Out_
PDWORD ReturnLength
);
总得来说, 这个函数算是Win32 API中比较有代表性的一个, 参数的含义也都是一目了然, 这里就不再过多獒述了(注: 关于GetTokenInformation参数含义这里倒是有一个趣事, 如果有兴趣看的朋友可以在文章最后找到我对它的说明), 有兴趣的朋友可以去MSDN上找这个API的具体文档, 下面我用一段代码示例来演示如何使用GetTokenInformation函数检索进程的所有特权信息
static PTOKEN_GROUPS GetProcessGroups(HANDLE hProcess)
{
HANDLE hToken;
PTOKEN_GROUPS pGroups = NULL;
DWORD neededSize;
// 这里会先获得一个进程访问令牌的句柄, 并且只允许该句柄具有信息查询的权限.
if (!OpenProcessToken(hProcess, TOKEN_QUERY, &hToken))
return NULL;
// 这里第一次调用GetTokenInformation是为了获取令牌信息需要的缓冲区的大小,
// 这是在使用Win32 API中的一个常用做法, 很多Win32 API都可以这样使用, 目的
// 是不用让程序员总是创建一个假设一定足够的缓冲区, 这在很多时候会造成空间上的浪费
neededSize = 0;
GetTokenInformation(hToken, TokenGroups, NULL, neededSize, &neededSize);
if (GetLastError() == ERROR_INSUFFICIENT_BUFFER && neededSize > 0)
{
pGroups = HeapAlloc(GetProcessHeap(), 0, neededSize);
if (pGroups != NULL)
{
// 这里是真正去检索特权信息, 并且检查成功或失败.
if (!GetTokenInformation(hToken, TokenGroups, pGroups, neededSize, &neededSize))
{
HeapFree(GetProcessHeap(), 0, pGroups);
pGroups = NULL;
}
}
}
CloseHandle(hToken);
return pGroups;
}
这个函数是用C编写的, 关键性的代码旁边都有注释说明其函数, 到这里文档的主要内容也就结束了, 不过值得多说一句的是, GetTokenInformation不仅可以获取进程的特权信息, 同时还能得到其它更多的信息, 比如进程所属的所有用户组, 进程拥有者以及虚拟化信息等, 而TOKEN_INFORMATION_CLASS会告诉GetTokenInformation你想要哪种信息.
关于GetTokenInformation函数参数的趣事
我在使用GetTokenInformation过程中发现了一个有趣的事情, 那就是Microsoft似乎在维护文档与Platform SDK头文件时出现了歧义,
BOOL
WINAPI
GetTokenInformation (
__in HANDLE TokenHandle,
__in TOKEN_INFORMATION_CLASS TokenInformationClass,
__out_bcount_part_opt(TokenInformationLength, *ReturnLength) LPVOID TokenInformation,
__in DWORD TokenInformationLength,
__out_opt PDWORD ReturnLength
);
此时ReturnLength这个参数带有_out_opt这样的修饰符, 它在WIN32 API中的文档约定是指被修饰的参数可以传一个NULL指针进去而不会任何问题, 最多也就是你不知道实际填充到TokenInformation缓冲区的令牌信息占用了多少字节, 不过有趣的是API的实现似乎是遵照了在MSDN官网文档中定义的形式, 也就是ReturnLength这个值必须指向一个有效的DWORD类型的变量, 所以如果你在调用GetTokenInformation时传递给ReturnLength是一个NULL值, 那么GetTokenInformation会返回失败, 并且调用GetLastError()会返回错误代码87(ERROR_INVALID_PARAMETER), 同样的问题可能不只是出现在GetTokenInformation函数中, 其它一些少数API可能也存在此类问题, 所以使用的时候还需要多加留意才行.
在MSDN的文档中ReturnLength这个参数被定义为"必选"参数, 这里所谓的"必选"一词是指它不是一个NULL指针值, 也就是不允许这样的调用行为GetTokenInformation(...., NULL);, 但如果细心的朋友在Microsoft Visual Stdio 2005中查看这个WinBase.h中这个函数的原型声明时会发现它的声明形式如下:
WINDOWS下调用GetTokenInformation的奇怪之处--两次调用的更多相关文章
- Windows下静态库、动态库的创建和调用过程
静态库和动态库的使用包括两个方面,1是使用已有的库(调用过程),2是编写一个库供别人使用(创建过程).这里不讲述过多的原理,只说明如何编写,以及不正确编写时会遇见的问题. //注:本文先从简单到复杂, ...
- windows下快速启动 nginx 和 php-cgi 的两个批处理
这是启动的批处理: set nginx=D:\nginx-1.9.5\ set php=D:\php\ start /MIN %nginx%nginx.exe start /MIN %php%php- ...
- Windows下GNU之gcc体验方法
Windows 现在在Windows下开发C/C++程序一般都是用微软的编译器,当年的Borland已经成为传说.但是如果你不想付钱的话,也可以考虑Windows下的GCC. 在Windows下体验G ...
- go语言执行windows下命令行的方法
转自:http://www.jb51.net/article/61727.htm 在golang里执行windows下的命令行,例如在golang里面调用 del d:\a.txt 命令 packag ...
- 关于Windows下的文件后缀名问题
一.背景说明 有很多的小伙伴对windows下的文件后缀名不能很好地理解作用和区别,更不用说高深的使用了,在这里给大家说一下这些文件后缀名到底有什么区别,有什么作用呢? 二.说明 简单的说来,wind ...
- 如何在Windows下安装Tomcat服务器
Tomcat 服务器是一个免费的开放源代码的Web 应用服务器,属于轻量级应用服务器,在中小型系统和并发访问用户不是很多的场合下被普遍使用,是开发和调试JSP 程序的首选服务器.在Windows下安装 ...
- 在Windows下编译Emacs
在Windows下编译Emacs Windows下编译好的Emacs主要有两个版本,一个来自http://nqmacs.sourceforge.net/,另一个来自http://www.crasseu ...
- windows下配置tomcat服务器的jvm内存大小的两种方式
难得遇到一次java堆内存溢出(心里想着,终于可以来一次jvm性能优化了$$) 先看下报错信息, java.lang.OutOfMemoryError: GC overhead limit excee ...
- Windows下Pycharm安装Tensorflow:ERROR: Could not find a version that satisfies the requirement tensorflow
今天在Windows下通过Pycharm安装Tensorflow时遇到两个问题: 使用pip安装其实原理都相同,只不过Pycharm是图形化的过程! 1.由于使用国外源总是导致Timeout 解决方法 ...
随机推荐
- JavaScript--DOM节点属性
节点属性 在文档对象模型 (DOM) 中,每个节点都是一个对象.DOM 节点有三个重要的属性 : 1. nodeName : 节点的名称 2. nodeValue :节点的值 3. nodeType ...
- Windows8.1查看已连接无线WIFI密码
Windows8.1操作系统下查看已连接无线wifi密码操作步骤如下: 1.右键任务栏中的无线图标,在弹出的菜单中选择"打开网络和共享中心": 2.在网络和共享中心界面中点击&qu ...
- 260 Single Number III 数组中除了两个数外,其他的数都出现了两次,找出这两个只出现一次的数
给定一个整数数组 nums,其中恰好有两个元素只出现一次,其他所有元素均出现两次. 找出只出现一次的那两个元素.示例:给定 nums = [1, 2, 1, 3, 2, 5], 返回 [3, 5].注 ...
- scala学习笔记2:面向对象编程部分基础
以下主要记录的是看完scala in programming这本书Functional Objects(第六章)后的要点总结. 1,程序中可变对象(var)和不可变对象(val)使用的权衡问题 不可变 ...
- [ SPOJ PT07J ] Query on a tree III
\(\\\) Description 其实这题才是正版的 Qtree3...... 给定 \(n\) 个点,以 \(1\) 号节点为根的树,点有点权. \(m\) 次询问 以 \(x\) 为根的子树内 ...
- ajax怎么理解?
Ajix是创建交互式网页的前端网页开发技术,不是一种语言,ajax是基于http来传输数据的,他是利用浏览器提供操作http的接口(XMLHttpRequest或者activeXobject),来操作 ...
- npm err报错解决
最近看vue官网:按照官网步骤正确按照vue脚手架却报错 翻了很多,才发现是webpack的问题 npm install webpack-dev-server@2.9.7 --save ok,好了!
- python学习笔记(6)——字典(Dictionary)
dict= {key1 : value1, key2 : value2 ...} 关键词:字典中元素成对出现- key:value 格式- 两端{ } ,键:值,每对键值间用 ,隔开. 键key-唯一 ...
- 【DVWA】【SQL Injection(Blind)】SQL盲注 Low Medium High Impossible
1.初级篇 Low.php 加单引号提交 http://localhost/DVWA-master/vulnerabilities/sqli_blind/?id=1'&Submit=Submi ...
- nginx--提供一键安装脚本
nginx特点 基于进程池实现的fastcgi 单一进程即可实现处理上千的连接 易于扩展的插件系统 安装篇 *下载源码 curl -O http://nginx.org/download/nginx- ...