QT程序监控不到拖拽事件如dragEnterEvent - Windows权限问题的解决方案

问题:当客户端已高完整性启动(例如启动客户端的进程是Bypass UAC启动的高完整性的进程,导致客户端继承了其高完整性),由于explorer.exe资源管理器是以中等Medium权限启动,客户端的权限较高,导致设置了qt编写的客户端设置了的setAcceptDrops(true)后依然无法触发dropEvent,导致无法接受其它程序或者资源管理器拖拽过来的文件。

解决方法与代码在文章的末尾。


完整性等级概念

强制完整性控制(Mandatory Integrity Control,MIC),它是对 discretionary access control list 的补充,并且是在 DACL 之前检查的
这是从 Windows Vista 新增的安全机制,在 Windows XP 中几乎所有的进程都是运行在管理员权限下的。
在官方文档中描述为 Windows 为其划分了四个完整性级别:低、中、高、系统;但从实际上看到的对应表中,有五个等级,多了一个不受信任等级。

具有低完整性级别的主体无法写入具有中等完整性级别的对象,这就相当于提供了一种在同一用户下,根据可信程度来限制不同进程之间的交互,低完整性等级的进程都无法对高完整性进程进行注入

虽然是限制了进程间的交互,但是高低完整性的进程还是可以通过其他的进程间通信的方式来进行交互:共享内存、Sockets、RPC、Windows 消息机制、命名管道,这些是不受限制的。

微软文档:https://learn.microsoft.com/zh-cn/previous-versions/dotnet/articles/bb625963(v=msdn.10)


完整性等级

Windows 直接使用了 SID 来定义完整性等级,这样就非常容易的将此机制集成到现有的结构当中,还不用修改代码
完整性等级所使用的 SID 格式是:S-1-16-xxxx(请与Session ID会话窗口ID区分开,并不是一个概念)

16 就是强制完整性的标识,后面的 xxxx,就是所对应的 RID,用来表示完整性等级的,这个值就是上面所提到的那几个十六进制值,它们以 0x1000 为间隔,也是为了将来能够再定义其他的等级
所以组合到一起以后完整性等级所对应的 SID 就变成了

  • System
    这是最高的完整性级别,由在本地服务、网络服务和系统账户下运行的进程和服务使用。此级别的目的是在管理员和系统之间提供一个安全层,即使以完全管理员身份运行的进程也无法与系统完整性级别进程交互
    唯一的例外情况是,如果管理员账户被授予 SE_DEBUG_NAME 权限,那么他就可以在 token 中启用这个权限,来进行交互
  • High
    分配给在管理员账户下运行的进程的默认完整性级别,如果启用了 UAC,则此级别将仅提供给提升过 UAC 权限的用户
  • Medium
    授予在非管理员用户账户下运行的进程或启用 UAC 的管理员账户上的进程。
    此完整性级别的进程只能修改 HKEY_CURRENT_USER、非受保护文件夹中的文件以及具有相同或更低完整性的进程。请注意explorer.exe是Medium等级
  • Low
    最低完整性级别默认不分配给进程,它要么通过继承,要么由父进程设置。
    以低完整性级别运行的进程只能在 HKEY_CURRENT_USER\Software\AppDataLow 下操作,或者将文件写入 %USERPROFILE%\AppData\LocalLow 目录下
    低完整性进程实际上不可能对系统进行任何更改,但仍然可以读取大部分的数据。
    在 Process Explorer 中可以查看到进程的完整性等级
    可以看到 Chrome 默认启动的是 Medium 等级的,其中还有 Low 等级的,这个可能就是沙盒用到的,给它们足够低的等级,能够最大限度的减少在出现问题时所带来的影响;而大量的不被信任的进程,有可能就是各个标签页所在的处理进程

其他注意:

1.进程是无法更改自己的完整性等级的
2.进程一旦运行,完整性等级是无法再修改了,即使是更高完整性等级的进程
3.进程只能够创建具有相同或者更低完整性等级的进程
4.进程不能修改或者写入具有更高完整性等级的进程或者文件

完整性等级的限制还有几个例外的情况
1.被授予 SE_DEBUG_NAME 权限的高完整性等级的进程可以修改更高完整性等级的进程
2.中等完整性的进程可以通过一些操作提升到高完整性等级,这就是平时的 Bypass UAC 的操作
3.进程可以请求从中等完整性提升到高完整性等级,这个只能在执行的时候发生,会弹出 UAC 的提示让用户来选择


使用 Process Explorer 查看进程完整性的等级:

点击View -> Select Columns -> Process Image -> 选择Integrity Level


解决方法:

方法1:启动客户端时,使用 CreateProcessAsUser 函数启动,复制父进程的Token,调用 SetTokenInformation 修改其中的完整性等级为Medium,再付给要启动的客户端进程,这样启动的客户端就具有Medium等级了。

修改方式也有两种,一种是使用 ConvertStringSidToSid 将文本转换成对应的SID,一种是调用 AllocateAndInitializeSid 直接创建初始化对应等级的SID

