OpenProcessToken LookupPrivilegeValue 和AdjustTokenPrivilege[通俗易懂]

2022-09-12 20:01:59 浏览数 (2)

大家好,又见面了,我是你们的朋友全栈君。

文章目录
  • OpenProcessToken
  • 函数功能
  • 函数申明
  • 第一个参数
  • 第二个参数
  • 第三个参数
  • 返回值
  • 补充:
  • LookupPrivilegeValue
  • 函数功能
  • 函数声明
  • 第一个参数
  • 第二个参数
  • 第三个参数
  • 返回值
  • AdjustTokenPrivilege
  • 函数功能
  • 函数声明
  • 第一个参数
  • 第二个参数
  • 第三个参数
  • 第四个参数
  • 第五个参数:
  • 第六个参数:
  • 返回值
  • 备注
  • 代码实现:(利用AdjustTokenPrivileges提升权限(准确的说不是提升,而是将访问令牌中禁用的权限启用),)

提升程序的特权,要用到三个函数: OpenProcessTokenAdjustTokenPrivilegesLookupPrivilegeValue

OpenProcessToken

函数功能

用来打开与进程相关联的访问令牌

函数申明

代码语言:javascript复制
WINADVAPI
BOOL
WINAPI
OpenProcessToken(
    _In_ HANDLE ProcessHandle,
    _In_ DWORD DesiredAccess,
    _Outptr_ PHANDLE TokenHandle
    );

第一个参数

ProcessHandle [in],输入参数,要打开的访问令牌所属的进程句柄,查询进程必须拥有PROCESS_QUERY_INFORMATION访问权限。

第二个参数

DesiredAccess [in] 输入参数, 提供一个访问掩码,该掩码用来指定将要从访问令牌中查询的访问请求类型。这个访问请求类型将会与Discretionary Access Control List(DACL) 中的令牌相比较,以确定哪些访问权将被允许或拒绝。

有关访问令牌的访问权限列表,请参见访问令牌对象的访问权限*。

第三个参数

TokenHandle [out] 输出参数, 一个指向句柄数据类型的指针。该指针标识出函数返回时最新打开的访问令牌

返回值

如果函数执行成功,返回非零值;

如果函数执行失败,返回值为零。如果要得到附加的错误信息,请调用GetLastError函数。

补充:

如果要关闭打开的访问令牌句柄(该句柄通过TokenHandle参数返回),请调用CloseHandle函数。

第一个参数 进程句柄(当前进程为GetCurrentProcess()为参数) 第二个参数 访问令牌特权 第三个参数 返回的参数 就是AdjustTokenPrivileges的第一个参数 注:第二个参数 是令牌的权限,这个权限是要有修改权限的特权,意思就是要把你程序的权限修改得更高。所有权限可以写TOKEN_ALL_ACCESS ,去查看一个令牌特权可以用TOKEN_QUERY

LookupPrivilegeValue

函数功能

函数查看系统权限的特权值,返回信息到一个LUID结构体里。

函数声明

代码语言:javascript复制
WINADVAPI
BOOL
WINAPI
LookupPrivilegeValue(
    _In_opt_ LPCSTR lpSystemName,
    _In_     LPCSTR lpName,
    _Out_    PLUID   lpLuid
    );

第一个参数

输入参数,表示所要查看的系统,本地系统直接用NULL

第二个参数

输入参数,向一个以零结尾的字符串,指定特权的名称,如在WinNT h头文件定义。例如,此参数可指定常数,se_security_name,或其对应的字符串,“sesecurityprivilege “;。

第三个参数

输出参数,用来接收所返回的制定特权名称的信息,函数调用成功后,信息存入第三个类型为LUID的结构体中,并且函数返回非0。

返回值

函数调用成功后,信息存入第三个类型为LUID的结构体中,并且函数返回非0。

第一个参数是系统的名字,如果为NULL,就是本地名字(这里就填NULL)

