目录
判断操作系统及指定进程是32位还是64位
背景
应该很多人开发程序的时候,都会遇到这样的一个功能需求,怎么判断一个进程是32位进程还是64位进程呢?通常,我们的解决方法是,调用IsWow64Process函数进行判断。本文介绍的也是这种方法。
但是,本文的这种方法考虑的更加全面。因为,大都数网上的方法都只是调用IsWow64Process函数来进行判断,这只考虑了64位操作系统,却没有考虑过程序如果运行在32位操作系统,那么刚才的判断方法是否会出错!
本文就完善使用IsWow64Process函数判断指定进程是64位还是32位,完美支持32位操作系统和64位操作系统。现在,把程序的实现思路和实现方法写成文档,分享给大家。
函数介绍
OpenProcess 函数
打开一个已存在的进程对象,并返回进程的句柄。
函数声明
HANDLE OpenProcess( DWORD dwDesiredAccess, //渴望得到的访问权限(标志) BOOL bInheritHandle, // 是否继承句柄 DWORD dwProcessId // 进程标示符 );
参数
- dwDesiredAccess [in]
访问进程对象。 此访问权限将针对进程的安全描述符进行检查。 此参数可以是一个或多个进程访问权限。如果调用者启用了SeDebugPrivilege权限,则无论安全描述符的内容如何,都会授予所请求的访问权限。- bInheritHandle [in]
如果此值为TRUE,则此进程创建的进程将继承该句柄。 否则,进程不会继承此句柄。- dwProcessId [in]
要打开的本地进程的标识符。返回值
- 如果函数成功,则返回值是指定进程的打开句柄。
- 如果函数失败,返回值为NULL。要获取扩展错误信息,请调用GetLastError。
GetCurrentProcess 函数
获取当前程序进程的句柄。
函数声明
HANDLE WINAPI GetCurrentProcess(void);
参数
- 无参数
返回值
- 返回当前程序进程的句柄。
IsWow64Process 函数
判断指定的进程是否在WOW64下运行。
函数声明
BOOL WINAPI IsWow64Process( _In_ HANDLE hProcess, _Out_ PBOOL Wow64Process );
参数
- hProcess [in]
过程的句柄。 句柄必须具有PROCESS_QUERY_INFORMATION或PROCESS_QUERY_LIMITED_INFORMATION权限。 有关更多信息,请参阅流程安全和访问权限。- Wow64Process [out]
指向如果进程在WOW64下运行时设置为TRUE的值的指针。 如果进程在32位Windows下运行,则该值设置为FALSE。 如果进程是在64位Windows下运行的64位应用程序,则该值也设置为FALSE。返回值
- 如果函数成功,则返回值为非零值。
- 如果函数失败,返回值为零。 要获取扩展错误信息,请调用GetLastError。
实现原理
先简单介绍下什么是WOW64,WOW64 (Windows-on-Windows 64-bit)是一个Windows操作系统的子系统,它为现有的 32 位应用程序提供了 32 位的模拟,可以使大多数 32 位应用程序在无需修改的情况下运行在 Windows 64 位版本上。也就是说,WOW64就是一个 64 位操作系统模拟 32 位操作系统的一个子系统,而且32位程序都运行在它上面。
那么,WIN32 API函数 IsWow64Process,就是判断指定程序是否运行在 WOW64 模拟系统中。而且,根据文档可知:
OS 32bits | OS 64BITS | |
---|---|---|
32bits process | FALSE | TRUE |
64bits process | ERROR | FALSE |
上面意思是说:
-
使用IsWow64Process在32位操作系统上获取32位进程的返回结果是FALSE
-
使用IsWow64Process在64位操作系统上获取32位进程的返回结果是TRUE
-
使用IsWow64Process在32位操作系统上获取64位进程的返回结果是ERROR,因为64位程序不能在32位系统上运行
-
使用IsWow64Process在64位操作系统上获取64位进程的返回结果是FALSE
也就是说,如果我们要写一个判断进程位数的程序,还要能在32位系统和64位系统上运行,那么就必须先判断操作系统的位数。
判断操作系统位数的原理是:
利用上述的结果,对于32位的进程,在32位系统上,IsWow64Process返回FALSE,而64位系统返回TRUE。而且,我们程序本身就是32位,只要我们获取程序自身的进程句柄,然后传入IsWow64Process函数中判断是否在仿真环境中,根据返回结果可以知道32位系统还是64位系统。
那么,判断全系统上,进程的位数的原理是:
-
程序自身是32位进程。首先,先判断操作操作系统的位数。若是32位操作系统,那么它上面的所有进程都是32位的
-
若是64位进程,那么就打开指定进程获取进程句柄。然后将进程句柄传递给IsWow64Process函数,进行判断。若是返回TRUE,则说明进程运行在WOW64模拟环境中,是一个32位进程;否则,是64位进程
编码实现
判断操作系统的位数
BOOL Is64BitsOperateSystem()
{
// 判断当前计算机操作系统是32位操作系统还是64位操作系统
BOOL bWow64Process = FALSE;
// 获取当前程序进程句柄
HANDLE hProcess = ::GetCurrentProcess();
if (NULL == hProcess)
{
ShowError("OpenProcess");
return bWow64Process;
}
// 判断进程是否处于WOW64仿真环境中
::IsWow64Process(hProcess, &bWow64Process);
return bWow64Process;
}
判断指定进程的位数
BOOL Is64BitsProcess(DWORD dwProcessId)
{
// 判断64位系统下, 进程指定是32位还是64位
// 先判断计算机操作系统位数, 32位系统只能执行32位进程
if (FALSE == Is64BitsOperateSystem)
{
return FALSE;
}
BOOL bWow64Process = FALSE;
// 打开进程, 获取进程句柄
HANDLE hProcess = NULL;
hProcess = ::OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwProcessId);
if (NULL == hProcess)
{
ShowError("OpenProcess");
return bWow64Process;
}
// 判断进程是否处于WOW64仿真环境中
::IsWow64Process(hProcess, &bWow64Process);
return bWow64Process;
}
程序测试
在 main 函数中调用上述封装好的函数进行测试,main 函数为:
int _tmain(int argc, _TCHAR* argv[])
{
// 11360 --> 32位进程
if (Is64BitsProcess(11360))
{
printf("32 bits\n");
}
else
{
printf("64 bits\n");
}
// 7400 --> 64位进程
if (Is64BitsProcess(7400))
{
printf("32 bits\n");
}
else
{
printf("64 bits\n");
}
system("pause");
return 0;
}
测试结果
测试的例子中,进程PID为11360的是32位程序,PDI为7400的是64位程序。
运行程序,程序判断正确。
总结
很多人使用IsWow64Process来判断进程的位数,往往会忽略考虑32位系统的情况,而造成程序在32位系统上运行出错。所以,这一点一定要考虑全面。
参考
参考自《Windows黑客编程技术详解》一书