📄 11.2 使用者环境.htm
字号:
style="LINE-HEIGHT: 25px" face=arial color=#000000 size=2>
<OL style="LINE-HEIGHT: 25px">
<LI style="LINE-HEIGHT: 25px">以系统的管理者登录。
<LI
style="LINE-HEIGHT: 25px">使用第九章的TrusteeMan范例应用程序或者Microsoft管理主控台(MMC)群组原则嵌入式管理单元,增加「增加配额」及「更换程序层Token」权限到您的使用者帐户中。
<LI style="LINE-HEIGHT: 25px">登出,然后再次登录,以使新的权限生效。
<LI style="LINE-HEIGHT: 25px">启动TokenMaster。 </LI></OL></FONT>
<P><FONT style="LINE-HEIGHT: 25px" face=arial color=#000000
size=2>假如您执行成功,当您执行TokenMaster时,应用程序中的状态视窗应该会包含以下的讯息:「Token Master,
Status - Token Master running as
SYSTEM」。否则视窗将会指示TokenMaster应以您用来启动应用程序的帐户身分执行。</FONT></P>
<P><FONT style="LINE-HEIGHT: 25px" face=arial color=#000000
size=2>应用程序的主要函数是检视有关权杖的资讯,以及修改可以被改变的资讯。以下是获得权杖的方法:</FONT></P><FONT
style="LINE-HEIGHT: 25px" face=arial color=#000000 size=2>
<UL style="LINE-HEIGHT: 25px">
<LI style="LINE-HEIGHT: 25px"><FONT style="LINE-HEIGHT: 25px"
face=arial color=#3e80d7 size=2><B
style="LINE-HEIGHT: 25px"> 从现行的处理程序或线程中开启一个权杖 </B></FONT>您可以经由使用Processes及Threads清单方块中选择一个处理程序及附加的线程(假如您对开启一个模拟权杖有兴趣)。点选名称为OpenProcessToken或OpenThreadToken的按钮以抓取权杖。<BR
style="LINE-HEIGHT: 25px">
<LI style="LINE-HEIGHT: 25px"><FONT style="LINE-HEIGHT: 25px"
face=arial color=#3e80d7 size=2><B
style="LINE-HEIGHT: 25px"> 经由用使用者的凭证从系统撷取一个处理程序 </B></FONT>您可以输入一个使用者名称及密码,以及选择一个登入类型及提供者。TokenMaster使用LogonUser(在本章稍后讨论)从系统撷取权杖。<BR
style="LINE-HEIGHT: 25px">
<LI style="LINE-HEIGHT: 25px"><FONT style="LINE-HEIGHT: 25px"
face=arial color=#3e80d7 size=2><B
style="LINE-HEIGHT: 25px"> 复制一个现存的权杖 </B></FONT>假如您已经由TokenMaster中获得一个可使用的权杖,则您可以点选DuplicateTokenEx按钮来复制权杖。这个复制选项可让您设定模拟等级和新权杖的权杖类型。假如TokenMaster中有一个可被复制的权杖,则权杖资讯视窗将会显示权杖资讯。<BR
style="LINE-HEIGHT: 25px"> </LI></UL></FONT>
<P><FONT style="LINE-HEIGHT: 25px" face=arial color=#000000
size=2>在您取得一个权杖后,您将会在Token
Information视窗中看到权杖资讯清单。您可以经由使用GetTokenInformation函数,以检视所有可取得的权杖资讯。</FONT></P>
<P><FONT style="LINE-HEIGHT: 25px" face=arial color=#000000
size=2>使用TokenMaster,您可以使用多种方法来修改及调整权杖:</FONT></P>
<UL style="LINE-HEIGHT: 25px"><FONT style="LINE-HEIGHT: 25px"
face=arial color=#000000 size=2>
<LI style="LINE-HEIGHT: 25px">调整权杖群组及权限,包括使个别项目启动或失效的能力。<BR
style="LINE-HEIGHT: 25px"> </FONT>
<LI style="LINE-HEIGHT: 25px"><FONT style="LINE-HEIGHT: 25px"
face=arial color=#000000
size=2>修改权杖的预设DACL。有关预设DACLs的更多资讯,请参阅 </FONT> <FONT
style="LINE-HEIGHT: 25px" face=arial color=#000000 size=2><A
style="LINE-HEIGHT: 25px"
href="http://e-msbooks.com/relaunch/XML/paser.asp?src=957-2085-84-0_210.xml#"
target=_new>第十章</A> 。<BR style="LINE-HEIGHT: 25px">
<LI style="LINE-HEIGHT: 25px">建立一个受限的权杖。<BR
style="LINE-HEIGHT: 25px">
<LI
style="LINE-HEIGHT: 25px">使用权杖来启动可执行档。这是TokenMaster的一个特别有用的特色。您可以经由使用TokenMaster修改过的权杖建立一个新的处理程序。这可让您改变权杖或者以某些方法限制它,然后再启动程序代码,看看程序如何受影响。<BR
style="LINE-HEIGHT: 25px"> </FONT></LI></UL>
<P><FONT style="LINE-HEIGHT: 25px" face=arial color=#000000
size=2>强烈地建议您花些时间使用TokenMaster范例应用程序,熟悉有关Windows使用者环境的特色。</FONT></P>
<P><FONT style="LINE-HEIGHT: 25px" face=arial color=#000000
size=2>您也将发现TokenMaster可以被用来减轻侦错的处理程序。例如,我常常从本机帐户处理程序中启动应用程序以及「窃取」权杖。然后再使用这个权杖执行Microsoft
Visual
Studio开发环境,就可以从本机使用者帐户编译及测试程序代码。就安全性而论,在一个服务中执行类似的测试程序代码时,应使用本机帐户权杖。</FONT></P>
<P><FONT style="LINE-HEIGHT: 25px" face=arial color=#000000
size=2>这个范例应用程序的原始程序代码中示范了一些有用的程序设计策略。首先,它几乎呼叫了本章所涵盖的每个系统函数。如果您对Windows的安全性程序设计没有经验,它也提供一些对您可能有帮助的秘诀。</FONT></P>
<P><FONT style="LINE-HEIGHT: 25px" face=arial color=#000000
size=2>Windows安全性函数时常需要配置及较小缓冲器的重新配置。这个要求时常被开发人员视为麻烦,包括我自己。结果,就会很想固定缓冲器的大小,或作些能导致程序代码不密闭的其他让步。TokenMaster范例应用程序经由利用一个简单的范本类别,即CAutoBuf,提出这个要求。此时您将会看到这个类别大大地简化了程序代码的部份,在那里,系统函数可以要求可变大小的缓冲器。</FONT></P><A
style="LINE-HEIGHT: 25px" name=211003>
<P><FONT style="LINE-HEIGHT: 25px" face=arial color=#3e70d7
size=5><B style="LINE-HEIGHT: 25px">修改权杖资讯<BR
style="LINE-HEIGHT: 25px"> </B></FONT></P>
<P><FONT style="LINE-HEIGHT: 25px" face=arial color=#000000
size=2>大部分的权杖资讯是固定的。例如,您不能设定一位权杖使用者的SID与它所拥有的不同,您也不能增加群组SIDs或权限给权杖。而您可以做的修改属于两类:</FONT></P><FONT
style="LINE-HEIGHT: 25px" face=arial color=#000000 size=2>
<UL style="LINE-HEIGHT: 25px">
<LI style="LINE-HEIGHT: 25px">可以被调整 的资讯<BR
style="LINE-HEIGHT: 25px">
<LI style="LINE-HEIGHT: 25px">可以被设定 的资讯<BR
style="LINE-HEIGHT: 25px"> </LI></UL></FONT>
<HR style="LINE-HEIGHT: 25px">
<P><FONT style="LINE-HEIGHT: 25px" face=Arial color=#3e77d7 size=3
Black><B style="LINE-HEIGHT: 25px">说明</B></FONT> </P>
<P><FONT style="LINE-HEIGHT: 25px" face=arial color=#000000
size=2>尽管已经存在的权杖可改变的部份很少,但是以现存的权杖为基础而产生一个增加限制的新权杖是可能的。这种技巧被称为建立一个受限的权杖,在本章稍后有详细的讨论。</FONT></P>
<HR style="LINE-HEIGHT: 25px">
<P><FONT style="LINE-HEIGHT: 25px" face=arial color=#000000
size=2>设定资讯的处理程序,让它以您能想像的的方法运作。您可以建立一个结构并把它及权杖的handle传递到系统函数中,然后由系统设定权杖中的资讯。</FONT></P>
<P><FONT style="LINE-HEIGHT: 25px" face=arial color=#000000
size=2>调整资讯与设定资讯的运作有点不同。权杖中的权限及群组都可以有两种状态:即启用及停用。例如,虽然您不能在权杖中「设定」权限清单,但是您可以使已经存在于清单的个别权限启用及停用。</FONT></P>
<P><FONT style="LINE-HEIGHT: 25px" face=arial color=#000000
size=2>我们最常对权杖做的修改是设定权杖预设的DACL(为了预设的安全性而使用,在前面章节中有描述过),以及调整权杖的权限。您会发现设定权杖之预设拥有者及调整群组的处理程序,分别与设定预设DACL及调整权杖的权限非常类似。</FONT></P></A><A
style="LINE-HEIGHT: 25px" name=605_1></A>
<P><FONT style="LINE-HEIGHT: 25px" face=arial color=#3e72d7
size=4><B style="LINE-HEIGHT: 25px">调整权杖的权限<BR
style="LINE-HEIGHT: 25px"> </B></FONT></P>
<P><FONT style="LINE-HEIGHT: 25px" face=arial color=#000000
size=2>在讨论如何调整权杖的权限前,让我们扼要地重述在第九章已经学习过的权限部份,然后再慢慢扩大范围:</FONT></P><FONT
style="LINE-HEIGHT: 25px" face=arial color=#000000 size=2>
<UL style="LINE-HEIGHT: 25px">
<LI style="LINE-HEIGHT: 25px">权限被分派到信任成员中(使用者及群组)。<BR
style="LINE-HEIGHT: 25px">
<LI style="LINE-HEIGHT: 25px">当使用者登入系统时,使用者的权限会被复制到使用者的权杖中。<BR
style="LINE-HEIGHT: 25px">
<LI style="LINE-HEIGHT: 25px">权限被显示的名称、程序名称及LUID识别。<BR
style="LINE-HEIGHT: 25px"> </LI></UL></FONT>
<P><FONT style="LINE-HEIGHT: 25px" face=arial color=#000000
size=2>在您可以调整权杖的权限之前,必须知道如何从权限的程序名称中取得系统使用的LUID。这必须经由呼叫LookupPrivilegeValue函数来完成:</FONT></P>
<DIV style="LINE-HEIGHT: 25px; BACKGROUND-COLOR: #d7d7d7"><FONT
style="LINE-HEIGHT: 25px" face=Arial size=3><PRE style="LINE-HEIGHT: 25px">BOOL LookupPrivilegeValue( <BR> LPCTSTR lpSystemName, <BR> LPCTSTR lpName, <BR> PLUID lpLuid);</PRE></FONT></DIV>
<P><FONT style="LINE-HEIGHT: 25px" face=arial color=#000000
size=2>您应该传递一个字串给lpSystemName参数,这个字串代表您想要收到LUID的系统名称。传递NULL以指出本地端机器。lpName参数则指出系统权限的程序名称,您应该传递出自《Platform
SDK》的#define(例如,SE_TCB_NAME或SE_DEBUG_NAME)。您必须传递一个指向LUID类型变数的指标给lpLuid参数,系统将会为要求的权限填入LUID。</FONT></P>
<P><FONT style="LINE-HEIGHT: 25px" face=arial color=#000000
size=2>现在我们需要探索权限如何从安全性资料库取得我们的权杖。您必须了解权杖中找到的权限,是授予使用者帐户的权限和授予使用者为成员之每个群组权限的混合。</FONT></P>
<P><FONT style="LINE-HEIGHT: 25px" face=arial color=#000000
size=2>一旦系统建立权杖后,权杖中的权限就被会固定-意即它们不能被增加或移除。假如我们可以增加一个权限到权杖中,Windows
2000的安全性将被大大地破坏。然而,权限维持一个指出它们是否为启用或停用的状态。</FONT></P>
<P><FONT style="LINE-HEIGHT: 25px" face=arial color=#000000
size=2>当系统呼叫PrivilegeCheck时,假如被要求的权限是无效的,这个函数将会执行失败。为了使问题复杂化,有些系统在试图呼叫PrivilegeCheck前,会自动地呼叫您权杖的启用权限。在这些实例中,保持权限就可以使函数执行成功。</FONT></P>
<P><FONT style="LINE-HEIGHT: 25px" face=arial color=#000000
size=2>为了要了解哪个函数要求一个启用的权限,您必须阅读文件并偶尔从事一些试验及尝试错误行为。</FONT></P>
<P><FONT style="LINE-HEIGHT: 25px" face=arial color=#000000
size=2>在呼叫安全函数之前,您必需调整权杖的权限,让它成为启用或停用必要的权限。这可经由呼叫AdjustTokenPrivileges完成:</FONT></P>
<DIV style="LINE-HEIGHT: 25px; BACKGROUND-COLOR: #d7d7d7"><FONT
style="LINE-HEIGHT: 25px" face=Arial size=3><PRE style="LINE-HEIGHT: 25px">BOOL AdjustTokenPrivileges( <BR> HANDLE hTokenHandle, <BR> BOOL fDisableAllPrivileges, <BR> PTOKEN_PRIVILEGES pNewState, <BR> DWORD dwBufferLength, <BR> PTOKEN_PRIVILEGES pPreviousState, <BR> PDWORD pdwReturnLength);</PRE></FONT></DIV>
<P><FONT style="LINE-HEIGHT: 25px" face=arial color=#000000
size=2>第一个参数为hTokenHandle,指出您想要修改权限状态的权杖。fDisableAllPrivileges参数为TRUE时,会导致所有在权杖中的权限都被停用,不理会传递进pNewState参数的任何东西。在这种情形下,您应该传递NULL给pNewState。当您只启用或停用授予权杖的子权限时,您通常会使用pNewState参数。pNewState参数是一个指向TOKEN_PRIVILEGES结构的指标,以下是它的函数定义:</FONT></P>
<DIV style="LINE-HEIGHT: 25px; BACKGROUND-COLOR: #d7d7d7"><FONT
style="LINE-HEIGHT: 25px" face=Arial size=3><PRE style="LINE-HEIGHT: 25px">typedef struct _TOKEN_PRIVILEGES { <BR> DWORD PrivilegeCount; <BR> LUID_AND_ATTRIBUTES Privileges [ANYSIZE_ARRAY ]; <BR>}TOKEN_PRIVILEGES;</PRE></FONT></DIV>
<P><FONT style="LINE-HEIGHT: 25px" face=arial color=#000000
size=2>请注意,权限是一个LUID_AND_ATTRIBUTES结构的可变大小阵列。您想要在权杖中调整的每个权限结构皆应该在阵列中,而且PrivilegeCount
成员应该反映出权限的数量。以下是LUID_AND_ATTRIBUTES结构的定义:</FONT></P>
<DIV style="LINE-HEIGHT: 25px; BACKGROUND-COLOR: #d7d7d7"><FONT
style="LINE-HEIGHT: 25px" face=Arial size=3><PRE style="LINE-HEIGHT: 25px">typedef struct _LUID_AND_ATTRIBUTES { <BR> LUID Luid; <BR> DWORD Attributes; <BR>}LUID_AND_ATTRIBUTES;</PRE></FONT></DIV>
<P><FONT style="LINE-HEIGHT: 25px" face=arial color=#000000
size=2>阵列中每个结构的Luid成员应该被设定为考虑之权限LUID。最后,<FONT
style="LINE-HEIGHT: 25px" face=arial color=#3e80d7 size=2><B
style="LINE-HEIGHT: 25px"> 属性 </B></FONT>成员应该被设定为0,用来停用权限,或被设定为SE_PRIVILEGE_ENABLED,用来启用权限。</FONT></P>
<P><FONT style="LINE-HEIGHT: 25px" face=arial color=#000000
size=2>AdjustTokenPrivileges函数的dwBufferLength参数指出经由pPreviousState指向缓冲器以位元组计算的长度,它会指向一个接收权限之先前状态的缓冲器。假如不需要先前的状态资讯,可以传递NULL给pPreviousState。如果需要先前的状态资讯,就必须提供一个充分大小的缓冲器。一个指向需要大小的指标会被传回到pdwReturnLength参数中。经由pPreviousState指向的缓冲器与TOKEN_PRIVILEGES结构与您为pNewState参数建立的嵌入阵列一样被建立。</FONT></P>
<P><FONT style="LINE-HEIGHT: 25px" face=arial color=#000000
size=2>如您所见,启用及停用个别权限是很重要的工作。然而,您将发现它也是很常见的工作。我常认为Windows的开发人员应该提供一个shorthand函数,就像以下的EnablePrivilege函数,定义了某些重要的事,并提供容易的权杖权限存取。</FONT></P>
<DIV style="LINE-HEIGHT: 25px; BACKGROUND-COLOR: #d7d7d7"><FONT
style="LINE-HEIGHT: 25px" face=Arial size=3><PRE style="LINE-HEIGHT: 25px">BOOL EnablePrivilege( <BR> HANDLE hToken, <BR> PTSTR szPriv, <BR> BOOL fEnabled);</PRE></FONT></DIV>
<P><FONT style="LINE-HEIGHT: 25px" face=arial color=#000000
size=2>szPriv参数是个字串,表示启用及停用权限的程序名称,fEnabled参数简单地指出是否启用及停用权限。TokenMaster范例应用程序中实作了这样的函数,如下所示。</FONT></P>
<DIV style="LINE-HEIGHT: 25px; BACKGROUND-COLOR: #d7d7d7"><FONT
style="LINE-HEIGHT: 25px" face=Arial size=3><PRE style="LINE-HEIGHT: 25px">BOOL EnablePrivilege(HANDLE hToken,LPTSTR szPriv,BOOL bEnabled) <BR>{ <BR> TOKEN_PRIVILEGES tp; <BR> LUID luid; <BR> BOOL bRet =FALSE ; <BR> __try{ <BR> //首先查询系统唯一的权限LUID <BR> if(!LookupPrivilegeValue(NULL,szPriv /*SE_DEBUG_NAME*/,&luid)) <BR> { <BR> //假如名称是膺造的... <BR> __leave ; <BR> } <BR> //建立我们的权杖权限「阵列」(我们的实例是一个阵列) <BR> tp.PrivilegeCount =1; <BR> tp.Privileges [0 ].Luid =luid; <BR> tp.Privileges [0 ].Attributes =bEnabled?SE_PRIVILEGE_ENABLED:0; <BR> //经由启用及停用这一个权限,调整我们的权杖权限 <BR> if(!AdjustTokenPrivileges( <BR> hToken, <BR> FALSE, <BR> &tp, <BR> sizeof(TOKEN_PRIVILEGES), <BR> NULL, <BR> NULL )) <BR> { <BR> __leave ; <BR> } <BR> bRet =TRUE ; <BR> }__finally{} <BR> return(bRet); <BR>}</PRE></FONT></DIV>
<HR style="LINE-HEIGHT: 25px">
<P><FONT style="LINE-HEIGHT: 25px" face=Arial color=#3e77d7 size=3
Black><B style="LINE-HEIGHT: 25px">说明</B></FONT> </P>
<P><FONT style="LINE-HEIGHT: 25px" face=arial color=#000000
size=2>系统已经实作了另一个名称为AdjustTokenGroups的函数,除了可让权杖群组的启用及停用取代权限外,它的呼叫惯例与AdjustTokenPrivileges非常类似。然而,权杖群组的启用及停用并不常用。TokenMaster范例应用程序展示了一个AdjustTokenGroups的例子。</FONT></P>
<HR style="LINE-HEIGHT: 25px">
<P><FONT style="LINE-HEIGHT: 25px" face=arial color=#3e72d7
size=4><B style="LINE-HEIGHT: 25px">设定预设的DACL<BR
style="LINE-HEIGHT: 25px"> </B></FONT></P>
<P><FONT style="LINE-HEIGHT: 25px" face=arial color=#000000
size=2>较少见的设定权杖预设DACL工作,比调整权杖的权限简单。权杖的预设DACL定义了以预设安全性建立安全物件的安全性存取。安全物件包括建构如文件、Mutexes(互斥)及线程的部份。安全物件通常会经由传递NULL以作为建立函数的LPSECURITY_ATTRIBUTES参数,并以预设安全性建立(有关这个主题的更多资讯,请参阅 </FONT><FONT
style="LINE-HEIGHT: 25px" face=arial color=#000000 size=2><A
style="LINE-HEIGHT: 25px"
href="http://e-msbooks.com/relaunch/XML/paser.asp?src=957-2085-84-0_210.xml#"
target=_new>第十章</A> 的内容)。藉由移除应用于程序代码之安全性所建立的每个物件之必要性来修改预设的DACL,可以大大地简化伺服端的程序代码。</FONT></P>
<P><FONT style="LINE-HEIGHT: 25px" face=arial color=#000000
size=2>经由使用SetTokenInformation函数,您可以设定权杖的预设DACL和它的预设拥有者,以及主要的群组(它们都不应该混淆权杖使用者的身分识别,并且不能被改变):</FONT></P>
<DIV style="LINE-HEIGHT: 25px; BACKGROUND-COLOR: #d7d7d7"><FONT
style="LINE-HEIGHT: 25px" face=Arial size=3><PRE style="LINE-HEIGHT: 25px">BOOL SetTokenInformation( <BR> HANDLE hTokenHandle, <BR> TOKEN_INFORMATION_CLASS TokenInformationClass, <BR> PVOID pTokenInformation, <BR> DWORD dwTokenInformationLength);</PRE></FONT></DIV>
<P><FONT style="LINE-HEIGHT: 25px" face=arial color=#000000
size=2>hTokenHandle参数是您要修改的权杖handle。TokenInformatonClass被用来指出您想改变的权杖部分。
前面已经讨论过您可选择的部分,在〈读取权杖资讯〉一节中所列的项目符号清单中。</FONT></P>
<P><FONT style="LINE-HEIGHT: 25px" face=arial color=#000000
size=2>SetTokenInformation的dwTokenInformationLength参数指出由pTokenInformation指向的缓冲器长度。有关作用中的SetTokenInformation完整范例,请参阅 <A
style="LINE-HEIGHT: 25px"
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -