Windows核心编程_提权

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/bjbz_cxy/article/details/82254183

在Windows下编程有些涉及到硬件或者跨内存的API会发现失效了,原因是因为权限问题,这也是Windows出于安全的保护,但是事物都有两面性的,Windows又为我们提供了提权的API!

1.AdjustTokenPrivileges方式为用户创建一个令牌权限并提权

步骤:

1.打开进程权限获得对此进程访问的权限OpenProcessToken

2.查看系统权限内容LookupPrivilegeValue

3.根据权限内容对其进行提权AdjustTokenPrivileges

函数介绍:

OpenProcessToken

 

作用:得到指定进程上的令牌地址

BOOL OpenProcessToken(
__in HANDLE ProcessHandle, //要修改访问权限的进程句柄
__in DWORD DesiredAccess, //指定你要进行的操作类型,进行AdjustTokenPrivileges提权必须使用TOKEN_ADJUST_PRIVILEGES方式来提权
__out PHANDLE TokenHandle //返回的访问令牌指针
);
LookupPrivilegeValue

作用:查看系统上所允许的令牌权限

BOOL LookupPrivilegeValue(LPCTSTR lpSystemName,LPCTSTR lpName,PLUID lpLuid);
第一个参数表示所要查看的系统,本地系统直接用NULL
第二个参数指向一个以零结尾的字符串,指定特权的名称,如在WinNT h头文件定义。例如,此参数可指定常数,se_security_name,或其对应的字符串,“sesecurityprivilege "。
第三个参数用来接收所返回的制定特权名称的信息。
函数调用成功后,信息存入第三个类型为LUID的结构体中,并且函数返回非0。
LUID结构体介绍:
		TOKEN_PRIVILEGES contains information about a set of privileges for an access token.
		typedef struct _TOKEN_PRIVILEGES
		{
		ULONG PrivilegeCount; //数组元素的个数
		LUID_AND_ATTRIBUTES Privileges[ANYSIZE_ARRAY]; //数组.类型为LUID_AND_ATTRIBUTES
		} TOKEN_PRIVILEGES, *PTOKEN_PRIVILEGES;
PrivilegeCount
指定 特权数组的个数(因为下一个参数是一个数组)
Privileges
一个LUID_AND_ATTRIBUTES结构体. 每个结构体包括LUID和特权的属性. 特权的属性可以是下列值的组合:
属性	描述
SE_PRIVILEGE_ENABLED_BY_DEFAULT	特权默认启用
SE_PRIVILEGE_ENABLED	特权启用.
SE_PRIVILEGE_USED_FOR_ACCESS	特权被用来访问一个对象或服务。
	这个标志 被用于 标识有关特权,因为
	通过一组客户端应用程序,可能包含不必要的特权



AdjustTokenPrivileges

AdjustTokenPrivileges这个函数启用或禁止 指定访问令牌的特权。

启用或禁用特权一个有TOKEN_ADJUST_PRIVILEGES访问的访问令牌.

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,这个参数无效.

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 被修改。

如果这个函数失败,返回0.要得到更多的错误信息,调用GetLastError.

备注

AdjustTokenPrivileges函数不能添加新的特权到访问令牌.它只能启用或禁用令牌现行的令牌.要想确定这个令牌的特权,调用GetTokenInformation函数.

请注意,参数NewState可以不给令牌指定权限,这不会导致函数失败.

在这种情况下,这个函数修改令牌现有的特权,其他特权无效,并成功返回.

调用GetLastError函数,以确定这个函数修改了所有指定的特权.

PreviousState参数表明特权被修改.

参数PreviousState 返回一个 包含 修改权限 原始状态的结构体 TOKEN_PRIVILEGES,

这样就可以在随后调用AdjustTokenPrivileges函数时,传递PreviousState指针到 参数NewState ,来恢复原来的状态.

最后关闭令牌对象即可

CloseHandleBOOL CloseHandle(HANDLE hObject);
参数
hObject :代表一个已打开对象handle。
返回值
TRUE:执行成功;
FALSE:执行失败,可以调用GetLastError()获知失败原因。

使用方法:

HANDLE hToken;	//令牌指针

	if (OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &hToken))	//ADJUST提权

	{

		TOKEN_PRIVILEGES tp;	//存储权限结构体

		tp.PrivilegeCount = 1;

		tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;	//要获取的权限类型

		if (LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &tp.Privileges[0].Luid))	//查看权限

		{

			AdjustTokenPrivileges(hToken, FALSE, &tp, sizeof(tp), NULL, NULL);	//提权

		}

		CloseHandle(hToken);	//关闭提权

	}

2.RtlAdjustPrivilege

此方法是MSDN没有公开的函数,相比上面的提权方法这个API更加直接,此函数存在于NsDll里

RtlAdjustPrivilege
	NTSTATUS RtlAdjustPrivilege(
	ULONG Privilege,
	BOOLEAN Enable,
	BOOLEAN CurrentThread,
	PBOOLEAN Enabled)

参数的含义:

	Privilege 
	// 所需要的权限名称
	msdn公开权限名,但没用给出具体作用,可以通过给出名来判别:
	SE_BACKUP_PRIVILEGE, "17"
	SE_RESTORE_PRIVILEGE, "18"
	SE_SHUTDOWN_PRIVILEGE, "19"
	SE_DEBUG_PRIVILEGE, "20"
	
	//需要自己手动声明出来#define
	
	
	Enable [In] If TRUE, then enable the privilege otherwise disable.
	// 如果为True 就是打开相应权限,如果为False 则是关闭相应权限
	CurrentThread [In] If TRUE, then enable in calling thread, otherwise process.
	// 如果为True 则仅提升当前线程权限,否则提升整个进程的权限
	Enabled [Out] Whether privilege was previously enabled or disabled.
	// 输出原来相应权限的状态(打开 | 关闭)

使用方法:

	const unsigned long SE_DEBUG_PRIVILEGE = 0x14;	//声明调试权限
	typedef int(__stdcall *fRtlAdjustPrivilege)(ULONG, BOOLEAN, BOOLEAN, PBOOLEAN);
	int main(int argc, char** argv) {
		
			HMODULE hNtDll = LoadLibrary("ntdll.dll");//得到dll句柄
	
			if (!hNtDll)
	
				return;
	
			fRtlAdjustPrivilege funcAdjustPrivilege =
	
				(fRtlAdjustPrivilege)GetProcAddress(hNtDll, "RtlAdjustPrivilege");	//获取API
	
			if (funcAdjustPrivilege)
	
			{
	
				BOOLEAN oldStatus;
	
				funcAdjustPrivilege(SE_DEBUG_PRIVILEGE, true, false, &oldStatus);	//调用API
	
			}
	
			FreeLibrary(hNtDll);	//释放dll
	}
	

 

 

 

 

 

 

 

猜你喜欢

转载自blog.csdn.net/bjbz_cxy/article/details/82254183