自学内容网 自学内容网

C++代码中因为权限不对等导致操作另一个进程窗口失败的问题排查(进程权限不对等 | 以标准用户权限启动程序)

目录

1、程序运行单实例说明

2、显示已启动程序进程的窗口失败

3、解决办法

4、最后


C++软件异常排查从入门到精通系列教程(专栏文章列表,欢迎订阅,持续更新...)icon-default.png?t=O83Ahttps://blog.csdn.net/chenlycly/article/details/125529931C/C++实战专栏(专栏文章已更新400多篇,持续更新中...)icon-default.png?t=O83Ahttps://blog.csdn.net/chenlycly/article/details/140824370C++ 软件开发从入门到精通(专栏文章,持续更新中...)icon-default.png?t=O83Ahttps://blog.csdn.net/chenlycly/category_12695902.htmlVC++常用功能开发汇总(专栏文章列表,欢迎订阅,持续更新...)icon-default.png?t=O83Ahttps://blog.csdn.net/chenlycly/article/details/124272585C++软件分析工具从入门到精通案例集锦(专栏文章,持续更新中...)icon-default.png?t=O83Ahttps://blog.csdn.net/chenlycly/article/details/131405795开源组件及数据库技术(专栏文章,持续更新中...)icon-default.png?t=O83Ahttps://blog.csdn.net/chenlycly/category_12458859.html网络编程与网络问题分享(专栏文章,持续更新中...)icon-default.png?t=O83Ahttps://blog.csdn.net/chenlycly/category_2276111.html       之前我们通过多个实例讲解了因为进程权限不对等导致软件工具无法正常使用的多个场景,今天来讲一个C++编码中遇到的因为权限不对等导致操作另一个进程窗口失败的案例,这是我们在项目中遇到的,以供大家借鉴或参考。

1、程序运行单实例说明

       很多程序只允许启动一个程序实例(只能运行一个进程),不像浏览器程序,可以启动多个程序(窗口)。只允许程序运行一个实例,大体是这么实现的,当程序启动时会去检测是否有程序进程已经启动,如果已经有程序进程运行且不是当前的进程,则自动将当前新启动的进程退出,这样就能保证程序只运行一个实例了。

       对于UI程序,要实现单实例运行,则要做到这样的效果。当程序已经运行,但我们没有看到程序窗口(可能程序主窗口被最小化到任务栏,或者被最小化到托盘区域了),此时我们再去双击桌面快捷方式启动程序(或者通过其他方式启动程序),会启动新的程序进程。新的进程会检测到已有程序进程运行,则会将已启动的程序的窗口显示出来,然后将新启动的程序进程退出。

2、显示已启动程序进程的窗口失败

       程序已经启动,然后我们将程序主窗口最小化了,然后我们双击桌面快捷方式启动新的程序进程,因为程序之前已经启动起来,按理我们应该要将已经运行的程序窗口自动弹出来。我们的软件代码也的确是这么实现的,但有用户反馈,在某个场合下并没有将已经运行的程序窗口弹出来。

       场景是这样的:已经运行的程序,是在使用安装包安装后,安装包自动将软件启动起来,因为安装包是以管理员权限运行的,所以被启动起来的程序默认是继承了管理员权限。而我们通过双击桌面快捷方式启动的新程序进程是以标准权限运行的,新启动的程序在初始化运行时会去检测程序是否已经运行,检测到程序已经运行,并找到了已经运行的程序主窗口,但在调用API函数ShowWindow将该窗口Show出来时却失败了。

       于是想到MSDN上查看API函数ShowWindow的说明,看看能不能将相关值打印出来,分析一下该函数为什么会调用失败。ShowWindow函数在MSDN上的说明如下:

该函数的返回值是BOOL型的,但这个返回值只是标识窗口之前的状态,并不是标识ShowWindow函数是否执行成功的,只能借助GetLastError函数,通过获取LastError值找到ShowWindow执行失败的原因。

有些Windows API需要借助GetLastError获取的LastError值去判断有没有执行成功:

1)如果LastError值为0,则表示执行成功;

2)如果LastError值不为0,则表示执行失败,LastError值对应的就是执行失败的原因。

