文章二:
GetCurrentProcessID 得到当前进程的ID OpenProcessToken 得到进程的令牌句柄LookupPrivilegeValue 查询进程的权限 AdjustTokenPrivileges 判断令牌权限
要对一个任意进程(包括系统安全进程和服务进程)进行指定了写相关的访问权的OpenProcess操作,只要当前进程具有SeDeDebug权限就可以了。要是一个用户是Administrator或是被给予了相应的权限,就可以具有该权限。可是,就算我们用Administrator帐号对一个系统安全进程执行OpenProcess(PROCESS_ALL_ACCESS,FALSE, dwProcessID)还是会遇到“访问拒绝”的错误。什么原因呢?原来在默认的情况下进程的一些访问权限是没有被使能(Enabled)的,所以我们要做的首先是使能这些权限。与此相关的一些API函数有OpenProcessToken、LookupPrivilegevalue、AdjustTokenPrivileges。我们要修改一个进程的访问令牌,首先要获得进程访问令牌的句柄,这可以通过OpenProcessToken得到,函数的原型如下:
BOOL OpenProcessToken(
HANDLE ProcessHandle,
DWORD DesiredAccess,
PHANDLE TokenHandle
);
第一参数是要修改访问权限的进程句柄;第三个参数就是返回的访问令牌指针;第二个参数指定你要进行的操作类型,如要修改令牌我们要指定第二个参数为TOKEN_ADJUST_PRIVILEGES(其它一些参数可参考Platform SDK)。通过这个函数我们就可以得到当前进程的访问令牌的句柄(指定函数的第一个参数为GetCurrentProcess()就可以了)。接着我们可以调用AdjustTokenPrivileges对这个访问令牌进行修改。AdjustTokenPrivileges的原型如下:
BOOL AdjustTokenPrivileges(
HANDLE TokenHandle, // handle to token
BOOL DisableAllPrivileges, // disabling option
PTOKEN_PRIVILEGES NewState, // privilege information
DWORD BufferLength, // size of buffer
PTOKEN_PRIVILEGES PreviousState, // original state buffer
PDWORD ReturnLength // required buffer size
);
第一个参数是访问令牌的句柄;第二个参数决定是进行权限修改还是除能(Disable)所有权限;第三个参数指明要修改的权限,是一个指向TOKEN_PRIVILEGES结构的指针,该结构包含一个数组,数据组的每个项指明了权限的类型和要进行的操作; 第四个参数是结构PreviousState的长度,如果PreviousState为空,该参数应为NULL;第五个参数也是一个指向TOKEN_PRIVILEGES结构的指针,存放修改前的访问权限的信息,可空;最后一个参数为实际PreviousState结构返回的大小。在使用这个函数前再看一下TOKEN_PRIVILEGES这个结构,其声明如下:
typedef struct _TOKEN_PRIVILEGES {
DWORD PrivilegeCount;
LUID_AND_ATTRIBUTES Privileges[];
} TOKEN_PRIVILEGES, *PTOKEN_PRIVILEGES;
PrivilegeCount指的数组原素的个数,接着是一个LUID_AND_ATTRIBUTES类型的数组,再来看一下LUID_AND_ATTRIBUTES这个结构的内容,声明如下:
typedef struct _LUID_AND_ATTRIBUTES {
LUID Luid;
DWORD Attributes;
} LUID_AND_ATTRIBUTES, *PLUID_AND_ATTRIBUTES
第二个参数就指明了我们要进行的操作类型,有三个可选项: SE_PRIVILEGE_ENABLED、SE_PRIVILEGE_ENABLED_BY_DEFAULT、SE_PRIVILEGE_USED_FOR_ACCESS。要使能一个权限就指定Attributes为SE_PRIVILEGE_ENABLED。第一个参数就是指权限的类型,是一个LUID的值,LUID就是指locally unique identifier,我想GUID大家是比较熟悉的,和GUID的要求保证全局唯一不同,LUID只要保证局部唯一,就是指在系统的每一次运行期间保证是唯一的就可以了。另外和GUID相同的一点,LUID也是一个64位的值,相信大家都看过GUID那一大串的值,我们要怎么样才能知道一个权限对应的LUID值是多少呢?这就要用到另外一个API函数LookupPrivilegevalue,其原形如下:
BOOL LookupPrivilegevalue(
LPCTSTR lpSystemName, // system name
LPCTSTR lpName, // privilege name
PLUID lpLuid // locally unique identifier
);
第一个参数是系统的名称,如果是本地系统只要指明为NULL就可以了,第三个参数就是返回LUID的指针,第二个参数就是指明了权限的名称,如“SeDebugPrivilege”。在Winnt.h中还定义了一些权限名称的宏,如:
#define SE_BACKUP_NAME TEXT("SeBackupPrivilege")
#define SE_RESTORE_NAME TEXT("SeRestorePrivilege")
#define SE_SHUTDOWN_NAME TEXT("SeShutdownPrivilege")
#define SE_DEBUG_NAME TEXT("SeDebugPrivilege")
这样通过这三个函数的调用,我们就可以用OpenProcess(PROCESS_ALL_ACCESS,FALSE, dwProcessID)来打获得任意进程的句柄,并且指定了所有的访问权。
==============================================================================
定时关机程序代码:
void CClosepcDlg::OnTimer(UINT nIDEvent)
{
// TODO: Add your message handler code here and/or call default
CTime t=CTime::GetCurrentTime();
int h=t.GetHour ();
int min=t.GetMinute ();
CString hh,mins;
hh.Format ("%d",h);
mins.Format ("%d",min);
CString str=t.Format("%H:%M:%S");
GetDlgItem(IDC_SHOW)->SetWindowText(str);
/////////////////准备关机//////////////////////
if(start && close_hour.CompareNoCase(hh)==0 && close_min.CompareNoCase(mins)==0)
{
KillTimer(1);
/////////首先声明3个全局变量///////////BOOL fResult;TOKEN_PRIVILEGES tkp;HANDLE hToken;
if (!OpenProcessToken(GetCurrentProcess(),TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken)) //得到进程的令牌句柄;
{
MessageBox("OpenProcessToken failed!");
}
LookupPrivilegeValue(NULL, SE_SHUTDOWN_NAME,&tkp.Privileges[0].Luid); //获得本地机唯一的标识,查询权限
tkp.PrivilegeCount = 1;
tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
AdjustTokenPrivileges(hToken, FALSE, &tkp, 0,(PTOKEN_PRIVILEGES) NULL, 0); //调整获得的权限
if (GetLastError() != ERROR_SUCCESS)
{
MessageBox("AdjustTokenPrivileges enable failed!");
}
fResult =InitiateSystemShutdown(
NULL, // 要关的计算机用户名
"你设置的自动关机时间以到,请保存好你的文件,系统马上就要关闭!", // 显示的消息
20, // 关机所需的时间
TRUE, // ask user to close apps
// TRUE); //设为TRUE为重起,设为FALSE为关机
FALSE);
if(!fResult)
{
MessageBox("InitiateSystemShutdown failed.");
}
tkp.Privileges[0].Attributes = 0;
AdjustTokenPrivileges(hToken, FALSE, &tkp, 0,(PTOKEN_PRIVILEGES) NULL, 0);
if (GetLastError() != ERROR_SUCCESS)
{
MessageBox("AdjustTokenPrivileges disable failed.");
}
ExitWindowsEx(EWX_SHUTDOWN,0);
}
CDialog::OnTimer(nIDEvent);
}
void CClosepcDlg::OnStar()
{
// TODO: Add your control notification handler code here
start=true;
ShowWindow(SW_HIDE);
//////////////////定义系统托盘//////////////////////////
m_nid.cbSize =sizeof(NOTIFYICONDATA);//设置结构大小
m_nid.hWnd =this->m_hWnd ;//设置图标对应的窗口
m_nid.uFlags =NIF_MESSAGE|NIF_ICON|NIF_TIP;//图标属性
m_nid.uCallbackMessage =MYWM_NOTIFYICON;//应用程序定义的回调消息ID
////////////设置NOTIFYICONDATA结构///////////
CString szToolTip;
szToolTip=_T("自动关机程序");
_tcscpy(m_nid.szTip ,szToolTip);//帮助信息
m_nid.uID =IDR_MAINFRAME;//应用程序图标
HICON hIcon;
hIcon=AfxGetApp()->LoadIcon (IDR_MAINFRAME);
m_nid.hIcon =hIcon;//图标句柄
// PNOTIFYICONDATA m_pnid=&m_nid;
::Shell_NotifyIcon (NIM_ADD,&m_nid);//增加图标到系统盘
if(hIcon)
::DestroyIcon (hIcon);
}
LRESULT CClosepcDlg::WindowProc(UINT message, WPARAM wParam, LPARAM lParam)
{
switch(message)
{
case MYWM_NOTIFYICON:
if(lParam==WM_LBUTTONDBLCLK)
{
AfxGetApp()->m_pMainWnd->ShowWindow(SW_SHOW);
}
else if(lParam==WM_RBUTTONDOWN)
{
CMenu menu;
menu.LoadMenu(IDR_MENU1);
CMenu *pMenu=menu.GetSubMenu(0);
CPoint pos;
GetCursorPos(&pos);
pMenu->TrackPopupMenu(TPM_LEFTALIGN|TPM_RIGHTBUTTON,pos.x,pos.y,AfxGetMainWnd());
}
break;
case WM_SYSCOMMAND:
if(wParam==SC_MINIMIZE)
{
//////////////////定义系统托盘//////////////////////////
m_nid.cbSize =sizeof(NOTIFYICONDATA);//设置结构大小
m_nid.hWnd =this->m_hWnd ;//设置图标对应的窗口
m_nid.uFlags =NIF_MESSAGE|NIF_ICON|NIF_TIP;//图标属性
m_nid.uCallbackMessage =MYWM_NOTIFYICON;//应用程序定义的回调消息ID
////////////设置NOTIFYICONDATA结构///////////
CString szToolTip;
szToolTip=_T("自动关机程序");
_tcscpy(m_nid.szTip ,szToolTip);//帮助信息
m_nid.uID =IDR_MAINFRAME;//应用程序图标
HICON hIcon;
hIcon=AfxGetApp()->LoadIcon (IDR_MAINFRAME);
m_nid.hIcon =hIcon;//图标句柄
// PNOTIFYICONDATA m_pnid=&m_nid;
::Shell_NotifyIcon (NIM_ADD,&m_nid);//增加图标到系统盘
if(hIcon)
::DestroyIcon (hIcon);
AfxGetApp()->m_pMainWnd->ShowWindow(SW_HIDE);
return 0;
}
break;
}
return CDialog::WindowProc(message, wParam, lParam);
}
void CClosepcDlg::OnQuit()
{
// TODO: Add your command handler code here
PostQuitMessage(0);
}
void CClosepcDlg::OnShow()
{
// TODO: Add your command handler code here
ShowWindow(1);
::Shell_NotifyIcon(NIM_DELETE,&m_nid);
}
void CClosepcDlg::OnStop()
{
// TODO: Add your command handler code here
start=false;
ShowWindow(1);
::Shell_NotifyIcon(NIM_DELETE,&m_nid);
}
void CClosepcDlg::OnSelchangeHour()
{
m_hour.GetWindowText(close_hour);
}
void CClosepcDlg::OnSelchangeMin()
{
m_min.GetWindowText (close_min);
}
文章三:
windows的每个用户登录系统后,系统会产生一个访问令牌(access token) ,其中关联了当前用户的权限信息,用户登录后创建的每一个进程都含有用户access token的拷贝,当进程试图执行某些需要特殊权限的操作或是访问受保护的内核对象时,系统会检查其acess token中的权限信息以决定是否授权操作。Administrator组成员的access token中会含有一些可以执行系统级操作的特权(privileges) ,如终止任意进程、关闭/重启系统、加载设备驱动和更改系统时间等,不过这些特权默认是被禁用的,当Administrator组成员创建的进程中包含一些需要特权的操作时,进程必须首先打开这些禁用的特权以提升自己的权限,否则系统将拒绝进程的操作。注意,非Administrator组成员创建的进程无法提升自身的权限,因此下面提到的进程均指Administrator组成员创建的进程。
Windows以字符串的形式表示系统特权,如“SeCreatePagefilePrivilege”表示该特权用于创建页面文件,“SeDebugPrivilege”表示该特权可用于调试及更改其它进程的内存,为了便于在代码中引用这些字符串,微软在winnt.h中定义了一组宏,如 #define SE_DEBUG_NAME TEXT("SeDebugPrivilege")。完整的特权列表可以查阅msdn的security一章。虽然Windows使用字符串表示特权,但查询或更改特权的API需要LUID来引用相应的特权,LUID表示local unique identifier,它是一个64位值,在当前系统中是唯一的。为了提升进程权限到指定的特权,我们必须先找到该特权对应的LUID,这时要调用LookupPrivilegeValue函数。
获得特权对应的LUID之后,我们要打开该特权。此时要用到LUID_AND_ATTRIBUTES结构,其定义如下:
typedef struct _LUID_AND_ATTRIBUTES { LUID Luid; DWORD Attributes; } LUID_AND_ATTRIBUTES, * PLUID_AND_ATTRIBUTES;
Attributes取SE_PRIVILEGE_ENABLED时将打开Luid对应的特权。设置完成后,我们需要调用AdjustTokenPrivileges函数通知操作系统将指定的access token权限中的特权置为打开状态,前面我们说过,进程执行需要特列权限的操作时系统将检查其access token,因此更改了进程的access token特权设置,也就是更改了所属进程的特权设置。AdjustTokenPrivileges函数的原型如下:
BOOL WINAPI AdjustTokenPrivileges( __in HANDLE TokenHandle, __in BOOL DisableAllPrivileges, __in_opt PTOKEN_PRIVILEGES NewState, __in DWORD BufferLength, __out_opt PTOKEN_PRIVILEGES PreviousState, __out_opt PDWORD ReturnLength );
TokenHandle是要更改特权设置的acess token的句柄,DisableAllPrivileges表示是否禁用该access token的所有特权,NewState用来传递要新的特权设置,注意它的类型是PTOKEN_PRIVILEGES,PTOKEN_PRIVILEGES是TOKEN_PRIVILEGES结构的指针,定义如下:
typedef struct _TOKEN_PRIVILEGES { DWORD PrivilegeCount; LUID_AND_ATTRIBUTES Privileges[ANYSIZE_ARRAY]; } TOKEN_PRIVILEGES, *PTOKEN_PRIVILEGES;
其中ANYSIZE_ARRAY被定义为1,可以看到TOKEN_PRIVILEGES中包含了用于设置特权信息的LUID_AND_ATTRIBUTES结构,在使用时,只需要将PrivilegeCount赋为1,然后把Privileges数组的第1个元素(Privileges[0])的Luid域设置为指定特权的Luid,再将其Attributes域设置为SE_PRIVILEGE_ENABLED,就可以完成TokenHandle表示的access token权限的提升了。
下面是一个实际的例子,用来将执行promoteProcessPrivilege的当前进程的指定特权打开,函数参数为指定的特权名,可以传递其宏定义,也可以是完整的字符串表示:
BOOL promoteProcessPrivileges(const TCHAR* newPrivileges) { HANDLE tokenHandle; //获得当前进程的access token句柄 if(::OpenProcessToken(::GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &tokenHandle) == FALSE) return FALSE; TOKEN_PRIVILEGES structTkp; //查找newPrivileges参数对应的Luid,并将结果写入structTkp.Privileges[0]的Luid域中 if(::LookupPrivilegeValue(NULL, newPrivileges, &structTkp.Privileges[0].Luid) == FALSE){ CloseHandle(tokenHandle); return FASLE; } //设置structTkp结构 structTkp.PrivilegeCount = 1; structTkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; //通知操作系统更改权限 if(::AdjustTokenPrivileges(tokenHandle, FALSE, &structTkp, sizeof(structTkp), NULL, NULL) == FALSE){ CloseHandle(tokenHandle); return FALSE; } CloseHandle(tokenHandle); return TRUE; }
我们来用一个简单的例子验证promoteProcessPrivileges函数。下面的traceSystemProcess用于遍历当前系统进程,如果调用traceSystemProcess函数的进程以默认权限运行,对于如csrss.exe之类的进程,函数将没有足够的权限获得其模块名。如果在traceSystemProcess之前调用了promoteProcessPrivileges将进程权限提升至SE_DEBUG_NAME级别,traceSystemProcess函数将能正确打印出如csrss.exe等关键进程的路径:
BOOL traceSystemProcess() { PROCESSENTRY32 processEntry; processEntry.dwSize = sizeof(processEntry); HANDLE hProcessSnap = ::CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS,0); if(hProcessSnap == INVALID_HANDLE_VALUE){ _tprintf(_T("CreateToolhelp32Snapshot 调用失败!/n")); return FALSE; } BOOL bMore = ::Process32First(hProcessSnap, &processEntry); while(bMore){ _tprintf(_T("进程名称:%s /n"), processEntry.szExeFile); _tprintf(_T("进程ID号:%u /n"), processEntry.th32ProcessID); HANDLE hProcess = ::OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, processEntry.th32ProcessID); if(hProcess != NULL){ TCHAR szBuffer[MAX_PATH] = {_T('/0')}; if(::GetModuleFileNameEx(hProcess, NULL, szBuffer, MAX_PATH)){ _tprintf(_T("进程路径:%s /n"), szBuffer); } ::CloseHandle(hProcess); } _tprintf(_T("/n")); bMore = ::Process32Next(hProcessSnap,&processEntry);
最近一直忙着写毕业论文,但对于我这种没语言天赋的人,写写实际做的工作还可以,但要写课题背景、意义什么的,头都要大了,憋了两天才憋出两页的绪论,我容易吗我。。。
所以这半个月也没时间更新博客,现在论文初稿终于写完了,所以来写点东西吧。
这还是要从我写的魔兽改键显血助手WarKey说起。之前的版本因为判断是否是聊天状态的功能不完善,于是我就按网上的说法,用CE(Cheat Engine,专门用于修改游戏内存的工具)搜索了一下魔兽进程的内存内容,找到存储是否处于聊天状态的内存地址。于是,在WarKey中,只需要取到该内存地址的内容,根据其内容来判断是否处于聊天状态,然后决定是否需要改键即可。但实际上,在调用API函数ReadProcessMemory()时,并不能取出其内容,也就是说无论魔兽是否处于聊天状态,ReadProcessMemory()总是调用失败。经查MSDN,发现该函数操作的句柄需要PROCESS_VM_READ访问权限,而这个是由OpenProcess()函数来处理的。OpenProcess()这个函数指定的访问权限的安全描述符比较复杂,但有一句话很给力:If the caller has enabled the SeDebugPrivilege privilege, the requested access is granted regardless of the contents of the security descriptor.也就是说如果调用者具有SeDebugPrivilege权限,那么就不用管什么安全描述符了。于是只需要给程序提升权限,使其具有SeDebugPrivilege权限即可。
关于提升权限的方法,在MSDN里面查了半天,居然找到了一个很给力的例子:
#include <windows.h>
#include <stdio.h>
#pragma comment(lib, "cmcfg32.lib")
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: %u\n", 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: %u\n", GetLastError() );
return FALSE;
}
if (GetLastError() == ERROR_NOT_ALL_ASSIGNED)
{
printf("The token does not have the specified privilege. \n");
return FALSE;
}
return TRUE;
}
这个例子应该是比较经典的,经过分析之后,于是写出开关Debug权限的函数:
BOOL CWarKeyDlg::EnableDebugPrivilege(BOOL bEnableDebugPrivilege)
{
HANDLE hToken;
TOKEN_PRIVILEGES tp;
LUID luid;
if(!::OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &hToken))
{
::MessageBox(this->GetSafeHwnd(), GET_TOKEN_ERROR, MSG_BOX_TITLE, MB_OK);
return FALSE;
}
if(!::LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &luid))
{
::MessageBox(this->GetSafeHwnd(), GET_PRIVILEGE_VALUE_ERROR, MSG_BOX_TITLE, MB_OK);
::CloseHandle(hToken);
return FALSE;
}
tp.PrivilegeCount = 1;
tp.Privileges[0].Luid = luid;
if(bEnableDebugPrivilege)
{
tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
}
else
{
tp.Privileges[0].Attributes = 0;
}
if(!::AdjustTokenPrivileges(hToken, FALSE, &tp, sizeof(tp), NULL, NULL))
{
::MessageBox(this->GetSafeHwnd(), ADJUST_PRIVILEGE_ERROR, MSG_BOX_TITLE, MB_OK);
::CloseHandle(hToken);
return FALSE;
}
::CloseHandle(hToken);
if(::GetLastError() == ERROR_NOT_ALL_ASSIGNED)
{
::MessageBox(this->GetSafeHwnd(), ENABLE_DEBUG_ERROR, MSG_BOX_TITLE, MB_OK);
return FALSE;
}
return TRUE;
}
使用过
1、进程相当于系统提供的一个平台,它可以包括一个或多个线程,如IE是个进程, 打开多个网页是它的多个线程,把IE进程Kill掉即可关闭多个打开网页的线程。 2、98和NT不一样。98下可以用CreateToolhelp32Snapshot函数Process32First和 Process32Next来枚举当前所有进程的进程ID(先调用函数CreateToolhelp32Snapshot) NT下用EnumProcesses函数来枚举。2000是支持CreateToolhelp32Snapshot函数的。 得到进程ID后就可以用OpenProcess函数得到句柄了,在NT和2000下要通过安全检测。 3、EnumProcess 也可以得到系统中的进程列表 杀掉本地进程其实很简单,取得进程ID后,调用OpenProcess函数打开进程句柄,然 后调用TerminateProcess函数就可以杀掉进程了。有些情况下并不能直接打开进程句柄, 例如WINLOGON等系统进程,因为权限不够。这个时候我们就得先提升自己的进程的权限了。 提升权限过程也不复杂,先调用GetCurrentProcess函数取得当前进程的句柄,然后调用 OpenProcessToken打开当前进程的访问令牌,接着调用LookupPrivilegeValue函数取得你 想提升的权限的值,最后调用AdjustTokenPrivileges函数给当前进程的访问令牌增加权限 就可以了。一般有了SeDebugPrivilege特权后,就可以杀掉除Idle外的所有进程了。 1.OpenProcessToken 要对一个任意进程(包括系统安全进程和服务进程)进行指定了写相关的访问权的OpenProcess操作,只要当前进程具有SeDeDebug权限就可以了。要是一个用户是Administrator或是被给予了相应的权限,就可以具有该权限。可是,就算我们用Administrator帐号对一个系统安全进程执行OpenProcess(PROCESS_ALL_ACCESS,FALSE, dwProcessID)还是会遇到"访问拒绝"的错误。什么原因呢?原来在默认的情况下进程的一些访问权限是没有被置为可用状态(即Enabled)的,所以我们要做的首先是使这些权限可用。与此相关的一些API函数有OpenProcessToken、LookupPrivilegevalue、AdjustTokenPrivileges。我们要修改一个进程的访问令牌,首先要获得进程访问令牌的句柄,这可以通过OpenProcessToken得到,函数的原型如下: BOOL OpenProcessToken( HANDLE ProcessHandle, //要修改访问权限的进程句柄 DWORD DesiredAccess, //指定你要进行的操作类型 PHANDLE TokenHandle //返回的访问令牌指针 ); 成功返回非0; 参数说明: 第一参数是要修改访问权限的进程句柄; 第三个参数就是返回的访问令牌指针; 第二个参数指定你要进行的操作类型,如要修改令牌我们要指定第二个参数为TOKEN_ADJUST_PRIVILEGES(其它一些参数可参考Platform SDK)。通过这个函数我们就可以得到当前进程的访问令牌的句柄(指定函数的第一个参数为GetCurrentProcess()就可以了)。接着我们可以调用AdjustTokenPrivileges对这个访问令牌进行修改。 包含头文件Winbase.h 2.LookupPrivilegeValue 获取当前系统上,指定权限名字的唯一标志(LUID),函数原形如下: BOOL LookupPrivilegeValue( LPCTSTR lpSystemName, LPCTSTR lpName, PLUID lpLuid ); 成功返回非0; 参数说明: lpSystemName [in]传入参数,字符传指针;指定需要获取权限的操作系统名字,如果传入null,那么将在本地系统上查询指定权限名的LUID; lpName [in]传入参数,字符串指针;指定需要查询LUID的权限名字,可以系统中定义了的权限产量(如SE_SECURITY_NAME),也可以是一个自己定义的字符串(如"SeSecurityPrivilege"); lpLuid [out]传出参数,字符串指针; 传出权限名字指定的LUID; 包含头文件Winbase.h 3.AdjustTokenPrivileges 根据指定的权限令牌,置进程的权限为可用或不可用; 函数原型: BOOL AdjustTokenPrivileges( HANDLE TokenHandle, BOOL DisableAllPrivileges, PTOKEN_PRIVILEGES NewState, DWORD BufferLength, PTOKEN_PRIVILEGES PreviousState, PDWORD ReturnLength ); 参数说明: TokenHandle [in]包含需要修改权限的令牌句柄.这个参速需要有TOKEN_ADJUST_PRIVILEGES权限.如果参数PreviousState=NULL,那么句柄已应该拥有TOKEN_QUERY权限. DisableAllPrivileges [in]是否置所有的权限为不可用状态.如果值=TRUE,使所有的权限不可用,并且忽略NewState参数.如果为FALSE,那么该函数将修改这些权限为NewState参数所指的状态. NewState [in]指向一个描述权限属性的TOKEN_PRIVILEGES结构数组.如果DisableAllPrivileges=FALSE,那么AdjustTokenPrivileges将使数组中指向的属性为可用,不可用状态或者删除. 系统中定义的三个常量SE_PRIVILEGE_ENABLED,SE_PRIVILEGE_ENABLED,SE_PRIVI LEGE_REMOVED. Windows XP/2000/NT中,不能删除权限 BufferLength [in] 以字节为单位指定了PreviousState所指缓冲buffer的长度,如果PreviousState参数为NULL,那么BufferLength可以被置为0. PreviousState [out] 传输AdjustTokenPrivileges参作将修改的属性的修改前状态,可以被置为NULL; ReturnLength [out] 返回PreviousState请求字节长度,如果PreviousState=NULL,这个参数可以为NULL;
包含头文件Winbase.h 4.OpenProcessToken ,LookupPrivilegeValue,AdjustTokenPrivileges引用举例 BOOL EnableDebugPrivilege(BOOL fEnable) { BOOL fOk = FALSE; // Assume function fails HANDLE hToken; //以修改选项,获取当前进程的令牌环 if (OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &hToken)) { TOKEN_PRIVILEGES tp; tp.PrivilegeCount = 1; //获取debug权限的luid LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &tp.Privileges[0].Luid); //将权限属性置为可用 tp.Privileges[0].Attributes = fEnable ? SE_PRIVILEGE_ENABLED : 0; //修改权限 AdjustTokenPrivileges(hToken, FALSE, &tp, sizeof(tp), NULL, NULL); fOk = (GetLastError() == ERROR_SUCCESS); CloseHandle(hToken); } return(fOk); } //结束进程 #include