知名安全标识符 (SID)对应文本S-1-16-0      不受信任的强制等级
S-1-16-4096    低强制级别
S-1-16-8192    中强制级别
S-1-16-12288    高强制级别
S-1-16-16384    系统强制级别

(1)使用ConvertStringSidToSid

#include <Windows.h>
#include <sddl.h>static void launch_notepad_as_user(HANDLE token) {PROCESS_INFORMATION pi;STARTUPINFO si;ZeroMemory(&si, sizeof(si));si.cb = sizeof( si );if (CreateProcessAsUser(token, TEXT("C:\\Windows\\Notepad.exe"), NULL, NULL,NULL, FALSE, 0, NULL, NULL, &si, &pi )) {/* Process has been created; work with the process and wait for it toterminate. */WaitForSingleObject(pi.hProcess, INFINITE);CloseHandle(pi.hThread);CloseHandle(pi.hProcess);}
}static BOOL adjust_token_integrity_level(HANDLE &token, const char *sid) {/* Convert the string SID to a SID *, then adjust the token'sprivileges. */BOOL ret;PSID psd = NULL;if (ConvertStringSidToSidA(sid, &psd)) {    // 将"S-1-16-8192"换算成SIDTOKEN_MANDATORY_LABEL tml;ZeroMemory(&tml, sizeof(tml));tml.Label.Attributes = SE_GROUP_INTEGRITY;tml.Label.Sid = psd;ret = SetTokenInformation(token, TokenIntegrityLevel, &tml,sizeof(tml) + GetLengthSid(psd));    // 修改Token的完整性等级LocalFree(psd);}return ret;
}void launch_notepad(void) {/* Low level; see table for integrity level string names */const char *requested_sid = "S-1-16-8192";        // 中强制等级HANDLE token_cur, token_dup;/* Get the current process' security token as a starting point, then modifya duplicate so that it runs with a fixed integrity level. */if (OpenProcessToken(GetCurrentProcess(), TOKEN_DUPLICATE |TOKEN_ADJUST_DEFAULT |TOKEN_QUERY |TOKEN_ASSIGN_PRIMARY,&token_cur)) {if (DuplicateTokenEx(token_cur, 0, NULL, SecurityImpersonation,  // 复制父进程tokenTokenPrimary, &token_dup)) {if (adjust_token_integrity_level(token_dup, requested_sid))    // 修改token的完整性等级launch_notepad_as_user(token_dup);CloseHandle(token_dup);}CloseHandle(token_cur);}
}


(2)使用AllocateAndInitializeSid

// 其他如上函数和调用方式,这里只写主要流程函数
static BOOL adjust_token_integrity_level(HANDLE &hToken) 
{SID_IDENTIFIER_AUTHORITY MLAuthority = SECURITY_MANDATORY_LABEL_AUTHORITY; PSID pIntegritySid = NULL;// 直接创建初始化对应等级的SIDif (!AllocateAndInitializeSid(&MLAuthority, 1, SECURITY_MANDATORY_MEDIUM_RID, 0, 0, 0, 0, 0, 0, 0, &pIntegritySid)){return FALSE;}TOKEN_MANDATORY_LABEL tml = {0};tml.Label.Attributes = SE_GROUP_INTEGRITY;tml.Label.Sid = pIntegritySid;// 修改Token的完整性等级const BOOL bRet = SetTokenInformation(hToken, TokenIntegrityLevel, &tml, (sizeof(tml) + GetLengthSid(pIntegritySid)));if (pIntegritySid) { FreeSid(pIntegritySid); } return bRet;
}

 

方法2:通过windows原生的事件过滤器来解决,屏蔽掉qt自带的拖拽事件过滤器,创建主窗口后启动原生事件过滤
(没试过不适合博主的项目,不知道好不好用,但应该是没问题的)

void EnableDrag(QMainWindow& w) {ChangeWindowMessageFilter(WM_DROPFILES, 1);w.winId() << w.effectiveWinId();ChangeWindowMessageFilterEx((HWND)w.effectiveWinId(), WM_DROPFILES, MSGFLT_ALLOW, NULL);ChangeWindowMessageFilterEx((HWND)w.effectiveWinId(), WM_COPYDATA, MSGFLT_ALLOW, NULL);ChangeWindowMessageFilterEx((HWND)w.effectiveWinId(), 0x0049, MSGFLT_ALLOW, NULL);DragAcceptFiles((HWND)w.effectiveWinId(), true);RevokeDragDrop((HWND)w.winId());
}{QMainWindow w;EnableDrag(w);    // 将窗口的qt拖拽过滤器用windows原生事件过滤器替换掉w.setAcceptDrops(true);    // 设置窗口接收拖拽w.show();a.exec();
}
// 此时窗口已经可以接受拖拽了,重载主窗口的nativeEvent即可
// 或者如果是控件,重写控件的dragEnterEvent等函数即可bool QMainWindow::nativeEvent(const QByteArray& eventType, void* message, long* result) {if (eventType == "windows_generic_MSG" || eventType == "windows_dispatcher_MSG") {MSG* pMsg = reinterpret_cast<MSG*>(message);if (pMsg->message == WM_DROPFILES) {HDROP hDropInfo = (HDROP)pMsg->wParam;wchar_t szFilePathName[_MAX_PATH] = { 0 };const UINT nNumOfFiles = DragQueryFile(hDropInfo, 0xFFFFFFFF, NULL, 0);if (nNumOfFiles > 0) {// DragQueryFile第二个参数为拖入文件的索引DragQueryFile(hDropInfo, 0, szFilePathName, _MAX_PATH); //直接取第一个 入参UINT iFile  = 0const QString currentfile = QString::fromWCharArray(szFilePathName);// currentfile 为当前拖拽文件// OnDragFinished(currentfile);}DragFinish(hDropInfo);}}return false;
}

 