于是添加如下的打印:

BOOL bShowTargetWndSuccess = FALSE;

SetLastError(0);
::ShowWindow(hPrevWnd, SW_RESTORE);
DWORD dwLastError = GetLastError();

if ( dwLastError == 0 )
{
    // 窗口Show成功了
    bShowTargetWndSuccess = TRUE;
}
else
{
    // 窗口Show失败了,将API函数ShowWindow设置完后设置的LastError值打印出来
    char szLog[256] = { 0 };
    sprintf(szLog, "[CheckShowExsitingWnd] show target window failed, LastError = %d.", dwLastError);
    WriteLog(szLog);
}

后来复现了这个问题,查看打印日志,看到调用ShowWindow窗口Show失败时设置的LastError值为5,到VS自带的错误查看工具中查看该值的含义如下:

拒绝访问,应该就是权限问题导致ShowWindow执行失败了。已经运行的程序进程因为是安装包安装完成后自动启动的,所以有管理员权限,而新启动的进程是双击桌面快捷方式启动的,所以是以标准用户权限运行的。新启动的进程检测到程序已经运行,低权限(标准用户权限)的新进程想要其Show高权限(管理员权限)的已启动进程中的窗口,系统是不允许的,所以导致ShowWindow执行失败。


       在这里,给大家重点推荐一下我的几个热门畅销专栏,欢迎订阅:(博客主页还有其他专栏,可以去查看)

专栏1:该精品技术专栏的订阅量已达到520多个,专栏中包含大量项目实战分析案例,有很强的实战参考价值,广受好评!专栏文章持续更新中,预计更新到200篇以上!欢迎订阅!)

C++软件调试与异常排查从入门到精通系列文章汇总icon-default.png?t=O83Ahttps://blog.csdn.net/chenlycly/article/details/125529931

本专栏根据多年C++软件异常排查的项目实践,系统地总结了引发C++软件异常的常见原因以及排查C++软件异常的常用思路与方法,详细讲述了C++软件的调试方法与手段,以图文并茂的方式给出具体的项目问题实战分析实例(很有实战参考价值),带领大家逐步掌握C++软件调试与异常排查的相关技术,适合基础进阶和想做技术提升的相关C++开发人员!

考察一个开发人员的水平,一是看其编码及设计能力,二是要看其软件调试能力!所以软件调试能力(排查软件异常的能力)很重要,必须重视起来!能解决一般人解决不了的问题,既能提升个人能力及价值,也能体现对团队及公司的贡献!

专栏中的文章都是通过项目实战总结出来的,包含大量项目问题实战分析案例,有很强的实战参考价值!专栏文章还在持续更新中,预计文章篇数能更新到200篇以上!

专栏2:(本专栏涵盖了C++多方面的内容,是当前重点打造的专栏,订阅量已达160多个,专栏文章已经更新到400多篇,持续更新中...)

C/C++实战进阶(专栏文章,持续更新中...)icon-default.png?t=O83Ahttps://blog.csdn.net/chenlycly/category_11931267.html

以多年的开发实战为基础,总结并讲解一些的C/C++基础与项目实战进阶内容,以图文并茂的方式对相关知识点进行详细地展开与阐述!专栏涉及了C/C++领域多个方面的内容,包括C++基础及编程要点(模版泛型编程、STL容器及算法函数的使用等)、数据结构与算法、C++11及以上新特性(不仅看开源代码会用到,日常编码中也会用到部分新特性,面试时也会涉及到)、常用C++开源库的介绍与使用、代码分享(调用系统API、使用开源库)、常用编程技术(动态库、多线程、多进程、数据库及网络编程等)、软件UI编程(Win32/duilib/QT/MFC)、C++软件调试技术(排查软件异常的手段与方法、分析C++软件异常的基础知识、常用软件分析工具使用、实战问题分析案例等)、设计模式、网络基础知识与网络问题分析进阶内容等。

专栏3:  

C++常用软件分析工具从入门到精通案例集锦汇总(专栏文章,持续更新中...)icon-default.png?t=O83Ahttps://blog.csdn.net/chenlycly/article/details/131405795

常用的C++软件辅助分析工具有SPY++、PE工具、Dependency Walker、GDIView、Process Explorer、Process Monitor、API Monitor、Clumsy、Windbg、IDA Pro等,本专栏详细介绍如何使用这些工具去巧妙地分析和解决日常工作中遇到的问题,很有实战参考价值!

专栏4:   

VC++常用功能开发汇总(专栏文章,持续更新中...)icon-default.png?t=O83Ahttps://blog.csdn.net/chenlycly/article/details/124272585

将10多年C++开发实践中常用的功能,以高质量的代码展现出来。这些常用的高质量规范代码,可以直接拿到项目中使用,能有效地解决软件开发过程中遇到的问题。

专栏5: 

C++ 软件开发从入门到精通(专栏文章,持续更新中...)icon-default.png?t=O83Ahttps://blog.csdn.net/chenlycly/category_12695902.html

根据多年C++软件开发实践,详细地总结了C/C++软件开发相关技术实现细节,分享了大量的实战案例,很有实战参考价值。


3、解决办法

       目前规避的办法是,当我们发现ShowWindow执行失败(判断LastError值)时,直接弹出一个提示框,但还是没有将已启动的程序窗口弹出来,这只是个规避问题的方法,用户体验并不好。

       最好的解决办法是,安装包在安装完成后自动启动进程时,直接以标准用户权限启动程序,这样就没有权限不对等的问题了,这样就能自动弹出已经运行的程序窗口了。

       和企业微信对比了一下,在同样的场景下企业微信是没问题的,企业微信能自动将已经运行的程序窗口弹出来。我们编写了监测程序进程是否以管理员权限运行的代码(本文后面会给出判断程序进程是否已管理员权限运行的代码),发现企业微信安装包执行完后自动启动起来的企业微信进程是标准用户权限运行的。企业微信安装包肯定是以管理员权限运行的(安装包要可能要向系统敏感路径写入内容,要写注册表,要注册控件,所以一般安装包需要以管理员权限运行),从企业微信的安装包程序的图标就能看出来,图标的右下角有个小盾牌:

以管理员权限运行的安装包进程,以标准用户权限去启动企业微信的主程序,即启动起来的企业微信主程序是以标准用户权限运行的。

       那如何启动一个标准用户权限运行的进程呢?还记得我之前讲过的工具Process Hacker吗?我们在日常排查问题时,会使用到Process Hacker,之前在菜单中看到以标准用户权限创建进程的功能。在该工具的菜单栏中,hacker -> Run as limited user...

而这个工具的代码是开源的,所以可以参考该工具的源码。大家需要这个功能的话,可以到源码中去找该菜单项对应的源码实现。此处给出Process Hacker开源代码中以标准用户权限创建一个进程的部分代码

NTSTATUS status;
HANDLE tokenHandle;
HANDLE newTokenHandle;

if (NT_SUCCESS(status = PhOpenProcessToken(
    NtCurrentProcess(),
    TOKEN_ASSIGN_PRIMARY | TOKEN_DUPLICATE | TOKEN_QUERY | TOKEN_ADJUST_GROUPS |
    TOKEN_ADJUST_DEFAULT | READ_CONTROL | WRITE_DAC,
    &tokenHandle
    )))
{
    if (NT_SUCCESS(status = PhFilterTokenForLimitedUser(
        tokenHandle,
        &newTokenHandle
        )))
    {
        status = PhCreateProcessWin32(
NULL,
(PWSTR)runFileDlg->lpszFile,
NULL,
NULL,
0,
newTokenHandle,
NULL,
NULL
);

        NtClose(newTokenHandle);
    }

    NtClose(tokenHandle);
}

如果要实现这个功能,则需要到Process Hacker开源代码中拷贝完整的源码。

我们之前还讲过一个类似的工具叫Process Explorer,这个工具我们日常用的比较多,它也有类似的功能,但该工具是微软提供的,不是开源的,我们看不到他的源码实现。 

4、最后

         本文分享了一个在项目中遇到的因为权限不对等导致在代码中操作另一个进程窗口失败的案例,详细讲解问题的排查过程,有一定的参考价值!


原文地址:https://blog.csdn.net/chenlycly/article/details/142312748

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!