openProcess时拒绝访问(GetlastError为5),返回的HANDLE为NULL的解决方法

遇到的问题:在winXP的VS2010里调试好的程序,直接双击exe文件能运行,但是什么都没执行,就是没有按我程序中写的去执行。
找出问题的方法:由于是执行exe文件出的错误,因此用普通的打印语句(printf,cout等)是没用的,我在程序 中每隔几行向一个文件写内容(写日志)或加一个messageBox来判断程序执行到哪儿出现了问题。
具体介绍:最近在写一个进程监控管理的程序,都已经写好了,并且在Win7上运行是OK的,但是把Realease版的exe文件和需要的dll文件放到winXP系统的机器上运行,也能运行,但是,就是不能达到预期的效果,就是需要kill一个进程的时候,它并没有kill掉,好像什么都没执行,后来,通过在程序中每隔几行向一个文件写内容(或弹出messageBox)来调试,发现openProcess的返回HANDLE为NULL。再用GetLastError()打印出错误码,发现为5(拒绝访问)。是权限不够。
     
后来就查资料,发现是权限不够造成的,可以用如下的函数来提升权限(获取权限):
BOOL  EnableDebugPrivilege()
{
  HANDLE hToken;
  BOOL fOk=FALSE;
  if(OpenProcessToken(GetCurrentProcess(),TOKEN_ADJUST_PRIVILEGES,&hToken)) //Get Token
  {
    TOKEN_PRIVILEGES tp;
    tp.PrivilegeCount=1;
    if(!LookupPrivilegeValue(NULL,SE_DEBUG_NAME,&tp.Privileges[0].Luid))//Get Luid
      printf("Can't lookup privilege value.\n");
    tp.Privileges[0].Attributes= SE_PRIVILEGE_ENABLED;//这一句很关键,修改其属性为SE_PRIVILEGE_ENABLED
    if(!AdjustTokenPrivileges(hToken,FALSE,&tp,sizeof(tp),NULL,NULL))//Adjust Token
      printf("Can't adjust privilege value.\n");
    fOk=(GetLastError()==ERROR_SUCCESS);
    CloseHandle(hToken);
  }
    return fOk;
}
在枚举进程之前,加上上述代码解决了我的问题。
     上述代码主要用到了四个API函数:
OpenProcessToken():得到进程的令牌句柄
LookupPrivilegeValue(): 查询进程的权限 
AdjustTokenPrivileges(): 判断令牌权限
GetCurrentProcess(): 得到当前进程的伪句柄
前三个是重点。
其中,
OpenProcessToken()的原型如下:
BOOL OpenProcessToken( 
HANDLE ProcessHandle, 
DWORD DesiredAccess, 
PHANDLE TokenHandle 
);
第一参数是要修改访问权限的进程句柄;第二个参数指定你要进行的操作类型,如要修改令牌我们要指定第二个参数为TOKEN_ADJUST_PRIVILEGES(其它一些参数可参考Platform SDK);第三个参数就是返回的访问令牌指针。通过这个函数我们就可以得到当前进程的访问令牌的句柄(指定函数的第一个参数为GetCurrentProcess()就可以了)。
后面三个的函数原型就不介绍了,可查MSDN。

         要对一个任意进程(包括系统安全进程和服务进程)进行指定了写相关的访问权的OpenProcess操作,只要当前进程具有SeDeDebug权限就可以了。要是一个用户是Administrator或是被给予了相应的权限,就可以具有该权限。可是,就算我们用Administrator帐号对一个系统安全进程执行OpenProcess(PROCESS_ALL_ACCESS,FALSE, dwProcessID)还是会遇到“访问拒绝”的错误。什么原因呢?原来在默认的情况下进程的一些访问权限是没有被使能(Enabled)的,所以我们要做的首先是使能这些权限。与此相关的一些API函数有OpenProcessToken、LookupPrivilegevalue、AdjustTokenPrivileges。我们要修改一个进程的访问令牌,首先要获得进程访问令牌的句柄,这可以通过OpenProcessToken得到。


-----注:在win7上是不需要提上权限的,若用上述代码提升权限,会提升失败。

==============================================================================
另外,还可以参考:
(1)http://www.cppblog.com/steven/articles/51109.html      学习任务管理器中进程管理部分发现问题.
      可以使用进程枚举出所有进程,但是处理进程的时候总是出现问题,无法操作进程,包括访问,结束.代码如下:
 HANDLE hProcess=INVALID_HANDLE_VALUE;
 HANDLE hSnapshot=INVALID_HANDLE_VALUE;
 hSnapshot=CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS,0);
 PROCESSENTRY32 pe;
 Process32First(hSnapshot,&pe);
 do
 {
      // do what you want
      hProcess=OpenProcess(PROCESS_ALL_ACCESS,FALSE,pe.th32ProcessID);

      if(hProcess==NULL) 

      {

           _stprintf(szTemp,"OpenProcess() fail\n %d\n%s",GetLastError(),pe.szExeFile);
           wsprintf(szExePath,_T("%s"),"not get Process handle OpenProcess()");

     }

    else if(0==GetModuleFileNameEx((HINSTANCE)hProcess,NULL,szExePath,MAX_PATH))

     {
         _stprintf(szTemp,"GetModuleFileName() fail %d\n%s\n%s",GetLastError(),pe.szExeFile,szExePath);
         wsprintf(szExePath,_T("%s"),"not get Process handle GetModuleFileName()");

    }


  }while(Process32Next(hSnapshot,&pe));

 CloseHandle(hSnapshot); 

OpenProcess() 错误ERROR CODE 5:拒绝访问.需要取得相应的权限.
OpenProcessToken函数的功能是打开一个与一进程相联系的访问令牌(access token),它的原型如下: 
BOOL OpenProcessToken( 
  HANDLE ProcessHandle,  
  DWORD DesiredAccess,  
  PHANDLE TokenHandle 
); 


如同MSDN上所说,对于Windows XP Professional,如果一台计算机加入到一个工作组中,而且"Force network logons using local accounts to authenticate as Guest"的限制被激活的话,此函数会失败。 


另外,如果在调用的时候使用了TOKEN_ALL_ACCESS请求,函数也可能会失败。这是因为TOKEN_ALL_ACCESS可能包含了TOKEN_ADJUST_SESSIONID(在Winnt.h中被定义)。TOKEN_ADJUST_SESSIONID是一个新的访问mask,是在Windows 2000和Windows XP中新增的。在Windows NT 4.0中,访问令牌的访问控制列表中是没有这个值的。所以,如果一个应用程序是使用新的Platform SDK中的Winnt.h但却在Windows NT 4.0下运行的话,在调用OpenProcessToken()或者OpenThreadToken时指定了TOKEN_ALL_ACCESS的话,函数也会失败(使用GetLastError()返回的是ERROR_ACCESS_DENIED)。 

typedef struct    _TOKEN_PRIVILEGES { 
  DWORD PrivilegeCount; 
  LUID_AND_ATTRIBUTES PrivilegeCount; 
  LUID_AND_ATTRIBUTES Privileges[]; } TOKEN_PRIVILEGES, *PTOKEN_PRIVILEGES; 


AdjustTokenPrivileges()函数原型如下:

BOOL AdjustTokenPrivileges(
  HANDLE TokenHandle,              // handle to token
  BOOL TokenHandle,              // handle to token
  BOOL DisableAllPrivileges,       // disabling option
  PTOKEN_PRIVILEGES NewState,      // privilege information
  DWORD NewState,      // privilege information
  DWORD BufferLength,              // size of buffer
  PTOKEN_PRIVILEGES PreviousState, // original state buffer
  PDWORD PreviousState, // original state buffer
  PDWORD ReturnLength              // required buffer size
);

在枚举所有进程之前获取操作权限,就可以避免出错的问题,当然参数要设置为Enable.
具体实现如下:
BOOL ProcessPrivilege(BOOL bEnable)
{
 BOOL                   bResult = TRUE;
 HANDLE               hToken=INVALID_HANDLE_VALUE;
 TOKEN_PRIVILEGES     TokenPrivileges;
 if(OpenProcessToken(GetCurrentProcess(),TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES,&hToken) == 0)
 {
     printf("OpenProcessToken Error: %d\n",GetLastError());
     bResult = FALSE;
 }
 TokenPrivileges.PrivilegeCount           = 1;
 TokenPrivileges.Privileges[0].Attributes = bEnable ? SE_PRIVILEGE_ENABLED : 0;
 LookupPrivilegeValue(NULL,SE_DEBUG_NAME,&TokenPrivileges.Privileges[0].Luid);
 AdjustTokenPrivileges(hToken,FALSE,&TokenPrivileges,sizeof(TOKEN_PRIVILEGES),NULL,NULL);
    if(GetLastError() != ERROR_SUCCESS)
 {
     bResult = FALSE;
 }
 CloseHandle(hToken);
    
 return bResult;

}

这样就OK了。

--------------------------------------------------------------------
(2)http://blog.csdn.net/stonesharp/article/details/7709674
-------------------------------------------------------------------
(3)http://bbs.csdn.net/topics/50003733

你可能感兴趣的:(windows开发)