参考文章链接:

https://www.cnblogs.com/SecSource/p/15949135.html

https://learn.microsoft.com/zh-cn/previous-versions/dotnet/articles/bb625963(v=msdn.10)

https://wiki.sei.cmu.edu/confluence/display/c/WIN02-C.+Restrict+privileges+when+spawning+child+processes

https://towriting.com/blog/2013/08/06/process-can-drag-drop/

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/861993.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Podman 安装 harbor

详细描述了在Debian系统上使用Podman部署Harbor的步骤。它包括安装Podman、创建专用网络、下载并加载Harbor镜像,接着依次部署Redis、PostgreSQL、Registry、Portal、JobService、Registryctl、Harbor核心服务和Nginx等组件,最后通过一系列命令检查部署状态并验证服务是否正常…

Linux 统计活跃线程和线程数

使用Linux命令ps -eT动态查看进程中,以指定字符串打头的活跃线程和线程数。摘要:使用Linux命令ps -eT动态查看进程中,以指定字符串打头的活跃线程和线程数。 动态查看进程的线程数及活跃线程数 实现方案在Linux系统中,可以使用以下命令来动态查看进程中名字包含“keyword”…

win平台运行smallpt

smallpt: Global Illumination in 99 lines of C++ 首先在win平台需要添加函数erand48,修改为main函数,其中的samps是每个像素的采样率,越大越慢修改后 #include <math.h> // smallpt, a Path Tracer by Kevin Beason, 2008 #include <stdlib.h> // Make : g+…

对Sentinel的链路分析与客户端服务端交互理解

Sentinel介绍 略 https://sentinelguard.io/zh-cn/ https://github.com/alibaba/Sentinel https://sentinelguard.io/zh-cn/docs/quick-start.html https://github.com/alibaba/Sentinel/wiki/Sentinel-核心类解析 Sentinel定义的术语 Entry: 表示对某个资源的访问请求,通过 S…

手写 k近邻 与 全连接神经网络 算法

KNN(K-近邻算法) K-近邻算法的介绍 参考: https://blog.csdn.net/weixin_39910711/article/details/114440816 手写knn算法,实现mnist的图片数字识别 # 手动 实现knn import io from struct import pack,unpack import random from PIL import Image import time import nump…

jmeter参数化取数机制

场景:参数化文件中只有3个账户 并发数设置的是4 执行一次,如何取值当参数化文件中所有值全部取完后,又会从头开始取值(如图所示,只有三个账户,并发数为4,第1个线程取值和第4个线程取值相同) 如果是一个线程,循环(迭代)4次,取值同上面一致

甲子光年智库发布《中国 AI 算力行业发展报告》

12月30日,甲子光年智库正式发布《中国AI算力行业发展报告》。中昊芯英受邀参与了该报告的编写工作,并为报告的编写贡献了专业的见解和实践经验。12 月 30 日,备受业界关注的《中国 AI 算力行业发展报告》(以下简称「报告」)由甲子光年智库正式发布。该报告为行业内外提供了…

盘点!2024年航空航天大事件

​2024年,航空航天领域再次迎来了丰硕成果。这一年,不仅见证了中国航空航天技术的飞速发展,也目睹了其他国家在航空航天探索中的持续突破。从嫦娥六号完成世界首次月球背面自动采样返回,到SpaceX星舰实现“筷子夹火箭”奇景,航空航天领域呈现出前所未有的活力和创造力。低…

谷歌浏览器json插件

1.下载插件 https://www.baidufe.com/fehelper/index/index.html 2.添加插件 浏览里里打开路径:chrome://extensions/3.将下载好的插件托拽到浏览器里即可 4.效果

lovelymem梭哈solar内存取证---Alex4nd3r

内存取证1 请找到rdp连接的跳板地址flag{192.168.60.220}内存取证2 请找到攻击者下载黑客工具的IP地址控制台信息flag{155.94.204.67}内存取证3 攻击者获取的“FusionManager节点操作系统帐户(业务帐户)”的密码是什么flag{GalaxManager_2012}内存取证4 请找到攻击者创建的用…

hot100-一刷-13堆(共3道题)

215. 数组中的第K个最大元素 题目链接 题目描述代码实现 分析:后面可以看下官方题解的,手动写排序或者大顶堆。代码: class Solution {public int findKthLargest(int[] nums, int k) {PriorityQueue<Integer> pq = new PriorityQueue<>((n1, n2) -> n1 - n2…