大家好,又见面了,我是你们的朋友全栈君。
文章目录- OpenProcessToken
- 函数功能
- 函数申明
- 第一个参数
- 第二个参数
- 第三个参数
- 返回值
- 补充:
- LookupPrivilegeValue
- 函数功能
- 函数声明
- 第一个参数
- 第二个参数
- 第三个参数
- 返回值
- AdjustTokenPrivilege
- 函数功能
- 函数声明
- 第一个参数
- 第二个参数
- 第三个参数
- 第四个参数
- 第五个参数:
- 第六个参数:
- 返回值
- 备注
- 代码实现:(利用AdjustTokenPrivileges提升权限(准确的说不是提升,而是将访问令牌中禁用的权限启用),)
提升程序的特权,要用到三个函数:
OpenProcessToken
,
AdjustTokenPrivileges
,
LookupPrivilegeValue
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