作者:周杰
背景
店长:“我电脑右下角总是弹框!”
我:“好的好的,马上处理!”
店长:“我电脑卡死了!”
我:“好的好的,马上处理!”
店长:“我电脑被小游戏占领了!”
远程
好吧,当门店这样反馈的时候,我们还是要处理的。上述情况,很多时候,是病毒、驱动安装程序、杀毒软件等造成的,对于病毒,就用杀毒软件清理,对于驱动安装程序、杀软等,就直接卸载。
最初主要通过teamviewer、向日葵、desktop这几款软件远程处理。步骤大概是:
但这样很麻烦,因为要门店提供远程。有时候门店不知道远程是啥意思,就要向他们解释;甚至有些都没装远程软件,还得告诉他们怎么安装
因此我们需要一种更便捷的远程方式
更便捷的远程
想要实现更便捷的远程,有很多方法,比如常见的远程软件本身都提供了这种能力,只不过需要收费~
我们自己实现了一个小软件:
输入门店编码后就可以直接一键远程过去(具体实现涉及公司信息,不方便说~)
如果有想实现这种一键远程能力的,已知的有几种途径:
- 杀毒软件企业版。其实本文内容,除了最后一点桌面管控,常见杀毒软件基本都能提供。因此可以购买他们的解决方案
- 远程软件企业版。比如teamviewer,他们提供一种批量部署包,被部署的电脑就可以一键远程。当然,部署数量有限制,要根据部署数量购买相应套餐
- github开源软件。github上有些开源软件支持远程能力,可以自己改改来用
删除异常软件
当我们可以一键远程门店电脑后,要删除异常软件就方便很多了
但如果只等门店反馈,再远程过去处理,就很被动。万一哪天门店集中反馈岂不是要完。
因此我们需要一种监控手段,能知道哪些门店有异常软件,一旦发现,我们可以直接远程过去处理掉
监控门店有哪些异常软件
可以从注册表拉取门店安装的软件,比如:
1 | c复制代码public static List<IAppData> getAllSoftWare () { |
接着我们把这些数据上报到云端,就可以知道门店的软件情况了(经测试跟控制面板 - 程序卸载里的程序是一样的)。但这种只能知道安装过的软件,如果是一些不用安装的程序,这里是扫不到的。因为我们目前没这种需求,所以没去看这块,想到的可能的两个方法:
- 扫进程 - 不靠谱,因为任务管理器里的进程是可以被程序隐藏的(使用的技术是下文提到的
SSDT Hook
),另外有些看起来正常的进程是被病毒程序代理的 - 扫文件系统,然后根据特征码识别文件(没错,听起来有点像杀毒软件)
好,这里就已经知道门店的软件列表了。但在前期,我们有很多门店,他们都安装了各种各样我们认为不好的软件,那我们要一家家的远程过去手动删除吗?
自动删除异常软件
自动删除软件有两个问题:
- 程序启动后占用文件,导致文件无法删除
- 杀毒软件对文件都做了权限控制,而且还不允许我们修改权限,导致无法删除(有些病毒也有这个能力),而且拦截了修改注册表操作,我们无法通过改注册表来阻止他开机自启
关于这两个问题,我们找到了一个比较厉害的工具:IObit Unlocker
,这个软件可以单独解除文件占用,也可以直接删除文件,而且支持命令行(大佬们也可以自己写代码做强删,这个复杂点,还在研究,以后有机会再分享~):
1 | c复制代码runCmd('IObitUnlocker.exe /Delete "文件的绝对路径"') |
这个执行后会有个弹框:
这是我们不希望用户看到的,但我们可以通过程序把弹框干掉,只要杀掉IObitUnlocker.exe进程就行了
1 | c复制代码// 杀进程之前判断弹框是否存在,可以用FindWindow函数去查找窗口 |
然后还有个问题是,这个程序是有安装界面的,我们也不希望用户看到,我测了下,把安装后的目录压缩传到云端,然后下载解压到用户电脑,也是能正常用的,这样门店就不会感知到软件安装过程(其实这个软件也支持静默安装,加上/silent参数就可以,但安装后会自动唤起程序,程序本身是有界面的)
好!假设现在我们把所有门店的所有异常软件都清掉了,那这就ok了吗?
非也!事实是没过两天,我们就会通过监控发现门店又出现了大量异常软件!原因是我们删归删,但门店可以再装回来啊~因此我们要彻底根绝门店装异常软件的场景!
拦截软件安装
这里列举两种我们调研或使用的方法,供参考
策略组
策略组是windows
自带的一种安全设置,使用Win键+R打开运行窗口并输入gpedit.msc
,可以打开如下界面:
接着新建规则:
这里有三种策略:
- 发布者。可以根据文件的数字签名做拦截(这种只能拦截MSI/MSP文件)。
- 路径。可以拦截某个指定路径的程序执行,或者拦截某个文件夹下的程序执行。如果选了文件夹,可以从中排除一些需要支持的软件
- 文件hash。系统会根据选择的文件生成hash,从而禁止hash相同的程序执行。比如如果我们要禁止chrome运行,可以配置拒绝Google文件夹内文件执行,此时运行chrome就会有报错提示:
通过这种方式,我们可以配置文件夹拒绝访问,然后把我们常用的几个软件排除掉,这样可以让电脑尽可能干净。
这里也可以通过Powershell
命令行去设置,先打开Powershell
,执行命令:Import-Module AppLocker
,这样就引入了一些AppLocker
的cmdlet,包括:Get-AppLockerPolicy
和Set-AppLockerPolicy
,看名字就知道,这是可以获取和设置AppLocker
的。具体使用可以去microsoft官网搜一下这两个命令
不过这种方式有两个问题:
- 提示内容固定,这是系统自带的,改不了,从体验角度来说,可能是一个不友好的提示。假设门店在电脑上一顿点,然后一顿弹框,门店又看不懂,那必然又是一个工单上来了
- win10/11默认是不支持组策略的,要通过手段去开启,这个可以自行百度
windows hook
程序本质上都是通过系统api唤起的,比如 CreateProcess
, 就跟浏览器上我们可以代理window
对象上的api
一样,我们也可以代理windows
系统的api
,在里面写上逻辑,判断如果是要拦截的程序,就不走原本的CreateProcess
,直接return就完事,核心代码如下(这里的实现用的是minhook
这个库,有兴趣的可以去了解下):
1 | c复制代码// dllmain.cpp : 定义 DLL 应用程序的入口点。 |
上述代码最终会编译成一个dll文件,接着我们要全局注入此dll文件
通过注册表注入
在注册表位置:HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Windows
有一个键:AppInit_DLLs,里面可以放一些dll
再把LoadAppInit_Dlls键的值改为1
原理是当程序加载了user32.dll后,user32.dll会取得上述注册表键的值,并加载。所以这种方式可以把dll注入到所有使用user32.dll的应用程序(user32.dll提供界面相关接口,因此绝大部分程序都会用到user32.dll)
理论上是这样,但实测存在两个限制
1、在64位电脑上只能注入到64位程序中
2、少部分系统进程无法注入
不过包括windows资源管理器(explore.exe
)、cmd、powershell、任务管理器在内的大部分系统进程都能注入。
这里有两种场景要考虑拦截:
1、在桌面或文件夹点击xx.exe
,实际上是explore.exe
这个程序的进程调用createProcess
来创建进程。
2、程序A
通过createProcess
来唤起xx.exe
的进程
第一种场景是可以被拦住的,因为dll可以通过上述方法注入资源管理器里
第二种场景通过windows用户层的hook很难完全拦截,因为不存在什么通用的办法能把dll注入到全局所有进程的。网上还有种全局注入方式,通过SetWindowsHookEx
消息挂钩实现注入,这种方式也有两个问题:
1、32位程序就只能给32位程序注入,要注入64位程序,就得把自己的程序编写为64位的
2、只能注入注册了窗口类的程序(通过测试,感觉是注册了Windows Form类的程序,WPF好像也不行)
所以SetWindowsHookEx
也是无法实现全局注入的。即使把他和注册表方式结合一起,也是无法做到全局注入的
不过我们可以把那些会安装其他软件的软件,统一强制卸载掉,然后只拦第一种场景就可以了
现在我们试试用cmd脚本唤起异常软件的安装程序,写个node
脚本
1 | javascript复制代码const { spawnSync } = require('child_process'); |
然后执行:
可以看到会有报错,实际上是创建进程的时候被拦了,因为cmd会被注入我们的dll,文件夹/桌面点击也会被拦住,效果就是点击安装包没效果
如果想把第二种场景也拦掉,需要借助SSDT HOOK,这是一种内核hook技术,原理是用户层调用CreateProcess
,最终会调到内核层的函数NtCreateProcessEx
。这个函数的地址存在一张叫SSDT的全局的表里,如果我们修改了这个地址指向我们自己的函数,就实现了对他的hook。杀毒软件就普遍使用这种技术来做自我保护、防毒。
关于SSDT hook
的实现,网上有很多很好的文章,可以百度搜索:SSDT 进程保护。感兴趣的同学可以自己去查阅下~
拦截浏览器 + 提供程序安装界面
各种垃圾软件被安装,起初都是因为门店想要安装一个正常的软件,比如音乐软件,然后去浏览器搜索,接着搜索引擎就推荐了一个😒,你懂的~
因此可以有个想法:
- 拦截浏览器进程 (门店用浏览器基本都是下载软件,所以可以拦截)
- 提供一个程序安装界面,引导门店去这里下载
我们判断如果门店要打开浏览器,直接拦截,拦截方式可以用上面拦截软件安装的方式拦截,也可以监听WMI
事件拦截:
1 | c复制代码public static void preventBrowser() |
__InstanceCreationEvent
这个代表系统里一些WMI
对象的创建事件,再通过Where
语句过滤出进程创建事件。
这种方式可以拦截绝大部分手动打开浏览器的行为,不过这种方式有两个地方有延迟,因此不太适合作为通用的软件拦截手段。两个延迟的地方是:
- 监听语句里的
WITHIN 5
,代表判断最近5s有无该类事件,本质就相当于5s轮询,那这就是一个5s的延迟 - 进程信息初始化有段时间,上面有个循环代码等待进程信息初始化。这里也是个延迟
延迟导致一个场景会有问题:如果是通过进程唤起程序静默安装,如果安装过程比较快,跳过了这个延迟,或者在延迟期间已经Hook了系统API做了防杀,那就拦截不了了。但简单拦截手点打开浏览器还是可以的
拦截打开浏览器还有个问题是,要判断是手点浏览器程序,还是浏览器的自动更新等进程。这里我们就没去做这种判断了,直接禁用了常见浏览器的自动更新任务,比如搜狗和火狐禁用如下:
1 | c复制代码Global.RunCmd("schtasks /change /tn \"SogouExplorer Updater Task\" /disable"); |
这里我们拦截浏览器后,弹框引导门店去我们的软件管理里安装想要的程序
点击确定后跳转到程序下载页面
这里就是云端配置好应用列表,点安装后,先下载安装包,然后执行即可。接着获取执行进程是否存在,不存在就可以认为执行完了,就可以再次点安装,否则安装按钮置灰,简单执行+判断代码如下:
1 | c复制代码Process process = new(); |
但这里有个问题:
有些门店会这个操作,我拦他操作,他直接把我程序干没了。。。就这么想要去浏览器下载,看来还是引导做的不够好💀
不过也有个技术手段能处理:像杀毒软件一样做防杀,用的方法就是上面提到的SSDT hook
,不过hook
的是NtTerminateProcess
这个api,判断如果是自己的程序,就return
。然后再结束任务就会出现如下弹框:
但我们没做这个,因为我们发现了一个终极办法,我们希望从根本上引导直至改变门店的认知,把电脑只当作点单机,而非一个正常的电脑。我们想对电脑做更彻底的管控,直接管控整个系统,让他们一看界面就知道,这只是个收银机。这样他们就不会做出一些他们觉得在电脑上能做的,但我们认为危险的操作
桌面管控
界面大概长这样:
功能目前主要是以下4块:
这样等于门店面对的不再是windows系统了,而是一个虚拟界面,在这个界面内模拟一些常规操作,比如唤起程序、网络、关机、音量等,这样门店就只能在点单、收银流程的正常范围进行操作了,门店再也不能愉快打蜘蛛纸牌了
(具体实现,以后有机会再说~)
总结
这篇文章由给门店清理电脑为切入点,讲了一些我们对这种场景的处理办法。
刚开始,由门店反馈过来,给我们提供远程密钥后,我们远程过去清理。
后来我们可以监控门店的软件并直接远程过去清理,甚至可以自动清理,并对门店安装、运行软件的动作进行拦截和管理,以绝后患;
最后对整个桌面做管控,从根本引导并改变门店对点单机的认知。
通过上述手段,我们可以防止门店的误操作导致一些异常软件对系统造成影响。同时大家可以发现,这些手段会大大加强我们对门店收银机的管控能力,这才是最终的目的
小茗推荐
最后
关注公众号「Goodme前端团队」,获取更多干货实践,欢迎交流分享。
本文转载自: 掘金