0x00.前言
终端对抗一直是红队研究的重点内容,本文主要通过前面已有的研究来解开Windows Defender的ASR规则的神秘面纱,由于国内可供参考资料很有限,多以国外会议和议题参考为主
0x01.什么是ASR
ASR位于Microsoft Defender for Endpoint
中,在官方文档中能够看到对其描述:
攻击表面减少是一个功能,有助于防止通常被寻求漏洞的恶意软件使用的行为和应用程序感染机器
https://learn.microsoft.com/zh-cn/microsoft-365/security/defender-endpoint/overview-attack-surface-reduction?view=o365-worldwide
基本上ASR是由一组规则组成的策略,可以设置为如下:
- 1.Disabled(默认策略)
- 2.Enabled
- 3.Audit
其中审核模式允许你查看如果启用了该功能将发生的情况的记录。
在测试功能的工作原理时,可以启用审核模式。 仅为测试,启用审核模式有助于防止审核模式影响业务线应用,还可以了解在一定时间段内发生了多少次可疑的文件修改尝试。简单来说,启用审核模式后,相关操作会记录到事件日志当中
当使用Procmon对MsMpEng.exe
监控时会出现如下情况:
MsMpEng.exe
代表着Windows Defender服务,此服务是需要始终运行的主要Microsoft Defender防病毒服务,也可以理解为是Windows Defender的主题
因此通过上面的过程,我们可以了解到Windows Defender在启动或者运行期间会去查询注册表项:
HKLM\Software\Policies\Microsoft\Windows Defender\Windows Defender Exploit Guard\ASR\Rules
的内容
ASR规则配置则是通过上面注册表项进行配置的,在上图中我们还看到了去查询具体的GUID,这里的GUID对应的是一个个ASR具体规则:
这些GUID规则均在官方文档中给出
因此如果要启用使用高级保护措施防止勒索软件(GUID c1db5bab-c21a-4637-bb3f-a12568109d35),需要将注册表值c1db55ab-c21a-4637-a12568109d35
设置为1。
Defender服务则会不断根据注册表项值来判断是否开启,从而实现对应的功能
这里我们不禁抛出一个问题,例如阻止 Adobe Reader 创建子进程这一ASR规则:
这项规则到底是如何实现的,既然涉及到进程相关,设想有如下解决措施:
- 1.首先通过签名或者Trusted Packages
来检测Adobe进程
- 通过文件路径正则来匹配Adobe进程
- 通过PID和PPID进而查询子进程所处绝对路径进行匹配
在这里只是假设,因此先将问题留在这里
0x02. Defender具体的组成
前文说到MsMpEng.exe
代表着Windows Defender服务,而Windows用户肯定知道Windows Defender,不仅包含了防病毒威胁防护,还有类似云保护、勒索软件服务等功能
并且Defender每个月会自动进行更新,当然也可以进行手动更新:
要清除当前缓存并触发更新,请使用以管理员身份运行以下命令的批处理脚本:
cd %ProgramFiles%\Windows Defender
MpCmdRun.exe -removedefinitions -dynamicsignatures
MpCmdRun.exe -SignatureUpdate
高兴的是微软文档中也提到了对于Defender更新的详细说明:
https://www.microsoft.com/en-us/wdsi/defenderupdates
下载的更新包为mpam-fe.exe
,其中通过cabextract
可以将其进行解包,得到如下6个文件:
- 1.mpengine.dll 微软恶意软件保护引擎,包含了微软的恶意软件保护引擎。
.vdm文件
会被恶意软件保护引擎引用,该引擎会扫描寻找恶意软件的系统资源。系统资源的一些示例是文件、进程和注册表项。这个文件通常每月只更新一次。 - 2.MPSigStub.exe 微软恶意软件保护签名更新存根,用于下载完整的软件和节省带宽
- 3.mpasbase.vdm,包含反间谍软件基本定义模块。这个文件通常是由微软每月只更新一次,并包含基础间谍软件信息和其他潜在的不需要的软件信息,用于构建增量定义。
- 4.mpasdlta.vdm,包含反间谍软件增量定义模块。这个文件通常由微软每周更新多次,并包含自上次反间谍软件基础创建以来发生的所有更改。
- 5.mpavbase.vdm,包含防病毒基础定义模块。这个文件通常由微软每月只更新一次,并包含用于构建增量定义的基本病毒信息。
- 6.mpavdlta.vdm,包含防病毒增量定义模块。这个文件通常由微软每天更新多次,并包含自上次创建防病毒库以来发生的所有更改。
其中mpengine.dll是Windows Defender核心的DLL文件,其中它包含了JS引擎,它继承了JS的一些基础语法,其中它支持eval函数,但是它会对eval函数的参数进行检测,如果发现恶意数据则会进行拦截,通俗的说Defender中是包含了一个JS引擎的,用于分析潜在的恶意代码
并且会通过triggerEvent
进行回调:
其中在@slipstream的工作中涉及到了针对triggerEvent
的利用,不过年份已久,给出的文件已经无法下载
https://mastodon.social/@slipstream/5485890
这里也没有进一步深入,不再叙述
0x03.mpengine.dll的那些事
借用国外研究人员发表的议题来看,mpengine.dll干了这么几件事:
- 1.加载未知的潜在恶意二进制文件
- 2.从入口点开始运行,并运行到终止条件,并且记录时间、指令数、API调用的数量、使用内存大小等
- 3.收集关于运行时行为的启发式观察,在内存中查找签名或放到磁盘等等
由于此篇主要针对于ASR相关进行展开,对mpengine.dll
的逆向会比较简短,同样也是参考之前已有的成果而言,针对上图而言,可以分为扫描的入口点,CPU模拟、系统和环境模拟、输出恶意描述等
1.Startup
该函数提供了一个入口点以便于进入Defender的扫描过程当中,参数为指定的数据缓冲区,它将返回一个恶意软件的分类
Defender主要使用模拟的方式来分析可执行程序,个人感觉类似于沙箱机制,并且模拟结果被缓存,意味着一个给定的二进制文件即使被扫描多次,最终也将只被模拟一次
首先是将可执行程序的相关参数传入到CreateProcessA
中,随后调用pe_create_process
跟进该函数继续调用PreCreateProcess
:
调用MpSuppCreate
,判断是创建Mp扫描器
在该函数中会做出一些判断,例如如果不是当前环境下可执行的,则会调用CleanProcess退出:
如果满足相关要求,则会调用pefile_scan_mp
函数对扫描的PE进行解析:
这里会对PE文件作出一个完整的解析后,调用pea_set_attributes
进行相关变量设置:
该函数会调用MpSetAttribute
来设置PE文件中包括sectionName、Ntheader、导入导出表等非常多的属性:
其中在pe_parse_imports
函数中来模拟导入函数时会调用vdll_get_index_by_name
初始化进程内存空间中的虚拟dll
2.CPU Emulation
这一部分比较复杂,我也没有深入去看,首先需要清楚地一点是Defender是支持许多体系结构,在模拟器执行过程中会转化成IL中间语言:
例如在x86_IL_translator::translate
中,将push寄存器的字节码进行翻译转换
而模拟器是可以运行IL中间语言的:
其他不再叙述
3.输出恶意描述
在每次的版本更新中都会发布更新检测的恶意软件描述:
以2022.10.28的更新为例:
https://www.microsoft.com/en-us/wdsi/definitions/antimalware-definition-release-notes?requestVersion=1.377.965.0
其中get_category_from_name
会将参数的名字同目前已有的威胁描述名相匹配:
一共对应29个威胁描述名称:
最后会通过__rsignal
入口函数返回。
0x04.ASR规则实现及提取
前文说到ASR实际上对应的是一组组规则,并且以GUID的形式在注册表中呈现,那么对于ASR规则实现的查找可以分为如下几个方面:
- 1.在DLL中寻找有关ASR GUID的内容
- 2.在VDM的原始文件中搜索
- 3.在DLL中搜索ASR关键词,查看是否与ASR规则相关
在@commial的研究中发现对于ASR规则的实现会调用mp_lua_IsHipsRuleEnabled
:
其中ksignal->completeEngineInitialization->HipsManager::LoadRulesFromDatabase
调用链中可以看到LoadRulesFromDatabase
调用CallInitScrtipts
调用内置脚本,继续跟进
该函数会首先将Lua执行引擎所需要的依赖导入后,调用LuaStandaloneScriptRunner::RunScript
来执行内置的Lua脚本
逆向到这,其实不难发现Defender中除了有一套完整的JS引擎之外还存在Lua引擎,负责对ASR的解析和处理相关,在这里VDM文件就派上用场了,前文说过VDM文件包含了更新的增量定义和更新的所有更改,我们可以利用WDExtract将VDM文件提取出来
将提取后的文件用16进制编辑器打开,并且搜索对应ASR的GUID可以发现(以7674ba52-37eb-4a4f-a9a1-f0f9a1619a2c
为例):
其中包含了对应ASR规则的GUID和LUAC文件头1B 4C 75 61 51
,其中51代表的是Lua Version
version字段表示Luac文件的格式版本,它的值对应于Lua编译的版本,对于 5.1 版本的 Lua 生成的 Luac 文件,它的值为 0x51。
我们将这一部分字节提取出来,从3D00670到3D04788中间的部分,对应的则是GUID为674ba52-37eb-4a4f-a9a1-f0f9a1619a2c
的ASR规则的lua指令
如何提取
LuaDec支持对Lua的反编译,可以将luac文件进行反编译,并且支持从Lua 5.1开始,而这正是Defender中所使用的Lua版本:
当我们想要使用Luadec进行反编译时发现报错:
这里利用@commial所做的工作能够恢复为luadec解析的luac文件:
parse.py
随后通过luadec解析后可以发现已经能够得到该ASR对应的lua脚本规则:
这是关于阻止 Adobe Reader 创建子进程
ASR规则的Lua脚本,其中我们可以看到存在GetRuleInfo
函数
-- Decompiled using luadec 2.2 rev: 895d923 for Lua 5.1 from https://github.com/viruscamp/luadec
-- Command line: 674ba52-37eb-4a4f-a9a1-f0f9a1619a2c.luac.parse
-- params : ...
-- function num : 0
GetRuleInfo = function()
-- function num : 0_0
local l_1_0 = {}
l_1_0.Name = "Block Adobe Reader from creating child processes"
l_1_0.Description = "Windows Defender Exploit Guard detected Adobe Reader launching child process"
l_1_0.NotificationDedupingInterval = 120
l_1_0.NotificationDedupingScope = HIPS.DEDUPE_SCOPE_UI
return l_1_0
end
GetMonitoredLocations = function()
-- function num : 0_1
local l_2_0 = {}
l_2_0["%programfiles%\\adobe\\acrobat reader 2015\\reader\\acrord32.exe"] = 2
l_2_0["%programfiles%\\adobe\\acrobat reader 2017\\reader\\acrord32.exe"] = 2
l_2_0["%programfiles%\\adobe\\acrobat reader 2018\\reader\\acrord32.exe"] = 2
l_2_0["%programfiles%\\adobe\\acrobat reader dc\\reader\\acrord32.exe"] = 2
l_2_0["%programfiles%\\adobe\\reader 10.0\\reader\\acrord32.exe"] = 2
l_2_0["%programfiles%\\adobe\\reader 11.0\\reader\\acrord32.exe"] = 2
l_2_0["%programfiles%\\adobe\\reader 8.0\\reader\\acrord32.exe"] = 2
l_2_0["%programfiles%\\adobe\\reader 9.0\\reader\\acrord32.exe"] = 2
l_2_0["%programfiles%\\adobe\\reader\\11.0\\reader\\acrord32.exe"] = 2
l_2_0["%programfiles%\\adobe\\reader\\acrord32.exe"] = 2
l_2_0["%programfiles%\\adobe\\reader\\reader\\acrord32.exe"] = 2
l_2_0["%programfiles(x86)%\\adobe\\acrobat reader 2015\\reader\\acrord32.exe"] = 2
l_2_0["%programfiles(x86)%\\adobe\\acrobat reader 2017\\reader\\acrord32.exe"] = 2
l_2_0["%programfiles(x86)%\\adobe\\acrobat reader 2018\\reader\\acrord32.exe"] = 2
l_2_0["%programfiles(x86)%\\adobe\\acrobat reader dc\\reader\\acrord32.exe"] = 2
l_2_0["%programfiles(x86)%\\adobe\\reader 10.0\\reader\\acrord32.exe"] = 2
l_2_0["%programfiles(x86)%\\adobe\\reader 11.0\\reader\\acrord32.exe"] = 2
l_2_0["%programfiles(x86)%\\adobe\\reader 8.0\\reader\\acrord32.exe"] = 2
l_2_0["%programfiles(x86)%\\adobe\\reader 9.0\\reader\\acrord32.exe"] = 2
l_2_0["%programfiles(x86)%\\adobe\\reader\\11.0\\reader\\acrord32.exe"] = 2
l_2_0["%programfiles(x86)%\\adobe\\reader\\acrord32.exe"] = 2
l_2_0["%programfiles(x86)%\\adobe\\reader\\reader\\acrord32.exe"] = 2
l_2_0["%programfiles%\\adobe\\acrobat 10.0\\acrobat\\acrobat.exe"] = 2
l_2_0["%programfiles%\\adobe\\acrobat 11.0\\acrobat\\acrobat.exe"] = 2
l_2_0["%programfiles%\\adobe\\acrobat 2015\\acrobat\\acrobat.exe"] = 2
l_2_0["%programfiles%\\adobe\\acrobat 2017\\acrobat\\acrobat.exe"] = 2
l_2_0["%programfiles%\\adobe\\acrobat 5.0\\acrobat\\acrobat.exe"] = 2
l_2_0["%programfiles%\\adobe\\acrobat 6.0\\acrobat\\acrobat.exe"] = 2
l_2_0["%programfiles%\\adobe\\acrobat 7.0\\acrobat\\acrobat.exe"] = 2
l_2_0["%programfiles%\\adobe\\acrobat 8.0\\acrobat\\acrobat.exe"] = 2
l_2_0["%programfiles%\\adobe\\acrobat 9.0\\acrobat\\acrobat.exe"] = 2
l_2_0["%programfiles%\\adobe\\acrobat dc\\acrobat\\acrobat.exe"] = 2
l_2_0["%programfiles(x86)%\\adobe\\acrobat 10.0\\acrobat\\acrobat.exe"] = 2
l_2_0["%programfiles(x86)%\\adobe\\acrobat 11.0\\acrobat\\acrobat.exe"] = 2
l_2_0["%programfiles(x86)%\\adobe\\acrobat 2015\\acrobat\\acrobat.exe"] = 2
l_2_0["%programfiles(x86)%\\adobe\\acrobat 2017\\acrobat\\acrobat.exe"] = 2
l_2_0["%programfiles(x86)%\\adobe\\acrobat 5.0\\acrobat\\acrobat.exe"] = 2
l_2_0["%programfiles(x86)%\\adobe\\acrobat 6.0\\acrobat\\acrobat.exe"] = 2
l_2_0["%programfiles(x86)%\\adobe\\acrobat 7.0\\acrobat\\acrobat.exe"] = 2
l_2_0["%programfiles(x86)%\\adobe\\acrobat 8.0\\acrobat\\acrobat.exe"] = 2
l_2_0["%programfiles(x86)%\\adobe\\acrobat 9.0\\acrobat\\acrobat.exe"] = 2
l_2_0["%programfiles(x86)%\\adobe\\acrobat dc\\acrobat\\acrobat.exe"] = 2
return 1, l_2_0
end
GetPathExclusions = function()
-- function num : 0_2
local l_3_0 = {}
l_3_0["%commonprogramfiles%\\adobe"] = 2
l_3_0["%commonprogramfiles%\\microsoft shared"] = 2
l_3_0["%commonprogramfiles(x86)%\\adobe"] = 2
l_3_0["%commonprogramfiles(x86)%\\microsoft shared"] = 2
l_3_0["%programdata%\\app-v"] = 2
l_3_0["%programfiles%\\acrobat"] = 2
l_3_0["%programfiles%\\adobe"] = 2
l_3_0["%programfiles%\\firefox developer edition"] = 2
l_3_0["%programfiles%\\foxit software"] = 2
l_3_0["%programfiles%\\google"] = 2
l_3_0["%programfiles%\\internet explorer"] = 2
l_3_0["%programfiles%\\microsoft application virtualization\\client\\subsystems\\appvdllsurrogate32.exe"] = 2
l_3_0["%programfiles%\\microsoft application virtualization\\client\\subsystems\\appvdllsurrogate64.exe"] = 2
l_3_0["%programfiles%\\microsoft office 15"] = 2
l_3_0["%programfiles%\\microsoft office 2003"] = 2
l_3_0["%programfiles%\\microsoft office 2010"] = 2
l_3_0["%programfiles%\\microsoft office 2016"] = 2
l_3_0["%programfiles%\\microsoft office"] = 2
l_3_0["%programfiles%\\microsoft office2003"] = 2
l_3_0["%programfiles%\\microsoft office2007"] = 2
l_3_0["%programfiles%\\microsoft office\\2010"] = 2
l_3_0["%programfiles%\\microsoft office\\live meeting 8"] = 2
l_3_0["%programfiles%\\microsoft office\\office"] = 2
l_3_0["%programfiles%\\microsoft office\\office10"] = 2
l_3_0["%programfiles%\\microsoft office\\office11"] = 2
l_3_0["%programfiles%\\microsoft office\\office12"] = 2
l_3_0["%programfiles%\\microsoft office\\office13"] = 2
l_3_0["%programfiles%\\microsoft office\\office14"] = 2
l_3_0["%programfiles%\\microsoft office\\office15"] = 2
l_3_0["%programfiles%\\microsoft office\\office16"] = 2
l_3_0["%programfiles%\\microsoft office\\root\\2010"] = 2
l_3_0["%programfiles%\\microsoft office\\root\\client\\appvdllsurrogate32.exe"] = 2
l_3_0["%programfiles%\\microsoft office\\root\\client\\appvdllsurrogate64.exe"] = 2
l_3_0["%programfiles%\\microsoft office\\root\\live meeting 8"] = 2
l_3_0["%programfiles%\\microsoft office\\root\\office"] = 2
l_3_0["%programfiles%\\microsoft office\\root\\office10"] = 2
l_3_0["%programfiles%\\microsoft office\\root\\office11"] = 2
l_3_0["%programfiles%\\microsoft office\\root\\office12"] = 2
l_3_0["%programfiles%\\microsoft office\\root\\office13"] = 2
l_3_0["%programfiles%\\microsoft office\\root\\office14"] = 2
l_3_0["%programfiles%\\microsoft office\\root\\office15"] = 2
l_3_0["%programfiles%\\microsoft office\\root\\office16"] = 2
l_3_0["%programfiles%\\microsoft office\\root\\updates"] = 2
l_3_0["%programfiles%\\microsoft office\\root\\vfs"] = 2
l_3_0["%programfiles%\\microsoft office\\root\\visio"] = 2
l_3_0["%programfiles%\\microsoft office\\root\\visio10"] = 2
l_3_0["%programfiles%\\microsoft office\\root\\visio11"] = 2
l_3_0["%programfiles%\\microsoft office\\root\\visio12"] = 2
l_3_0["%programfiles%\\microsoft office\\root\\visio13"] = 2
l_3_0["%programfiles%\\microsoft office\\updates"] = 2
l_3_0["%programfiles%\\microsoft office\\vfs"] = 2
l_3_0["%programfiles%\\microsoft office\\visio"] = 2
l_3_0["%programfiles%\\microsoft office\\visio10"] = 2
l_3_0["%programfiles%\\microsoft office\\visio11"] = 2
l_3_0["%programfiles%\\microsoft office\\visio12"] = 2
l_3_0["%programfiles%\\microsoft office\\visio13"] = 2
l_3_0["%programfiles%\\microsoft security client"] = 2
l_3_0["%programfiles%\\mozilla firefox"] = 2
l_3_0["%programfiles%\\opera"] = 2
l_3_0["%programfiles%\\reader"] = 2
l_3_0["%programfiles%\\sogouinput"] = 2
l_3_0["%programfiles%\\tencent"] = 2
l_3_0["%programfiles%\\ucbrowser"] = 2
l_3_0["%programfiles%\\winrar"] = 2
l_3_0["%programfiles%\\winzip"] = 2
l_3_0["%programfiles%\\Microsoft\\Edge\\Application"] = 2
l_3_0["%programfiles%\\Microsoft\\Edge\\Application\\msedge.exe"] = 2
l_3_0["%programfiles%\\Microsoft\\Edge Dev\\Application\\msedge.exe"] = 2
l_3_0["%programfiles%\\Microsoft\\Edge Beta\\Application\\msedge.exe"] = 2
l_3_0["%programfiles%\\Microsoft\\Edge\\Application\\*\\msedgewebview2.exe"] = 2
l_3_0["%programfiles%\\Microsoft\\Edge Dev\\Application\\*\\msedgewebview2.exe"] = 2
l_3_0["%programfiles%\\Microsoft\\Edge Beta\\Application\\*\\msedgewebview2.exe"] = 2
l_3_0["%programfiles%\\Microsoft\\EdgeWebView\\Application\\*\\msedgewebview2.exe"] = 2
l_3_0["%programfiles(x86)%\\acrobat"] = 2
l_3_0["%programfiles(x86)%\\acrobat dc"] = 2
l_3_0["%programfiles(x86)%\\adobe"] = 2
l_3_0["%programfiles(x86)%\\firefox developer edition"] = 2
l_3_0["%programfiles(x86)%\\foxit software"] = 2
l_3_0["%programfiles(x86)%\\google"] = 2
l_3_0["%programfiles(x86)%\\internet explorer"] = 2
l_3_0["%programfiles(x86)%\\microsoft application virtualization\\client\\subsystems\\appvdllsurrogate32.exe"] = 2
l_3_0["%programfiles(x86)%\\microsoft application virtualization\\client\\subsystems\\appvdllsurrogate64.exe"] = 2
l_3_0["%programfiles(x86)%\\microsoft office 15"] = 2
l_3_0["%programfiles(x86)%\\microsoft office 2003"] = 2
l_3_0["%programfiles(x86)%\\microsoft office 2010"] = 2
l_3_0["%programfiles(x86)%\\microsoft office 2016"] = 2
l_3_0["%programfiles(x86)%\\microsoft office"] = 2
l_3_0["%programfiles(x86)%\\microsoft office2003"] = 2
l_3_0["%programfiles(x86)%\\microsoft office2007"] = 2
l_3_0["%programfiles(x86)%\\microsoft office\\2010"] = 2
l_3_0["%programfiles(x86)%\\microsoft office\\live meeting 8"] = 2
l_3_0["%programfiles(x86)%\\microsoft office\\office"] = 2
l_3_0["%programfiles(x86)%\\microsoft office\\office10"] = 2
l_3_0["%programfiles(x86)%\\microsoft office\\office11"] = 2
l_3_0["%programfiles(x86)%\\microsoft office\\office12"] = 2
l_3_0["%programfiles(x86)%\\microsoft office\\office13"] = 2
l_3_0["%programfiles(x86)%\\microsoft office\\office14"] = 2
l_3_0["%programfiles(x86)%\\microsoft office\\office15"] = 2
l_3_0["%programfiles(x86)%\\microsoft office\\office16"] = 2
l_3_0["%programfiles(x86)%\\microsoft office\\root\\2010"] = 2
l_3_0["%programfiles(x86)%\\microsoft office\\root\\client\\appvdllsurrogate32.exe"] = 2
l_3_0["%programfiles(x86)%\\microsoft office\\root\\client\\appvdllsurrogate64.exe"] = 2
l_3_0["%programfiles(x86)%\\microsoft office\\root\\live meeting 8"] = 2
l_3_0["%programfiles(x86)%\\microsoft office\\root\\office"] = 2
l_3_0["%programfiles(x86)%\\microsoft office\\root\\office10"] = 2
l_3_0["%programfiles(x86)%\\microsoft office\\root\\office11"] = 2
l_3_0["%programfiles(x86)%\\microsoft office\\root\\office12"] = 2
l_3_0["%programfiles(x86)%\\microsoft office\\root\\office13"] = 2
l_3_0["%programfiles(x86)%\\microsoft office\\root\\office14"] = 2
l_3_0["%programfiles(x86)%\\microsoft office\\root\\office15"] = 2
l_3_0["%programfiles(x86)%\\microsoft office\\root\\office16"] = 2
l_3_0["%programfiles(x86)%\\microsoft office\\root\\updates"] = 2
l_3_0["%programfiles(x86)%\\microsoft office\\root\\vfs"] = 2
l_3_0["%programfiles(x86)%\\microsoft office\\root\\visio"] = 2
l_3_0["%programfiles(x86)%\\microsoft office\\root\\visio10"] = 2
l_3_0["%programfiles(x86)%\\microsoft office\\root\\visio11"] = 2
l_3_0["%programfiles(x86)%\\microsoft office\\root\\visio12"] = 2
l_3_0["%programfiles(x86)%\\microsoft office\\root\\visio13"] = 2
l_3_0["%programfiles(x86)%\\microsoft office\\updates"] = 2
l_3_0["%programfiles(x86)%\\microsoft office\\vfs"] = 2
l_3_0["%programfiles(x86)%\\microsoft office\\visio"] = 2
l_3_0["%programfiles(x86)%\\microsoft office\\visio10"] = 2
l_3_0["%programfiles(x86)%\\microsoft office\\visio11"] = 2
l_3_0["%programfiles(x86)%\\microsoft office\\visio12"] = 2
l_3_0["%programfiles(x86)%\\microsoft office\\visio13"] = 2
l_3_0["%programfiles(x86)%\\microsoft security client"] = 2
l_3_0["%programfiles(x86)%\\mozilla firefox"] = 2
l_3_0["%programfiles(x86)%\\opera"] = 2
l_3_0["%programfiles(x86)%\\reader"] = 2
l_3_0["%programfiles(x86)%\\sogouinput"] = 2
l_3_0["%programfiles(x86)%\\tencent"] = 2
l_3_0["%programfiles(x86)%\\ucbrowser"] = 2
l_3_0["%programfiles(x86)%\\winrar"] = 2
l_3_0["%programfiles(x86)%\\winzip"] = 2
l_3_0["%programfiles(x86)%\\Microsoft\\Edge\\Application"] = 2
l_3_0["%programfiles(x86)%\\Microsoft\\Edge\\Application\\msedge.exe"] = 2
l_3_0["%programfiles(x86)%\\Microsoft\\Edge Dev\\Application\\msedge.exe"] = 2
l_3_0["%programfiles(x86)%\\Microsoft\\Edge Beta\\Application\\msedge.exe"] = 2
l_3_0["%programfiles(x86)%\\Microsoft\\Edge\\Application\\*\\msedgewebview2.exe"] = 2
l_3_0["%programfiles(x86)%\\Microsoft\\Edge Dev\\Application\\*\\msedgewebview2.exe"] = 2
l_3_0["%programfiles(x86)%\\Microsoft\\Edge Beta\\Application\\*\\msedgewebview2.exe"] = 2
l_3_0["%programfiles(x86)%\\Microsoft\\EdgeWebView\\Application\\*\\msedgewebview2.exe"] = 2
l_3_0["%programW6432%\\Microsoft\\Edge\\Application\\msedge.exe"] = 2
l_3_0["%programW6432%\\Microsoft\\Edge Dev\\Application\\msedge.exe"] = 2
l_3_0["%programW6432%\\Microsoft\\Edge Beta\\Application\\msedge.exe"] = 2
l_3_0["%programW6432%\\Microsoft\\Edge\\Application\\*\\msedgewebview2.exe"] = 2
l_3_0["%programW6432%\\Microsoft\\Edge Dev\\Application\\*\\msedgewebview2.exe"] = 2
l_3_0["%programW6432%\\Microsoft\\Edge Beta\\Application\\*\\msedgewebview2.exe"] = 2
l_3_0["%programW6432%\\Microsoft\\EdgeWebView\\Application\\*\\msedgewebview2.exe"] = 2
l_3_0["%programfiles(x86)%\\BraveSoftware\\Brave-Browser\\Application\\brave.exe"] = 2
l_3_0["%localappdata%\\microsoft\\edge\\application\\msedge.exe"] = 1
l_3_0["%localappdata%\\microsoft\\edge sxs\\application\\msedge.exe"] = 1
l_3_0["%localappdata%\\microsoft\\edge dev\\application\\msedge.exe"] = 1
l_3_0["%localappdata%\\microsoft\\edge beta\\application\\msedge.exe"] = 1
l_3_0["%localappdata%\\microsoft\\edgewebview\\application\\*\\msedgewebview2.exe"] = 1
l_3_0["%localappdata%\\microsoft\\edge sxs\\application\\*\\msedgewebview2.exe"] = 1
l_3_0["%localappdata%\\microsoft\\edge dev\\application\\*\\msedgewebview2.exe"] = 1
l_3_0["%localappdata%\\microsoft\\edge beta\\application\\*\\msedgewebview2.exe"] = 1
l_3_0["%localappdata%\\mozilla firefox\\*\\firefoxportable\\app\\firefox64\\firefox.exe"] = 1
l_3_0["%localappdata%\\mozilla firefox\\firefox.exe"] = 1
l_3_0["%localappdata%\\centbrowser\\application\\chrome.exe"] = 1
l_3_0["%localappdata%\\chromium\\application\\chrome.exe"] = 1
l_3_0["%localappdata%\\epic privacy browser\\application\\epic.exe"] = 1
l_3_0["%localappdata%\\firefox developer edition\\firefox.exe"] = 1
l_3_0["%localappdata%\\google chrome\\*\\googlechromeportable\\app\\chrome-bin\\chrome.exe"] = 1
l_3_0["%localappdata%\\google\\chrome beta\\application\\chrome.exe"] = 1
l_3_0["%localappdata%\\google\\chrome dev\\application\\chrome.exe"] = 1
l_3_0["%localappdata%\\google\\chrome sxs\\application\\chrome.exe"] = 1
l_3_0["%localappdata%\\google\\chrome\\application\\chrome.exe"] = 1
l_3_0["%windir%\\explorer.exe"] = 2
l_3_0["%windir%\\microsoft.net\\framework\\*\\dw20.exe"] = 2
l_3_0["%windir%\\notepad.exe"] = 2
l_3_0["%windir%\\splwow64.exe"] = 2
l_3_0["%windir%\\ssdal.exe"] = 2
l_3_0["%windir%\\system32\\atbroker.exe"] = 2
l_3_0["%windir%\\system32\\bdeunlock.exe"] = 2
l_3_0["%windir%\\system32\\buaappnt.exe"] = 2
l_3_0["%windir%\\system32\\conhost.exe"] = 2
l_3_0["%windir%\\system32\\ctfmon.exe"] = 2
l_3_0["%windir%\\system32\\dwwin.exe"] = 2
l_3_0["%windir%\\system32\\ie4uinit.exe"] = 2
l_3_0["%windir%\\system32\\igfxem.exe"] = 2
l_3_0["%windir%\\system32\\igfxhk.exe"] = 2
l_3_0["%windir%\\system32\\igfxtray.exe"] = 2
l_3_0["%windir%\\system32\\macromed\\flash\\flashplayerupdateservice.exe"] = 2
l_3_0["%windir%\\system32\\microsoft.uev.synccontroller.exe"] = 2
l_3_0["%windir%\\system32\\notepad.exe"] = 2
l_3_0["%windir%\\system32\\ntprint.exe"] = 2
l_3_0["%windir%\\system32\\pcaui.exe"] = 2
l_3_0["%windir%\\system32\\searchprotocolhost.exe"] = 2
l_3_0["%windir%\\system32\\slui.exe"] = 2
l_3_0["%windir%\\system32\\spool\\drivers"] = 2
l_3_0["%windir%\\system32\\verclsid.exe"] = 2
l_3_0["%windir%\\system32\\werfault.exe"] = 2
l_3_0["%windir%\\system32\\werfaultsecure.exe"] = 2
l_3_0["%windir%\\system32\\wermgr.exe"] = 2
l_3_0["%windir%\\system32\\wevtutil.exe"] = 2
l_3_0["%windir%\\system32\\wfs.exe"] = 2
l_3_0["%windir%\\system32\\xpsrchvw.exe"] = 2
l_3_0["%windir%\\system32\\msiexec.exe"] = 2
l_3_0["%windir%\\syswow64\\config\\systemprofile\\sogouinput\\*\\sgtool.exe"] = 2
l_3_0["%windir%\\syswow64\\ctfmon.exe"] = 2
l_3_0["%windir%\\syswow64\\dwwin.exe"] = 2
l_3_0["%windir%\\syswow64\\ieunatt.exe"] = 2
l_3_0["%windir%\\syswow64\\ime\\imejp\\imjpdct.exe"] = 2
l_3_0["%windir%\\syswow64\\ime\\shared\\imecfmui.exe"] = 2
l_3_0["%windir%\\syswow64\\ime\\shared\\imepadsv.exe"] = 2
l_3_0["%windir%\\syswow64\\macromed\\flash\\flashplayerupdateservice.exe"] = 2
l_3_0["%windir%\\syswow64\\mspaint.exe"] = 2
l_3_0["%windir%\\syswow64\\notepad.exe"] = 2
l_3_0["%windir%\\syswow64\\openwith.exe"] = 2
l_3_0["%windir%\\syswow64\\prevhost.exe"] = 2
l_3_0["%windir%\\syswow64\\verclsid.exe"] = 2
l_3_0["%windir%\\syswow64\\werfault.exe"] = 2
l_3_0["%windir%\\syswow64\\wermgr.exe"] = 2
l_3_0["%windir%\\syswow64\\xpsrchvw.exe"] = 2
l_3_0["%windir%\\syswow64\\msiexec.exe"] = 2
l_3_0["%windir%\\syswow64\\launchwinapp.exe"] = 2
l_3_0["%windir%\\systemapps\\*\\microsoftedgecp.exe"] = 2
l_3_0["%windir%\\winsxs\\*\\iexplore.exe"] = 2
l_3_0["%windir%\\winsxs\\*\\splwow64.exe"] = 2
l_3_0["%windir%\\winsxs\\*\\werfault.exe"] = 2
l_3_0["%windir%\\system32\fsiso.exe"] = 2
l_3_0["%userprofile%\\appdata\\local\\google\\chrome"] = 1
l_3_0["%userprofile%\\appdata\\local\\microsoft\\onedrive"] = 1
l_3_0["%userprofile%\\appdata\\locallow\\copitrak"] = 1
l_3_0["%userprofile%\\appdata\\local\\centbrowser\\application\\chrome.exe"] = 1
l_3_0["%userprofile%\\appdata\\local\\microsoft\\edge\\application\\msedge.exe"] = 1
l_3_0["%userprofile%\\appdata\\local\\microsoft\\edge sxs\\application\\msedge.exe"] = 1
l_3_0["%userprofile%\\appdata\\local\\microsoft\\edge dev\\application\\msedge.exe"] = 1
l_3_0["%userprofile%\\appdata\\local\\microsoft\\edge beta\\application\\msedge.exe"] = 1
l_3_0["%userprofile%\\appdata\\local\\microsoft\\edgewebview\\application\\*\\msedgewebview2.exe"] = 1
l_3_0["%userprofile%\\appdata\\local\\microsoft\\edge sxs\\application\\*\\msedgewebview2.exe"] = 1
l_3_0["%userprofile%\\appdata\\local\\microsoft\\edge dev\\application\\*\\msedgewebview2.exe"] = 1
l_3_0["%userprofile%\\appdata\\local\\microsoft\\edge beta\\application\\*\\msedgewebview2.exe"] = 1
l_3_0["%userprofile%\\appdata\\local\\mozilla firefox\\*\\firefoxportable\\app\\firefox64\\firefox.exe"] = 1
l_3_0["%userprofile%\\appdata\\local\\mozilla firefox\\firefox.exe"] = 1
l_3_0["%userprofile%\\appdata\\local\\packages\\*\\localcache\\local\\google\\chrome\\application\\chrome.exe"] = 1
l_3_0["%userprofile%\\appdata\\local\\packages\\*\\localcache\\local\\mozilla firefox\\firefox.exe"] = 1
return l_3_0
end
GetCommandLineExclusions = function()
-- function num : 0_3
local l_4_0 = "\\\"?rundll32(\\.exe)?\\\"?\\s+\\\"?.:\\\\windows\\\\system32\\\\spool\\\\drivers\\\\x64\\\\\\d+\\\\hpmsn\\d+\\.dll\\\"?,monitorprintjobstatus\\s+/pjob=\\d+\\s+/pname"
local l_4_1 = {}
l_4_1[l_4_0] = 0
return l_4_1
end
而该函数在mpengine.dll中被LoadRulesFromDatabase
所调用:
因此,我们可以通过遍历所有的lua标志来解析VDM文件中所有的lua脚本,其中自然包括所有的ASR规则,这里笔者已经提取出Released: 10/28/2022 9:21:17 PM
的lua脚本,放置在Github中(暂为Private)
https://github.com/crisprss/Extracted_WD_VDM
0x05.ASR Lua解析
下面对反编译的lua脚本深入分析,首先便是GetRuleInfo
函数,函数主要是申明ASR规则的名称、描述等相关信息,这里让我们以GUID为be9ba2d9-53ea-4cdc-84e5-9b1eeee46550
为例,其代表的ASR规则为阻止电子邮件客户端和 Webmail 中的可执行内容
-- Decompiled using luadec 2.2 rev: 895d923 for Lua 5.1 from https://github.com/viruscamp/luadec
-- Command line: ./lua/3527.luac
-- params : ...
-- function num : 0
local l_0_0 = function(l_1_0, l_1_1)
-- function num : 0_0
local l_1_2 = {}
l_1_2[1952539182] = ""
l_1_2[1684890414] = ""
l_1_2[1836016430] = ""
l_1_2[1819304750] = ""
l_1_2[1702389038] = ""
l_1_2[1718186030] = ""
l_1_2[1919120174] = ""
l_1_2[1935832622] = ""
l_1_2[1802398766] = ""
l_1_2[1718843182] = ""
l_1_2[1700951598] = ""
l_1_2[1702062638] = ""
l_1_2[1635018798] = ""
l_1_2[1936338432] = ""
l_1_2[1819042862] = ""
l_1_2[2019782446] = ""
l_1_2[1918986798] = ""
l_1_2[1668511534] = ""
l_1_2[1752397614] = ""
local l_1_3 = (mp.bitor)((mp.readu_u32)(l_1_0, l_1_1), 538976288)
if l_1_2[l_1_3] or l_1_2[(mp.bitand)(l_1_3, 4294967040)] then
return true
end
return false
end
if not (mp.IsHipsRuleEnabled)("be9ba2d9-53ea-4cdc-84e5-9b1eeee46550") then
return mp.CLEAN
end
if (mp.get_contextdata)(mp.CONTEXT_DATA_SCANREASON) ~= mp.SCANREASON_ONMODIFIEDHANDLECLOSE then
return mp.CLEAN
end
if (mp.get_contextdata)(mp.CONTEXT_DATA_NEWLYCREATEDHINT) ~= true then
return mp.CLEAN
end
if mp.HEADERPAGE_SZ < 1024 then
return mp.CLEAN
end
if (mp.readu_u32)(headerpage, 1) ~= 67324752 then
return mp.CLEAN
end
if (mp.bitand)((mp.readu_u16)(headerpage, 7), 1) ~= 1 then
return mp.CLEAN
end
local l_0_2 = function(l_2_0)
-- function num : 0_1 , upvalues : l_0_0
if (mp.readu_u32)(footerpage, l_2_0 + 1) == 33639248 and l_2_0 + 48 < mp.FOOTERPAGE_SZ then
local l_2_1 = 47
local l_2_2 = (mp.readu_u16)(footerpage, l_2_0 + 29)
if (mp.bitand)((mp.readu_u16)(footerpage, l_2_0 + 9), 1) == 1 and l_2_2 > 4 and l_2_0 + l_2_1 + l_2_2 < mp.FOOTERPAGE_SZ and l_0_0(footerpage, l_2_0 + l_2_1 + l_2_2 - 4) then
return true, 0
end
local l_2_3 = l_2_0 + l_2_1 + l_2_2 + (mp.readu_u16)(footerpage, l_2_0 + 31) - 1
return false, l_2_3
end
end
local l_0_3 = 31
if (mp.readu_u16)(headerpage, 27) > 4 and l_0_3 + (mp.readu_u16)(headerpage, 27) < mp.HEADERPAGE_SZ and l_0_0(headerpage, l_0_3 + (mp.readu_u16)(headerpage, 27) - 4) then
(mp.set_mpattribute)("Lua:ZipHasEncryptedFileWithExeExtension")
return mp.CLEAN
end
local l_0_4 = nil
local l_0_5 = (mp.getfilesize)()
do
if (mp.readu_u32)(footerpage, mp.FOOTERPAGE_SZ - 21) ~= 101010256 then
local l_0_6 = nil
if (tostring(footerpage)):find("PK\005\006", 1, true) == nil then
return mp.CLEAN
end
end
-- DECOMPILER ERROR at PC121: Confused about usage of register: R5 in 'UnsetPending'
local l_0_7 = nil
local l_0_8 = (mp.readu_u32)(footerpage, l_0_6 + 16)
-- DECOMPILER ERROR at PC128: Overwrote pending register: R7 in 'AssignReg'
-- DECOMPILER ERROR at PC133: Overwrote pending register: R7 in 'AssignReg'
if l_0_5 < mp.FOOTERPAGE_SZ then
local l_0_9 = 0
do
local l_0_10 = 0
while 1 do
-- DECOMPILER ERROR at PC147: Overwrote pending register: R9 in 'AssignReg'
if l_0_10 < 3 and l_0_9 + 4 < mp.FOOTERPAGE_SZ then
if nil then
(mp.set_mpattribute)("Lua:ZipHasEncryptedFileWithExeExtension")
return mp.CLEAN
end
l_0_10 = l_0_10 + 1
-- DECOMPILER ERROR at PC158: LeaveBlock: unexpected jumping out IF_THEN_STMT
-- DECOMPILER ERROR at PC158: LeaveBlock: unexpected jumping out IF_STMT
end
end
do return mp.CLEAN end
-- DECOMPILER ERROR at PC162: freeLocal<0 in 'ReleaseLocals'
end
end
end
反编译的代码实际上还存在一定的错误,例如1_1_2
参数,其实代表这一系列文件后缀的集合,因为其中是ASCII编码:
因此函数1_1_0
则代表这当参数是以下后缀时将返回True
.bat, .cmd, .com, .cpl, .exe, .pif, .scr, .vbs, .lnk, .wsf, .vbe, .jse, .hta, .js, .dll, .ocx, .jar, .wsc, .wsh
回到主代码中,我们可以看到会有如下判断:
if not (mp.IsHipsRuleEnabled)("be9ba2d9-53ea-4cdc-84e5-9b1eeee46550") then
return mp.CLEAN
来判断该GUID是否被启动,只有这条规则触发后才会进入后续步骤,随后检查被调用的原因,例如SCANREASON_ONMODIFIEDHANDLECLOSE
,随后检查标题页大小、并且还会判断footerpage
是否包含ZIP压缩包(PK\005\006)
其实在这里可以很明显的知道,Lua引擎能够调用在MpEngine.DLL
中实现的函数,IsHipsRuleEnabled
对应的函数就是在该DLL中的mp_lua_IsHipsRuleEnabled
并且最后会通过调用:
(mp.set_mpattribute)("Lua:ZipHasEncryptedFileWithExeExtension")
设置一个mp属性,这里判断是得到加密文件的Hash从而判断是否匹配恶意文件,同时这个属性可以方便后续重用检查工作
最后我们和这条ASR给出的规则描述进行对比:
可以看到规则描述的后缀均在lua代码中进行匹配,并且还有一些没有提及的后缀同样会进行匹配
0x06.Lua 规则分类
在笔者将Version: 1.377.965.0
的Defender更新规则的所有LUA脚本提取后
可以对这些脚本进行一个简单的分类处理,分为如下一些单元:
- 1.Infrastructure Lua
- 2.Malware scanning Lua
- 3.Helpers Lua
- 4.Lolbins Lua
- 5.ASR lua
- ..etc
下面我们依次提供一部分例子以供说明
Infrastructure Lua
顾名思义,其就是一些utils函数,例如RestoreRegValueDataFromAnotherRegValueAsString
,从给定的注册表项中查询保存后删除原有表项
又如FixHostsFile
函数来检查一些配置和主机的hosts文件
Malware scanning Lua
该脚本用于检查已知的恶意文件签名或者行为,并且这里会对行为进行打分,这里贴出该Lua:
-- Decompiled using luadec 2.2 rev: 895d923 for Lua 5.1 from https://github.com/viruscamp/luadec
-- Command line: ./lua/21951.luac
-- params : ...
-- function num : 0
do
if ((((((((((mp.get_mpattribute)("SCRIPT:PowerShell/Mikatz!dllcheck") and not (mp.get_mpattribute)("SCRIPT:PowerShell/Mikatz!MachineType")) or (mp.get_mpattribute)("SCRIPT:PowerShell/Mikatz!MagicType")) and not (mp.get_mpattribute)("SCRIPT:PowerShell/Mikatz!VirtualAlloc")) or (mp.get_mpattribute)("SCRIPT:PowerShell/Mikatz!memcpy")) and not (mp.get_mpattribute)("SCRIPT:PowerShell/Mikatz!CreateThread")) or (mp.get_mpattribute)("SCRIPT:PowerShell/Mikatz!IsWow64Process")) and not (mp.get_mpattribute)("SCRIPT:PowerShell/Mikatz!WriteShellCode")) or (mp.get_mpattribute)("SCRIPT:PowerShell/Mikatz!GetProcAddressSCx64")) and not (mp.get_mpattribute)("SCRIPT:PowerShell/Mikatz!GetProcAddressSCx86")) or (mp.get_mpattribute)("SCRIPT:PowerShell/Mikatz!Invoke") then
local l_0_0, l_0_1, l_0_2, l_0_3, l_0_4, l_0_5 = 0 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1
end
-- DECOMPILER ERROR at PC78: Confused about usage of register: R0 in 'UnsetPending'
if l_0_0 >= 4 then
(mp.set_mpattribute)("Lua:Powershell/MemCodeInject.A:4")
end
-- DECOMPILER ERROR at PC84: Confused about usage of register: R0 in 'UnsetPending'
if l_0_0 >= 6 then
(mp.set_mpattribute)("Lua:Powershell/MemCodeInject.A:6")
end
-- DECOMPILER ERROR at PC90: Confused about usage of register: R0 in 'UnsetPending'
if l_0_0 >= 8 then
(mp.set_mpattribute)("Lua:Powershell/MemCodeInject.A:8")
end
-- DECOMPILER ERROR at PC96: Confused about usage of register: R0 in 'UnsetPending'
if l_0_0 >= 10 then
return mp.INFECTED
end
return mp.CLEAN
end
这里可以很明显的看出,只有当特征达到一定分数,在这里为10分时,才会返回mp.INFECTED
,代表确认检测为恶意行为,一些检测项包括dllcheck
、MachineType
、VirtualAlloc
、memcpy
、CreateThread
等非常常见的注入API,并且根据分数来对行为进行评级处理,例如大于6分时,设置为Powershell/MemCodeInject.A:6
Helpers Lua
这一部分脚本和Infrastructure Lua
类似,也是提供一些封装函数以供调用,例如在阻止 Office 应用程序创建可执行内容
这一项ASR规则中
这里就需要判断哪些是Office应用,在这里顺便解答了之前遗留的问题,我们来看一下Defender是如何检测和判断Office应用的:
这里有一段代码判断,GetCtxOfficeProc
如果返回不是productivity
,便不在向下继续,我们跟进到这个函数:
GetCtxOfficeProc = function()
-- function num : 0_0
local l_1_0 = {}
l_1_0["excel.exe"] = "productivity"
l_1_0["onenote.exe"] = "productivity"
l_1_0["outlook.exe"] = "communication"
l_1_0["powerpnt.exe"] = "productivity"
l_1_0["winword.exe"] = "productivity"
l_1_0["lync.exe"] = "communication2"
l_1_0["msaccess.exe"] = "productivity2"
l_1_0["mspub.exe"] = "productivity2"
l_1_0["visio.exe"] = "productivity2"
local l_1_1 = (mp.get_contextdata)(mp.CONTEXT_DATA_PROCESSNAME)
l_1_1 = (l_1_1 == nil and "" or l_1_1):lower()
if l_1_0[l_1_1] == nil and not isOutlookProcess(l_1_1) then
return ""
end
local l_1_2 = (MpCommon.PathToWin32Path)((mp.get_contextdata)(mp.CONTEXT_DATA_PROCESSDEVICEPATH))
l_1_2 = (l_1_2 == nil and "" or l_1_2):lower()
local l_1_3 = (mp.ContextualExpandEnvironmentVariables)("%programfiles%")
l_1_3 = (l_1_3 == nil and "" or l_1_3):lower()
local l_1_4 = (mp.ContextualExpandEnvironmentVariables)("%programfiles(x86)%")
l_1_4 = (l_1_4 == nil and "" or l_1_4):lower()
if l_1_2 == l_1_3 .. "\\microsoft office\\root\\office14" or l_1_2 == l_1_3 .. "\\microsoft office\\root\\office15" or l_1_2 == l_1_3 .. "\\microsoft office\\root\\office16" or l_1_2 == l_1_3 .. "\\microsoft office\\office14" or l_1_2 == l_1_3 .. "\\microsoft office\\office15" or l_1_2 == l_1_3 .. "\\microsoft office\\office16" or l_1_2 == l_1_4 .. "\\microsoft office\\root\\office14" or l_1_2 == l_1_4 .. "\\microsoft office\\root\\office15" or l_1_2 == l_1_4 .. "\\microsoft office\\root\\office16" or l_1_2 == l_1_4 .. "\\microsoft office\\office14" or l_1_2 == l_1_4 .. "\\microsoft office\\office15" or l_1_2 == l_1_4 .. "\\microsoft office\\office16" or l_1_2:find(l_1_3 .. "\\windowsapps\\microsoft.office.desktop.", 1, true) ~= nil or l_1_2:find(l_1_4 .. "\\windowsapps\\microsoft.office.desktop.", 1, true) ~= nil then
return l_1_0[l_1_1]
end
return ""
end
可以看到根据PROCESSDEVICEPATH
是否在%programfiles(x86)%\microsoft
或者%programfiles(x86)%\windowsapps
那几个特定目录中,并且判断进程名是否是excel.exe/onenote.exe/powerpnt.exe/winword.exe
,从而来判断特定的office应用,其实也算是一套标准的正则匹配来定位的
0x07. ASR Bypass
上文探讨了关于ASR规则的详细说明,这里我们来扩展一下对于开启ASR后的Bypass方式,在这里我们以阻止从 Windows 本地安全机构子系统窃取凭据该规则为例,对应的GUID为9e6c4e1f-7d60-472f-ba1a-a39ef669e4b2
先来观察其说明
在配置ASR规则时微软给出了以下几种方式:
- 1.Microsoft Endpoint Manager
- 2.组策略
- 3.PowerShell cmdlet
在这里我们使用最方便的cmdlet来启用ASR,使用PowerShell在审核模式下启用 ASR 规则,以查看在功能完全启用时会被阻止的应用的记录。 还可以了解规则在正常使用期间触发的频率。
若要在审核模式下启用攻击面减少规则,请使用以下 PowerShell cmdlet:
Add-MpPreference -AttackSurfaceReductionRules_Ids <rule ID> -AttackSurfaceReductionRules_Actions AuditMode
这里Lsass保护对应的GUID为:9e6c4e1f-7d60-472f-ba1a-a39ef669e4b2
在没有开启ASR规则时可以看到,虽然Defender检测到恶意行为,但不会对其进行拦截,因为在这里使用了已开源的工具,并且静默退出涉及到操作注册表,存在一定风险
如果使用其他方法则不会存在影响:
当我们开启这个ASR规则,并设置为Enabled
后:
此时无法Dump Lsass进程的内存,该ASR基本上防止了极大部分对于Lsass Dump的手段和方式,其中在日志管理器中也能够看到对应ASR的日志:
转移到对应9e6c4e1f-7d60-472f-ba1a-a39ef669e4b2.lua
中我们来查看一下相关规则:
GetRuleInfo = function()
-- function num : 0_0
local l_1_0 = {}
l_1_0.Name = "Block credential stealing from the Windows local security authority subsystem (lsass.exe)"
l_1_0.Description = "Windows Defender Exploit Guard detected an attempt to extract credentials from LSASS."
l_1_0.NotificationDedupingInterval = 14400
l_1_0.NotificationDedupingScope = HIPS.DEDUPE_SCOPE_ALL
return l_1_0
end
GetMonitoredLocations = function()
-- function num : 0_1
local l_2_0 = {}
l_2_0["%windir%\\system32\\lsass.exe"] = 2
return 7, l_2_0
end
GetPathExclusions = function()
-- function num : 0_2
local l_3_0 = {}
l_3_0["%windir%\\system32\\WerFaultSecure.exe"] = 2
l_3_0["%windir%\\system32\\mrt.exe"] = 2
l_3_0["%windir%\\system32\\svchost.exe"] = 2
l_3_0["%windir%\\system32\\wbem\\WmiPrvSE.exe"] = 2
l_3_0["%windir%\\SysWOW64\\wbem\\WmiPrvSE.exe"] = 2
l_3_0["%windir%\\system32\\DriverStore\\FileRepository\\*\\NVWMI\\nvWmi64.exe"] = 2
l_3_0["%programfiles(x86)%\\Microsoft Intune Management Extension\\ClientHealthEval.exe"] = 2
l_3_0["%programfiles(x86)%\\Microsoft Intune Management Extension\\SensorLogonTask.exe"] = 2
l_3_0["%programfiles(x86)%\\Microsoft Intune Management Extension\\Microsoft.Management.Services.IntuneWindowsAgent.exe"] = 2
l_3_0["%programdata%\\Microsoft\\Windows Defender Advanced Threat Protection\\DataCollection\\*\\OpenHandleCollector.exe"] = 2
l_3_0["%programfiles%\\WindowsApps\\Microsoft.GamingServices_*\\gamingservices.exe"] = 2
l_3_0["%programfiles(x86)%\\Cisco\\Cisco AnyConnect Secure Mobility Client\\vpnagent.exe"] = 2
l_3_0["%programfiles(x86)%\\Zoom\\bin\\CptHost.exe"] = 2
l_3_0["%programfiles(x86)%\\Microsoft\\EdgeUpdate\\MicrosoftEdgeUpdate.exe"] = 2
l_3_0["%programfiles(x86)%\\Microsoft\\Edge\\Application\\*\\Installer\\setup.exe"] = 2
l_3_0["%programfiles(x86)%\\Google\\Update\\GoogleUpdate.exe"] = 2
l_3_0["%programfiles(x86)%\\Splunk\\bin\\splunkd.exe"] = 2
l_3_0["%programfiles(x86)%\\Zscaler\\ZSAUpm\\ZSAUpm.exe"] = 2
l_3_0["%programfiles(x86)%\\Fortinet\\FortiClient\\FortiESNAC.exe"] = 2
l_3_0["%programfiles(x86)%\\FireEye\\xagt\\xagt.exe"] = 2
l_3_0["%programfiles(x86)%\\Autodesk\\Autodesk Desktop App\\AdAppMgrSvc.exe"] = 2
l_3_0["%programfiles(x86)%\\Dropbox\\Update\\DropboxUpdate.exe"] = 2
l_3_0["%programfiles(x86)%\\HP\\HP Touchpoint Analytics Client\\Provider Data Sources\\ProcInfo\\ProcInfo.exe"] = 2
l_3_0["%programfiles(x86)%\\Common Files\\Adobe\\AdobeGCClient\\AGMService.exe"] = 2
l_3_0["%programfiles(x86)%\\Tanium\\Tanium Client\\Tools\\Detect3\\TaniumDetectEngine.exe"] = 2
l_3_0["%programfiles(x86)%\\Airwatch\\AgentUI\\AWProcessCommands.exe"] = 2
l_3_0["%programfiles(x86)%\\Bit9\\Parity Agent\\Parity.exe"] = 2
l_3_0["%programfiles(x86)%\\Arctic Wolf Networks\\Agent\\ossec-agent.exe"] = 2
l_3_0["%programfiles(x86)%\\Cordaware\\Infoband\\Infoclient.exe"] = 2
l_3_0["%programfiles(x86)%\\Splunk\\bin\\splunk-regmon.exe"] = 2
l_3_0["%programfiles(x86)%\\Lenovo\\VantageService\\*\\LenovoVantage-(LenovoBoostSystemAddin).exe"] = 2
l_3_0["%programfiles(x86)%\\Micro Focus\\Discovery Agent\\bin32\\discagnt.exe"] = 2
l_3_0["%programfiles(x86)%\\Hewlett-Packard\\Discovery Agent\\bin32\\discagnt.exe"] = 2
l_3_0["%programfiles(x86)%\\Micro Focus\\Discovery Agent\\Plugins\\usage\\discusge.exe"] = 2
l_3_0["%programfiles(x86)%\\Hewlett-Packard\\Discovery Agent\\Plugins\\usage\\discusge.exe"] = 2
l_3_0["%programfiles%\\Avecto\\Privilege Guard Client\\DefendpointService.exe"] = 2
l_3_0["%programfiles%\\Intel\\SUR\\QUEENCREEK\\x64\\esrv_svc.exe"] = 2
l_3_0["%programfiles%\\Microsoft Monitoring Agent\\Agent\\HealthService.exe"] = 2
l_3_0["%programfiles%\\Microsoft Monitoring Agent\\Agent\\MOMPerfSnapshotHelper.exe"] = 2
l_3_0["%programfiles%\\Nexthink\\Collector\\Collector\\nxtsvc.exe"] = 2
l_3_0["%programfiles%\\Splunk\\bin\\splunkd.exe"] = 2
l_3_0["%programfiles%\\Azure Advanced Threat Protection Sensor\\*\\Microsoft.Tri.Sensor.Updater.exe"] = 2
l_3_0["%programfiles%\\common files\\microsoft shared\\ClickToRun\\Updates\\*\\OfficeClickToRun.exe"] = 2
l_3_0["%programfiles%\\Zscaler\\ZSAUpm\\ZSAUpm.exe"] = 2
l_3_0["%programfiles%\\Fortinet\\FortiClient\\FortiESNAC.exe"] = 2
l_3_0["%programfiles%\\FireEye\\xagt\\xagt.exe"] = 2
l_3_0["%programfiles%\\Autodesk\\Autodesk Desktop App\\AdAppMgrSvc.exe"] = 2
l_3_0["%programfiles%\\Qualys\\QualysAgent\\QualysAgent.exe"] = 2
l_3_0["%programfiles%\\Altiris\\Altiris Agent\\AeXNSAgent.exe"] = 2
l_3_0["%programfiles%\\VMware\\VMware Tools\\vmtoolsd.exe"] = 2
l_3_0["%programfiles%\\Dell\\DTP\\InstrumentationSubAgent\\Dell.TechHub.Instrumentation.SubAgent.exe"] = 2
l_3_0["%programfiles%\\Rapid7\\Insight Agent\\components\\insight_agent\\*\\ir_agent.exe"] = 2
l_3_0["%programfiles%\\Microsoft RDInfra\\RDMonitoringAgent_*\\Agent\\MonAgentCore.exe"] = 2
l_3_0["%programfiles%\\BMCSoftware\\Client Management\\Client\\bin\\mtxagent.exe"] = 2
l_3_0["%programfiles%\\DisplayLink Core Software\\DisplayLinkHotDeskService.exe"] = 2
l_3_0["%programfiles%\\ManageSoft\\Tracker\\ndtrack.exe"] = 2
l_3_0["C:\\Packages\\Plugins\\Microsoft.Azure.Diagnostics.IaaSDiagnostics\\*\\Monitor\\x64\\MonAgentCore.exe"] = 2
l_3_0["%windir%\\CCM\\CcmExec.exe"] = 2
l_3_0["%windir%\\CCM\\SensorLogonTask.exe"] = 2
l_3_0["%windir%\\System32\\DriverStore\\FileRepository\\hpanalyticscomp.*\\x64\\Provider Data Sources\\ProcInfo\\ProcInfo.exe"] = 2
l_3_0["%windir%\\system32\\RtkAudUService64.exe"] = 2
l_3_0["%windir%\\Temp\\Ctx-*\\Extract\\TrolleyExpress.exe"] = 2
l_3_0["%programdata%\\Citrix\\Citrix Receiver*\\TrolleyExpress.exe"] = 2
l_3_0["%programdata%\\Citrix\\Citrix Workspace *\\TrolleyExpress.exe"] = 2
l_3_0["%programfiles(x86)%\\Citrix\\Citrix Workspace *\\TrolleyExpress.exe"] = 2
l_3_0["%temp%\\Ctx-*\\Extract\\TrolleyExpress.exe"] = 2
l_3_0["%programfiles%\\Quest\\ChangeAuditor\\Agent\\NPSrvHost.exe"] = 2
l_3_0["%programfiles%\\Quest\\ChangeAuditor\\Service\\ChangeAuditor.Service.exe"] = 2
l_3_0["%windir%\\system32\\DriverStore\\FileRepository\\hpqkbsoftwarecompnent.inf_amd64_*\\HotKeyServiceUWP.exe"] = 2
l_3_0["%windir%\\system32\\CompatTelRunner.exe"] = 2
l_3_0["%programfiles(x86)%\\Printer Properties Pro\\Printer Installer Client\\PrinterInstallerClient.exe"] = 2
l_3_0["%programfiles%\\Printer Properties Pro\\Printer Installer Client\\PrinterInstallerClient.exe"] = 2
l_3_0["%programfiles(x86)%\\Zscaler\\ZSATunnel\\ZSATunnel.exe"] = 2
l_3_0["%programfiles%\\Zscaler\\ZSATunnel\\ZSATunnel.exe"] = 2
l_3_0["%programfiles(x86)%\\ManageSoft\\Security Agent\\mgssecsvc.exe"] = 2
l_3_0["%programfiles%\\ManageSoft\\Security Agent\\mgssecsvc.exe"] = 2
l_3_0["%programfiles(x86)%\\Snow Software\\Inventory\\Agent\\snowagent.exe"] = 2
l_3_0["%programfiles%\\Snow Software\\Inventory\\Agent\\snowagent.exe"] = 2
l_3_0["c:\\windows\\system32\\WerFaultSecure.exe"] = 2
l_3_0["c:\\windows\\system32\\wbem\\WmiPrvSE.exe"] = 2
l_3_0["c:\\windows\\SysWOW64\\wbem\\WmiPrvSE.exe"] = 2
l_3_0["\\Device\\HarddiskVolume?\\Windows\\System32\\svchost.exe"] = 2
l_3_0["\\Device\\HarddiskVolume?\\Windows\\System32\\wbem\\wmiprvse.exe"] = 2
l_3_0["%windir%\\system32\fsiso.exe"] = 2
return l_3_0
end
GetCommandLineExclusions = function()
-- function num : 0_3
local l_4_0 = "^\\\"?.:\\\\windows\\\\system32\\\\werfault\\.exe\\\"?((?!\\-s).)*$"
local l_4_1 = {}
l_4_1[l_4_0] = 0
return l_4_1
end
自然将目光放到了PathExclusions
中,在之前关于Windows Defender的对抗中,部分免杀手段也是与排除项有关,放到特定的目录下,从而来避免Defender的扫描,在lua脚本中我们可以很清晰的看到所有的排除项,这里以%programfiles(x86)%\\Zoom\\bin\\CptHost.exe
为例,将文件伪装成CptHost.exe
:
此时开启ASR,由于该文件在排除项中,而排除项是通过正则进行匹配的,因此能够绕过ASR,实现Dump Lsass
值得注意的是,在Defender的检测实现中,很多规则也是依赖于父子进程的关系和CommandLine来判断的,例如对于winrm的判断:
因此父进程欺骗、Argue spoof等老手段对于Defender检测的绕过不失为一种有效的方式
0x08. ASR features
这里顺便记录一下一些关于ASR规则,个人觉得较为奇葩的一些规则,并且理论上是可以用来绕过的(搞不懂你软的逻辑)
在阻止电子邮件客户端和 Webmail 中的可执行内容的ASR规则中,前文做过涉及,但让我们重新审视一下:
来看一下这个函数:
再者阻止可执行文件运行,除非它们满足普遍性、年龄或受信任的列表条件,此规则阻止可执行文件(如 .exe、.dll 或 .scr)启动。 因此,启动不受信任或未知的可执行文件可能会有风险,因为最初可能不清楚这些文件是否为恶意文件,对应GUID为01443614-cd74-433a-b99e-2ecdc07bfc25
个人认为这是防护等级最高的一个ASR规则,但同样存在可能绕过的地方:
个人认为Defender在规则中加入了硬编码默认的排除项,此举实际上是为了方便用户,减小误报的概率,但很多时候可以被滥用,排除项的滥用在此前应该出现了很多方式
对于Defender的ASR研究和审计工作可能止步于此,后续可能会对Defender其他方面进行研究,另外参考国外文献较多,个人能力有限,若有不对之处方请谅解。
反汇编的Lua合集
暂时设置为Private,后续会公开
https://github.com/crisprss/Extracted_WD_VDM
参考
us-18-Bulazel-Windows-Offender-Reverse-Engineering-Windows-Defenders-Antivirus-Emulator
RECON-BRX-2018-Reverse-Engineering-Windows-Defender-s-JavaScript-Engine
EU-21-Mougey-Windows-Defender-demystifying-and-bypassing-asr-by-understanding-the-avs-signatures