第二个参数是特权的名字,要查看详细特权,看我的博客里翻译分类里的 包含特权 的文章。(在这里写SE_DEBUG_NAME)

第三个参数就可以通过指针返回一个LUID类型的Luid的标识了。 通过这个值就可以填入刚才的结构体里了。

AdjustTokenPrivilege

函数功能

这个函数启用或禁止 指定访问令牌的特权。启用或禁用特权一个有TOKEN_ADJUST_PRIVILEGES访问的访问令牌.

函数声明

代码语言:javascript复制
BOOL AdjustTokenPrivileges(  
HANDLE TokenHandle, //包含特权的句柄 
BOOL DisableAllPrivileges,  //禁用所有权限标志  
PTOKEN_PRIVILEGES NewState,  //新特权信息的指针(结构体) 
DWORD BufferLength, //大小,以字节为单位的PreviousState的缓存区(sizeof)  
PTOKEN_PRIVILEGES PreviousState,  //接收被改变特权当前状态的Buffer  
PDWORD ReturnLength //接收PreviousState缓存区要求的大小  );

第一个参数

TokenHandle包含要修改特权的访问令牌的标识(句柄).这个句柄必须有TOKEN_ADJUST_PRIVILEGES访问令牌.如果PreviousState不是NULL,这个句柄还必须有TOKEN_QUERY访问特权.

第二个参数

DisableAllPrivileges  标志这个函数是否禁用该令牌的所有特权.如果为TRUE,这个函数禁用所有特权,NewState参数无效.如果为假,以NewState参数指针的信息为基础来修改特权.

第三个参数

NewState 一个TOKEN_PRIVILEGES结构体的指针指定了一组特权和他们的属性.   如果参数DisableAllPrivileges为FALSE,AdjustTokenPrivileges 启用或禁用这些令牌的特权.   如果你给一个特权设置了SE_PRIVILEGE_ENABLED的属性,这个函数将启动特权,否则禁用特权.  如果DisableAllPrivileges为TRUE,这个参数无效.

代码语言:javascript复制
typedef struct _TOKEN_PRIVILEGES 
{ 
    
       DWORD PrivilegeCount;  
       LUID_AND_ATTRIBUTES Privileges[ANYSIZE_ARRAY]; 
}TOKEN_PRIVILEGES;

下面的参数是个特权数组。上面的参数是要修改的特权数目LUID_AND_ATTRIBUTES 结构体

代码语言:javascript复制
typedef struct _LUID_AND_ATTRIBUTES  
{ 
      
       LUID Luid;   
       DWORD Attributes; 
} LUID_AND_ATTRIBUTES;

第一个参数是Luid是一个标志,不同的Luid代表着各种不同的特权类型

第二个参数是要这个特权干嘛,如启用这个特权(SE_PRIVILEGE_ENABLED),这里的Luid的值需要用LookupPrivilegeValue来获取。

第四个参数

BufferLength 标志参数PreviousState指针以字节大小缓存区(sizeof).   如果参数PreviousState是NULL,这个参数可以为NULL.

第五个参数:

PreviousState这个函数填充一个TOKEN_PRIVILEGES结构体【指针】,它包括该函数修改之前任何特权状态.这个参数可以为NULL.  如果指定的缓冲区太小,无法收到完整的修改权限列表,这个函数失败并不会修改任何特权.  这个函数设置了一个 拥有修改权限完成列表【 参数ReturnLength 】的字节数 的指针变量.[结果的Buffer]

第六个参数:

ReturnLength 接收 参数PreviousState的缓存区指针的 字节大小 的 变量指针(长度指针).  如果PreviousState为NULL,这个参数可以为NULL.

返回值

如果这个函数成功,返回非0.为了确定这个函数是否修改了所有指定的特权,可以调用GetLastError函数,当这个函数返回下面的值之一时就代表函数成功:

描述

ERROR_SUCCESS

这个函数修改了所有指定的特权.

ERROR_NOT_ALL_ASSIGNED

这个令牌没有参数NewState里指定一个或多个的权限.(一个或多个没有修改成功).  即使权限没有被修改.这个函数也可能成功(返回这个error值)  表明 参数PreviousState 被修改.

第一个参数为OpenProcessToken第三个指针参数传出的句柄值

第二个参数为是否禁用所有所有的特权(这里填false)

第三个参数为新的TOKEN_PRIVILEGES的特权结构体指针

第四个参数是上面结构体的字节长度(sizeof)

第五个参数是 接受原先的特权的结构体

第六个参数也是这个结构体的字节长度的指针

如果第五个参数不是NULL,在OpenProcessToken加特权时除了需要指定TOKEN_ADJUST_PRIVILEGES还必须指定TOKEN_QUERY

如果第五个参数是NULL,你不接受原先的结构体(第六个当然也是NULL), 就不用再指定附加的TOKEN_QUERY的特权了。

还要注意:就算这个函数返回为真,还要调用GetLastError()来检验是否完全成功。如果返回ERROR_SUCCESS就代表修改非常成功 。还有就是Vista和Window7 里 一定要开管理员模式 才能获取成功

备注

AdjustTokenPrivileges函数不能添加新的特权到访问令牌.它只能启用或禁用令牌现行的令牌.要想确定这个令牌的特权,调用GetTokenInformation函数.   请注意,参数NewState可以不给令牌指定权限,这不会导致函数失败.  在这种情况下,这个函数修改令牌现有的特权,其他特权无效,并成功返回.   调用GetLastError函数,以确定这个函数修改了所有指定的特权.  PreviousState参数表明特权被修改.  参数PreviousState 返回一个 包含 修改权限 原始状态的结构体 TOKEN_PRIVILEGES,  这样就可以在随后调用AdjustTokenPrivileges函数时,传递PreviousState指针到 参数NewState ,来恢复原来的状态.

代码实现:(利用AdjustTokenPrivileges提升权限(准确的说不是提升,而是将访问令牌中禁用的权限启用),)

代码语言:javascript复制
BOOL SetPrivilege(
				  HANDLE hToken,          // access token handle
				  LPCTSTR lpszPrivilege,  // name of privilege to enable/disable
				  BOOL bEnablePrivilege   // to enable or disable privilege
				  ) 
{ 
   
	TOKEN_PRIVILEGES tp;
	LUID luid;
 
	if ( !LookupPrivilegeValue( 
		NULL,            // lookup privilege on local system
		lpszPrivilege,   // privilege to lookup 
		&luid ) )        // receives LUID of privilege
	{ 
   
		printf("LookupPrivilegeValue error: %un", GetLastError() ); 
		return FALSE; 
	}
 
	tp.PrivilegeCount = 1;
	tp.Privileges[0].Luid = luid;
	if (bEnablePrivilege)
		tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
	else
		tp.Privileges[0].Attributes = 0;
 
	// Enable the privilege or disable all privileges.
 
	if ( !AdjustTokenPrivileges(
		hToken, 
		FALSE, 
		&tp, 
		sizeof(TOKEN_PRIVILEGES), 
		(PTOKEN_PRIVILEGES) NULL, 
		(PDWORD) NULL) )
	{ 
    
		printf("AdjustTokenPrivileges error: %un", GetLastError() ); 
		return FALSE; 
	} 
 
	if (GetLastError() == ERROR_NOT_ALL_ASSIGNED)
 
	{ 
   
		printf("The token does not have the specified privilege. n");
		return FALSE;
	} 
 
	return TRUE;
}
 
void main( )
{ 
   
 
	HANDLE hToken;
	BOOL bRet = OpenProcessToken(GetCurrentProcess(),TOKEN_ALL_ACCESS,&hToken);
	SetPrivilege(hToken,SE_DEBUG_NAME,TRUE);
}

发布者:全栈程序员栈长,转载请注明出处:https://javaforall.cn/152917.html原文链接:https://javaforall.cn

0 人点赞