您的位置:首页 > 其它

WINDOWS下调用GetTokenInformation的奇怪之处--两次调用

2016-07-24 17:06 260 查看
就是用getLastErr可以得到错误号,同时,会将需要的长度写到参数里,再进行第二次调用,以此来节约内存空间。

神奇的长见识了。

相关说法如下:

======================

Theerroroccursbecausethebufferisinsufficient.:-)It'snotlargeenoughforthecontent.Onceagain,Ireferyoutothedocumentation.Ifthefunctionfails,the
ReturnLength
parameterissettothesizeofthebufferneeded,soyoucanallocatesufficientmemoryandcallthefunctionagain.ThegeneralruleformanyAPIcallsthathavevariablebufferrequirementsis"CallthefunctiononcewithaNULLbuffertodeterminethebuffersizeneeded,allocatethememory,andthencallitagaintoactuallyretrievetheinformation"

======================

The
TOKEN_USER
structurecontainspointers(inparticular,apointertoa
SID
thatitselfhasvariablelength).Thosepointershavetopointsomewhere.TheAPIfunctionwillexpectabufferbigenoughtoholdnotonlythethe
TOKEN_USER
structure,butalsoallthethingsthatstructurepointsto.Thefunctiontellsyouhowmuchmemoryitneedsforeverything.Itwillallresideinadjacentmemory.

======================

最近又在重新编写一些以前已经实现过的功能,一来是温习之前学的一些东西,二是希望多次重写一个功能的过程中提升自己现有的编程技术和水平,今天这篇文章算是一个小的总结.

在写之前请容许我唠叨片刻,文章中涉及的技术与代码示例可能早遍布在百度与GOOGLE上的各种原创或转载文章中,所以我的内容多少也会与那些文章中的东西有所相同,对于那些已经看过那些文章或者早已熟悉这些技术朋友可能会略显平庸,不过这都算是自己对技术积累的心得吧,见笑了,那么言归正传了.

Win32API中提供了GetTokenInformation与SetTokenInformation函数,这2个函数别分是检索与设置一个访问令牌的信息,关于访问令牌的具体细节有兴趣的朋友可以去MSDN上找,因为与文章主题没有直接的关系,所以就不在具体细说了.
以下是GetTokenInformation的API原型(如果想对这个函数的细节做更多了解,可以去MSDN上查询它的详细信息)


WINADVAPI

BOOL

WINAPI

GetTokenInformation(

_In_HANDLETokenHandle,

_In_TOKEN_INFORMATION_CLASSTokenInformationClass,

_Out_opt_LPVOIDTokenInformation,_In_

DWORDTokenInformationLength,_Out_

PDWORDReturnLength

);

总得来说,这个函数算是Win32API中比较有代表性的一个,参数的含义也都是一目了然,这里就不再过多獒述了(注:关于GetTokenInformation参数含义这里倒是有一个趣事,如果有兴趣看的朋友可以在文章最后找到我对它的说明),有兴趣的朋友可以去MSDN上找这个API的具体文档,下面我用一段代码示例来演示如何使用GetTokenInformation函数检索进程的所有特权信息


staticPTOKEN_GROUPSGetProcessGroups(HANDLEhProcess)

{

HANDLEhToken;

PTOKEN_GROUPSpGroups=NULL;

DWORDneededSize;


//这里会先获得一个进程访问令牌的句柄,并且只允许该句柄具有信息查询的权限.

if(!OpenProcessToken(hProcess,TOKEN_QUERY,&hToken))

returnNULL;


//这里第一次调用GetTokenInformation是为了获取令牌信息需要的缓冲区的大小,

//这是在使用Win32API中的一个常用做法,很多Win32API都可以这样使用,目的

//是不用让程序员总是创建一个假设一定足够的缓冲区,这在很多时候会造成空间上的浪费

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

returnpGroups;

}

这个函数是用C编写的,关键性的代码旁边都有注释说明其函数,到这里文档的主要内容也就结束了,不过值得多说一句的是,GetTokenInformation不仅可以获取进程的特权信息,同时还能得到其它更多的信息,比如进程所属的所有用户组,进程拥有者以及虚拟化信息等,而TOKEN_INFORMATION_CLASS会告诉GetTokenInformation你想要哪种信息.


关于GetTokenInformation函数参数的趣事

我在使用GetTokenInformation过程中发现了一个有趣的事情,那就是Microsoft似乎在维护文档与PlatformSDK头文件时出现了歧义,

BOOL

WINAPI

GetTokenInformation(

__inHANDLETokenHandle,

__inTOKEN_INFORMATION_CLASSTokenInformationClass,

__out_bcount_part_opt(TokenInformationLength,*ReturnLength)LPVOIDTokenInformation,

__inDWORDTokenInformationLength,

__out_optPDWORDReturnLength

);

此时ReturnLength这个参数带有_out_opt这样的修饰符,它在WIN32API中的文档约定是指被修饰的参数可以传一个NULL指针进去而不会任何问题,最多也就是你不知道实际填充到TokenInformation缓冲区的令牌信息占用了多少字节,不过有趣的是API的实现似乎是遵照了在MSDN官网文档中定义的形式,也就是ReturnLength这个值必须指向一个有效的DWORD类型的变量,所以如果你在调用GetTokenInformation时传递给ReturnLength是一个NULL值,那么GetTokenInformation会返回失败,并且调用GetLastError()会返回错误代码87(ERROR_INVALID_PARAMETER),同样的问题可能不只是出现在GetTokenInformation函数中,其它一些少数API可能也存在此类问题,所以使用的时候还需要多加留意才行.

在MSDN的文档中ReturnLength这个参数被定义为"必选"参数,这里所谓的"必选"一词是指它不是一个NULL指针值,也就是不允许这样的调用行为GetTokenInformation(....,NULL);,但如果细心的朋友在MicrosoftVisualStdio2005中查看这个WinBase.h中这个函数的原型声明时会发现它的声明形式如下:
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: