您的位置:首页 > 运维架构

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

2014-04-29 20:37 633 查看
遇到的问题:在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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: